mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-23 23:05:46 +00:00
refactor(FE): Replace active filter count logic with ButtonFilter
component
This commit is contained in:
@@ -42,6 +42,7 @@ import {
|
||||
} from './filter/ProjectFlockFilter';
|
||||
import Modal from '@/components/Modal';
|
||||
import SelectInputRadio from '@/components/input/SelectInputRadio';
|
||||
import ButtonFilter from '@/components/helper/ButtonFilter';
|
||||
|
||||
const RowOptionsMenu = ({
|
||||
props,
|
||||
@@ -346,25 +347,6 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
||||
);
|
||||
}, [formik.values.period, periodOptions]);
|
||||
|
||||
// ===== ACTIVE FILTERS COUNT =====
|
||||
const activeFiltersCount = useMemo(() => {
|
||||
let count = 0;
|
||||
if (tableFilterState.area_id) count += 1;
|
||||
if (tableFilterState.location_id) count += 1;
|
||||
if (tableFilterState.kandang_id) count += 1;
|
||||
if (tableFilterState.category) count += 1;
|
||||
if (tableFilterState.period) count += 1;
|
||||
return count;
|
||||
}, [
|
||||
tableFilterState.area_id,
|
||||
tableFilterState.location_id,
|
||||
tableFilterState.kandang_id,
|
||||
tableFilterState.category,
|
||||
tableFilterState.period,
|
||||
]);
|
||||
|
||||
const hasFilters = activeFiltersCount > 0;
|
||||
|
||||
// ===== FILTER DEPENDENCY HANDLERS =====
|
||||
const handleFilterAreaChange = (area: OptionType | null) => {
|
||||
const areaId = area?.value ? String(area.value) : undefined;
|
||||
@@ -961,25 +943,12 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
||||
}}
|
||||
/>
|
||||
|
||||
<Button
|
||||
variant='outline'
|
||||
color='none'
|
||||
<ButtonFilter
|
||||
values={tableFilterState}
|
||||
excludeFields={['page', 'pageSize', 'search']}
|
||||
onClick={handleFilterModalOpen}
|
||||
className={cn(
|
||||
'px-3 py-2.5 gap-1.5 text-sm text-base-content/50 border border-base-content/10 rounded-xl shadow-button-soft transition-all',
|
||||
{
|
||||
'border-primary-gradient text-primary': hasFilters,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<Icon icon='heroicons:funnel' width={20} height={20} />
|
||||
Filter
|
||||
{hasFilters && (
|
||||
<span className='w-5 h-5 text-white bg-[#FF3535] rounded-lg border border-base-300 flex items-center justify-center text-xs'>
|
||||
{activeFiltersCount}
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
className='px-3 py-2.5'
|
||||
/>
|
||||
|
||||
<Dropdown
|
||||
align='end'
|
||||
|
||||
@@ -45,6 +45,7 @@ import StatusBadge from '@/components/helper/StatusBadge';
|
||||
import CheckboxInput from '@/components/input/CheckboxInput';
|
||||
import { useUiStore } from '@/stores/ui/ui.store';
|
||||
import { Color } from '@/types/theme';
|
||||
import ButtonFilter from '@/components/helper/ButtonFilter';
|
||||
|
||||
// ===== STATUS BADGE UTILITIES =====
|
||||
const statusTextMap: Record<string, string> = {
|
||||
@@ -511,36 +512,6 @@ const RecordingTable = () => {
|
||||
);
|
||||
}, [formik.values.kandang_id, kandangOptions]);
|
||||
|
||||
// ===== ACTIVE FILTERS COUNT =====
|
||||
const activeFiltersCount = useMemo(() => {
|
||||
let count = 0;
|
||||
|
||||
if (tableFilterState.areaFilter) {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
if (tableFilterState.locationFilter) {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
if (tableFilterState.kandangFilter) {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
if (tableFilterState.projectFlockKandangFilter) {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
return count;
|
||||
}, [
|
||||
tableFilterState.areaFilter,
|
||||
tableFilterState.locationFilter,
|
||||
tableFilterState.kandangFilter,
|
||||
tableFilterState.projectFlockKandangFilter,
|
||||
]);
|
||||
|
||||
const hasFilters = activeFiltersCount > 0;
|
||||
|
||||
// ===== HANDLE FILTER MODAL OPEN =====
|
||||
const handleFilterModalOpen = () => {
|
||||
filterModal.openModal();
|
||||
@@ -1264,25 +1235,12 @@ const RecordingTable = () => {
|
||||
}}
|
||||
/>
|
||||
|
||||
<Button
|
||||
variant='outline'
|
||||
color='none'
|
||||
<ButtonFilter
|
||||
values={tableFilterState}
|
||||
excludeFields={['page', 'pageSize', 'search']}
|
||||
onClick={handleFilterModalOpen}
|
||||
className={cn(
|
||||
'px-3 py-2.5 gap-1.5 text-sm text-base-content/50 border border-base-content/10 rounded-xl shadow-button-soft transition-all',
|
||||
{
|
||||
'border-primary-gradient text-primary': hasFilters,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<Icon icon='heroicons:funnel' width={20} height={20} />
|
||||
Filter
|
||||
{hasFilters && (
|
||||
<span className='w-5 h-5 text-white bg-[#FF3535] rounded-lg border border-base-300 flex items-center justify-center text-xs'>
|
||||
{activeFiltersCount}
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
className='px-3 py-2.5'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
||||
import { useTableFilter } from '@/services/hooks/useTableFilter';
|
||||
import { Color } from '@/types/theme';
|
||||
import DebouncedTextInput from '@/components/input/DebouncedTextInput';
|
||||
import ButtonFilter from '@/components/helper/ButtonFilter';
|
||||
|
||||
const RowOptionsMenu = ({
|
||||
props,
|
||||
@@ -159,30 +160,6 @@ const TransferToLayingsTable = () => {
|
||||
TransferToLayingApi.getAllFetcher
|
||||
);
|
||||
|
||||
const filterCount = useMemo(() => {
|
||||
let count = 0;
|
||||
|
||||
if (tableFilterState.startDate && tableFilterState.endDate) {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
if (tableFilterState.flockSource.length > 0) {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
if (tableFilterState.flockDestination.length > 0) {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
if (tableFilterState.status.length > 0) {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
return count;
|
||||
}, [tableFilterState]);
|
||||
|
||||
const isFilterActive = filterCount > 0;
|
||||
|
||||
const [isLoadingExportingToExcel, setIsLoadingExportingToExcel] =
|
||||
useState(false);
|
||||
|
||||
@@ -559,30 +536,19 @@ const TransferToLayingsTable = () => {
|
||||
}}
|
||||
/>
|
||||
|
||||
<Button
|
||||
variant='outline'
|
||||
color='none'
|
||||
<ButtonFilter
|
||||
values={tableFilterState}
|
||||
excludeFields={[
|
||||
'page',
|
||||
'pageSize',
|
||||
'search',
|
||||
'filter_by',
|
||||
'sort_by',
|
||||
]}
|
||||
fieldGroups={[['startDate', 'endDate']]}
|
||||
onClick={filterModal.openModal}
|
||||
className={cn(
|
||||
'px-3 py-2.5 gap-1.5 text-sm text-base-content/50 border border-base-content/10 rounded-xl shadow-button-soft transition-all',
|
||||
{
|
||||
'border-primary-gradient text-primary': isFilterActive,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<Icon icon='heroicons:funnel' width={20} height={20} />
|
||||
Filter
|
||||
{isFilterActive && (
|
||||
<Badge
|
||||
className={{
|
||||
badge:
|
||||
'p-1.5 bg-[#FF3535] text-xs text-base-100 border border-base-300 rounded-lg',
|
||||
}}
|
||||
>
|
||||
{filterCount}
|
||||
</Badge>
|
||||
)}
|
||||
</Button>
|
||||
className='px-3 py-2.5'
|
||||
/>
|
||||
|
||||
<Dropdown
|
||||
align='end'
|
||||
|
||||
@@ -48,6 +48,7 @@ import {
|
||||
import { generateUniformityPDF } from '@/components/pages/production/uniformity/export/UniformityExportPDF';
|
||||
import { generateUniformityExcel } from '@/components/pages/production/uniformity/export/UniformityExportExcel';
|
||||
import Dropdown from '@/components/Dropdown';
|
||||
import ButtonFilter from '@/components/helper/ButtonFilter';
|
||||
import { useFormik } from 'formik';
|
||||
import {
|
||||
UniformityTableFilterSchema,
|
||||
@@ -192,16 +193,28 @@ const UniformityTable = () => {
|
||||
|
||||
const {
|
||||
state: tableFilterState,
|
||||
updateFilter,
|
||||
setPage,
|
||||
setPageSize,
|
||||
toQueryString: getTableFilterQueryString,
|
||||
} = useTableFilter({
|
||||
initial: {
|
||||
search: '',
|
||||
start_date: '',
|
||||
end_date: '',
|
||||
location_id: '',
|
||||
project_flock_id: '',
|
||||
kandang_id: '',
|
||||
},
|
||||
paramMap: {
|
||||
page: 'page',
|
||||
pageSize: 'limit',
|
||||
search: 'search',
|
||||
start_date: 'start_date',
|
||||
end_date: 'end_date',
|
||||
location_id: 'location_id',
|
||||
project_flock_id: 'project_flock_id',
|
||||
kandang_id: 'kandang_id',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -233,8 +246,6 @@ const UniformityTable = () => {
|
||||
const [filterKandang, setFilterKandang] = useState<OptionType | null>(null);
|
||||
const [filterProjectFlockKandangId, setFilterProjectFlockKandangId] =
|
||||
useState<number | undefined>(undefined);
|
||||
const [filterStartDate, setFilterStartDate] = useState('');
|
||||
const [filterEndDate, setFilterEndDate] = useState('');
|
||||
const [filterProjectFlockLocationId, setFilterProjectFlockLocationId] =
|
||||
useState<string>('');
|
||||
const [, setFilterErrors] = useState<Record<string, string>>({});
|
||||
@@ -319,8 +330,8 @@ const UniformityTable = () => {
|
||||
// ===== FORMIK FILTER =====
|
||||
const filterFormik = useFormik<UniformityTableFilterValues>({
|
||||
initialValues: {
|
||||
start_date: filterStartDate,
|
||||
end_date: filterEndDate,
|
||||
start_date: tableFilterState.start_date,
|
||||
end_date: tableFilterState.end_date,
|
||||
location: filterLocation,
|
||||
project_flock: filterProjectFlock,
|
||||
project_flock_kandang_id: filterProjectFlockKandangId,
|
||||
@@ -329,8 +340,21 @@ const UniformityTable = () => {
|
||||
validationSchema: UniformityTableFilterSchema,
|
||||
enableReinitialize: true,
|
||||
onSubmit: async (values) => {
|
||||
setFilterStartDate(values.start_date);
|
||||
setFilterEndDate(values.end_date);
|
||||
updateFilter('start_date', values.start_date);
|
||||
updateFilter('end_date', values.end_date);
|
||||
updateFilter(
|
||||
'location_id',
|
||||
values.location?.value ? String(values.location.value) : ''
|
||||
);
|
||||
updateFilter(
|
||||
'project_flock_id',
|
||||
values.project_flock?.value ? String(values.project_flock.value) : ''
|
||||
);
|
||||
updateFilter(
|
||||
'kandang_id',
|
||||
values.kandang?.value ? String(values.kandang.value) : ''
|
||||
);
|
||||
|
||||
setFilterLocation(values.location ?? null);
|
||||
setFilterProjectFlock(values.project_flock ?? null);
|
||||
setFilterKandang(values.kandang ?? null);
|
||||
@@ -356,11 +380,11 @@ const UniformityTable = () => {
|
||||
filterProjectFlockKandangId.toString()
|
||||
);
|
||||
}
|
||||
if (filterStartDate) {
|
||||
queryParams.append('start_date', filterStartDate);
|
||||
if (tableFilterState.start_date) {
|
||||
queryParams.append('start_date', tableFilterState.start_date);
|
||||
}
|
||||
if (filterEndDate) {
|
||||
queryParams.append('end_date', filterEndDate);
|
||||
if (tableFilterState.end_date) {
|
||||
queryParams.append('end_date', tableFilterState.end_date);
|
||||
}
|
||||
queryParams.append('with_chart', 'true');
|
||||
}
|
||||
@@ -379,8 +403,8 @@ const UniformityTable = () => {
|
||||
}, [
|
||||
isSubmitted,
|
||||
filterProjectFlockKandangId,
|
||||
filterStartDate,
|
||||
filterEndDate,
|
||||
tableFilterState.start_date,
|
||||
tableFilterState.end_date,
|
||||
getTableFilterQueryString,
|
||||
]);
|
||||
|
||||
@@ -456,30 +480,16 @@ const UniformityTable = () => {
|
||||
setFilterProjectFlock(null);
|
||||
setFilterKandang(null);
|
||||
setFilterProjectFlockKandangId(undefined);
|
||||
setFilterStartDate('');
|
||||
setFilterEndDate('');
|
||||
setFilterErrors({});
|
||||
|
||||
updateFilter('start_date', '');
|
||||
updateFilter('end_date', '');
|
||||
updateFilter('location_id', '');
|
||||
updateFilter('project_flock_id', '');
|
||||
updateFilter('kandang_id', '');
|
||||
|
||||
filterFormik.resetForm();
|
||||
}, [filterFormik]);
|
||||
|
||||
const handleFilterStartDateChange = useCallback(
|
||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value;
|
||||
setFilterStartDate(value);
|
||||
filterFormik.setFieldValue('start_date', value);
|
||||
},
|
||||
[filterFormik]
|
||||
);
|
||||
|
||||
const handleFilterEndDateChange = useCallback(
|
||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value;
|
||||
setFilterEndDate(value);
|
||||
filterFormik.setFieldValue('end_date', value);
|
||||
},
|
||||
[filterFormik]
|
||||
);
|
||||
}, [filterFormik, updateFilter]);
|
||||
|
||||
const selectedRowIds = useMemo(() => {
|
||||
return Object.keys(rowSelection)
|
||||
@@ -662,11 +672,11 @@ const UniformityTable = () => {
|
||||
filterProjectFlockKandangId.toString()
|
||||
);
|
||||
}
|
||||
if (filterStartDate) {
|
||||
queryParams.append('start_date', filterStartDate);
|
||||
if (tableFilterState.start_date) {
|
||||
queryParams.append('start_date', tableFilterState.start_date);
|
||||
}
|
||||
if (filterEndDate) {
|
||||
queryParams.append('end_date', filterEndDate);
|
||||
if (tableFilterState.end_date) {
|
||||
queryParams.append('end_date', tableFilterState.end_date);
|
||||
}
|
||||
queryParams.append('limit', '100');
|
||||
queryParams.append('page', '1');
|
||||
@@ -677,7 +687,7 @@ const UniformityTable = () => {
|
||||
const response = await UniformityApi.getAllFetcher(url);
|
||||
|
||||
return isResponseSuccess(response) ? response.data : null;
|
||||
}, [filterProjectFlockKandangId, filterStartDate, filterEndDate]);
|
||||
}, [filterProjectFlockKandangId, tableFilterState.start_date, tableFilterState.end_date]);
|
||||
|
||||
const handleExportExcel = useCallback(async () => {
|
||||
setIsExcelExportLoading(true);
|
||||
@@ -698,8 +708,8 @@ const UniformityTable = () => {
|
||||
location_name: locationName,
|
||||
project_flock_name: projectFlockName,
|
||||
kandang_name: kandangName,
|
||||
start_date: filterStartDate,
|
||||
end_date: filterEndDate,
|
||||
start_date: tableFilterState.start_date,
|
||||
end_date: tableFilterState.end_date,
|
||||
});
|
||||
|
||||
toast.success('Excel berhasil dibuat dan diunduh.');
|
||||
@@ -713,8 +723,8 @@ const UniformityTable = () => {
|
||||
filterLocation,
|
||||
filterProjectFlock,
|
||||
filterKandang,
|
||||
filterStartDate,
|
||||
filterEndDate,
|
||||
tableFilterState.start_date,
|
||||
tableFilterState.end_date,
|
||||
]);
|
||||
|
||||
const handleExportPDF = useCallback(async () => {
|
||||
@@ -736,8 +746,8 @@ const UniformityTable = () => {
|
||||
location_name: locationName,
|
||||
project_flock_name: projectFlockName,
|
||||
kandang_name: kandangName,
|
||||
start_date: filterStartDate,
|
||||
end_date: filterEndDate,
|
||||
start_date: tableFilterState.start_date,
|
||||
end_date: tableFilterState.end_date,
|
||||
});
|
||||
|
||||
toast.success('PDF berhasil dibuat dan diunduh.');
|
||||
@@ -751,8 +761,8 @@ const UniformityTable = () => {
|
||||
filterLocation,
|
||||
filterProjectFlock,
|
||||
filterKandang,
|
||||
filterStartDate,
|
||||
filterEndDate,
|
||||
tableFilterState.start_date,
|
||||
tableFilterState.end_date,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -883,37 +893,6 @@ const UniformityTable = () => {
|
||||
[]
|
||||
);
|
||||
|
||||
// ===== CALCULATE FILTER COUNT =====
|
||||
const filterCount = useMemo(() => {
|
||||
let count = 0;
|
||||
|
||||
if (filterStartDate && filterEndDate) {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
if (filterLocation) {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
if (filterProjectFlock) {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
if (filterKandang) {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
return count;
|
||||
}, [
|
||||
filterStartDate,
|
||||
filterEndDate,
|
||||
filterLocation,
|
||||
filterProjectFlock,
|
||||
filterKandang,
|
||||
]);
|
||||
|
||||
const isFilterActive = filterCount > 0;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='@container w-full'>
|
||||
@@ -932,30 +911,13 @@ const UniformityTable = () => {
|
||||
</div>
|
||||
|
||||
<div className='flex flex-1 flex-row justify-start sm:justify-end items-center gap-3 flex-wrap'>
|
||||
<Button
|
||||
variant='outline'
|
||||
color='none'
|
||||
<ButtonFilter
|
||||
values={tableFilterState}
|
||||
excludeFields={['page', 'pageSize', 'search']}
|
||||
fieldGroups={[['start_date', 'end_date']]}
|
||||
onClick={filterModal.openModal}
|
||||
className={cn(
|
||||
'px-3 py-2.5 gap-1.5 text-sm text-base-content/50 border border-base-content/10 rounded-xl shadow-button-soft transition-all',
|
||||
{
|
||||
'border-primary-gradient text-primary': isFilterActive,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<Icon icon='heroicons:funnel' width={20} height={20} />
|
||||
Filter
|
||||
{isFilterActive && (
|
||||
<Badge
|
||||
className={{
|
||||
badge:
|
||||
'p-1.5 bg-[#FF3535] text-xs text-base-100 border border-base-300 rounded-lg',
|
||||
}}
|
||||
>
|
||||
{filterCount}
|
||||
</Badge>
|
||||
)}
|
||||
</Button>
|
||||
className='px-3 py-2.5'
|
||||
/>
|
||||
|
||||
<Dropdown
|
||||
align='end'
|
||||
@@ -1279,7 +1241,7 @@ const UniformityTable = () => {
|
||||
placeholder='Tanggal Mulai'
|
||||
value={filterFormik.values.start_date}
|
||||
errorMessage={filterFormik.errors.start_date}
|
||||
onChange={handleFilterStartDateChange}
|
||||
onChange={(e) => filterFormik.setFieldValue('start_date', e.target.value)}
|
||||
isError={
|
||||
filterFormik.touched.start_date &&
|
||||
Boolean(filterFormik.errors.start_date)
|
||||
@@ -1291,7 +1253,7 @@ const UniformityTable = () => {
|
||||
placeholder='Tanggal Akhir'
|
||||
value={filterFormik.values.end_date}
|
||||
errorMessage={filterFormik.errors.end_date}
|
||||
onChange={handleFilterEndDateChange}
|
||||
onChange={(e) => filterFormik.setFieldValue('end_date', e.target.value)}
|
||||
isError={
|
||||
filterFormik.touched.end_date &&
|
||||
Boolean(filterFormik.errors.end_date)
|
||||
|
||||
Reference in New Issue
Block a user