From 31205a44f9a2adb908a4e411d957527021dff475 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Wed, 29 Apr 2026 15:55:22 +0700 Subject: [PATCH] feat: add new context to CLAUDE.md --- CLAUDE.md | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index b1025264..d0a2f23c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -160,3 +160,62 @@ const handleFilterLocationChange = useCallback( - `SupplierTable`, `KandangsTable`, `LocationsTable`, `CustomersTable` in `src/components/pages/master-data/` - Use same pattern for data tables in other modules (inventory, finance, purchase, etc.) + +## Server-side file export pattern + +All file exports (Excel, PDF, or any format) must use **server-side generation** — the server returns a binary blob and the browser triggers a download. Never generate files client-side with `xlsx`, `@react-pdf/renderer`, `jspdf`, or similar libraries. + +**Rule:** Export methods live in the API service class, not in components. Components only build the query string and call the service method. + +### Service method (in `src/services/api/{feature}.ts`) + +```ts +async exportToExcel(initialQueryString: string) { + const params = new URLSearchParams(initialQueryString); + + params.set('export', 'excel'); // or 'pdf', 'csv', etc. + params.set('page', '1'); + params.set('limit', '99999999999'); + + const res = await httpClient(`${this.basePath}?${params.toString()}`, { + method: 'GET', + responseType: 'blob', + }); + + const url = window.URL.createObjectURL(new Blob([res])); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', `filename-${formatDate(Date.now(), 'DD-MM-YYYY')}.xlsx`); + document.body.appendChild(link); + link.click(); + link.remove(); +} +``` + +- Change `export=excel` → `export=pdf` (and the file extension) for PDF exports. +- Add one method per format; keep them side-by-side in the same service class. + +### Component handler (in the page/tab component) + +```ts +const handleExportExcel = useCallback(async () => { + setIsExcelExportLoading(true); + try { + const params = new URLSearchParams(); + if (filterParams.foo) params.set('foo', filterParams.foo); + // ... map all active filter params ... + + await FeatureApi.exportToExcel(params.toString()); + toast.success('Excel berhasil dibuat dan diunduh.'); + } catch { + toast.error('Gagal membuat Excel. Silakan coba lagi.'); + } finally { + setIsExcelExportLoading(false); + } +}, [filterParams, searchValue]); +``` + +- Do **not** fetch all rows into the component to build the file — delegate entirely to the service method. +- Do **not** import `xlsx`, `@react-pdf/renderer`, `jspdf`, `exceljs` in page/tab components. + +**Reference implementation:** `MarketingReportApiService.exportDailyMarketingToExcel` / `exportDailyMarketingToPDF` in [src/services/api/report/marketing-report.ts](src/services/api/report/marketing-report.ts), consumed by [src/components/pages/report/marketing/tab/DailyMarketingTab.tsx](src/components/pages/report/marketing/tab/DailyMarketingTab.tsx).