import Button from '@/components/Button'; import Card from '@/components/Card'; import Dropdown from '@/components/Dropdown'; import DateInput from '@/components/input/DateInput'; import SelectInput, { OptionType, useSelect, } from '@/components/input/SelectInput'; import Menu from '@/components/menu/Menu'; import MenuItem from '@/components/menu/MenuItem'; import Modal, { useModal } from '@/components/Modal'; import Table from '@/components/Table'; import { isResponseSuccess } from '@/lib/api-helper'; import { formatCurrency, formatDate, formatNumber } from '@/lib/helper'; import { SupplierApi } from '@/services/api/master-data'; import { FinanceApi } from '@/services/api/report/finance-report'; import { DebtRow, DebtSupplier } from '@/types/api/report/debt-supplier'; import { generateDebtSupplierExcel } from '@/components/pages/report/finance/export/DebtSupplierExportXLSX'; import { generateDebtSupplierPDF } from '@/components/pages/report/finance/export/DebtSupllierExportPDF'; import { Icon } from '@iconify/react'; import { ColumnDef } from '@tanstack/react-table'; import { useCallback, useMemo, useState } from 'react'; import toast from 'react-hot-toast'; import useSWR from 'swr'; import Pagination from '@/components/Pagination'; const DebtSupplierTab = () => { // ===== STATE MANAGEMENT ===== const [isPdfExportLoading, setIsPdfExportLoading] = useState(false); const [isExcelExportLoading, setIsExcelExportLoading] = useState(false); const isAnyExportLoading = isPdfExportLoading || isExcelExportLoading; // ===== PAGINATION STATE ===== const [currentPage, setCurrentPage] = useState(1); const [pageSize, setPageSize] = useState(10); // ===== SUBMISSION STATE ===== const [isSubmitted, setIsSubmitted] = useState(false); // ===== FILTER STATE ===== const [filterSupplier, setFilterSupplier] = useState([]); const [filterStartDate, setFilterStartDate] = useState(''); const [filterEndDate, setFilterEndDate] = useState(''); const [filterDataType, setFilterDataType] = useState(); const [filterErrors, setFilterErrors] = useState>({}); const filterModal = useModal(); const { options: supplierOptions, isLoadingOptions: isLoadingSuppliers } = useSelect(SupplierApi.basePath, 'id', 'name', '', { limit: 'limit', }); const dataTypeOptions = useMemo( () => [ { value: 'do_date', label: 'Tanggal Terima' }, { value: 'po_date', label: 'Tanggal PO' }, ], [] ); // ===== FILTER HANDLERS ===== const handleResetFilters = useCallback(() => { setIsSubmitted(false); setFilterSupplier([]); setFilterStartDate(''); setFilterEndDate(''); setFilterErrors({}); }, []); const handleApplyFilters = useCallback(() => { const errors: Record = {}; if (!filterStartDate) { errors.start_date = 'Tanggal mulai wajib diisi'; } if (!filterEndDate) { errors.end_date = 'Tanggal akhir wajib diisi'; } setFilterErrors(errors); if (Object.keys(errors).length === 0) { setIsSubmitted(true); setCurrentPage(1); filterModal.closeModal(); } }, [filterModal, filterStartDate, filterEndDate]); // ===== DATA FETCHING ===== const { data: debtSupplier, isLoading } = useSWR( isSubmitted ? () => { const params = { supplier_ids: filterSupplier.length > 0 ? filterSupplier.map((v) => String(v.value)).join(',') : undefined, filter_by: filterDataType?.value || 'do_date', start_date: filterStartDate || undefined, end_date: filterEndDate || undefined, page: currentPage, limit: pageSize, }; return ['debt-supplier-report', params]; } : null, ([, params]) => FinanceApi.getDebtSupplierReport( params.supplier_ids, params.filter_by?.toString(), params.start_date, params.end_date, params.page, params.limit ) ); // const { data: debtSupplier, isLoading } = useSWR(FinanceApi.basePath, () => // FinanceApi.getDebtSupplierReport() // ); const data: DebtSupplier[] = useMemo( () => isResponseSuccess(debtSupplier) ? (debtSupplier?.data as unknown as DebtSupplier[]) || [] : [], [debtSupplier] ); const meta = isResponseSuccess(debtSupplier) && debtSupplier?.meta ? debtSupplier.meta : null; // ===== EXPORT DATA FETCHER ===== const debtSupplierExport = useCallback(async (): Promise< DebtSupplier[] | null > => { const params = { supplier_ids: filterSupplier.length > 0 ? filterSupplier.map((v) => String(v.value)).join(',') : undefined, filter_by: 'do_date' as const, start_date: filterStartDate || undefined, end_date: filterEndDate || undefined, date_type: filterDataType ? filterDataType.value : undefined, limit: 100, page: 1, }; const response = await FinanceApi.getDebtSupplierReport( params.supplier_ids, params.filter_by, params.start_date, params.end_date, params.page, params.limit ); return isResponseSuccess(response) ? (response.data as unknown as DebtSupplier[]) : null; }, [filterSupplier, filterStartDate, filterEndDate]); // ===== EXPORT HANDLERS ===== const handleExportExcel = useCallback(async () => { setIsExcelExportLoading(true); try { const allDataForExport = await debtSupplierExport(); if ( !allDataForExport || !Array.isArray(allDataForExport) || allDataForExport.length === 0 ) { toast.error('Tidak ada data untuk diekspor.'); return; } generateDebtSupplierExcel({ data: allDataForExport }); toast.success('Excel berhasil dibuat dan diunduh.'); } catch { toast.error('Gagal membuat Excel. Silakan coba lagi.'); } finally { setIsExcelExportLoading(false); } }, [debtSupplierExport]); const handleExportPdf = useCallback(async () => { setIsPdfExportLoading(true); try { const allDataForExport = await debtSupplierExport(); if ( !allDataForExport || !Array.isArray(allDataForExport) || allDataForExport.length === 0 ) { toast.error('Tidak ada data untuk diekspor.'); return; } await generateDebtSupplierPDF({ data: allDataForExport }); toast.success('PDF berhasil dibuat dan diunduh.'); } catch { toast.error('Gagal membuat PDF. Silakan coba lagi.'); } finally { setIsPdfExportLoading(false); } }, [debtSupplierExport]); // ===== PAGINATION HANDLERS ===== const handlePageChange = (page: number) => { setCurrentPage(page); }; const handleRowChange = (pageSize: number) => { setPageSize(pageSize); }; const handleNextPage = () => { if (meta && currentPage < meta.total_pages) { setCurrentPage(currentPage + 1); } }; const handlePrevPage = () => { if (currentPage > 1) { setCurrentPage(currentPage - 1); } }; const getTableColumns = (supplier: DebtSupplier): ColumnDef[] => [ { id: 'no', header: 'No', cell: (props) => props.row.index + 1, }, { id: 'pr_number', header: 'Nomor PR', accessorKey: 'pr_number', cell: (props) => { const value = props.row.original.pr_number; return value || '-'; }, }, { id: 'po_number', header: 'Nomor PO', accessorKey: 'po_number', cell: (props) => { const value = props.row.original.po_number; return value || '-'; }, }, { id: 'pr_date', header: 'Tanggal PR', accessorKey: 'pr_date', cell: (props) => { const value = props.row.original.pr_date; return formatDate(value, 'DD MMM YYYY'); }, }, { id: 'po_date', header: 'Tanggal PO', accessorKey: 'po_date', cell: (props) => { const value = props.row.original.po_date; return formatDate(value, 'DD MMM YYYY'); }, }, { id: 'aging', header: 'Aging', accessorKey: 'aging', cell: (props) => { const value = props.row.original.aging; return
{formatNumber(value)} Hari
; }, footer: () => { const value = supplier.total.aging; return
{formatNumber(value)} Hari
; }, }, { id: 'area', header: 'Area', accessorKey: 'area', cell: (props) => { const value = props.row.original.area?.name; return value || '-'; }, }, { id: 'warehouse', header: 'Gudang', accessorKey: 'warehouse', cell: (props) => { const value = props.row.original.warehouse?.name; return value || '-'; }, }, { id: 'due_date', header: 'Tanggal Jatuh Tempo', accessorKey: 'due_date', cell: (props) => { const value = props.row.original.due_date; return formatDate(value, 'DD MMM YYYY'); }, }, { id: 'due_status', header: 'Status Jatuh Tempo', accessorKey: 'due_status', cell: (props) => { const value = props.row.original.due_status; return value || '-'; }, }, { id: 'total_price', header: 'Total Harga', accessorKey: 'total_price', cell: (props) => { const value = props.row.original.total_price; return
{formatCurrency(value)}
; }, footer: () => { const value = supplier.total.total_price; return
{formatCurrency(value)}
; }, }, { id: 'payment_price', header: 'Harga Pembayaran', accessorKey: 'payment_price', cell: (props) => { const value = props.row.original.payment_price; return
{formatCurrency(value)}
; }, footer: () => { const value = supplier.total.payment_price; return
{formatCurrency(value)}
; }, }, { id: 'debt_price', header: 'Harga Hutang', accessorKey: 'debt_price', cell: (props) => { const value = props.row.original.debt_price; return (
{formatCurrency(value)}
); }, footer: () => { const value = supplier.total.debt_price; return (
{formatCurrency(value)}
); }, }, { id: 'status', header: 'Status', accessorKey: 'status', cell: (props) => { const value = props.row.original.status; return value || '-'; }, }, { id: 'travel_number', header: 'Nomor Perjalanan', accessorKey: 'travel_number', cell: (props) => { const value = props.row.original.travel_number; return value || '-'; }, }, ]; return ( <>
Export } align='end' >
{!isSubmitted ? (
Silakan klik tombol Filter untuk mengatur filter dan menampilkan data.
) : isLoading ? (
) : data.length === 0 ? (
Tidak ada data yang dapat ditampilkan...
) : ( data.map((supplierReport) => { return ( 0} className={{ containerClassName: 'w-full', tableWrapperClassName: 'overflow-x-auto mt-4', tableClassName: 'w-full table-auto text-sm', headerRowClassName: 'border-b border-b-gray-200 bg-gray-50', headerColumnClassName: 'px-4 py-3 text-xs font-semibold text-gray-700 text-left border border-gray-200', bodyRowClassName: 'hover:bg-gray-50 transition-colors border-b border-l border-r border-b-gray-200 border-l-gray-200 border-r-gray-200', bodyColumnClassName: 'px-4 py-3 text-xs text-gray-900 whitespace-nowrap', tableFooterClassName: 'bg-gray-100 font-semibold border border-gray-200', footerRowClassName: 'border-t-2 border-gray-300', footerColumnClassName: 'px-4 py-3 text-xs text-gray-900 whitespace-nowrap', paginationClassName: 'hidden', }} /> ); }) )} {meta && data.length > 0 && (
)} {/* Filter Modal */}
{/* Modal Header */}

Filter Data

{ setFilterStartDate(e.target.value); setFilterErrors((prev) => ({ ...prev, start_date: '' })); }} className={{ wrapper: 'w-full' }} /> {filterErrors.start_date && (

{filterErrors.start_date}

)}
{ setFilterEndDate(e.target.value); setFilterErrors((prev) => ({ ...prev, end_date: '' })); }} className={{ wrapper: 'w-full' }} /> {filterErrors.end_date && (

{filterErrors.end_date}

)}
{ setFilterSupplier( Array.isArray(val) ? val : val ? [val] : [] ); }} isLoading={isLoadingSuppliers} isClearable className={{ wrapper: 'w-full' }} />
{ setFilterDataType(val ? (val as OptionType) : undefined); }} className={{ wrapper: 'w-full' }} />
{/* Action Buttons */}
); }; export default DebtSupplierTab;