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
@@ -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,