mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-25 15:55:48 +00:00
feat: add Excel export to BalanceMonitoringTab
Add exportBalanceMonitoringToExcel to FinanceApiService (server-side blob download hitting reports/balance-monitoring?export=excel). Wire it into BalanceMonitoringTab via a Dropdown export button in the tab actions. Wrap the handler in useCallback to prevent an infinite setTabActions loop caused by a new function reference on every render. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useMemo, useEffect } from 'react';
|
||||
import { useState, useMemo, useEffect, useCallback } from 'react';
|
||||
import useSWR from 'swr';
|
||||
import { Icon } from '@iconify/react';
|
||||
import { useFormik } from 'formik';
|
||||
@@ -24,6 +24,7 @@ import { BalanceMonitoringRow } from '@/types/api/report/balance-monitoring';
|
||||
import { CustomerPaymentRow } from '@/types/api/report/customer-payment';
|
||||
import Modal, { useModal } from '@/components/Modal';
|
||||
import Button from '@/components/Button';
|
||||
import Dropdown from '@/components/Dropdown';
|
||||
import DateInput from '@/components/input/DateInput';
|
||||
import Table from '@/components/Table';
|
||||
import CustomerSupplierSkeleton from '@/components/pages/report/finance/skeleton/CustomerSupplierSkeleton';
|
||||
@@ -40,6 +41,7 @@ const filterByOptions: OptionType<string>[] = [
|
||||
const BalanceMonitoringTab = ({ tabId }: BalanceMonitoringTabProps) => {
|
||||
const [hasDateError, setHasDateError] = useState(false);
|
||||
const [dateErrorShown, setDateErrorShown] = useState(false);
|
||||
const [isExcelExportLoading, setIsExcelExportLoading] = useState(false);
|
||||
|
||||
const filterModal = useModal();
|
||||
|
||||
@@ -230,6 +232,33 @@ const BalanceMonitoringTab = ({ tabId }: BalanceMonitoringTabProps) => {
|
||||
? balanceMonitoringsResponse.meta
|
||||
: null;
|
||||
|
||||
const handleExportExcel = useCallback(async () => {
|
||||
setIsExcelExportLoading(true);
|
||||
try {
|
||||
const customer_ids =
|
||||
tableFilterState.customers.length > 0
|
||||
? tableFilterState.customers.map((o) => String(o.value)).join(',')
|
||||
: undefined;
|
||||
const sales_ids =
|
||||
tableFilterState.salesPersons.length > 0
|
||||
? tableFilterState.salesPersons.map((o) => String(o.value)).join(',')
|
||||
: undefined;
|
||||
|
||||
await FinanceApi.exportBalanceMonitoringToExcel(
|
||||
customer_ids,
|
||||
sales_ids,
|
||||
tableFilterState.filterBy?.value,
|
||||
tableFilterState.start_date || undefined,
|
||||
tableFilterState.end_date || undefined
|
||||
);
|
||||
toast.success('Excel berhasil dibuat dan diunduh.');
|
||||
} catch {
|
||||
toast.error('Gagal membuat Excel. Silakan coba lagi.');
|
||||
} finally {
|
||||
setIsExcelExportLoading(false);
|
||||
}
|
||||
}, [tableFilterState]);
|
||||
|
||||
// Inject tab actions directly — no nested component, no remount cycle
|
||||
useEffect(() => {
|
||||
setTabActions(
|
||||
@@ -248,9 +277,55 @@ const BalanceMonitoringTab = ({ tabId }: BalanceMonitoringTabProps) => {
|
||||
variant='outline'
|
||||
className='px-3 py-2.5'
|
||||
/>
|
||||
|
||||
<Dropdown
|
||||
align='end'
|
||||
direction='bottom'
|
||||
className={{
|
||||
content:
|
||||
'mt-1 rounded-xl border border-base-content/5 shadow-sm overflow-hidden',
|
||||
}}
|
||||
trigger={
|
||||
<Button
|
||||
variant='outline'
|
||||
color='none'
|
||||
isLoading={isExcelExportLoading}
|
||||
className='px-3 py-2.5 text-sm text-base-content/50 border border-base-content/10 rounded-xl shadow-button-soft'
|
||||
>
|
||||
<div className='flex flex-row items-center gap-1.5'>
|
||||
<Icon
|
||||
icon='heroicons:cloud-arrow-down'
|
||||
width={20}
|
||||
height={20}
|
||||
/>
|
||||
<span>Export</span>
|
||||
<div className='w-px self-stretch bg-base-content/10' />
|
||||
<Icon icon='heroicons:chevron-down' width={14} height={14} />
|
||||
</div>
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<Button
|
||||
variant='ghost'
|
||||
color='none'
|
||||
onClick={handleExportExcel}
|
||||
isLoading={isExcelExportLoading}
|
||||
className='w-full p-3 justify-start text-sm text-base-content/50 font-semibold text-nowrap'
|
||||
>
|
||||
<Icon icon='heroicons:table-cells' width={20} height={20} />
|
||||
Ekspor ke Excel
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</div>
|
||||
);
|
||||
}, [tabId, setTabActions, tableFilterState, filterModal.openModal]);
|
||||
}, [
|
||||
tabId,
|
||||
setTabActions,
|
||||
tableFilterState,
|
||||
filterModal.openModal,
|
||||
isExcelExportLoading,
|
||||
handleExportExcel,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => clearTabActions(tabId);
|
||||
|
||||
@@ -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<Blob>(
|
||||
`${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;
|
||||
|
||||
Reference in New Issue
Block a user