Merge branch 'dev/hotfix/restu' into 'development'

[HOTFIX/FE] Adjustment Param State on Customer Payment Tab

See merge request mbugroup/lti-web-client!313
This commit is contained in:
Rivaldi A N S
2026-02-05 08:54:05 +00:00
3 changed files with 202 additions and 78 deletions
@@ -96,8 +96,7 @@ interface CustomerPaymentExportPDFParams {
// sales?: string; // sales?: string;
start_date?: string; start_date?: string;
end_date?: string; end_date?: string;
// TODO: Uncomment when BE is ready filter_by?: string;
// filter_by?: string;
}; };
} }
@@ -3,18 +3,18 @@ import useSWR from 'swr';
import { Icon } from '@iconify/react'; import { Icon } from '@iconify/react';
import Card from '@/components/Card'; import Card from '@/components/Card';
import Badge from '@/components/Badge'; import Badge from '@/components/Badge';
import SelectInput, { useSelect } from '@/components/input/SelectInput'; import { useSelect } from '@/components/input/SelectInput';
import SelectInputCheckbox from '@/components/input/SelectInputCheckbox'; import SelectInputCheckbox from '@/components/input/SelectInputCheckbox';
import SelectInputRadio from '@/components/input/SelectInputRadio';
import DateInput from '@/components/input/DateInput'; import DateInput from '@/components/input/DateInput';
import { CustomerApi } from '@/services/api/master-data'; import { CustomerApi } from '@/services/api/master-data';
import { FinanceApi } from '@/services/api/report/finance-report'; import { FinanceApi } from '@/services/api/report/finance-report';
import { UserApi } from '@/services/api/user'; // import { UserApi } from '@/services/api/user';
import Table from '@/components/Table'; import Table from '@/components/Table';
import { ColumnDef } from '@tanstack/react-table'; import { ColumnDef } from '@tanstack/react-table';
import { formatCurrency, formatDate, formatNumber, cn } from '@/lib/helper'; import { formatCurrency, formatDate, formatNumber, cn } from '@/lib/helper';
import { import {
CustomerPaymentReport, CustomerPaymentReport,
CustomerPaymentRow,
CustomerPaymentSummary, CustomerPaymentSummary,
} from '@/types/api/report/customer-payment'; } from '@/types/api/report/customer-payment';
import { isResponseSuccess } from '@/lib/api-helper'; import { isResponseSuccess } from '@/lib/api-helper';
@@ -48,38 +48,58 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => {
const [isSubmitted, setIsSubmitted] = useState(false); const [isSubmitted, setIsSubmitted] = useState(false);
// ===== FILTER STATE ===== // ===== FILTER STATE =====
const [appliedFilterCustomer, setAppliedFilterCustomer] = useState<
typeof customerOptions
>([]);
// TODO: Uncomment when BE is ready
// const [appliedFilterSales, setAppliedFilterSales] = useState<
// typeof salesOptions
// >([]);
const [appliedFilterByType, setAppliedFilterByType] = useState<
(typeof dataTypeOptions)[0] | null
>(null);
const [appliedFilterStartDate, setAppliedFilterStartDate] = useState('');
const [appliedFilterEndDate, setAppliedFilterEndDate] = useState('');
const [dateErrorShown, setDateErrorShown] = useState(false);
const [hasDateError, setHasDateError] = useState(false);
const [filterCustomer, setFilterCustomer] = useState<typeof customerOptions>( const [filterCustomer, setFilterCustomer] = useState<typeof customerOptions>(
[] []
); );
// TODO: Uncomment when BE is ready // TODO: Uncomment when BE is ready
// const [filterSales, setFilterSales] = useState<typeof salesOptions>([]); // const [filterSales, setFilterSales] = useState<typeof salesOptions>([]);
const [filterSales, setFilterSales] = useState<typeof salesOptions>([]);
const [filterStartDate, setFilterStartDate] = useState(''); const [filterStartDate, setFilterStartDate] = useState('');
const [filterEndDate, setFilterEndDate] = useState(''); const [filterEndDate, setFilterEndDate] = useState('');
const filterModal = useModal(); const filterModal = useModal();
const dataTypeOptions = useMemo(
() => [
{ value: 'trans_date', label: 'Tanggal Jual/Bayar' },
{ value: 'realization_date', label: 'Tanggal Realisasi' },
],
[]
);
const [filterByType, setFilterByType] = useState<
(typeof dataTypeOptions)[0] | null
>(null);
const { const {
options: customerOptions, options: customerOptions,
setInputValue: setCustomerInputValue, setInputValue: setCustomerInputValue,
isLoadingOptions: isLoadingCustomers, isLoadingOptions: isLoadingCustomers,
loadMore: loadMoreCustomers, loadMore: loadMoreCustomers,
hasMore: hasMoreCustomers,
} = useSelect(CustomerApi.basePath, 'id', 'name', 'search'); } = useSelect(CustomerApi.basePath, 'id', 'name', 'search');
// TODO: Uncomment when BE is ready // TODO: Uncomment when BE is ready
const { // const {
options: salesOptions, // options: salesOptions,
setInputValue: setSalesInputValue, // setInputValue: setSalesInputValue,
isLoadingOptions: isLoadingSales, // isLoadingOptions: isLoadingSales,
loadMore: loadMoreSales, // loadMore: loadMoreSales,
hasMore: hasMoreSales, // hasMore: hasMoreSales,
} = useSelect(UserApi.basePath, 'id', 'name', 'search'); // } = useSelect(UserApi.basePath, 'id', 'name', 'search');
const dataTypeOptions = useMemo(
() => [{ value: 'do_date', label: 'Tanggal Jual' }],
[]
);
const getPaymentStatusColor = (notes: string) => { const getPaymentStatusColor = (notes: string) => {
const normalizedValue = notes.toLowerCase(); const normalizedValue = notes.toLowerCase();
@@ -119,49 +139,145 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => {
// ===== FILTER HANDLERS ===== // ===== FILTER HANDLERS =====
const handleFilterModalOpen = useCallback(() => { const handleFilterModalOpen = useCallback(() => {
setFilterCustomer(appliedFilterCustomer);
// setFilterSales(appliedFilterSales);
setFilterByType(appliedFilterByType);
setFilterStartDate(appliedFilterStartDate);
setFilterEndDate(appliedFilterEndDate);
filterModal.openModal(); filterModal.openModal();
}, [filterModal]); }, [
filterModal,
appliedFilterCustomer,
appliedFilterByType,
appliedFilterStartDate,
appliedFilterEndDate,
]);
const handleResetFilters = useCallback(() => { const handleResetFilters = useCallback(() => {
setIsSubmitted(false); setIsSubmitted(false);
setFilterCustomer([]); setFilterCustomer([]);
setFilterSales([]); setFilterByType(null);
setFilterStartDate(''); setFilterStartDate('');
setFilterEndDate(''); setFilterEndDate('');
}, []); setAppliedFilterCustomer([]);
setAppliedFilterByType(null);
setAppliedFilterStartDate('');
setAppliedFilterEndDate('');
setHasDateError(false);
if (dateErrorShown) {
toast.dismiss();
setDateErrorShown(false);
}
}, [dateErrorShown]);
const handleApplyFilters = useCallback(() => { const handleApplyFilters = useCallback(() => {
setAppliedFilterCustomer(filterCustomer);
setAppliedFilterByType(filterByType);
setAppliedFilterStartDate(filterStartDate);
setAppliedFilterEndDate(filterEndDate);
setIsSubmitted(true); setIsSubmitted(true);
setCurrentPage(1); setCurrentPage(1);
filterModal.closeModal(); filterModal.closeModal();
}, [filterModal]); }, [
filterModal,
filterCustomer,
filterByType,
filterStartDate,
filterEndDate,
]);
const handleStartDateChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
setFilterStartDate(value);
if (value && filterEndDate) {
const startDate = new Date(value);
const endDateObj = new Date(filterEndDate);
if (endDateObj < startDate) {
setHasDateError(true);
if (!dateErrorShown) {
toast.error('Tanggal akhir tidak boleh masa lampau', {
duration: Infinity,
});
setDateErrorShown(true);
}
} else {
setHasDateError(false);
if (dateErrorShown) {
toast.dismiss();
setDateErrorShown(false);
}
}
} else {
setHasDateError(false);
}
},
[filterEndDate, dateErrorShown]
);
const handleEndDateChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
setFilterEndDate(value);
if (value && filterStartDate) {
const startDateObj = new Date(filterStartDate);
const endDate = new Date(value);
if (endDate < startDateObj) {
setHasDateError(true);
if (!dateErrorShown) {
toast.error('Tanggal akhir tidak boleh masa lampau', {
duration: Infinity,
});
setDateErrorShown(true);
}
return;
}
}
setHasDateError(false);
if (dateErrorShown) {
toast.dismiss();
setDateErrorShown(false);
}
},
[filterStartDate, dateErrorShown]
);
// ===== ACTIVE FILTERS COUNT ===== // ===== ACTIVE FILTERS COUNT =====
const activeFiltersCount = useMemo(() => { const activeFiltersCount = useMemo(() => {
let count = 0; let count = 0;
// Date filter (start_date + end_date = 1 filter) // Date filter (start_date + end_date = 1 filter)
if (filterStartDate || filterEndDate) { if (appliedFilterStartDate || appliedFilterEndDate) {
count += 1; count += 1;
} }
// Customer filter // Customer filter
if (filterCustomer.length > 0) { if (appliedFilterCustomer.length > 0) {
count += 1;
}
// Filter by type filter (hanya dihitung jika ada nilai yang dipilih)
if (appliedFilterByType) {
count += 1; count += 1;
} }
// TODO: Uncomment when BE is ready // TODO: Uncomment when BE is ready
// // Sales filter // // Sales filter
// if (filterSales.length > 0) { // if (appliedFilterSales.length > 0) {
// count += 1; // count += 1;
// } // }
return count; return count;
}, [ }, [
filterStartDate, appliedFilterStartDate,
filterEndDate, appliedFilterEndDate,
filterCustomer, appliedFilterCustomer,
// filterSales, appliedFilterByType,
]); ]);
const hasFilters = activeFiltersCount > 0; const hasFilters = activeFiltersCount > 0;
@@ -172,17 +288,20 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => {
? () => { ? () => {
const params = { const params = {
customer_ids: customer_ids:
filterCustomer.length > 0 appliedFilterCustomer.length > 0
? filterCustomer.map((v) => String(v.value)).join(',') ? appliedFilterCustomer.map((v) => String(v.value)).join(',')
: undefined, : undefined,
// TODO: Uncomment when BE is ready // TODO: Uncomment when BE is ready
// sales_id: // sales_id:
// filterSales.length > 0 // appliedFilterSales.length > 0
// ? filterSales.map((v) => String(v.value)).join(',') // ? appliedFilterSales.map((v) => String(v.value)).join(',')
// : undefined, // : undefined,
// filter_by: 'do_date' as const, filter_by: appliedFilterByType?.value as
start_date: filterStartDate || undefined, | 'trans_date'
end_date: filterEndDate || undefined, | 'realization_date'
| undefined,
start_date: appliedFilterStartDate || undefined,
end_date: appliedFilterEndDate || undefined,
page: currentPage, page: currentPage,
limit: pageSize, limit: pageSize,
}; };
@@ -193,8 +312,7 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => {
([, params]) => ([, params]) =>
FinanceApi.getCustomerPaymentReport( FinanceApi.getCustomerPaymentReport(
params.customer_ids, params.customer_ids,
undefined, // TODO: Change to params.sales_id when BE is ready params.filter_by,
undefined, // TODO: Change to params.filter_by when BE is ready
params.start_date, params.start_date,
params.end_date, params.end_date,
params.page, params.page,
@@ -216,24 +334,27 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => {
> => { > => {
const params = { const params = {
customer_ids: customer_ids:
filterCustomer.length > 0 appliedFilterCustomer.length > 0
? filterCustomer.map((v) => String(v.value)).join(',') ? appliedFilterCustomer.map((v) => String(v.value)).join(',')
: undefined, : undefined,
// TODO: Uncomment when BE is ready // TODO: Uncomment when BE is ready
// sales_id: // sales_id:
// filterSales.length > 0 // appliedFilterSales.length > 0
// ? filterSales.map((v) => String(v.value)).join(',') // ? appliedFilterSales.map((v) => String(v.value)).join(',')
// : undefined, // : undefined,
start_date: filterStartDate || undefined, filter_by: appliedFilterByType?.value as
end_date: filterEndDate || undefined, | 'trans_date'
| 'realization_date'
| undefined,
start_date: appliedFilterStartDate || undefined,
end_date: appliedFilterEndDate || undefined,
limit: 100, limit: 100,
page: 1, page: 1,
}; };
const response = await FinanceApi.getCustomerPaymentReport( const response = await FinanceApi.getCustomerPaymentReport(
params.customer_ids, params.customer_ids,
undefined, // TODO: Change to params.sales_id when BE is ready params.filter_by,
undefined, // TODO: Change to params.filter_by when BE is ready
params.start_date, params.start_date,
params.end_date, params.end_date,
params.page, params.page,
@@ -243,7 +364,13 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => {
return isResponseSuccess(response) return isResponseSuccess(response)
? (response.data as unknown as CustomerPaymentReport[]) ? (response.data as unknown as CustomerPaymentReport[])
: null; : null;
}, [filterCustomer, filterSales, filterStartDate, filterEndDate]); }, [
appliedFilterCustomer,
// appliedFilterSales,
appliedFilterStartDate,
appliedFilterEndDate,
appliedFilterByType,
]);
// ===== EXPORT HANDLERS ===== // ===== EXPORT HANDLERS =====
const handleExportExcel = useCallback(async () => { const handleExportExcel = useCallback(async () => {
@@ -287,18 +414,20 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => {
data: allDataForExport, data: allDataForExport,
params: { params: {
customer_name: customer_name:
filterCustomer.length > 0 appliedFilterCustomer.length > 0
? filterCustomer.map((c) => c.label).join(', ') ? appliedFilterCustomer.map((c) => c.label).join(', ')
: undefined, : undefined,
// TODO: Uncomment when BE is ready // TODO: Uncomment when BE is ready
// sales: // sales:
// filterSales.length > 0 // appliedFilterSales.length > 0
// ? filterSales.map((s) => s.label).join(', ') // ? appliedFilterSales.map((s) => s.label).join(', ')
// : undefined, // : undefined,
start_date: filterStartDate || undefined, start_date: appliedFilterStartDate || undefined,
end_date: filterEndDate || undefined, end_date: appliedFilterEndDate || undefined,
// TODO: Uncomment when BE is ready filter_by: appliedFilterByType?.value as
// filter_by: 'do_date' as const, | 'trans_date'
| 'realization_date'
| undefined,
}, },
}); });
toast.success('PDF berhasil dibuat dan diunduh.'); toast.success('PDF berhasil dibuat dan diunduh.');
@@ -406,7 +535,7 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => {
footer: () => <div className='font-semibold text-gray-900'>Total</div>, footer: () => <div className='font-semibold text-gray-900'>Total</div>,
}, },
{ {
id: 'do_date_or_payment_date', id: 'trans_date',
header: 'Tanggal Jual/Bayar', header: 'Tanggal Jual/Bayar',
accessorKey: 'trans_date', accessorKey: 'trans_date',
enableSorting: false, enableSorting: false,
@@ -811,9 +940,7 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => {
<DateInput <DateInput
name='start_date' name='start_date'
value={filterStartDate} value={filterStartDate}
onChange={(e) => { onChange={handleStartDateChange}
setFilterStartDate(e.target.value);
}}
className={{ wrapper: 'w-full' }} className={{ wrapper: 'w-full' }}
isNestedModal isNestedModal
/> />
@@ -822,9 +949,7 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => {
<DateInput <DateInput
name='end_date' name='end_date'
value={filterEndDate} value={filterEndDate}
onChange={(e) => { onChange={handleEndDateChange}
setFilterEndDate(e.target.value);
}}
className={{ wrapper: 'w-full' }} className={{ wrapper: 'w-full' }}
isNestedModal isNestedModal
/> />
@@ -864,17 +989,18 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => {
/> />
</div> */} </div> */}
{/* TODO: Uncomment when BE is ready */} <SelectInputRadio
{/* <div> label='Filter Berdasarkan'
<SelectInput placeholder='Pilih Filter Berdasarkan'
label='Filter Berdasarkan' options={dataTypeOptions}
placeholder='Pilih Filter Berdasarkan' value={filterByType}
options={dataTypeOptions} onChange={(val) => {
value={dataTypeOptions[0]} if (val && !Array.isArray(val)) {
isDisabled={true} setFilterByType(val);
className={{ wrapper: 'w-full' }} }
/> }}
</div> */} className={{ wrapper: 'w-full' }}
/>
{/* Action Buttons */} {/* Action Buttons */}
</div> </div>
@@ -889,6 +1015,7 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => {
<Button <Button
className='min-w-40 text-sm rounded-lg py-3 text-white font-semibold' className='min-w-40 text-sm rounded-lg py-3 text-white font-semibold'
onClick={handleApplyFilters} onClick={handleApplyFilters}
disabled={hasDateError}
> >
Apply Filter Apply Filter
</Button> </Button>
+2 -4
View File
@@ -15,9 +15,7 @@ export class FinanceApiService extends BaseApiService<
customer_ids?: string, customer_ids?: string,
// TODO: Uncomment when BE is ready // TODO: Uncomment when BE is ready
// sales_id?: string, // sales_id?: string,
// filter_by?: 'do_date', filter_by?: 'trans_date' | 'realization_date',
sales_id?: string,
filter_by?: 'do_date' | undefined,
start_date?: string, start_date?: string,
end_date?: string, end_date?: string,
page?: number, page?: number,
@@ -31,7 +29,7 @@ export class FinanceApiService extends BaseApiService<
customer_ids: customer_ids, customer_ids: customer_ids,
// TODO: Uncomment when BE is ready // TODO: Uncomment when BE is ready
// sales_id: sales_id, // sales_id: sales_id,
// filter_by: filter_by, filter_by: filter_by,
start_date: start_date, start_date: start_date,
end_date: end_date, end_date: end_date,
page: page, page: page,