From f51236fcfcc5deca97d3ee2cc06f9426eff3c7dc Mon Sep 17 00:00:00 2001 From: rstubryan Date: Tue, 30 Dec 2025 10:23:01 +0700 Subject: [PATCH] refactor(FE-316): Use single-select filters, add PF-Kandang lookup --- .../pages/uniformity/UniformityTable.tsx | 127 +++++++++++------- src/services/api/uniformity.ts | 8 +- 2 files changed, 76 insertions(+), 59 deletions(-) diff --git a/src/components/pages/uniformity/UniformityTable.tsx b/src/components/pages/uniformity/UniformityTable.tsx index 205d6966..8e557983 100644 --- a/src/components/pages/uniformity/UniformityTable.tsx +++ b/src/components/pages/uniformity/UniformityTable.tsx @@ -12,6 +12,7 @@ import { useTableFilter } from '@/services/hooks/useTableFilter'; import { UniformityApi } from '@/services/api/uniformity'; import { type Uniformity } from '@/types/api/uniformity/uniformity'; import { isResponseSuccess } from '@/lib/api-helper'; +import { type BaseApiResponse } from '@/types/api/api-general'; import Table from '@/components/Table'; import Badge from '@/components/Badge'; import CheckboxInput from '@/components/input/CheckboxInput'; @@ -30,11 +31,9 @@ import SelectInput, { } from '@/components/input/SelectInput'; import DateInput from '@/components/input/DateInput'; import { LocationApi } from '@/services/api/master-data'; -import { - ProjectFlockApi, - ProjectFlockKandangApi, -} from '@/services/api/production'; +import { ProjectFlockApi } from '@/services/api/production'; import { Kandang } from '@/types/api/master-data/kandang'; +import { ProjectFlockKandangLookup } from '@/types/api/production/project-flock'; import { getStatusColor, getStatusIndicatorColor, @@ -185,11 +184,12 @@ const UniformityTable = ({ refresh }: { refresh?: () => void }) => { const filterModal = useModal(); // ===== FILTER STATE ===== - const [filterLocation, setFilterLocation] = useState([]); - const [filterProjectFlock, setFilterProjectFlock] = useState( - [] - ); - const [filterKandang, setFilterKandang] = useState([]); + const [filterLocation, setFilterLocation] = useState(null); + const [filterProjectFlock, setFilterProjectFlock] = + useState(null); + const [filterKandang, setFilterKandang] = useState(null); + const [filterProjectFlockKandangId, setFilterProjectFlockKandangId] = + useState(undefined); const [filterStartDate, setFilterStartDate] = useState(''); const [filterEndDate, setFilterEndDate] = useState(''); const [projectFlockSearchValue, setProjectFlockSearchValue] = useState(''); @@ -206,9 +206,8 @@ const UniformityTable = ({ refresh }: { refresh?: () => void }) => { search: projectFlockSearchValue || '', limit: '100', }); - if (filterLocation.length > 0) { - const locationIds = filterLocation.map((loc) => loc.value).join(','); - params.append('location_id', locationIds); + if (filterLocation) { + params.append('location_id', filterLocation.value.toString()); } return `${ProjectFlockApi.basePath}?${params.toString()}`; }, [projectFlockSearchValue, filterLocation]); @@ -245,42 +244,70 @@ const UniformityTable = ({ refresh }: { refresh?: () => void }) => { const filterKandangOptions = useMemo(() => { let options: OptionType[] = []; - if (filterProjectFlock.length > 0 && filterProjectFlocksDataList) { - const selectedProjectFlockIds = filterProjectFlock.map((pf) => pf.value); + if (filterProjectFlock && filterProjectFlocksDataList) { + const selectedProjectFlockData = filterProjectFlocksDataList.find( + (pf) => pf.id === filterProjectFlock.value + ); - filterProjectFlocksDataList.forEach((projectFlock) => { - if ( - selectedProjectFlockIds.includes(projectFlock.id) && - projectFlock.kandangs - ) { - const kandangOpts = projectFlock.kandangs.map((kandang: Kandang) => ({ + if (selectedProjectFlockData?.kandangs) { + const kandangOpts = selectedProjectFlockData.kandangs.map( + (kandang: Kandang) => ({ value: kandang.id, label: kandang.name || '', - })); - options = options.concat(kandangOpts); - } - }); + }) + ); + options = options.concat(kandangOpts); + } } return options; }, [filterProjectFlock, filterProjectFlocksDataList]); + // ===== PROJECT FLOCK KANDANG LOOKUP ===== + const projectFlockKandangLookupUrl = useMemo(() => { + if (!filterProjectFlock || !filterKandang) return null; + const params = new URLSearchParams({ + project_flock_id: filterProjectFlock.value.toString(), + kandang_id: filterKandang.value.toString(), + withpopulation: Boolean(true).toString(), + }); + return `${ProjectFlockApi.basePath}/kandangs/lookup?${params.toString()}`; + }, [filterProjectFlock, filterKandang]); + + const { data: projectFlockKandangLookupData } = useSWR( + projectFlockKandangLookupUrl, + projectFlockKandangLookupUrl + ? () => + ProjectFlockApi.getAllFetcher( + projectFlockKandangLookupUrl + ) as Promise> + : null + ); + + const projectFlockKandangLookup = + projectFlockKandangLookupData?.status === 'success' + ? projectFlockKandangLookupData.data + : undefined; + + // Update filterProjectFlockKandangId when lookup changes + useEffect(() => { + if (projectFlockKandangLookup?.id) { + setFilterProjectFlockKandangId(projectFlockKandangLookup.id); + } else { + setFilterProjectFlockKandangId(undefined); + } + }, [projectFlockKandangLookup]); + // ===== BUILD SWR KEY WITH FILTERS ===== const uniformitySwrKey = useMemo(() => { const basePath = UniformityApi.basePath; const queryParams = new URLSearchParams(); - if (filterLocation.length > 0) { - const locationIds = filterLocation.map((loc) => loc.value).join(','); - queryParams.append('location_id', locationIds); - } - if (filterProjectFlock.length > 0) { - const flockIds = filterProjectFlock.map((pf) => pf.value).join(','); - queryParams.append('project_flock_id', flockIds); - } - if (filterKandang.length > 0) { - const kandangIds = filterKandang.map((k) => k.value).join(','); - queryParams.append('kandang_id', kandangIds); + if (filterProjectFlockKandangId) { + queryParams.append( + 'project_flock_kandang_id', + filterProjectFlockKandangId.toString() + ); } if (filterStartDate) { queryParams.append('start_date', filterStartDate); @@ -301,9 +328,7 @@ const UniformityTable = ({ refresh }: { refresh?: () => void }) => { const queryString = queryParams.toString(); return queryString ? `${basePath}?${queryString}` : basePath; }, [ - filterLocation, - filterProjectFlock, - filterKandang, + filterProjectFlockKandangId, filterStartDate, filterEndDate, getTableFilterQueryString, @@ -318,32 +343,33 @@ const UniformityTable = ({ refresh }: { refresh?: () => void }) => { // ===== FILTER HANDLERS ===== const handleFilterLocationChange = useCallback( (val: OptionType | OptionType[] | null) => { - const arr = Array.isArray(val) ? val : val ? [val] : []; - setFilterLocation(arr); + setFilterLocation(val as OptionType | null); + setFilterProjectFlock(null); + setFilterKandang(null); }, [] ); const handleFilterProjectFlockChange = useCallback( (val: OptionType | OptionType[] | null) => { - const arr = Array.isArray(val) ? val : val ? [val] : []; - setFilterProjectFlock(arr); + setFilterProjectFlock(val as OptionType | null); + setFilterKandang(null); }, [] ); const handleFilterKandangChange = useCallback( (val: OptionType | OptionType[] | null) => { - const arr = Array.isArray(val) ? val : val ? [val] : []; - setFilterKandang(arr); + setFilterKandang(val as OptionType | null); }, [] ); const handleResetFilters = useCallback(() => { - setFilterLocation([]); - setFilterProjectFlock([]); - setFilterKandang([]); + setFilterLocation(null); + setFilterProjectFlock(null); + setFilterKandang(null); + setFilterProjectFlockKandangId(undefined); setFilterStartDate(''); setFilterEndDate(''); }, []); @@ -899,7 +925,6 @@ const UniformityTable = ({ refresh }: { refresh?: () => void }) => { onInputChange={setFilterLocationInputValue} isLoading={isLoadingFilterLocations} isClearable - isMulti className={{ wrapper: 'w-full' }} /> @@ -911,9 +936,8 @@ const UniformityTable = ({ refresh }: { refresh?: () => void }) => { options={filterProjectFlockOptions} onInputChange={setProjectFlockSearchValue} isLoading={isLoadingFilterProjectFlocks} - isDisabled={filterLocation.length === 0} + isDisabled={!filterLocation} isClearable - isMulti className={{ wrapper: 'w-full' }} /> @@ -923,9 +947,8 @@ const UniformityTable = ({ refresh }: { refresh?: () => void }) => { value={filterKandang} onChange={handleFilterKandangChange} options={filterKandangOptions} - isDisabled={filterProjectFlock.length === 0} + isDisabled={!filterProjectFlock} isClearable - isMulti className={{ wrapper: 'w-full' }} /> diff --git a/src/services/api/uniformity.ts b/src/services/api/uniformity.ts index 59161734..1f048dc6 100644 --- a/src/services/api/uniformity.ts +++ b/src/services/api/uniformity.ts @@ -18,10 +18,7 @@ export class UniformityApiService extends BaseApiService< } async getUniformity( - location_id?: string, - project_flock_id?: string, - kandang_id?: string, - project_flock_kandang_id?: string, + project_flock_kandang_id?: number, start_date?: string, end_date?: string, page?: number, @@ -30,9 +27,6 @@ export class UniformityApiService extends BaseApiService< return await this.customRequest>('', { method: 'GET', params: { - location_id: location_id, - project_flock_id: project_flock_id, - kandang_id: kandang_id, project_flock_kandang_id: project_flock_kandang_id, start_date: start_date, end_date: end_date,