refactor(FE): Replace active filter count logic with ButtonFilter

component
This commit is contained in:
rstubryan
2026-02-25 10:39:14 +07:00
parent 47a2439777
commit f701ab0d91
13 changed files with 147 additions and 605 deletions
+6 -35
View File
@@ -31,6 +31,7 @@ import {
ClosingFilterType,
} from '@/components/pages/closing/filter/ClosingFilter';
import ClosingTableSkeleton from '@/components/pages/closing/skeleton/ClosingTableSkeleton';
import ButtonFilter from '@/components/helper/ButtonFilter';
const RowOptionsMenu = ({
props,
@@ -287,23 +288,6 @@ const ClosingsTable = () => {
);
}, [formik.values.project_status, projectStatusOptions]);
// ===== ACTIVE FILTERS COUNT =====
const activeFiltersCount = useMemo(() => {
let count = 0;
if (tableFilterState.location_id) {
count += 1;
}
if (tableFilterState.project_status) {
count += 1;
}
return count;
}, [tableFilterState.location_id, tableFilterState.project_status]);
const hasFilters = activeFiltersCount > 0;
// ===== SEARCH CHANGE HANDLER =====
const searchChangeHandler: ChangeEventHandler<HTMLInputElement> = (e) => {
updateFilter('search', e.target.value);
@@ -352,25 +336,12 @@ const ClosingsTable = () => {
}}
/>
<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>
@@ -30,6 +30,7 @@ import PopoverButton from '@/components/popover/PopoverButton';
import PopoverContent from '@/components/popover/PopoverContent';
import StatusBadge from '@/components/helper/StatusBadge';
import MarketingFilterModal from '@/components/pages/marketing/MarketingFilter';
import ButtonFilter from '@/components/helper/ButtonFilter';
const RowsOptionsMenu = ({
props,
@@ -214,32 +215,6 @@ const MarketingTable = () => {
updateFilter('customer_id', '');
};
// ===== ACTIVE FILTERS COUNT =====
const activeFiltersCount = useMemo(() => {
let count = 0;
// Product filter
if (tableFilterState.product_ids) {
count += 1;
}
// Status filter
if (tableFilterState.status) {
count += 1;
}
// Customer filter
if (tableFilterState.customer_id) {
count += 1;
}
return count;
}, [
tableFilterState.product_ids,
tableFilterState.status,
tableFilterState.customer_id,
]);
const approveClickHandler = () => {
setApproveAction('APPROVED');
confirmationModal.openModal();
@@ -588,28 +563,14 @@ const MarketingTable = () => {
)}
</div>
<div className='flex flex-row gap-3'>
<Button
variant='outline'
color='none'
<ButtonFilter
values={tableFilterState}
excludeFields={['page', 'pageSize', 'search']}
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':
activeFiltersCount > 0,
}
)}
>
<Icon icon='heroicons:funnel' width={20} height={20} />
Filter
{activeFiltersCount > 0 && (
<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'
direction='bottom'
@@ -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)
@@ -38,6 +38,7 @@ import { Nonstock } from '@/types/api/master-data/nonstock';
import { ColumnDef } from '@tanstack/react-table';
import { httpClient } from '@/services/http/client';
import { BaseApiResponse } from '@/types/api/api-general';
import ButtonFilter from '@/components/helper/ButtonFilter';
interface ReportExpenseTabProps {
tabId: string;
@@ -169,20 +170,6 @@ const ReportExpenseTab = ({ tabId }: ReportExpenseTabProps) => {
[formik.values.category]
);
// ===== ACTIVE FILTERS COUNT =====
const activeFiltersCount = useMemo(() => {
let count = 0;
if (filterParams.location_id) count += 1;
if (filterParams.supplier_id) count += 1;
if (filterParams.kandang_id) count += 1;
if (filterParams.nonstock_id) count += 1;
if (filterParams.realization_date) count += 1;
if (filterParams.category) count += 1;
return count;
}, [filterParams]);
const hasFilters = activeFiltersCount > 0;
// ===== DATA FETCHING =====
const { data: reportExpenseResponse, isLoading } = useSWR(
isSubmitted
@@ -312,25 +299,12 @@ const ReportExpenseTab = ({ tabId }: ReportExpenseTabProps) => {
setTabActions(
tabId,
<div className='flex flex-row gap-3'>
<Button
variant='outline'
color='none'
<ButtonFilter
values={formik.values}
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': 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>
variant='outline'
className='px-3 py-2.5'
/>
<Dropdown
align='end'
@@ -387,8 +361,7 @@ const ReportExpenseTab = ({ tabId }: ReportExpenseTabProps) => {
);
}, [
tabId,
hasFilters,
activeFiltersCount,
formik.values,
isAnyExportLoading,
handleExportExcel,
handleExportPDF,
@@ -38,6 +38,7 @@ import { useTabActionsStore } from '@/stores/tab-actions/tab-actions.store';
import CustomerSupplierSkeleton from '@/components/pages/report/finance/skeleton/CustomerSupplierSkeleton';
import { OptionType } from '@/components/table/TableRowSizeSelector';
import { Color } from '@/types/theme';
import ButtonFilter from '@/components/helper/ButtonFilter';
interface CustomerPaymentTabProps {
tabId: string;
@@ -213,30 +214,6 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => {
);
}, [formik.values.filter_by]);
// ===== ACTIVE FILTERS COUNT =====
const activeFiltersCount = useMemo(() => {
let count = 0;
// Date filter (start_date + end_date = 1 filter)
if (filterParams.start_date || filterParams.end_date) {
count += 1;
}
// Customer filter
if (filterParams.customer_ids) {
count += 1;
}
// Filter by type filter (hanya dihitung jika ada nilai yang dipilih)
if (filterParams.filter_by) {
count += 1;
}
return count;
}, [filterParams]);
const hasFilters = activeFiltersCount > 0;
// ===== DATA FETCHING =====
const { data: customerPayment, isLoading } = useSWR(
isSubmitted
@@ -380,25 +357,13 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => {
setTabActions(
tabId,
<div className='flex flex-row gap-3'>
<Button
variant='outline'
color='none'
<ButtonFilter
values={formik.values}
fieldGroups={[['start_date', 'end_date']]}
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>
variant='outline'
className='px-3 py-2.5'
/>
<Dropdown
align='end'
@@ -455,8 +420,7 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => {
);
}, [
tabId,
hasFilters,
activeFiltersCount,
formik.values,
isAnyExportLoading,
handleExportExcel,
handleExportPdf,
@@ -274,6 +274,7 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => {
<div className='flex flex-row gap-3'>
<ButtonFilter
values={formik.values}
fieldGroups={[['startDate', 'endDate']]}
onClick={handleFilterModalOpen}
variant='outline'
className='px-3 py-2.5'
@@ -32,6 +32,7 @@ import SelectInputCheckbox from '@/components/input/SelectInputCheckbox';
import SelectInputRadio from '@/components/input/SelectInputRadio';
import { useTabActionsStore } from '@/stores/tab-actions/tab-actions.store';
import PurchasePerSupplierSkeleton from '@/components/pages/report/logistic-stock/skeleton/PurchasePerSupplierSkeleton';
import ButtonFilter from '@/components/helper/ButtonFilter';
interface PurchasesPerSupplierTabProps {
tabId: string;
@@ -253,43 +254,6 @@ const PurchasesPerSupplierTab = ({ tabId }: PurchasesPerSupplierTabProps) => {
);
}, [formik.values.sort_by, sortByOptions]);
// ===== ACTIVE FILTERS COUNT =====
const activeFiltersCount = useMemo(() => {
let count = 0;
if (filterParams.start_date || filterParams.end_date) {
count += 1;
}
if (filterParams.area_id) {
count += 1;
}
if (filterParams.supplier_id) {
count += 1;
}
if (filterParams.product_id) {
count += 1;
}
if (filterParams.product_category_id) {
count += 1;
}
if (filterParams.filter_by) {
count += 1;
}
if (filterParams.sort_by) {
count += 1;
}
return count;
}, [filterParams]);
const hasFilters = activeFiltersCount > 0;
// ===== DATA FETCHING =====
const { data: purchasePerSupplier, isLoading } = useSWR(
isSubmitted
@@ -486,25 +450,13 @@ const PurchasesPerSupplierTab = ({ tabId }: PurchasesPerSupplierTabProps) => {
setTabActions(
tabId,
<div className='flex flex-row gap-3'>
<Button
variant='outline'
color='none'
<ButtonFilter
values={formik.values}
fieldGroups={[['start_date', 'end_date']]}
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>
variant='outline'
className='px-3 py-2.5'
/>
<Dropdown
align='end'
@@ -561,8 +513,7 @@ const PurchasesPerSupplierTab = ({ tabId }: PurchasesPerSupplierTabProps) => {
);
}, [
tabId,
hasFilters,
activeFiltersCount,
formik.values,
isAnyExportLoading,
filterModal.open,
setTabActions,
@@ -47,6 +47,7 @@ import {
MARKETING_TYPE_OPTIONS,
} from '@/config/constant';
import Badge from '@/components/Badge';
import ButtonFilter from '@/components/helper/ButtonFilter';
interface DailyMarketingTabProps {
tabId: string;
@@ -202,47 +203,6 @@ const DailyMarketingTab = ({ tabId }: DailyMarketingTabProps) => {
);
}, [formik.values.marketing_type]);
// ===== ACTIVE FILTERS COUNT =====
const activeFiltersCount = useMemo(() => {
let count = 0;
if (filterParams.area_id) {
count += 1;
}
if (filterParams.location_id) {
count += 1;
}
if (filterParams.warehouse_id) {
count += 1;
}
if (filterParams.customer_id) {
count += 1;
}
if (filterParams.start_date || filterParams.end_date) {
count += 1;
}
if (filterParams.filter_by) {
count += 1;
}
if (filterParams.marketing_type) {
count += 1;
}
if (filterParams.sort_by) {
count += 1;
}
return count;
}, [filterParams]);
const hasFilters = activeFiltersCount > 0;
// ===== DATA FETCHING =====
const { data: dailyMarketings, isLoading } = useSWR(
isSubmitted
@@ -412,30 +372,13 @@ const DailyMarketingTab = ({ tabId }: DailyMarketingTabProps) => {
}}
/>
<Button
variant='outline'
color='none'
<ButtonFilter
values={formik.values}
fieldGroups={[['start_date', 'end_date']]}
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 && (
<Badge
className={{
badge:
'p-1.5 bg-[#FF3535] text-xs text-base-100 border border-base-300 rounded-lg',
}}
>
{activeFiltersCount}
</Badge>
)}
</Button>
variant='outline'
className='px-3 py-2.5'
/>
<Dropdown
align='end'
@@ -493,8 +436,7 @@ const DailyMarketingTab = ({ tabId }: DailyMarketingTabProps) => {
}, [
tabId,
searchValue,
hasFilters,
activeFiltersCount,
formik.values,
isAnyExportLoading,
filterModal.open,
setTabActions,
@@ -17,6 +17,7 @@ import {
} from '@/types/api/report/hpp-per-kandang';
import { isResponseSuccess } from '@/lib/api-helper';
import Button from '@/components/Button';
import ButtonFilter from '@/components/helper/ButtonFilter';
import Dropdown from '@/components/Dropdown';
import { generateHppPerKandangPDF } from '@/components/pages/report/marketing/export/HppPerkandangExportPDF';
import { generateHppPerKandangExcel } from '@/components/pages/report/marketing/export/HppPerkandangExportXLSX';
@@ -233,42 +234,6 @@ const HppPerKandangTab = ({ tabId }: HppPerKandangTabProps) => {
);
}, [formik.values.show_unrecorded, showUnrecordedOptions]);
// ===== ACTIVE FILTERS COUNT =====
const activeFiltersCount = useMemo(() => {
let count = 0;
if (filterParams.period) {
count += 1;
}
if (filterParams.area_id) {
count += 1;
}
if (filterParams.location_id) {
count += 1;
}
if (filterParams.kandang_id) {
count += 1;
}
if (filterParams.weight_min || filterParams.weight_max) {
count += 1;
}
if (filterParams.show_unrecorded !== undefined) {
count += 1;
}
if (filterParams.sort_by) {
count += 1;
}
return count;
}, [filterParams]);
const hasFilters = activeFiltersCount > 0;
// ===== DATA FETCHING =====
const { data: hppPerKandang, isLoading } = useSWR(
@@ -486,25 +451,12 @@ const HppPerKandangTab = ({ tabId }: HppPerKandangTabProps) => {
setTabActions(
tabId,
<div className='flex flex-row gap-3'>
<Button
variant='outline'
color='none'
<ButtonFilter
values={formik.values}
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>
variant='outline'
className='px-3 py-2.5'
/>
<Dropdown
align='end'
@@ -561,8 +513,7 @@ const HppPerKandangTab = ({ tabId }: HppPerKandangTabProps) => {
);
}, [
tabId,
hasFilters,
activeFiltersCount,
formik.values,
isAnyExportLoading,
filterModal.open,
setTabActions,
@@ -7,6 +7,7 @@ import toast from 'react-hot-toast';
import { Icon } from '@iconify/react';
import Button from '@/components/Button';
import ButtonFilter from '@/components/helper/ButtonFilter';
import Dropdown from '@/components/dropdown/Dropdown';
import SelectInput, { useSelect } from '@/components/input/SelectInput';
import ProductionResultProjectFlockKandangTable from '@/components/pages/report/production-result/tab/ProductionResultProjectFlockKandangTable';
@@ -324,20 +325,6 @@ const ProductionResultContent = ({ tabId }: ProductionResultTabProps) => {
[formik.values.kandang_id]
);
// ===== ACTIVE FILTERS COUNT =====
const activeFiltersCount = useMemo(() => {
let count = 0;
if (filterParams.area_id) count += 1;
if (filterParams.location_id) count += 1;
if (filterParams.project_flock_id) count += 1;
if (filterParams.project_flock_kandang_id) count += 1;
return count;
}, [filterParams]);
const hasFilters = activeFiltersCount > 0;
// ===== DATA FETCHING =====
const { data: projectFlockKandangsData, isLoading } = useSWR<
BaseApiResponse<ProjectFlockKandang[]>
@@ -539,25 +526,12 @@ const ProductionResultContent = ({ tabId }: ProductionResultTabProps) => {
setTabActions(
tabId,
<div className='flex flex-row gap-3'>
<Button
variant='outline'
color='none'
<ButtonFilter
values={filterParams}
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': 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>
variant='outline'
className='px-3 py-2.5'
/>
<Dropdown
align='end'
@@ -614,8 +588,7 @@ const ProductionResultContent = ({ tabId }: ProductionResultTabProps) => {
);
}, [
tabId,
hasFilters,
activeFiltersCount,
filterParams,
isAnyExportLoading,
exportToExcelHandler,
exportToPdfHandler,