refactor(FE-316): Use single-select filters, add PF-Kandang lookup

This commit is contained in:
rstubryan
2025-12-30 10:23:01 +07:00
parent c385c42c8f
commit f51236fcfc
2 changed files with 76 additions and 59 deletions
@@ -12,6 +12,7 @@ import { useTableFilter } from '@/services/hooks/useTableFilter';
import { UniformityApi } from '@/services/api/uniformity'; import { UniformityApi } from '@/services/api/uniformity';
import { type Uniformity } from '@/types/api/uniformity/uniformity'; import { type Uniformity } from '@/types/api/uniformity/uniformity';
import { isResponseSuccess } from '@/lib/api-helper'; import { isResponseSuccess } from '@/lib/api-helper';
import { type BaseApiResponse } from '@/types/api/api-general';
import Table from '@/components/Table'; import Table from '@/components/Table';
import Badge from '@/components/Badge'; import Badge from '@/components/Badge';
import CheckboxInput from '@/components/input/CheckboxInput'; import CheckboxInput from '@/components/input/CheckboxInput';
@@ -30,11 +31,9 @@ import SelectInput, {
} from '@/components/input/SelectInput'; } from '@/components/input/SelectInput';
import DateInput from '@/components/input/DateInput'; import DateInput from '@/components/input/DateInput';
import { LocationApi } from '@/services/api/master-data'; import { LocationApi } from '@/services/api/master-data';
import { import { ProjectFlockApi } from '@/services/api/production';
ProjectFlockApi,
ProjectFlockKandangApi,
} from '@/services/api/production';
import { Kandang } from '@/types/api/master-data/kandang'; import { Kandang } from '@/types/api/master-data/kandang';
import { ProjectFlockKandangLookup } from '@/types/api/production/project-flock';
import { import {
getStatusColor, getStatusColor,
getStatusIndicatorColor, getStatusIndicatorColor,
@@ -185,11 +184,12 @@ const UniformityTable = ({ refresh }: { refresh?: () => void }) => {
const filterModal = useModal(); const filterModal = useModal();
// ===== FILTER STATE ===== // ===== FILTER STATE =====
const [filterLocation, setFilterLocation] = useState<OptionType[]>([]); const [filterLocation, setFilterLocation] = useState<OptionType | null>(null);
const [filterProjectFlock, setFilterProjectFlock] = useState<OptionType[]>( const [filterProjectFlock, setFilterProjectFlock] =
[] useState<OptionType | null>(null);
); const [filterKandang, setFilterKandang] = useState<OptionType | null>(null);
const [filterKandang, setFilterKandang] = useState<OptionType[]>([]); const [filterProjectFlockKandangId, setFilterProjectFlockKandangId] =
useState<number | undefined>(undefined);
const [filterStartDate, setFilterStartDate] = useState(''); const [filterStartDate, setFilterStartDate] = useState('');
const [filterEndDate, setFilterEndDate] = useState(''); const [filterEndDate, setFilterEndDate] = useState('');
const [projectFlockSearchValue, setProjectFlockSearchValue] = useState(''); const [projectFlockSearchValue, setProjectFlockSearchValue] = useState('');
@@ -206,9 +206,8 @@ const UniformityTable = ({ refresh }: { refresh?: () => void }) => {
search: projectFlockSearchValue || '', search: projectFlockSearchValue || '',
limit: '100', limit: '100',
}); });
if (filterLocation.length > 0) { if (filterLocation) {
const locationIds = filterLocation.map((loc) => loc.value).join(','); params.append('location_id', filterLocation.value.toString());
params.append('location_id', locationIds);
} }
return `${ProjectFlockApi.basePath}?${params.toString()}`; return `${ProjectFlockApi.basePath}?${params.toString()}`;
}, [projectFlockSearchValue, filterLocation]); }, [projectFlockSearchValue, filterLocation]);
@@ -245,42 +244,70 @@ const UniformityTable = ({ refresh }: { refresh?: () => void }) => {
const filterKandangOptions = useMemo(() => { const filterKandangOptions = useMemo(() => {
let options: OptionType[] = []; let options: OptionType[] = [];
if (filterProjectFlock.length > 0 && filterProjectFlocksDataList) { if (filterProjectFlock && filterProjectFlocksDataList) {
const selectedProjectFlockIds = filterProjectFlock.map((pf) => pf.value); const selectedProjectFlockData = filterProjectFlocksDataList.find(
(pf) => pf.id === filterProjectFlock.value
);
filterProjectFlocksDataList.forEach((projectFlock) => { if (selectedProjectFlockData?.kandangs) {
if ( const kandangOpts = selectedProjectFlockData.kandangs.map(
selectedProjectFlockIds.includes(projectFlock.id) && (kandang: Kandang) => ({
projectFlock.kandangs
) {
const kandangOpts = projectFlock.kandangs.map((kandang: Kandang) => ({
value: kandang.id, value: kandang.id,
label: kandang.name || '', label: kandang.name || '',
})); })
options = options.concat(kandangOpts); );
} options = options.concat(kandangOpts);
}); }
} }
return options; return options;
}, [filterProjectFlock, filterProjectFlocksDataList]); }, [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<BaseApiResponse<ProjectFlockKandangLookup>>
: 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 ===== // ===== BUILD SWR KEY WITH FILTERS =====
const uniformitySwrKey = useMemo(() => { const uniformitySwrKey = useMemo(() => {
const basePath = UniformityApi.basePath; const basePath = UniformityApi.basePath;
const queryParams = new URLSearchParams(); const queryParams = new URLSearchParams();
if (filterLocation.length > 0) { if (filterProjectFlockKandangId) {
const locationIds = filterLocation.map((loc) => loc.value).join(','); queryParams.append(
queryParams.append('location_id', locationIds); 'project_flock_kandang_id',
} filterProjectFlockKandangId.toString()
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 (filterStartDate) { if (filterStartDate) {
queryParams.append('start_date', filterStartDate); queryParams.append('start_date', filterStartDate);
@@ -301,9 +328,7 @@ const UniformityTable = ({ refresh }: { refresh?: () => void }) => {
const queryString = queryParams.toString(); const queryString = queryParams.toString();
return queryString ? `${basePath}?${queryString}` : basePath; return queryString ? `${basePath}?${queryString}` : basePath;
}, [ }, [
filterLocation, filterProjectFlockKandangId,
filterProjectFlock,
filterKandang,
filterStartDate, filterStartDate,
filterEndDate, filterEndDate,
getTableFilterQueryString, getTableFilterQueryString,
@@ -318,32 +343,33 @@ const UniformityTable = ({ refresh }: { refresh?: () => void }) => {
// ===== FILTER HANDLERS ===== // ===== FILTER HANDLERS =====
const handleFilterLocationChange = useCallback( const handleFilterLocationChange = useCallback(
(val: OptionType | OptionType[] | null) => { (val: OptionType | OptionType[] | null) => {
const arr = Array.isArray(val) ? val : val ? [val] : []; setFilterLocation(val as OptionType | null);
setFilterLocation(arr); setFilterProjectFlock(null);
setFilterKandang(null);
}, },
[] []
); );
const handleFilterProjectFlockChange = useCallback( const handleFilterProjectFlockChange = useCallback(
(val: OptionType | OptionType[] | null) => { (val: OptionType | OptionType[] | null) => {
const arr = Array.isArray(val) ? val : val ? [val] : []; setFilterProjectFlock(val as OptionType | null);
setFilterProjectFlock(arr); setFilterKandang(null);
}, },
[] []
); );
const handleFilterKandangChange = useCallback( const handleFilterKandangChange = useCallback(
(val: OptionType | OptionType[] | null) => { (val: OptionType | OptionType[] | null) => {
const arr = Array.isArray(val) ? val : val ? [val] : []; setFilterKandang(val as OptionType | null);
setFilterKandang(arr);
}, },
[] []
); );
const handleResetFilters = useCallback(() => { const handleResetFilters = useCallback(() => {
setFilterLocation([]); setFilterLocation(null);
setFilterProjectFlock([]); setFilterProjectFlock(null);
setFilterKandang([]); setFilterKandang(null);
setFilterProjectFlockKandangId(undefined);
setFilterStartDate(''); setFilterStartDate('');
setFilterEndDate(''); setFilterEndDate('');
}, []); }, []);
@@ -899,7 +925,6 @@ const UniformityTable = ({ refresh }: { refresh?: () => void }) => {
onInputChange={setFilterLocationInputValue} onInputChange={setFilterLocationInputValue}
isLoading={isLoadingFilterLocations} isLoading={isLoadingFilterLocations}
isClearable isClearable
isMulti
className={{ wrapper: 'w-full' }} className={{ wrapper: 'w-full' }}
/> />
@@ -911,9 +936,8 @@ const UniformityTable = ({ refresh }: { refresh?: () => void }) => {
options={filterProjectFlockOptions} options={filterProjectFlockOptions}
onInputChange={setProjectFlockSearchValue} onInputChange={setProjectFlockSearchValue}
isLoading={isLoadingFilterProjectFlocks} isLoading={isLoadingFilterProjectFlocks}
isDisabled={filterLocation.length === 0} isDisabled={!filterLocation}
isClearable isClearable
isMulti
className={{ wrapper: 'w-full' }} className={{ wrapper: 'w-full' }}
/> />
@@ -923,9 +947,8 @@ const UniformityTable = ({ refresh }: { refresh?: () => void }) => {
value={filterKandang} value={filterKandang}
onChange={handleFilterKandangChange} onChange={handleFilterKandangChange}
options={filterKandangOptions} options={filterKandangOptions}
isDisabled={filterProjectFlock.length === 0} isDisabled={!filterProjectFlock}
isClearable isClearable
isMulti
className={{ wrapper: 'w-full' }} className={{ wrapper: 'w-full' }}
/> />
</div> </div>
+1 -7
View File
@@ -18,10 +18,7 @@ export class UniformityApiService extends BaseApiService<
} }
async getUniformity( async getUniformity(
location_id?: string, project_flock_kandang_id?: number,
project_flock_id?: string,
kandang_id?: string,
project_flock_kandang_id?: string,
start_date?: string, start_date?: string,
end_date?: string, end_date?: string,
page?: number, page?: number,
@@ -30,9 +27,6 @@ export class UniformityApiService extends BaseApiService<
return await this.customRequest<BaseApiResponse<Uniformity>>('', { return await this.customRequest<BaseApiResponse<Uniformity>>('', {
method: 'GET', method: 'GET',
params: { params: {
location_id: location_id,
project_flock_id: project_flock_id,
kandang_id: kandang_id,
project_flock_kandang_id: project_flock_kandang_id, project_flock_kandang_id: project_flock_kandang_id,
start_date: start_date, start_date: start_date,
end_date: end_date, end_date: end_date,