57 lines
1.4 KiB
TypeScript
57 lines
1.4 KiB
TypeScript
export class CheckoutPrice {
|
|
private constructor(private readonly amountUsd: number) {
|
|
if (amountUsd < 0) {
|
|
throw new Error('Price cannot be negative');
|
|
}
|
|
if (amountUsd > 10000) {
|
|
throw new Error('Price exceeds maximum of $10,000');
|
|
}
|
|
}
|
|
|
|
static fromString(priceStr: string): CheckoutPrice {
|
|
const trimmed = priceStr.trim();
|
|
|
|
if (!trimmed.startsWith('$')) {
|
|
throw new Error('Invalid price format: missing dollar sign');
|
|
}
|
|
|
|
const dollarSignCount = (trimmed.match(/\$/g) || []).length;
|
|
if (dollarSignCount > 1) {
|
|
throw new Error('Invalid price format: multiple dollar signs');
|
|
}
|
|
|
|
const numericPart = trimmed.substring(1).replace(/,/g, '');
|
|
|
|
if (numericPart === '') {
|
|
throw new Error('Invalid price format: no numeric value');
|
|
}
|
|
|
|
const amount = parseFloat(numericPart);
|
|
|
|
if (isNaN(amount)) {
|
|
throw new Error('Invalid price format: not a valid number');
|
|
}
|
|
|
|
return new CheckoutPrice(amount);
|
|
}
|
|
|
|
/**
|
|
* Factory for a neutral/zero checkout price.
|
|
* Used when no explicit price can be extracted from the DOM.
|
|
*/
|
|
static zero(): CheckoutPrice {
|
|
return new CheckoutPrice(0);
|
|
}
|
|
|
|
toDisplayString(): string {
|
|
return `$${this.amountUsd.toFixed(2)}`;
|
|
}
|
|
|
|
getAmount(): number {
|
|
return this.amountUsd;
|
|
}
|
|
|
|
isZero(): boolean {
|
|
return this.amountUsd < 0.001;
|
|
}
|
|
} |