feat(FE-361,363): Add product category filter and API params

This commit is contained in:
rstubryan
2025-12-16 10:26:31 +07:00
parent 31b2a5a548
commit 68437b3b7e
2 changed files with 93 additions and 59 deletions
@@ -10,6 +10,7 @@ import DateInput from '@/components/input/DateInput';
import { AreaApi } from '@/services/api/master-data';
import { SupplierApi } from '@/services/api/master-data';
import { ProductApi } from '@/services/api/master-data';
import { ProductCategoryApi } from '@/services/api/master-data';
import { LogisticApi } from '@/services/api/logistic';
import Table from '@/components/Table';
import { ColumnDef } from '@tanstack/react-table';
@@ -33,10 +34,6 @@ interface Totals {
}
const PurchasesPerSupplierTab = () => {
const [dataType, setDataType] = useState<'received_date' | 'po_date'>(
'received_date'
);
// ===== PAGINATION STATE =====
const [currentPage, setCurrentPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
@@ -50,10 +47,13 @@ const PurchasesPerSupplierTab = () => {
area_id: '',
supplier_id: '',
product_id: '',
product_category_id: '',
received_date: '',
po_date: '',
start_date: '',
end_date: '',
sort_by: '',
filter_by: 'received_date',
},
paramMap: {
page: 'page',
@@ -61,16 +61,6 @@ const PurchasesPerSupplierTab = () => {
},
});
const updateDataType = useCallback(
(newDataType: 'received_date' | 'po_date') => {
setDataType(newDataType);
updateFilter('received_date', '');
updateFilter('po_date', '');
setIsSubmitted(false);
},
[updateFilter]
);
const { options: areaOptions, isLoadingOptions: isLoadingAreas } = useSelect(
AreaApi.basePath,
'id',
@@ -84,6 +74,11 @@ const PurchasesPerSupplierTab = () => {
const { options: productOptions, isLoadingOptions: isLoadingProducts } =
useSelect(ProductApi.basePath, 'id', 'name', 'search');
const {
options: productCategoryOptions,
isLoadingOptions: isLoadingProductCategories,
} = useSelect(ProductCategoryApi.basePath, 'id', 'name', 'search');
const dataTypeOptions = useMemo(
() => [
{ value: 'received_date', label: 'Tanggal Terima' },
@@ -119,15 +114,29 @@ const PurchasesPerSupplierTab = () => {
[updateFilter]
);
const dataTypeChangeHandler = useCallback(
const productCategoryChangeHandler = useCallback(
(val: OptionType | OptionType[] | null) => {
const newVal = val as OptionType;
updateDataType(
(newVal?.value as 'received_date' | 'po_date') || 'received_date'
updateFilter(
'product_category_id',
newVal?.value ? String(newVal.value) : ''
);
setIsSubmitted(false);
},
[updateDataType]
[updateFilter]
);
const dataTypeChangeHandler = useCallback(
(val: OptionType | OptionType[] | null) => {
const newVal = val as OptionType;
const filterValue =
(newVal?.value as 'received_date' | 'po_date') || 'received_date';
updateFilter('filter_by', filterValue);
updateFilter('received_date', '');
updateFilter('po_date', '');
setIsSubmitted(false);
},
[updateFilter]
);
const startDateChangeHandler = useCallback<
@@ -156,11 +165,13 @@ const PurchasesPerSupplierTab = () => {
updateFilter('area_id', '');
updateFilter('supplier_id', '');
updateFilter('product_id', '');
updateFilter('product_category_id', '');
updateFilter('received_date', '');
updateFilter('po_date', '');
updateFilter('start_date', '');
updateFilter('end_date', '');
setDataType('received_date');
updateFilter('sort_by', '');
updateFilter('filter_by', 'received_date');
setIsSubmitted(false);
}, [updateFilter]);
@@ -183,10 +194,21 @@ const PurchasesPerSupplierTab = () => {
product_id: tableFilterState.product_id
? Number(tableFilterState.product_id)
: undefined,
received_date: tableFilterState.received_date || undefined,
po_date: tableFilterState.po_date || undefined,
product_category_id: tableFilterState.product_category_id
? Number(tableFilterState.product_category_id)
: undefined,
received_date:
tableFilterState.filter_by === 'received_date'
? tableFilterState.start_date || undefined
: undefined,
po_date:
tableFilterState.filter_by === 'po_date'
? tableFilterState.start_date || undefined
: undefined,
start_date: tableFilterState.start_date || undefined,
end_date: tableFilterState.end_date || undefined,
sort_by: tableFilterState.sort_by || undefined,
filter_by: tableFilterState.filter_by || undefined,
page: currentPage,
limit: pageSize,
};
@@ -199,10 +221,13 @@ const PurchasesPerSupplierTab = () => {
params.area_id,
params.supplier_id,
params.product_id,
params.product_category_id,
params.received_date,
params.po_date,
params.start_date,
params.end_date,
params.sort_by,
params.filter_by,
params.page,
params.limit
)
@@ -254,7 +279,6 @@ const PurchasesPerSupplierTab = () => {
items: LogisticPurchasePerSupplierReport['rows'];
}
// Group data by supplier for display
const groupedData = useMemo(() => {
const groups: { [key: number]: GroupedSupplierData } = {};
@@ -468,7 +492,7 @@ const PurchasesPerSupplierTab = () => {
</Menu>
</Dropdown>
</div>
<div className='grid grid-cols-12 gap-4'>
<div className='grid grid-cols-3 gap-4'>
<SelectInput
label='Area'
placeholder='Pilih Area'
@@ -484,9 +508,6 @@ const PurchasesPerSupplierTab = () => {
onChange={areaChangeHandler}
isLoading={isLoadingAreas}
isClearable
className={{
wrapper: 'col-span-12 sm:col-span-4',
}}
/>
<SelectInput
label='Supplier'
@@ -503,9 +524,6 @@ const PurchasesPerSupplierTab = () => {
onChange={supplierChangeHandler}
isLoading={isLoadingSuppliers}
isClearable
className={{
wrapper: 'col-span-12 sm:col-span-4',
}}
/>
<SelectInput
label='Produk'
@@ -522,34 +540,46 @@ const PurchasesPerSupplierTab = () => {
onChange={productChangeHandler}
isLoading={isLoadingProducts}
isClearable
className={{
wrapper: 'col-span-12 sm:col-span-4',
}}
/>
</div>
<div className='grid grid-cols-3 gap-4'>
<SelectInput
label='Kategori Produk'
placeholder='Pilih Kategori Produk'
options={productCategoryOptions}
value={
tableFilterState.product_category_id
? productCategoryOptions.find(
(option) =>
option.value ===
Number(tableFilterState.product_category_id)
) || null
: null
}
onChange={productCategoryChangeHandler}
isLoading={isLoadingProductCategories}
isClearable
/>
<SelectInput
label='Tipe Data'
placeholder='Pilih Tipe Data'
label='Filter Berdasarkan'
placeholder='Pilih Filter Berdasarkan'
options={dataTypeOptions}
value={
dataTypeOptions?.find((option) => option.value === dataType) ||
null
dataTypeOptions?.find(
(option) => option.value === tableFilterState.filter_by
) || null
}
onChange={dataTypeChangeHandler}
isLoading={false}
isClearable={false}
className={{
wrapper: 'col-span-12 sm:col-span-4',
}}
/>
<div className='flex flex-row gap-4'>
<DateInput
label='Tanggal Awal'
name='start_date'
placeholder='Pilih Tanggal Awal'
value={tableFilterState.start_date}
onChange={startDateChangeHandler}
className={{
wrapper: 'col-span-12 sm:col-span-4',
}}
/>
<DateInput
label='Tanggal Akhir'
@@ -557,11 +587,9 @@ const PurchasesPerSupplierTab = () => {
placeholder='Pilih Tanggal Akhir'
value={tableFilterState.end_date}
onChange={endDateChangeHandler}
className={{
wrapper: 'col-span-12 sm:col-span-4',
}}
/>
</div>
</div>
{!isSubmitted ? (
<div className='mt-6 text-center text-gray-500'>
+6
View File
@@ -15,10 +15,13 @@ export class LogisticApiService extends BaseApiService<
area_id?: number,
supplier_id?: number,
product_id?: number,
product_category_id?: number,
received_date?: string,
po_date?: string,
start_date?: string,
end_date?: string,
sort_by?: string,
filter_by?: string,
page?: number,
limit?: number
): Promise<BaseApiResponse<LogisticPurchasePerSupplierReport> | undefined> {
@@ -30,10 +33,13 @@ export class LogisticApiService extends BaseApiService<
area_id: area_id,
supplier_id: supplier_id,
product_id: product_id,
product_category_id: product_category_id,
received_date: received_date,
po_date: po_date,
start_date: start_date,
end_date: end_date,
sort_by: sort_by,
filter_by: filter_by,
page: page,
limit: limit,
},