From d41600d8e229bf476d662a969f164596b1afc54a Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 5 Feb 2026 13:48:07 +0700 Subject: [PATCH 1/9] refactor(FE): Replace week SelectInputRadio with NumberInput --- .../delivery-order/DeliverOrderProduct.tsx | 21 ++++++++++++------- .../sales-order/SalesOrderProductForm.tsx | 21 ++++++++++++------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx b/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx index 850d88d2..f5089c84 100644 --- a/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx +++ b/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx @@ -511,19 +511,24 @@ const DeliveryOrderProductForm = ({ {/* Konversi Satuan Week Pullet */} {formik.values.marketing_type?.value.toLowerCase() === 'ayam_pullet' && ( - { - formik.setFieldValue('week', val); + onChange={(e) => { + formik.setFieldValue('week', Number(e.target.value)); + setCurrentInput(e.target.name); }} - placeholder='Pilih Week' + onBlur={() => handleBlurField('week')} + isError={formik.touched.week && Boolean(formik.errors.week)} + errorMessage={formik.errors.week as string} + placeholder='Masukan Minggu' + decimalScale={0} /> )} diff --git a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx index c718c40c..ae1e4a44 100644 --- a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx +++ b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx @@ -467,19 +467,24 @@ const SalesOrderProductForm = ({ {/* Konversi Satuan Week Pullet */} {formik.values.marketing_type?.value.toLowerCase() === 'ayam_pullet' && ( - { - formik.setFieldValue('week', val); + onChange={(e) => { + formik.setFieldValue('week', Number(e.target.value)); + setCurrentInput(e.target.name); }} - placeholder='Pilih Week' + onBlur={() => handleBlurField('week')} + isError={formik.touched.week && Boolean(formik.errors.week)} + errorMessage={formik.errors.week as string} + placeholder='Masukan Minggu' + decimalScale={0} /> )} From 3b221795baf19b5eb945ddc3008147b3046430a8 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 5 Feb 2026 14:08:05 +0700 Subject: [PATCH 2/9] refactor(FE): Add filter_by option to customer payment reports --- .../export/CustomerPaymentExportPDF.tsx | 3 +- .../report/finance/tab/CustomerPaymentTab.tsx | 103 ++++++++++-------- src/services/api/report/finance-report.ts | 6 +- 3 files changed, 63 insertions(+), 49 deletions(-) diff --git a/src/components/pages/report/finance/export/CustomerPaymentExportPDF.tsx b/src/components/pages/report/finance/export/CustomerPaymentExportPDF.tsx index e6c5d66e..d132be9a 100644 --- a/src/components/pages/report/finance/export/CustomerPaymentExportPDF.tsx +++ b/src/components/pages/report/finance/export/CustomerPaymentExportPDF.tsx @@ -96,8 +96,7 @@ interface CustomerPaymentExportPDFParams { // sales?: string; start_date?: string; end_date?: string; - // TODO: Uncomment when BE is ready - // filter_by?: string; + filter_by?: string; }; } diff --git a/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx b/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx index 2987455a..4f12a4b8 100644 --- a/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx +++ b/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx @@ -14,7 +14,6 @@ import { ColumnDef } from '@tanstack/react-table'; import { formatCurrency, formatDate, formatNumber, cn } from '@/lib/helper'; import { CustomerPaymentReport, - CustomerPaymentRow, CustomerPaymentSummary, } from '@/types/api/report/customer-payment'; import { isResponseSuccess } from '@/lib/api-helper'; @@ -53,33 +52,39 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { ); // TODO: Uncomment when BE is ready // const [filterSales, setFilterSales] = useState([]); - const [filterSales, setFilterSales] = useState([]); const [filterStartDate, setFilterStartDate] = useState(''); const [filterEndDate, setFilterEndDate] = useState(''); const filterModal = useModal(); + const dataTypeOptions = useMemo( + () => [ + { value: 'do_date', label: 'Tanggal Jual' }, + { value: 'payment_date', label: 'Tanggal Bayar' }, + { value: 'realization_date', label: 'Tanggal Realisasi' }, + ], + [] + ); + + const [filterByType, setFilterByType] = useState<(typeof dataTypeOptions)[0]>( + dataTypeOptions[0] + ); + const { options: customerOptions, setInputValue: setCustomerInputValue, isLoadingOptions: isLoadingCustomers, loadMore: loadMoreCustomers, - hasMore: hasMoreCustomers, } = useSelect(CustomerApi.basePath, 'id', 'name', 'search'); // TODO: Uncomment when BE is ready - const { - options: salesOptions, - setInputValue: setSalesInputValue, - isLoadingOptions: isLoadingSales, - loadMore: loadMoreSales, - hasMore: hasMoreSales, - } = useSelect(UserApi.basePath, 'id', 'name', 'search'); - - const dataTypeOptions = useMemo( - () => [{ value: 'do_date', label: 'Tanggal Jual' }], - [] - ); + // const { + // options: salesOptions, + // setInputValue: setSalesInputValue, + // isLoadingOptions: isLoadingSales, + // loadMore: loadMoreSales, + // hasMore: hasMoreSales, + // } = useSelect(UserApi.basePath, 'id', 'name', 'search'); const getPaymentStatusColor = (notes: string) => { const normalizedValue = notes.toLowerCase(); @@ -125,10 +130,11 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { const handleResetFilters = useCallback(() => { setIsSubmitted(false); setFilterCustomer([]); - setFilterSales([]); + // setFilterSales([]); + setFilterByType(dataTypeOptions[0]); setFilterStartDate(''); setFilterEndDate(''); - }, []); + }, [dataTypeOptions]); const handleApplyFilters = useCallback(() => { setIsSubmitted(true); @@ -157,12 +163,7 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { // } return count; - }, [ - filterStartDate, - filterEndDate, - filterCustomer, - // filterSales, - ]); + }, [filterStartDate, filterEndDate, filterCustomer]); const hasFilters = activeFiltersCount > 0; @@ -180,7 +181,10 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { // filterSales.length > 0 // ? filterSales.map((v) => String(v.value)).join(',') // : undefined, - // filter_by: 'do_date' as const, + filter_by: filterByType.value as + | 'do_date' + | 'payment_date' + | 'realization_date', start_date: filterStartDate || undefined, end_date: filterEndDate || undefined, page: currentPage, @@ -193,8 +197,7 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { ([, params]) => FinanceApi.getCustomerPaymentReport( params.customer_ids, - undefined, // TODO: Change to params.sales_id when BE is ready - undefined, // TODO: Change to params.filter_by when BE is ready + params.filter_by, params.start_date, params.end_date, params.page, @@ -224,6 +227,10 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { // filterSales.length > 0 // ? filterSales.map((v) => String(v.value)).join(',') // : undefined, + filter_by: filterByType.value as + | 'do_date' + | 'payment_date' + | 'realization_date', start_date: filterStartDate || undefined, end_date: filterEndDate || undefined, limit: 100, @@ -232,8 +239,7 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { const response = await FinanceApi.getCustomerPaymentReport( params.customer_ids, - undefined, // TODO: Change to params.sales_id when BE is ready - undefined, // TODO: Change to params.filter_by when BE is ready + params.filter_by, params.start_date, params.end_date, params.page, @@ -243,7 +249,13 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { return isResponseSuccess(response) ? (response.data as unknown as CustomerPaymentReport[]) : null; - }, [filterCustomer, filterSales, filterStartDate, filterEndDate]); + }, [ + filterCustomer, + // filterSales, + filterStartDate, + filterEndDate, + filterByType, + ]); // ===== EXPORT HANDLERS ===== const handleExportExcel = useCallback(async () => { @@ -297,8 +309,10 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { // : undefined, start_date: filterStartDate || undefined, end_date: filterEndDate || undefined, - // TODO: Uncomment when BE is ready - // filter_by: 'do_date' as const, + filter_by: filterByType.value as + | 'do_date' + | 'payment_date' + | 'realization_date', }, }); toast.success('PDF berhasil dibuat dan diunduh.'); @@ -406,7 +420,7 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { footer: () =>
Total
, }, { - id: 'do_date_or_payment_date', + id: 'trans_date', header: 'Tanggal Jual/Bayar', accessorKey: 'trans_date', enableSorting: false, @@ -864,17 +878,20 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { /> */} - {/* TODO: Uncomment when BE is ready */} - {/*
- -
*/} +
+ { + if (val && !Array.isArray(val)) { + setFilterByType(val); + } + }} + className={{ wrapper: 'w-full' }} + /> +
{/* Action Buttons */} diff --git a/src/services/api/report/finance-report.ts b/src/services/api/report/finance-report.ts index 1102f99c..f9c296d8 100644 --- a/src/services/api/report/finance-report.ts +++ b/src/services/api/report/finance-report.ts @@ -15,9 +15,7 @@ export class FinanceApiService extends BaseApiService< customer_ids?: string, // TODO: Uncomment when BE is ready // sales_id?: string, - // filter_by?: 'do_date', - sales_id?: string, - filter_by?: 'do_date' | undefined, + filter_by?: 'do_date' | 'payment_date' | 'realization_date', start_date?: string, end_date?: string, page?: number, @@ -31,7 +29,7 @@ export class FinanceApiService extends BaseApiService< customer_ids: customer_ids, // TODO: Uncomment when BE is ready // sales_id: sales_id, - // filter_by: filter_by, + filter_by: filter_by, start_date: start_date, end_date: end_date, page: page, From fb1b310d1d49da40d4ee779073fd02170c43ac90 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 5 Feb 2026 14:13:13 +0700 Subject: [PATCH 3/9] refactor(FE): Replace SelectInput with SelectInputRadio --- .../report/finance/tab/CustomerPaymentTab.tsx | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx b/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx index 4f12a4b8..91f8df42 100644 --- a/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx +++ b/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx @@ -3,12 +3,13 @@ import useSWR from 'swr'; import { Icon } from '@iconify/react'; import Card from '@/components/Card'; 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 SelectInputRadio from '@/components/input/SelectInputRadio'; import DateInput from '@/components/input/DateInput'; import { CustomerApi } from '@/services/api/master-data'; 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 { ColumnDef } from '@tanstack/react-table'; import { formatCurrency, formatDate, formatNumber, cn } from '@/lib/helper'; @@ -878,20 +879,18 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { /> */} -
- { - if (val && !Array.isArray(val)) { - setFilterByType(val); - } - }} - className={{ wrapper: 'w-full' }} - /> -
+ { + if (val && !Array.isArray(val)) { + setFilterByType(val); + } + }} + className={{ wrapper: 'w-full' }} + /> {/* Action Buttons */} From 92886fe5e229811c42af49cd4b36a1036e18c083 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 5 Feb 2026 14:28:14 +0700 Subject: [PATCH 4/9] refactor(FE): Consolidate date filters into trans_date --- .../report/finance/tab/CustomerPaymentTab.tsx | 18 ++++-------------- src/services/api/report/finance-report.ts | 2 +- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx b/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx index 91f8df42..05aa36c0 100644 --- a/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx +++ b/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx @@ -60,8 +60,7 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { const dataTypeOptions = useMemo( () => [ - { value: 'do_date', label: 'Tanggal Jual' }, - { value: 'payment_date', label: 'Tanggal Bayar' }, + { value: 'trans_date', label: 'Tanggal Jual/Bayar' }, { value: 'realization_date', label: 'Tanggal Realisasi' }, ], [] @@ -182,10 +181,7 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { // filterSales.length > 0 // ? filterSales.map((v) => String(v.value)).join(',') // : undefined, - filter_by: filterByType.value as - | 'do_date' - | 'payment_date' - | 'realization_date', + filter_by: filterByType.value as 'trans_date' | 'realization_date', start_date: filterStartDate || undefined, end_date: filterEndDate || undefined, page: currentPage, @@ -228,10 +224,7 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { // filterSales.length > 0 // ? filterSales.map((v) => String(v.value)).join(',') // : undefined, - filter_by: filterByType.value as - | 'do_date' - | 'payment_date' - | 'realization_date', + filter_by: filterByType.value as 'trans_date' | 'realization_date', start_date: filterStartDate || undefined, end_date: filterEndDate || undefined, limit: 100, @@ -310,10 +303,7 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { // : undefined, start_date: filterStartDate || undefined, end_date: filterEndDate || undefined, - filter_by: filterByType.value as - | 'do_date' - | 'payment_date' - | 'realization_date', + filter_by: filterByType.value as 'trans_date' | 'realization_date', }, }); toast.success('PDF berhasil dibuat dan diunduh.'); diff --git a/src/services/api/report/finance-report.ts b/src/services/api/report/finance-report.ts index f9c296d8..95a85b85 100644 --- a/src/services/api/report/finance-report.ts +++ b/src/services/api/report/finance-report.ts @@ -15,7 +15,7 @@ export class FinanceApiService extends BaseApiService< customer_ids?: string, // TODO: Uncomment when BE is ready // sales_id?: string, - filter_by?: 'do_date' | 'payment_date' | 'realization_date', + filter_by?: 'trans_date' | 'realization_date', start_date?: string, end_date?: string, page?: number, From eb95afe9a04c89a9c099920a898539a771f36667 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 5 Feb 2026 14:39:33 +0700 Subject: [PATCH 5/9] refactor(FE): Separate applied and modal filter state --- .../report/finance/tab/CustomerPaymentTab.tsx | 101 ++++++++++++------ 1 file changed, 71 insertions(+), 30 deletions(-) diff --git a/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx b/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx index 05aa36c0..7160a273 100644 --- a/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx +++ b/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx @@ -48,6 +48,19 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { const [isSubmitted, setIsSubmitted] = useState(false); // ===== 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] + >({ value: 'trans_date', label: 'Tanggal Jual/Bayar' }); + const [appliedFilterStartDate, setAppliedFilterStartDate] = useState(''); + const [appliedFilterEndDate, setAppliedFilterEndDate] = useState(''); + const [filterCustomer, setFilterCustomer] = useState( [] ); @@ -124,23 +137,47 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { // ===== FILTER HANDLERS ===== const handleFilterModalOpen = useCallback(() => { + setFilterCustomer(appliedFilterCustomer); + // setFilterSales(appliedFilterSales); + setFilterByType(appliedFilterByType); + setFilterStartDate(appliedFilterStartDate); + setFilterEndDate(appliedFilterEndDate); filterModal.openModal(); - }, [filterModal]); + }, [ + filterModal, + appliedFilterCustomer, + appliedFilterByType, + appliedFilterStartDate, + appliedFilterEndDate, + ]); const handleResetFilters = useCallback(() => { setIsSubmitted(false); setFilterCustomer([]); - // setFilterSales([]); setFilterByType(dataTypeOptions[0]); setFilterStartDate(''); setFilterEndDate(''); + setAppliedFilterCustomer([]); + setAppliedFilterByType(dataTypeOptions[0]); + setAppliedFilterStartDate(''); + setAppliedFilterEndDate(''); }, [dataTypeOptions]); const handleApplyFilters = useCallback(() => { + setAppliedFilterCustomer(filterCustomer); + setAppliedFilterByType(filterByType); + setAppliedFilterStartDate(filterStartDate); + setAppliedFilterEndDate(filterEndDate); setIsSubmitted(true); setCurrentPage(1); filterModal.closeModal(); - }, [filterModal]); + }, [ + filterModal, + filterCustomer, + filterByType, + filterStartDate, + filterEndDate, + ]); // ===== ACTIVE FILTERS COUNT ===== const activeFiltersCount = useMemo(() => { @@ -163,7 +200,7 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { // } return count; - }, [filterStartDate, filterEndDate, filterCustomer]); + }, [appliedFilterStartDate, appliedFilterEndDate, appliedFilterCustomer]); const hasFilters = activeFiltersCount > 0; @@ -173,17 +210,19 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { ? () => { const params = { customer_ids: - filterCustomer.length > 0 - ? filterCustomer.map((v) => String(v.value)).join(',') + appliedFilterCustomer.length > 0 + ? appliedFilterCustomer.map((v) => String(v.value)).join(',') : undefined, // TODO: Uncomment when BE is ready // sales_id: - // filterSales.length > 0 - // ? filterSales.map((v) => String(v.value)).join(',') + // appliedFilterSales.length > 0 + // ? appliedFilterSales.map((v) => String(v.value)).join(',') // : undefined, - filter_by: filterByType.value as 'trans_date' | 'realization_date', - start_date: filterStartDate || undefined, - end_date: filterEndDate || undefined, + filter_by: appliedFilterByType.value as + | 'trans_date' + | 'realization_date', + start_date: appliedFilterStartDate || undefined, + end_date: appliedFilterEndDate || undefined, page: currentPage, limit: pageSize, }; @@ -216,17 +255,17 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { > => { const params = { customer_ids: - filterCustomer.length > 0 - ? filterCustomer.map((v) => String(v.value)).join(',') + appliedFilterCustomer.length > 0 + ? appliedFilterCustomer.map((v) => String(v.value)).join(',') : undefined, // TODO: Uncomment when BE is ready // sales_id: - // filterSales.length > 0 - // ? filterSales.map((v) => String(v.value)).join(',') + // appliedFilterSales.length > 0 + // ? appliedFilterSales.map((v) => String(v.value)).join(',') // : undefined, - filter_by: filterByType.value as 'trans_date' | 'realization_date', - start_date: filterStartDate || undefined, - end_date: filterEndDate || undefined, + filter_by: appliedFilterByType.value as 'trans_date' | 'realization_date', + start_date: appliedFilterStartDate || undefined, + end_date: appliedFilterEndDate || undefined, limit: 100, page: 1, }; @@ -244,11 +283,11 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { ? (response.data as unknown as CustomerPaymentReport[]) : null; }, [ - filterCustomer, - // filterSales, - filterStartDate, - filterEndDate, - filterByType, + appliedFilterCustomer, + // appliedFilterSales, + appliedFilterStartDate, + appliedFilterEndDate, + appliedFilterByType, ]); // ===== EXPORT HANDLERS ===== @@ -293,17 +332,19 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { data: allDataForExport, params: { customer_name: - filterCustomer.length > 0 - ? filterCustomer.map((c) => c.label).join(', ') + appliedFilterCustomer.length > 0 + ? appliedFilterCustomer.map((c) => c.label).join(', ') : undefined, // TODO: Uncomment when BE is ready // sales: - // filterSales.length > 0 - // ? filterSales.map((s) => s.label).join(', ') + // appliedFilterSales.length > 0 + // ? appliedFilterSales.map((s) => s.label).join(', ') // : undefined, - start_date: filterStartDate || undefined, - end_date: filterEndDate || undefined, - filter_by: filterByType.value as 'trans_date' | 'realization_date', + start_date: appliedFilterStartDate || undefined, + end_date: appliedFilterEndDate || undefined, + filter_by: appliedFilterByType.value as + | 'trans_date' + | 'realization_date', }, }); toast.success('PDF berhasil dibuat dan diunduh.'); From b4353cf834249f35d307cc75a0784a4c1e404b4c Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 5 Feb 2026 14:55:27 +0700 Subject: [PATCH 6/9] refactor(FE): Make filter type nullable and use applied filters --- .../report/finance/tab/CustomerPaymentTab.tsx | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx b/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx index 7160a273..e26abceb 100644 --- a/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx +++ b/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx @@ -56,8 +56,8 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { // typeof salesOptions // >([]); const [appliedFilterByType, setAppliedFilterByType] = useState< - (typeof dataTypeOptions)[0] - >({ value: 'trans_date', label: 'Tanggal Jual/Bayar' }); + (typeof dataTypeOptions)[0] | null + >(null); const [appliedFilterStartDate, setAppliedFilterStartDate] = useState(''); const [appliedFilterEndDate, setAppliedFilterEndDate] = useState(''); @@ -79,9 +79,9 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { [] ); - const [filterByType, setFilterByType] = useState<(typeof dataTypeOptions)[0]>( - dataTypeOptions[0] - ); + const [filterByType, setFilterByType] = useState< + (typeof dataTypeOptions)[0] | null + >(null); const { options: customerOptions, @@ -154,14 +154,14 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { const handleResetFilters = useCallback(() => { setIsSubmitted(false); setFilterCustomer([]); - setFilterByType(dataTypeOptions[0]); + setFilterByType(null); setFilterStartDate(''); setFilterEndDate(''); setAppliedFilterCustomer([]); - setAppliedFilterByType(dataTypeOptions[0]); + setAppliedFilterByType(null); setAppliedFilterStartDate(''); setAppliedFilterEndDate(''); - }, [dataTypeOptions]); + }, []); const handleApplyFilters = useCallback(() => { setAppliedFilterCustomer(filterCustomer); @@ -184,23 +184,33 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { let count = 0; // Date filter (start_date + end_date = 1 filter) - if (filterStartDate || filterEndDate) { + if (appliedFilterStartDate || appliedFilterEndDate) { count += 1; } // 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; } // TODO: Uncomment when BE is ready // // Sales filter - // if (filterSales.length > 0) { + // if (appliedFilterSales.length > 0) { // count += 1; // } return count; - }, [appliedFilterStartDate, appliedFilterEndDate, appliedFilterCustomer]); + }, [ + appliedFilterStartDate, + appliedFilterEndDate, + appliedFilterCustomer, + appliedFilterByType, + ]); const hasFilters = activeFiltersCount > 0; @@ -218,9 +228,10 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { // appliedFilterSales.length > 0 // ? appliedFilterSales.map((v) => String(v.value)).join(',') // : undefined, - filter_by: appliedFilterByType.value as + filter_by: appliedFilterByType?.value as | 'trans_date' - | 'realization_date', + | 'realization_date' + | undefined, start_date: appliedFilterStartDate || undefined, end_date: appliedFilterEndDate || undefined, page: currentPage, @@ -263,7 +274,10 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { // appliedFilterSales.length > 0 // ? appliedFilterSales.map((v) => String(v.value)).join(',') // : undefined, - filter_by: appliedFilterByType.value as 'trans_date' | 'realization_date', + filter_by: appliedFilterByType?.value as + | 'trans_date' + | 'realization_date' + | undefined, start_date: appliedFilterStartDate || undefined, end_date: appliedFilterEndDate || undefined, limit: 100, @@ -342,9 +356,10 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { // : undefined, start_date: appliedFilterStartDate || undefined, end_date: appliedFilterEndDate || undefined, - filter_by: appliedFilterByType.value as + filter_by: appliedFilterByType?.value as | 'trans_date' - | 'realization_date', + | 'realization_date' + | undefined, }, }); toast.success('PDF berhasil dibuat dan diunduh.'); From 4fd4374e64a8722d20a15a4fb7119eaf968af7d5 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 5 Feb 2026 15:04:12 +0700 Subject: [PATCH 7/9] refactor(FE): Validate date range and show toast on error --- .../report/finance/tab/CustomerPaymentTab.tsx | 79 +++++++++++++++++-- 1 file changed, 72 insertions(+), 7 deletions(-) diff --git a/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx b/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx index e26abceb..4e0e3f25 100644 --- a/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx +++ b/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx @@ -60,6 +60,8 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { >(null); const [appliedFilterStartDate, setAppliedFilterStartDate] = useState(''); const [appliedFilterEndDate, setAppliedFilterEndDate] = useState(''); + const [dateErrorShown, setDateErrorShown] = useState(false); + const [hasDateError, setHasDateError] = useState(false); const [filterCustomer, setFilterCustomer] = useState( [] @@ -161,7 +163,12 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { setAppliedFilterByType(null); setAppliedFilterStartDate(''); setAppliedFilterEndDate(''); - }, []); + setHasDateError(false); + if (dateErrorShown) { + toast.dismiss(); + setDateErrorShown(false); + } + }, [dateErrorShown]); const handleApplyFilters = useCallback(() => { setAppliedFilterCustomer(filterCustomer); @@ -179,6 +186,67 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { filterEndDate, ]); + const handleStartDateChange = useCallback( + (e: React.ChangeEvent) => { + 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) => { + 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 ===== const activeFiltersCount = useMemo(() => { let count = 0; @@ -872,9 +940,7 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { { - setFilterStartDate(e.target.value); - }} + onChange={handleStartDateChange} className={{ wrapper: 'w-full' }} isNestedModal /> @@ -883,9 +949,7 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { { - setFilterEndDate(e.target.value); - }} + onChange={handleEndDateChange} className={{ wrapper: 'w-full' }} isNestedModal /> @@ -951,6 +1015,7 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { From 70a9fa15eca83003abd1440784f651cb5707dbc4 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 5 Feb 2026 15:43:03 +0700 Subject: [PATCH 8/9] refactor(FE): Switch week input to SelectInputRadio --- .../delivery-order/DeliverOrderProduct.tsx | 22 ++++++++----------- .../sales-order/SalesOrderProductForm.tsx | 22 ++++++++----------- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx b/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx index f5089c84..cdeded75 100644 --- a/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx +++ b/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx @@ -511,24 +511,20 @@ const DeliveryOrderProductForm = ({ {/* Konversi Satuan Week Pullet */} {formik.values.marketing_type?.value.toLowerCase() === 'ayam_pullet' && ( - { - formik.setFieldValue('week', Number(e.target.value)); - setCurrentInput(e.target.name); + onChange={(val) => { + formik.setFieldValue('week', val); + handleBlurField('week'); }} - onBlur={() => handleBlurField('week')} - isError={formik.touched.week && Boolean(formik.errors.week)} - errorMessage={formik.errors.week as string} - placeholder='Masukan Minggu' - decimalScale={0} + placeholder='Pilih Week' /> )} diff --git a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx index ae1e4a44..d5327644 100644 --- a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx +++ b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx @@ -467,24 +467,20 @@ const SalesOrderProductForm = ({ {/* Konversi Satuan Week Pullet */} {formik.values.marketing_type?.value.toLowerCase() === 'ayam_pullet' && ( - { - formik.setFieldValue('week', Number(e.target.value)); - setCurrentInput(e.target.name); + onChange={(val) => { + formik.setFieldValue('week', val); + handleBlurField('week'); }} - onBlur={() => handleBlurField('week')} - isError={formik.touched.week && Boolean(formik.errors.week)} - errorMessage={formik.errors.week as string} - placeholder='Masukan Minggu' - decimalScale={0} + placeholder='Pilih Week' /> )} From d5eeadc9a7a3f4c5df8376714e23ca7cb1b6a57f Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 5 Feb 2026 15:47:05 +0700 Subject: [PATCH 9/9] refactor(FE): Remove handleBlurField call on week change --- .../form/repeater/delivery-order/DeliverOrderProduct.tsx | 1 - .../form/repeater/sales-order/SalesOrderProductForm.tsx | 1 - 2 files changed, 2 deletions(-) diff --git a/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx b/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx index cdeded75..850d88d2 100644 --- a/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx +++ b/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx @@ -522,7 +522,6 @@ const DeliveryOrderProductForm = ({ } onChange={(val) => { formik.setFieldValue('week', val); - handleBlurField('week'); }} placeholder='Pilih Week' /> diff --git a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx index d5327644..c718c40c 100644 --- a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx +++ b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx @@ -478,7 +478,6 @@ const SalesOrderProductForm = ({ } onChange={(val) => { formik.setFieldValue('week', val); - handleBlurField('week'); }} placeholder='Pilih Week' />