fix: implement table filter persist state

This commit is contained in:
ValdiANS
2026-04-30 15:01:21 +07:00
parent e52ba7b394
commit 039c926e2d
5 changed files with 125 additions and 291 deletions
@@ -1,14 +1,7 @@
'use client';
import {
ChangeEventHandler,
useCallback,
useEffect,
useMemo,
useState,
} from 'react';
import { usePathname } from 'next/navigation';
import useSWR, { mutate } from 'swr';
import { ChangeEventHandler, useMemo, useState } from 'react';
import useSWR from 'swr';
import { SortingState, CellContext, ColumnDef } from '@tanstack/react-table';
import { useFormik } from 'formik';
@@ -20,7 +13,6 @@ import { WarehouseApi, ProductApi } from '@/services/api/master-data';
import { cn } from '@/lib/helper';
import { isResponseSuccess } from '@/lib/api-helper';
import { useTableFilter } from '@/services/hooks/useTableFilter';
import { useUiStore } from '@/stores/ui/ui.store';
import ConfirmationModal from '@/components/modal/ConfirmationModal';
import toast from 'react-hot-toast';
import Button from '@/components/Button';
@@ -108,22 +100,21 @@ const RowOptionsMenu = ({
};
const MovementTable = () => {
const { searchValue, setSearchValue, setTableState } = useUiStore();
const pathname = usePathname();
const {
state: tableFilterState,
updateFilter,
setPage,
setPageSize,
toQueryString: getTableFilterQueryString,
} = useTableFilter({
} = useTableFilter<{
search: string;
productFilter?: OptionType<string>;
warehouseFilter?: OptionType<string>;
}>({
initial: {
search: '',
productFilter: '',
warehouseFilter: '',
productName: '',
warehouseName: '',
productFilter: undefined,
warehouseFilter: undefined,
},
paramMap: {
page: 'page',
@@ -131,7 +122,6 @@ const MovementTable = () => {
productFilter: 'product_id',
warehouseFilter: 'warehouse_id',
},
excludeKeysFromUrl: ['productName', 'warehouseName'],
persist: true,
storeName: 'movement-table',
});
@@ -142,29 +132,19 @@ const MovementTable = () => {
// ===== FORMIK SETUP =====
const formik = useFormik<MovementFilterType>({
initialValues: {
product_id: null,
warehouse_id: null,
product: tableFilterState.productFilter,
warehouse: tableFilterState.warehouseFilter,
},
validationSchema: MovementFilterSchema,
onSubmit: (values, { setSubmitting }) => {
updateFilter('productFilter', values.product_id || '');
updateFilter('warehouseFilter', values.warehouse_id || '');
updateFilter(
'productName',
productIdValue?.label ? String(productIdValue.label) : ''
);
updateFilter(
'warehouseName',
warehouseIdValue?.label ? String(warehouseIdValue.label) : ''
);
updateFilter('productFilter', values.product || undefined, true);
updateFilter('warehouseFilter', values.warehouse || undefined, true);
filterModal.closeModal();
setSubmitting(false);
},
onReset: () => {
updateFilter('productFilter', '');
updateFilter('warehouseFilter', '');
updateFilter('productName', '');
updateFilter('warehouseName', '');
updateFilter('productFilter', undefined, true);
updateFilter('warehouseFilter', undefined, true);
filterModal.closeModal();
},
});
@@ -196,64 +176,21 @@ const MovementTable = () => {
);
// ===== FILTER HANDLERS =====
const handleFilterProductChange = useCallback(
(val: OptionType | OptionType[] | null) => {
const product = val as OptionType | null;
const productId = product?.value ? String(product.value) : null;
formik.setFieldValue('product_id', productId);
},
[formik]
);
const handleFilterProductChange = (val: OptionType | OptionType[] | null) => {
formik.setFieldValue('product', val);
};
const handleFilterWarehouseChange = useCallback(
(val: OptionType | OptionType[] | null) => {
const warehouse = val as OptionType | null;
const warehouseId = warehouse?.value ? String(warehouse.value) : null;
formik.setFieldValue('warehouse_id', warehouseId);
},
[formik]
);
// ===== FILTER HELPERS =====
const productIdValue = useMemo(() => {
if (!formik.values.product_id) return null;
const found = productOptions.find(
(opt) => String(opt.value) === formik.values.product_id
);
if (found) return found;
if (tableFilterState.productName) {
return {
value: formik.values.product_id,
label: tableFilterState.productName,
};
}
return null;
}, [formik.values.product_id, productOptions, tableFilterState.productName]);
const warehouseIdValue = useMemo(() => {
if (!formik.values.warehouse_id) return null;
const found = warehouseOptions.find(
(opt) => String(opt.value) === formik.values.warehouse_id
);
if (found) return found;
if (tableFilterState.warehouseName) {
return {
value: formik.values.warehouse_id,
label: tableFilterState.warehouseName,
};
}
return null;
}, [
formik.values.warehouse_id,
warehouseOptions,
tableFilterState.warehouseName,
]);
const handleFilterWarehouseChange = (
val: OptionType | OptionType[] | null
) => {
formik.setFieldValue('warehouse', val);
};
// ===== HANDLE FILTER MODAL OPEN =====
const handleFilterModalOpen = () => {
formik.setValues({
product_id: tableFilterState.productFilter || null,
warehouse_id: tableFilterState.warehouseFilter || null,
product: tableFilterState.productFilter ?? undefined,
warehouse: tableFilterState.warehouseFilter ?? undefined,
});
filterModal.openModal();
};
@@ -290,17 +227,8 @@ const MovementTable = () => {
}
};
useEffect(() => {
updateFilter('search', searchValue);
}, [searchValue, updateFilter]);
useEffect(() => {
setTableState('movement-table', pathname);
}, [pathname, setTableState]);
const searchChangeHandler: ChangeEventHandler<HTMLInputElement> = (e) => {
setSearchValue(e.target.value);
updateFilter('search', e.target.value);
updateFilter('search', e.target.value, true);
};
const movementColumns: ColumnDef<Movement>[] = useMemo(
@@ -419,13 +347,7 @@ const MovementTable = () => {
<ButtonFilter
values={tableFilterState}
excludeFields={[
'page',
'pageSize',
'search',
'productName',
'warehouseName',
]}
excludeFields={['page', 'pageSize', 'search']}
onClick={handleFilterModalOpen}
className='px-3 py-2.5'
/>
@@ -505,7 +427,7 @@ const MovementTable = () => {
label='Produk'
placeholder='Pilih Produk'
options={productOptions}
value={productIdValue}
value={formik.values.product}
onChange={handleFilterProductChange}
onInputChange={setProductInputValue}
isLoading={isLoadingProductOptions}
@@ -517,7 +439,7 @@ const MovementTable = () => {
label='Gudang'
placeholder='Pilih Gudang'
options={warehouseOptions}
value={warehouseIdValue}
value={formik.values.warehouse}
onChange={handleFilterWarehouseChange}
onInputChange={setWarehouseInputValue}
isLoading={isLoadingWarehouseOptions}