From 7e6f2508649093804384d6d016bb147c92362e94 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Mon, 25 May 2026 11:28:41 +0700 Subject: [PATCH 1/2] feat: add server-side Excel export to PurchasesPerSupplierTab Add exportToExcelSupplierPerSheet and exportToExcelGeneral methods to LogisticApiService, hitting the existing purchase-supplier endpoint with export=excel / export=excel-all query params and downloading the server blob response. Replace the client-side Excel generation in PurchasesPerSupplierTab with calls to these two service methods, and split the single Export to Excel button into Export to Excel - Supplier Per Sheet and Export to Excel - General. --- .../tab/PurchasesPerSupplierTab.tsx | 65 +++++++--- src/services/api/report/logistic-stock.ts | 111 ++++++++++++++++++ 2 files changed, 160 insertions(+), 16 deletions(-) diff --git a/src/components/pages/report/logistic-stock/tab/PurchasesPerSupplierTab.tsx b/src/components/pages/report/logistic-stock/tab/PurchasesPerSupplierTab.tsx index 9a9bb6c2..cd4f7d3b 100644 --- a/src/components/pages/report/logistic-stock/tab/PurchasesPerSupplierTab.tsx +++ b/src/components/pages/report/logistic-stock/tab/PurchasesPerSupplierTab.tsx @@ -16,7 +16,6 @@ import { LogisticPurchasePerSupplierReport, LogisticPurchasePerSupplierSummary, } from '@/types/api/report/logistic-stock'; -import { generatePurchasesPerSupplierExcel } from '@/components/pages/report/logistic-stock/export/PurchasesPerSupplierExportXLSX'; import { generatePurchasesPerSupplierPDF } from '@/components/pages/report/logistic-stock/export/PurchasesPerSupplierExportPDF'; import { Icon } from '@iconify/react'; import { ColumnDef } from '@tanstack/react-table'; @@ -53,7 +52,10 @@ const PurchasesPerSupplierTab = ({ tabId }: PurchasesPerSupplierTabProps) => { // ===== STATE MANAGEMENT ===== const [isPdfExportLoading, setIsPdfExportLoading] = useState(false); const [isExcelExportLoading, setIsExcelExportLoading] = useState(false); - const isAnyExportLoading = isPdfExportLoading || isExcelExportLoading; + const [isExcelGeneralExportLoading, setIsExcelGeneralExportLoading] = + useState(false); + const isAnyExportLoading = + isPdfExportLoading || isExcelExportLoading || isExcelGeneralExportLoading; // ===== PAGINATION STATE ===== const [currentPage, setCurrentPage] = useState(1); @@ -360,25 +362,44 @@ const PurchasesPerSupplierTab = ({ tabId }: PurchasesPerSupplierTabProps) => { const handleExportExcel = useCallback(async () => { setIsExcelExportLoading(true); try { - const allDataForExport = await logisticPurchasePerSupplierExport(); - - if ( - !allDataForExport || - !Array.isArray(allDataForExport) || - allDataForExport.length === 0 - ) { - toast.error('Tidak ada data untuk diekspor.'); - return; - } - - await generatePurchasesPerSupplierExcel({ data: allDataForExport }); + await LogisticApi.exportToExcelSupplierPerSheet( + filterParams.area_id, + filterParams.supplier_id, + filterParams.product_id, + filterParams.product_category_id, + filterParams.start_date, + filterParams.end_date, + filterParams.sort_by, + filterParams.filter_by + ); toast.success('Excel berhasil dibuat dan diunduh.'); } catch { toast.error('Gagal membuat Excel. Silakan coba lagi.'); } finally { setIsExcelExportLoading(false); } - }, [logisticPurchasePerSupplierExport]); + }, [filterParams]); + + const handleExportExcelGeneral = useCallback(async () => { + setIsExcelGeneralExportLoading(true); + try { + await LogisticApi.exportToExcelGeneral( + filterParams.area_id, + filterParams.supplier_id, + filterParams.product_id, + filterParams.product_category_id, + filterParams.start_date, + filterParams.end_date, + filterParams.sort_by, + filterParams.filter_by + ); + toast.success('Excel General berhasil dibuat dan diunduh.'); + } catch { + toast.error('Gagal membuat Excel General. Silakan coba lagi.'); + } finally { + setIsExcelGeneralExportLoading(false); + } + }, [filterParams]); const handleExportPdf = useCallback(async () => { setIsPdfExportLoading(true); @@ -523,7 +544,17 @@ const PurchasesPerSupplierTab = ({ tabId }: PurchasesPerSupplierTabProps) => { className='w-full p-3 justify-start text-sm text-base-content/50 font-semibold text-nowrap' > - Export to Excel + Export to Excel - Supplier Per Sheet + + + } + > + + ); - }, [tabId, setTabActions, tableFilterState, filterModal.openModal]); + }, [ + tabId, + setTabActions, + tableFilterState, + filterModal.openModal, + isExcelExportLoading, + handleExportExcel, + ]); useEffect(() => { return () => clearTabActions(tabId); diff --git a/src/services/api/report/finance-report.ts b/src/services/api/report/finance-report.ts index 132e3063..171e59d0 100644 --- a/src/services/api/report/finance-report.ts +++ b/src/services/api/report/finance-report.ts @@ -86,6 +86,40 @@ export class FinanceApiService extends BaseApiService< link.remove(); } + async exportBalanceMonitoringToExcel( + customer_ids?: string, + sales_ids?: string, + filter_by?: string, + start_date?: string, + end_date?: string + ) { + const params = new URLSearchParams(); + if (customer_ids) params.set('customer_ids', customer_ids); + if (sales_ids) params.set('sales_ids', sales_ids); + if (filter_by) params.set('filter_by', filter_by); + if (start_date) params.set('start_date', start_date); + if (end_date) params.set('end_date', end_date); + params.set('export', 'excel'); + params.set('page', '1'); + params.set('limit', '9999999999'); + + const res = await httpClient( + `${this.basePath}/balance-monitoring?${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', + `laporan-balance-monitoring-${formatDate(Date.now(), 'DD-MM-YYYY')}.xlsx` + ); + document.body.appendChild(link); + link.click(); + link.remove(); + } + async getBalanceMonitoringReport(params: { start_date?: string; end_date?: string;