Merge branch 'feat/export-balance-monitoring' into 'development'

[FEAT/FE] Export Balance Monitoring

See merge request mbugroup/lti-web-client!495
This commit is contained in:
Rivaldi A N S
2026-05-25 07:25:07 +00:00
2 changed files with 111 additions and 2 deletions
@@ -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);
+34
View File
@@ -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;