const EMPTY_TABLE_FALLBACK = [['-']]; function normalizeNumber( amount: number | string | null | undefined ): number | null { if (typeof amount === 'number' && Number.isFinite(amount)) { return amount; } if (typeof amount === 'string') { const normalized = Number(amount.replaceAll(',', '').trim()); return Number.isFinite(normalized) ? normalized : null; } return null; } export function formatPdfDate( dateString: string | Date | null | undefined, language: 'th' | 'en' = 'en' ): string { if (!dateString) { return '-'; } const date = dateString instanceof Date ? dateString : new Date(dateString); if (Number.isNaN(date.getTime())) { return '-'; } if (language === 'th') { return date.toLocaleDateString('th-TH', { day: 'numeric', month: 'short', year: 'numeric', calendar: 'buddhist' }); } return date.toLocaleDateString('en-US', { day: 'numeric', month: 'short', year: 'numeric' }); } export function formatPdfCurrency( amount: number | string | null | undefined, currencyCode = 'THB' ): string { const numericAmount = normalizeNumber(amount); if (numericAmount === null) { return '-'; } const normalizedCode = currencyCode.toUpperCase(); const symbols: Record = { THB: 'THB ', USD: '$', EUR: 'EUR ' }; const symbol = symbols[normalizedCode] ?? `${normalizedCode} `; const formatted = new Intl.NumberFormat('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(numericAmount); return `${symbol}${formatted}`.trim(); } export function formatTopicItems(topic?: { items?: Array<{ content?: string | null; sortOrder?: number | null }> | string[]; }): string[][] { if (!topic?.items?.length) { return EMPTY_TABLE_FALLBACK; } const rows = [...topic.items] .sort((left, right) => { if (typeof left === 'string' || typeof right === 'string') { return 0; } return (left.sortOrder ?? Number.MAX_SAFE_INTEGER) - (right.sortOrder ?? Number.MAX_SAFE_INTEGER); }) .map((item) => { if (typeof item === 'string') { return item.trim() || '-'; } return item?.content?.trim() || '-'; }) .filter(Boolean) .map((content) => [content]); return rows.length ? rows : EMPTY_TABLE_FALLBACK; } export function normalizePdfmeTable( value: unknown, columns?: Array<{ sourceField: string; formatMask?: string | null }> ): string[][] { if (!Array.isArray(value) || value.length === 0) { return EMPTY_TABLE_FALLBACK; } if (value.every((row) => Array.isArray(row))) { const normalizedRows = value.map((row) => (row as unknown[]).map((cell) => { const stringValue = String(cell ?? '').trim(); return stringValue || '-'; }) ); return normalizedRows.length ? normalizedRows : EMPTY_TABLE_FALLBACK; } if (!columns?.length) { return value.map((row) => [String(row ?? '').trim() || '-']) || EMPTY_TABLE_FALLBACK; } const rows = value.map((row) => { const rowRecord = row as Record; return columns.map((column) => { const cell = rowRecord[column.sourceField]; if (typeof cell === 'number' || typeof cell === 'string') { return String(cell).trim() || '-'; } if (cell === null || cell === undefined) { return '-'; } return String(cell).trim() || '-'; }); }); return rows.length ? rows : EMPTY_TABLE_FALLBACK; }