Files
gridpilot.gg/apps/website/lib/view-models/BillingViewModel.ts
Marc Mintel d97f50ed72
Some checks failed
Contract Testing / contract-tests (pull_request) Failing after 6m4s
Contract Testing / contract-snapshot (pull_request) Has been skipped
view data fixes
2026-01-23 11:59:49 +01:00

185 lines
5.7 KiB
TypeScript

/**
* Billing View Model
*
* View model for sponsor billing data with UI-specific transformations.
* Transforms BillingViewData into UI-ready state with formatting and derived fields.
*/
import type { BillingViewData } from '@/lib/view-data/BillingViewData';
import { ViewModel } from "../contracts/view-models/ViewModel";
import { CurrencyDisplay } from "../display-objects/CurrencyDisplay";
import { DateDisplay } from "../display-objects/DateDisplay";
/**
* BillingViewModel
*
* View Model for sponsor billing data.
* Transforms BillingViewData into UI-ready state with formatting and derived fields.
*/
export class BillingViewModel extends ViewModel {
paymentMethods: PaymentMethodViewModel[];
invoices: InvoiceViewModel[];
stats: BillingStatsViewModel;
constructor(viewData: BillingViewData) {
super();
this.paymentMethods = viewData.paymentMethods.map(pm => new PaymentMethodViewModel(pm));
this.invoices = viewData.invoices.map(inv => new InvoiceViewModel(inv));
this.stats = new BillingStatsViewModel(viewData.stats);
}
}
/**
* PaymentMethodViewModel
*
* View Model for payment method data.
* Provides formatted display labels and expiry information.
*/
export class PaymentMethodViewModel extends ViewModel {
id: string;
type: 'card' | 'bank' | 'sepa';
last4: string;
brand?: string;
isDefault: boolean;
expiryMonth?: number;
expiryYear?: number;
bankName?: string;
// UI-specific derived fields (primitive outputs only)
readonly displayLabel: string;
readonly expiryDisplay: string | null;
constructor(viewData: {
id: string;
type: 'card' | 'bank' | 'sepa';
last4: string;
brand?: string;
isDefault: boolean;
expiryMonth?: number;
expiryYear?: number;
bankName?: string;
displayLabel: string;
expiryDisplay: string | null;
}) {
super();
this.id = viewData.id;
this.type = viewData.type;
this.last4 = viewData.last4;
this.brand = viewData.brand;
this.isDefault = viewData.isDefault;
this.expiryMonth = viewData.expiryMonth;
this.expiryYear = viewData.expiryYear;
this.bankName = viewData.bankName;
this.displayLabel = viewData.displayLabel;
this.expiryDisplay = viewData.expiryDisplay;
}
}
/**
* InvoiceViewModel
*
* View Model for invoice data.
* Provides formatted amounts, dates, and derived status flags.
*/
export class InvoiceViewModel extends ViewModel {
id: string;
invoiceNumber: string;
date: Date;
dueDate: Date;
amount: number;
vatAmount: number;
totalAmount: number;
status: 'paid' | 'pending' | 'overdue' | 'failed';
description: string;
sponsorshipType: 'league' | 'team' | 'driver' | 'race' | 'platform';
pdfUrl: string;
// UI-specific derived fields (primitive outputs only)
readonly formattedTotalAmount: string;
readonly formattedVatAmount: string;
readonly formattedDate: string;
readonly isOverdue: boolean;
constructor(viewData: {
id: string;
invoiceNumber: string;
date: string;
dueDate: string;
amount: number;
vatAmount: number;
totalAmount: number;
status: 'paid' | 'pending' | 'overdue' | 'failed';
description: string;
sponsorshipType: 'league' | 'team' | 'driver' | 'race' | 'platform';
pdfUrl: string;
formattedTotalAmount: string;
formattedVatAmount: string;
formattedDate: string;
isOverdue: boolean;
}) {
super();
this.id = viewData.id;
this.invoiceNumber = viewData.invoiceNumber;
this.date = new Date(viewData.date);
this.dueDate = new Date(viewData.dueDate);
this.amount = viewData.amount;
this.vatAmount = viewData.vatAmount;
this.totalAmount = viewData.totalAmount;
this.status = viewData.status;
this.description = viewData.description;
this.sponsorshipType = viewData.sponsorshipType;
this.pdfUrl = viewData.pdfUrl;
this.formattedTotalAmount = viewData.formattedTotalAmount;
this.formattedVatAmount = viewData.formattedVatAmount;
this.formattedDate = viewData.formattedDate;
this.isOverdue = viewData.isOverdue;
}
}
/**
* BillingStatsViewModel
*
* View Model for billing statistics.
* Provides formatted monetary fields and derived metrics.
*/
export class BillingStatsViewModel extends ViewModel {
totalSpent: number;
pendingAmount: number;
nextPaymentDate: Date;
nextPaymentAmount: number;
activeSponsorships: number;
averageMonthlySpend: number;
// UI-specific derived fields (primitive outputs only)
readonly formattedTotalSpent: string;
readonly formattedPendingAmount: string;
readonly formattedNextPaymentAmount: string;
readonly formattedAverageMonthlySpend: string;
readonly formattedNextPaymentDate: string;
constructor(viewData: {
totalSpent: number;
pendingAmount: number;
nextPaymentDate: string;
nextPaymentAmount: number;
activeSponsorships: number;
averageMonthlySpend: number;
formattedTotalSpent: string;
formattedPendingAmount: string;
formattedNextPaymentAmount: string;
formattedAverageMonthlySpend: string;
formattedNextPaymentDate: string;
}) {
super();
this.totalSpent = viewData.totalSpent;
this.pendingAmount = viewData.pendingAmount;
this.nextPaymentDate = new Date(viewData.nextPaymentDate);
this.nextPaymentAmount = viewData.nextPaymentAmount;
this.activeSponsorships = viewData.activeSponsorships;
this.averageMonthlySpend = viewData.averageMonthlySpend;
this.formattedTotalSpent = viewData.formattedTotalSpent;
this.formattedPendingAmount = viewData.formattedPendingAmount;
this.formattedNextPaymentAmount = viewData.formattedNextPaymentAmount;
this.formattedAverageMonthlySpend = viewData.formattedAverageMonthlySpend;
this.formattedNextPaymentDate = viewData.formattedNextPaymentDate;
}
}