144 lines
3.4 KiB
TypeScript
144 lines
3.4 KiB
TypeScript
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<string, string> = {
|
|
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<string, unknown>;
|
|
|
|
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;
|
|
}
|