fix: implement server-side export

This commit is contained in:
ValdiANS
2026-04-29 15:55:03 +07:00
parent 7a4f93cf0c
commit 3c9c55e049
2 changed files with 79 additions and 120 deletions
@@ -17,16 +17,10 @@ import {
formatVechicleNumber, formatVechicleNumber,
formatTitleCase, formatTitleCase,
} from '@/lib/helper'; } from '@/lib/helper';
import { import { DailyMarketingRow } from '@/types/api/report/marketing';
DailyMarketingRow,
DailyMarketingReportResponse,
} from '@/types/api/report/marketing';
import { isResponseSuccess } from '@/lib/api-helper'; import { isResponseSuccess } from '@/lib/api-helper';
import Button from '@/components/Button'; import Button from '@/components/Button';
import Dropdown from '@/components/Dropdown'; import Dropdown from '@/components/Dropdown';
import DailyMarketingReportPDF from '@/components/pages/report/marketing/export/DailyMarketingExportPDF';
import { generateDailyMarketingExcel } from '@/components/pages/report/marketing/export/DailyMarketingExportXLSX';
import { pdf } from '@react-pdf/renderer';
import toast from 'react-hot-toast'; import toast from 'react-hot-toast';
import { Icon } from '@iconify/react'; import { Icon } from '@iconify/react';
import { useFormik } from 'formik'; import { useFormik } from 'formik';
@@ -39,8 +33,6 @@ import Modal, { useModal } from '@/components/Modal';
import { useTabActionsStore } from '@/stores/tab-actions/tab-actions.store'; import { useTabActionsStore } from '@/stores/tab-actions/tab-actions.store';
import DailyMarketingReportSkeleton from '@/components/pages/report/marketing/skeleton/DailyMarketingSkeleton'; import DailyMarketingReportSkeleton from '@/components/pages/report/marketing/skeleton/DailyMarketingSkeleton';
import { useEffect as useEffectHook } from 'react'; import { useEffect as useEffectHook } from 'react';
import { httpClient } from '@/services/http/client';
import { isResponseError } from '@/lib/api-helper';
import { import {
MARKETING_DATE_FILTER_TYPE_OPTIONS, MARKETING_DATE_FILTER_TYPE_OPTIONS,
MARKETING_TYPE_OPTIONS, MARKETING_TYPE_OPTIONS,
@@ -284,10 +276,10 @@ const DailyMarketingTab = ({ tabId }: DailyMarketingTabProps) => {
[dailyMarketings] [dailyMarketings]
); );
// ===== EXPORT DATA FETCHER ===== // ===== EXPORT HANDLERS =====
const dailyMarketingsExport = useCallback(async (): Promise< const handleExportExcel = useCallback(async () => {
DailyMarketingRow[] | null setIsExcelExportLoading(true);
> => { try {
const params = new URLSearchParams(); const params = new URLSearchParams();
if (searchValue) params.set('search', searchValue); if (searchValue) params.set('search', searchValue);
@@ -301,51 +293,13 @@ const DailyMarketingTab = ({ tabId }: DailyMarketingTabProps) => {
if (filterParams.start_date) if (filterParams.start_date)
params.set('start_date', filterParams.start_date); params.set('start_date', filterParams.start_date);
if (filterParams.end_date) params.set('end_date', filterParams.end_date); if (filterParams.end_date) params.set('end_date', filterParams.end_date);
if (filterParams.filter_by) params.set('filter_by', filterParams.filter_by); if (filterParams.filter_by)
params.set('filter_by', filterParams.filter_by);
if (filterParams.marketing_type) if (filterParams.marketing_type)
params.set('marketing_type', filterParams.marketing_type); params.set('marketing_type', filterParams.marketing_type);
if (filterParams.sort_by) params.set('sort_by', filterParams.sort_by); if (filterParams.sort_by) params.set('sort_by', filterParams.sort_by);
params.set('page', '1');
params.set('limit', '9999999');
const queryString = `?${params.toString()}`; await MarketingReportApi.exportDailyMarketingToExcel(params.toString());
try {
const response = await httpClient<DailyMarketingReportResponse>(
`${MarketingReportApi.basePath}${queryString}`
);
if (isResponseError(response)) {
return null;
}
return response.data || [];
} catch {
return null;
}
}, [filterParams, searchValue]);
// ===== EXPORT HANDLERS =====
const handleExportExcel = useCallback(async () => {
setIsExcelExportLoading(true);
try {
const allDataForExport = await dailyMarketingsExport();
if (!allDataForExport || allDataForExport.length === 0) {
toast.error('Tidak ada data untuk diekspor.');
return;
}
const period =
filterParams.start_date && filterParams.end_date
? `${formatDate(filterParams.start_date, 'DD-MMM-YYYY')}_to_${formatDate(filterParams.end_date, 'DD-MMM-YYYY')}`
: undefined;
await generateDailyMarketingExcel({
data: allDataForExport,
summaryTotal: summaryTotal,
period: period,
});
toast.success('Excel berhasil dibuat dan diunduh.'); toast.success('Excel berhasil dibuat dan diunduh.');
} catch { } catch {
@@ -353,34 +307,39 @@ const DailyMarketingTab = ({ tabId }: DailyMarketingTabProps) => {
} finally { } finally {
setIsExcelExportLoading(false); setIsExcelExportLoading(false);
} }
}, [filterParams, dailyMarketingsExport, summaryTotal]); }, [filterParams, searchValue]);
const handleExportPDF = useCallback(async () => { const handleExportPDF = useCallback(async () => {
setIsPdfExportLoading(true); setIsPdfExportLoading(true);
try { try {
const allDataForExport = await dailyMarketingsExport(); const params = new URLSearchParams();
if (!allDataForExport || allDataForExport.length === 0) { if (searchValue) params.set('search', searchValue);
toast.error('Tidak ada data untuk diekspor.'); if (filterParams.area_id) params.set('area_id', filterParams.area_id);
return; if (filterParams.location_id)
} params.set('location_id', filterParams.location_id);
if (filterParams.warehouse_id)
params.set('warehouse_id', filterParams.warehouse_id);
if (filterParams.customer_id)
params.set('customer_id', filterParams.customer_id);
if (filterParams.start_date)
params.set('start_date', filterParams.start_date);
if (filterParams.end_date) params.set('end_date', filterParams.end_date);
if (filterParams.filter_by)
params.set('filter_by', filterParams.filter_by);
if (filterParams.marketing_type)
params.set('marketing_type', filterParams.marketing_type);
if (filterParams.sort_by) params.set('sort_by', filterParams.sort_by);
const dailyMarketingReportPdfBlob = await pdf( await MarketingReportApi.exportDailyMarketingToPDF(params.toString());
<DailyMarketingReportPDF data={allDataForExport} total={summaryTotal} />
).toBlob();
const dailyMarketingReportPdfUrl = URL.createObjectURL( toast.success('PDF berhasil dibuat dan diunduh.');
dailyMarketingReportPdfBlob
);
window.open(dailyMarketingReportPdfUrl, '_blank');
toast.success('PDF berhasil dibuat.');
} catch { } catch {
toast.error('Gagal membuat PDF. Silakan coba lagi.'); toast.error('Gagal membuat PDF. Silakan coba lagi.');
} finally { } finally {
setIsPdfExportLoading(false); setIsPdfExportLoading(false);
} }
}, [dailyMarketingsExport, summaryTotal]); }, [filterParams, searchValue]);
// ===== TAB ACTIONS COMPONENT ===== // ===== TAB ACTIONS COMPONENT =====
const TabActions = useMemo(() => { const TabActions = useMemo(() => {
+41 -41
View File
@@ -1,14 +1,9 @@
import * as XLSX from 'xlsx';
import toast from 'react-hot-toast';
import { BaseApiService } from '@/services/api/base'; import { BaseApiService } from '@/services/api/base';
import { httpClientFetcher } from '@/services/http/client'; import { httpClient, httpClientFetcher } from '@/services/http/client';
import { BaseApiResponse } from '@/types/api/api-general';
import { import {
DailyMarketingReport, DailyMarketingReport,
DailyMarketingReportResponse, DailyMarketingReportResponse,
} from '@/types/api/report/marketing'; } from '@/types/api/report/marketing';
import { isResponseError } from '@/lib/api-helper';
import { formatDate } from '@/lib/helper'; import { formatDate } from '@/lib/helper';
export class MarketingReportApiService extends BaseApiService< export class MarketingReportApiService extends BaseApiService<
@@ -29,48 +24,53 @@ export class MarketingReportApiService extends BaseApiService<
async exportDailyMarketingToExcel(initialQueryString: string) { async exportDailyMarketingToExcel(initialQueryString: string) {
const params = new URLSearchParams(initialQueryString); const params = new URLSearchParams(initialQueryString);
params.set('limit', '9999999'); params.set('export', 'excel');
params.set('page', '1');
params.set('limit', '99999999999');
const queryString = `?${params.toString()}`; const queryString = `?${params.toString()}`;
try { const res = await httpClient<Blob>(`${this.basePath}${queryString}`, {
const dailyMarketingsReport = await httpClientFetcher< method: 'GET',
BaseApiResponse<DailyMarketingReport> responseType: 'blob',
>(`${this.basePath}${queryString}`);
if (isResponseError(dailyMarketingsReport)) {
toast.error('Gagal melakukan export penjualan harian! Coba lagi.');
return;
}
const rows = dailyMarketingsReport.data;
const formattedRows = [];
for (let i = 0; i < rows.length; i++) {
formattedRows.push({
...rows[i],
// created_user: rows[i].created_user.name,
// created_at: formatDate(rows[i].created_at, 'YYYY-MM-DD'),
// updated_at: formatDate(rows[i].updated_at, 'YYYY-MM-DD'),
so_date: formatDate(rows[i].so_date, 'YYYY-MM-DD'),
realization_date: formatDate(rows[i].realization_date, 'YYYY-MM-DD'),
sales: rows[i].sales.name,
warehouse: rows[i].warehouse.name,
customer: rows[i].customer.name,
product: rows[i].product.name,
}); });
const url = window.URL.createObjectURL(new Blob([res]));
const link = document.createElement('a');
link.href = url;
const fileName = `laporan-penjualan-harian-${formatDate(Date.now(), 'DD-MM-YYYY')}.xlsx`;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
link.remove();
} }
const ws = XLSX.utils.json_to_sheet(formattedRows); async exportDailyMarketingToPDF(initialQueryString: string) {
const wb = XLSX.utils.book_new(); const params = new URLSearchParams(initialQueryString);
XLSX.utils.book_append_sheet(wb, ws, 'laporan-penjualan-harian');
// triggers download in browser params.set('export', 'pdf');
XLSX.writeFile(wb, 'laporan-penjualan-harian.xlsx'); params.set('page', '1');
} catch { params.set('limit', '99999999999');
toast.error('Gagal melakukan export penjualan harian! Coba lagi.');
} const queryString = `?${params.toString()}`;
const res = await httpClient<Blob>(`${this.basePath}${queryString}`, {
method: 'GET',
responseType: 'blob',
});
const url = window.URL.createObjectURL(new Blob([res]));
const link = document.createElement('a');
link.href = url;
const fileName = `laporan-penjualan-harian-${formatDate(Date.now(), 'DD-MM-YYYY')}.pdf`;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
link.remove();
} }
} }