From 73d05d6b4b6d1bece02169ae7224e6df610b94bf Mon Sep 17 00:00:00 2001 From: rstubryan Date: Mon, 13 Apr 2026 14:23:21 +0700 Subject: [PATCH 1/6] refactor(FE-add-param): Update MarketingFilter to refine API calls and options handling --- .../pages/marketing/MarketingFilter.tsx | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/components/pages/marketing/MarketingFilter.tsx b/src/components/pages/marketing/MarketingFilter.tsx index 624c573c..0142cf07 100644 --- a/src/components/pages/marketing/MarketingFilter.tsx +++ b/src/components/pages/marketing/MarketingFilter.tsx @@ -41,9 +41,12 @@ const MarketingFilterModal = ({ isLoadingOptions: isLoadingProductsOptions, setInputValue: setProductsInputValue, loadMore: loadMoreProducts, - } = useSelect(MarketingApi.basePath, 'id', 'so_number', '', { - limit: 'limit', - }); + } = useSelect( + MarketingApi.basePath, + 'id', + 'so_number', + 'search' + ); const productsOptions = useMemo(() => { if (!productsRawData || !isResponseSuccess(productsRawData)) return []; @@ -70,18 +73,15 @@ const MarketingFilterModal = ({ isLoadingOptions: isLoadingCustomersOptions, setInputValue: setCustomersInputValue, loadMore: loadMoreCustomers, - } = useSelect(MarketingApi.basePath, 'customer.id', 'customer.name', '', { - limit: 'limit', - }); - - const salesCustomerOptions = useMemo(() => { - const seen = new Set(); - return customersOptions.filter((customer) => { - if (seen.has(customer.value)) return false; - seen.add(customer.value); - return true; - }); - }, [customersOptions]); + } = useSelect( + MarketingApi.basePath, + 'customer.id', + 'customer.name', + 'search', + { + has_marketing: 'true', + } + ); const statusOptions = [ ...MARKETING_APPROVAL_LINE.map((item) => ({ @@ -190,7 +190,7 @@ const MarketingFilterModal = ({ label='Customer' isClearable placeholder='Pilih customer' - options={salesCustomerOptions} + options={customersOptions} isLoading={isLoadingCustomersOptions} value={formik.values.customer} onChange={customerChangeHandler} From 62dc8235d408a167f236f3b08be32992611d2c54 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Mon, 13 Apr 2026 14:37:23 +0700 Subject: [PATCH 2/6] refactor(FE-change-api): Refactor Kandang input handling in DashboardProduction --- .../pages/dashboard/DashboardProduction.tsx | 103 ++++++------------ 1 file changed, 31 insertions(+), 72 deletions(-) diff --git a/src/components/pages/dashboard/DashboardProduction.tsx b/src/components/pages/dashboard/DashboardProduction.tsx index 81254442..6b3dabbd 100644 --- a/src/components/pages/dashboard/DashboardProduction.tsx +++ b/src/components/pages/dashboard/DashboardProduction.tsx @@ -5,11 +5,14 @@ import { Icon } from '@iconify/react'; import Modal, { useModal } from '@/components/Modal'; import DateInput from '@/components/input/DateInput'; import { OptionType, useSelect } from '@/components/input/SelectInput'; -import { useState, useEffect, useRef, useCallback, useMemo } from 'react'; +import { useState, useEffect, useRef, useCallback } from 'react'; import useSWR from 'swr'; import { DashboardApi } from '@/services/api/dashboard'; import { useFormik } from 'formik'; -import { ProjectFlockApi } from '@/services/api/production'; +import { + ProjectFlockApi, + ProjectFlockKandangApi, +} from '@/services/api/production'; import { LocationApi } from '@/services/api/master-data'; import { generateDashboardPDF } from '@/components/pages/dashboard/export/DashboardPDF'; import { @@ -22,10 +25,7 @@ import DashboardExportCharts, { DashboardExportChartsRef, } from '@/components/pages/dashboard/export/DashboardExportCharts'; import { RadioGroup, RadioGroupItem } from '@/components/input/RadioInput'; -import { - DashboardFilter, - DashboardMeta, -} from '@/types/api/dashboard/dashboard'; +import { DashboardMeta } from '@/types/api/dashboard/dashboard'; import DashboardStats from '@/components/pages/dashboard/chart/DashboardStats'; import { isResponseSuccess } from '@/lib/api-helper'; import AlertErrorList from '@/components/helper/form/FormErrors'; @@ -43,6 +43,7 @@ import DashboardExportStats, { DashboardExportStatsRef, } from '@/components/pages/dashboard/export/DashboardExportStats'; import { ProjectFlock } from '@/types/api/production/project-flock'; +import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang'; // Helper function to normalize values to array const normalizeToArray = ( @@ -72,7 +73,6 @@ const DashboardProduction = () => { const [selectedLocationIds, setSelectedLocationIds] = useState( normalizeToArray(filterValues.location) ); - const [kandangInputValue, setRawKandangInputValue] = useState(''); const [exporting, setExporting] = useState(false); const allChartsRef = useRef(null); const allStatsRef = useRef(null); @@ -116,15 +116,13 @@ const DashboardProduction = () => { options: flockOptions, isLoadingOptions: isLoadingFlockOptions, loadMore: loadMoreFlock, - rawData: projectFlocksRawData, } = useSelect( ProjectFlockApi.basePath, 'id', 'flock_name', - '', + 'search', { - location_id: - selectedLocationIds.length > 0 ? selectedLocationIds.toString() : '', + location_id: selectedLocationIds ? selectedLocationIds.toString() : '', } ); @@ -165,66 +163,34 @@ const DashboardProduction = () => { const { resetForm } = formik; - const selectedFlockIds = useMemo( - () => normalizeToArray(formik.values.flock), - [formik.values.flock] - ); - - const derivedKandangOptions = useMemo(() => { - if (!isResponseSuccess(projectFlocksRawData)) return []; - - const availableProjectFlocks = projectFlocksRawData.data.filter( - (projectFlock) => - selectedFlockIds.length === 0 || - selectedFlockIds.includes(projectFlock.id) - ); - - const kandangMap = new Map>(); - - availableProjectFlocks.forEach((projectFlock) => { - projectFlock.kandangs?.forEach((kandang) => { - if (!kandangMap.has(kandang.id)) { - kandangMap.set(kandang.id, { - value: kandang.id, - label: kandang.name, - }); - } - }); - }); - - const normalizedSearch = kandangInputValue.trim().toLowerCase(); - const allOptions = Array.from(kandangMap.values()); - - if (!normalizedSearch) return allOptions; - - return allOptions.filter((option) => - option.label.toLowerCase().includes(normalizedSearch) - ); - }, [projectFlocksRawData, selectedFlockIds, kandangInputValue]); - - const kandangSelect = useMemo( - () => ({ - setInputValue: setRawKandangInputValue, - options: derivedKandangOptions, - isLoadingOptions: isLoadingFlockOptions, - loadMore: loadMoreFlock, - }), - [derivedKandangOptions, isLoadingFlockOptions, loadMoreFlock] - ); + const selectedLocationValues = normalizeToArray(formik.values.location); + const selectedFlockValues = normalizeToArray(formik.values.flock); const { setInputValue: setInputValueKandang, options: kandangOptions, isLoadingOptions: isLoadingKandangOptions, loadMore: loadMoreKandang, - } = kandangSelect; + } = useSelect( + ProjectFlockKandangApi.basePath, + 'kandang_id', + 'kandang.name', + 'search', + { + location_id: + selectedLocationValues.length > 0 + ? selectedLocationValues.toString() + : '', + project_flock_id: + selectedFlockValues.length > 0 ? selectedFlockValues.toString() : '', + } + ); const handleResetFilter = useCallback(() => { resetForm(); resetFilterValues(); // Clear stored filter values setAnalysisMode('OVERVIEW'); setSelectedLocationIds([]); - setRawKandangInputValue(''); filterModal.closeModal(); }, [filterModal, resetForm, resetFilterValues]); @@ -520,7 +486,6 @@ const DashboardProduction = () => { formik.setFieldValue('kandang', []); formik.setFieldValue('comparisonType', ''); setSelectedLocationIds([]); - setRawKandangInputValue(''); }} color='primary' className={{ @@ -592,7 +557,6 @@ const DashboardProduction = () => { // Reset dependent fields when location changes formik.setFieldValue('flock', []); formik.setFieldValue('kandang', []); - setRawKandangInputValue(''); }} errorMessage={formik.errors.location as string} options={locationOptions} @@ -625,7 +589,6 @@ const DashboardProduction = () => { // Reset dependent fields when location changes formik.setFieldValue('flock', []); formik.setFieldValue('kandang', []); - setRawKandangInputValue(''); }} errorMessage={formik.errors.location as string} options={locationOptions} @@ -662,11 +625,9 @@ const DashboardProduction = () => { | null | undefined } - onChange={(selected) => { - formik.setFieldValue('flock', selected); - formik.setFieldValue('kandang', []); - setInputValueKandang(''); - }} + onChange={(selected) => + formik.setFieldValue('flock', selected) + } errorMessage={formik.errors.flock as string} onInputChange={setInputValueFlock} onMenuScrollToBottom={loadMoreFlock} @@ -691,11 +652,9 @@ const DashboardProduction = () => { | null | undefined } - onChange={(selected) => { - formik.setFieldValue('flock', selected); - formik.setFieldValue('kandang', []); - setInputValueKandang(''); - }} + onChange={(selected) => + formik.setFieldValue('flock', selected) + } errorMessage={formik.errors.flock as string} onInputChange={setInputValueFlock} onMenuScrollToBottom={loadMoreFlock} From ff39514b78c85485b6c93da1f79fee569be00296 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Mon, 13 Apr 2026 14:54:19 +0700 Subject: [PATCH 3/6] refactor(FE-endpoint-path): Fix customer API integration in MarketingFilter --- src/components/pages/marketing/MarketingFilter.tsx | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/components/pages/marketing/MarketingFilter.tsx b/src/components/pages/marketing/MarketingFilter.tsx index 0142cf07..823d2dd2 100644 --- a/src/components/pages/marketing/MarketingFilter.tsx +++ b/src/components/pages/marketing/MarketingFilter.tsx @@ -17,6 +17,7 @@ import { import { MarketingFilter } from '@/types/api/marketing/marketing'; import SelectInputCheckbox from '@/components/input/SelectInputCheckbox'; import { MarketingApi } from '@/services/api/marketing/marketing'; +import { CustomerApi } from '@/services/api/master-data'; import { isResponseSuccess } from '@/lib/api-helper'; import { BaseMarketing, BaseSalesOrder } from '@/types/api/marketing/marketing'; @@ -73,15 +74,9 @@ const MarketingFilterModal = ({ isLoadingOptions: isLoadingCustomersOptions, setInputValue: setCustomersInputValue, loadMore: loadMoreCustomers, - } = useSelect( - MarketingApi.basePath, - 'customer.id', - 'customer.name', - 'search', - { - has_marketing: 'true', - } - ); + } = useSelect(CustomerApi.basePath, 'id', 'name', 'search', { + has_marketing: 'true', + }); const statusOptions = [ ...MARKETING_APPROVAL_LINE.map((item) => ({ From 7168270527d087b10634df783d9596eef2658d4c Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Mon, 13 Apr 2026 15:28:25 +0700 Subject: [PATCH 4/6] fix: use isNaN to check valid kandang ID --- src/components/pages/expense/form/ExpenseRealizationForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/pages/expense/form/ExpenseRealizationForm.tsx b/src/components/pages/expense/form/ExpenseRealizationForm.tsx index e9720d0b..9aa8eb7f 100644 --- a/src/components/pages/expense/form/ExpenseRealizationForm.tsx +++ b/src/components/pages/expense/form/ExpenseRealizationForm.tsx @@ -207,7 +207,7 @@ const ExpenseRealizationForm = ({ // add new realizations for each kandang kandangs.forEach((kandangItem) => { - if (!kandangItem.id) return; + if (isNaN(Number(kandangItem.id))) return; const existingRealization = formik.values.realizations?.find( (realizationItem) => realizationItem.kandang_id === kandangItem.id From 4b8853b7662c4db073dd07a1fedd0728c0f2b451 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Mon, 13 Apr 2026 15:31:04 +0700 Subject: [PATCH 5/6] fix: implement lazy loading in nontstock select input --- .../expense/form/ExpenseRealizationKandangDetailExpense.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/pages/expense/form/ExpenseRealizationKandangDetailExpense.tsx b/src/components/pages/expense/form/ExpenseRealizationKandangDetailExpense.tsx index fcf367eb..95d12703 100644 --- a/src/components/pages/expense/form/ExpenseRealizationKandangDetailExpense.tsx +++ b/src/components/pages/expense/form/ExpenseRealizationKandangDetailExpense.tsx @@ -35,6 +35,7 @@ const ExpenseRealizationKandangDetailExpense: React.FC< setInputValue: setNonstockInputValue, options: nonstockOptions, isLoadingOptions: isLoadingNonstockOptions, + loadMore: loadMoreNonstocks, } = useSelect( NonstockApi.basePath, 'id', @@ -164,6 +165,7 @@ const ExpenseRealizationKandangDetailExpense: React.FC< options={nonstockOptions} isLoading={isLoadingNonstockOptions} onInputChange={setNonstockInputValue} + onMenuScrollToBottom={loadMoreNonstocks} className={{ wrapper: 'min-w-48' }} isDisabled /> From 57ea81fdf2b7d13b98bcb397cd0b4eeae9d41117 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Mon, 13 Apr 2026 16:30:57 +0700 Subject: [PATCH 6/6] fix: change kandang_id to project_flock_kandang_id in report expense params --- src/components/pages/report/expense/tab/ReportExpenseTab.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/pages/report/expense/tab/ReportExpenseTab.tsx b/src/components/pages/report/expense/tab/ReportExpenseTab.tsx index f045621e..e439c09a 100644 --- a/src/components/pages/report/expense/tab/ReportExpenseTab.tsx +++ b/src/components/pages/report/expense/tab/ReportExpenseTab.tsx @@ -198,7 +198,7 @@ const ReportExpenseTab = ({ tabId }: ReportExpenseTabProps) => { if (filterParams.supplier_id) params.append('supplier_id', filterParams.supplier_id); if (filterParams.kandang_id) - params.append('kandang_id', filterParams.kandang_id); + params.append('project_flock_kandang_id', filterParams.kandang_id); if (filterParams.nonstock_id) params.append('nonstock_id', filterParams.nonstock_id); if (filterParams.realization_date)