export const BILL_NOT_FOUND = "Bill not found yet. If you just received the SMS, wait a moment and refresh."; export type BillLine = { description: string; qty: number | string | null; unitPrice: number; lineTotal: number; }; export type BillView = { shopName: string; address: string; phone: string; number: string; createdAt: string; customerName: string; customerPhone: string; vehicleReg: string; vehicleModel: string; lines: BillLine[]; total: number; paymentMethod: string; }; function isRecord(value: unknown): value is Record { return !!value && typeof value === "object" && !Array.isArray(value); } function asString(value: unknown): string { return typeof value === "string" ? value : ""; } function asNumber(value: unknown): number { return typeof value === "number" && Number.isFinite(value) ? value : 0; } export function parseBill(raw: string): BillView | null { let data: unknown; try { data = JSON.parse(raw); } catch { return null; } if (!isRecord(data)) return null; const lines = Array.isArray(data.lines) ? data.lines.filter(isRecord) : []; return { shopName: asString(data.shopName), address: asString(data.address), phone: asString(data.phone), number: asString(data.number), createdAt: asString(data.createdAt), customerName: asString(data.customerName), customerPhone: asString(data.customerPhone), vehicleReg: asString(data.vehicleReg), vehicleModel: asString(data.vehicleModel), lines: lines.map((line) => ({ description: asString(line.description), qty: typeof line.qty === "number" || typeof line.qty === "string" ? line.qty : null, unitPrice: asNumber(line.unitPrice), lineTotal: asNumber(line.lineTotal), })), total: asNumber(data.total), paymentMethod: asString(data.paymentMethod), }; } export function formatBillDate(iso: string): string { if (!iso) return ""; const date = new Date(iso); if (Number.isNaN(date.getTime())) return ""; return date.toLocaleString("en-LK", { timeZone: "Asia/Colombo" }); }