mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
refactor(FE): Use Formik for finance table filters
This commit is contained in:
@@ -1,13 +1,9 @@
|
|||||||
import {
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
ChangeEventHandler,
|
|
||||||
useEffect,
|
|
||||||
useMemo,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from 'react';
|
|
||||||
import { CellContext } from '@tanstack/react-table';
|
import { CellContext } from '@tanstack/react-table';
|
||||||
import { useSearchParams } from 'next/navigation';
|
import { useSearchParams } from 'next/navigation';
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
|
import { useFormik } from 'formik';
|
||||||
|
import * as yup from 'yup';
|
||||||
|
|
||||||
import Button from '@/components/Button';
|
import Button from '@/components/Button';
|
||||||
import Card from '@/components/Card';
|
import Card from '@/components/Card';
|
||||||
@@ -40,6 +36,10 @@ import { Icon } from '@iconify/react';
|
|||||||
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
|
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
|
||||||
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
|
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
|
||||||
import { useUiStore } from '@/stores/ui/ui.store';
|
import { useUiStore } from '@/stores/ui/ui.store';
|
||||||
|
import {
|
||||||
|
FinanceTableFilterSchema,
|
||||||
|
FinanceTableFilterValues,
|
||||||
|
} from './FinanceTableFilter.schema';
|
||||||
|
|
||||||
const RowOptionsMenu = ({
|
const RowOptionsMenu = ({
|
||||||
type = 'dropdown',
|
type = 'dropdown',
|
||||||
@@ -176,16 +176,6 @@ const FinanceTable = () => {
|
|||||||
// ===== State =====
|
// ===== State =====
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
const deleteModal = useModal();
|
const deleteModal = useModal();
|
||||||
const [pendingFilters, setPendingFilters] = useState({
|
|
||||||
search: searchValue,
|
|
||||||
transactionTypes: '',
|
|
||||||
bankIds: '',
|
|
||||||
customerIds: '',
|
|
||||||
supplierIds: '',
|
|
||||||
sortBy: '',
|
|
||||||
startDate: '',
|
|
||||||
endDate: '',
|
|
||||||
});
|
|
||||||
const [selectedTransactionType, setSelectedTransactionType] = useState<
|
const [selectedTransactionType, setSelectedTransactionType] = useState<
|
||||||
OptionType | OptionType[] | null
|
OptionType | OptionType[] | null
|
||||||
>(null);
|
>(null);
|
||||||
@@ -202,6 +192,33 @@ const FinanceTable = () => {
|
|||||||
const [selectedFinance, setSelectedFinance] = useState<Finance | null>(null);
|
const [selectedFinance, setSelectedFinance] = useState<Finance | null>(null);
|
||||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||||
|
|
||||||
|
// ===== Formik for Filter =====
|
||||||
|
const filterFormik = useFormik<FinanceTableFilterValues>({
|
||||||
|
initialValues: {
|
||||||
|
search: searchValue,
|
||||||
|
transaction_types: '',
|
||||||
|
bank_ids: '',
|
||||||
|
customer_ids: '',
|
||||||
|
supplier_ids: '',
|
||||||
|
sort_by: '',
|
||||||
|
start_date: '',
|
||||||
|
end_date: '',
|
||||||
|
},
|
||||||
|
validationSchema: FinanceTableFilterSchema,
|
||||||
|
enableReinitialize: true,
|
||||||
|
onSubmit: (values) => {
|
||||||
|
updateFilter('search', values.search);
|
||||||
|
setSearchValue(values.search);
|
||||||
|
updateFilter('transactionTypes', values.transaction_types);
|
||||||
|
updateFilter('bankIds', values.bank_ids);
|
||||||
|
updateFilter('customerIds', values.customer_ids);
|
||||||
|
updateFilter('supplierIds', values.supplier_ids);
|
||||||
|
updateFilter('sortBy', values.sort_by);
|
||||||
|
updateFilter('startDate', values.start_date);
|
||||||
|
updateFilter('endDate', values.end_date);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// ===== Fetch Data =====
|
// ===== Fetch Data =====
|
||||||
const {
|
const {
|
||||||
data: finances,
|
data: finances,
|
||||||
@@ -238,83 +255,66 @@ const FinanceTable = () => {
|
|||||||
} = useSelect<Bank>(BankApi.basePath, 'id', 'alias');
|
} = useSelect<Bank>(BankApi.basePath, 'id', 'alias');
|
||||||
|
|
||||||
// ===== Handler =====
|
// ===== Handler =====
|
||||||
const searchChangeHandler: ChangeEventHandler<HTMLInputElement> = (e) => {
|
const searchChangeHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setPendingFilters((prev) => ({ ...prev, search: e.target.value }));
|
filterFormik.setFieldValue('search', e.target.value);
|
||||||
};
|
};
|
||||||
const transactionTypeChangeHandler = (
|
const transactionTypeChangeHandler = (
|
||||||
val: OptionType | OptionType[] | null
|
val: OptionType | OptionType[] | null
|
||||||
) => {
|
) => {
|
||||||
setSelectedTransactionType(val);
|
setSelectedTransactionType(val);
|
||||||
setPendingFilters((prev) => ({
|
filterFormik.setFieldValue(
|
||||||
...prev,
|
'transaction_types',
|
||||||
transactionTypes: val
|
val
|
||||||
? Array.isArray(val)
|
? Array.isArray(val)
|
||||||
? val.map((item) => item.value).join(',')
|
? val.map((item) => item.value).join(',')
|
||||||
: (val.value as string)
|
: (val.value as string)
|
||||||
: '',
|
: ''
|
||||||
}));
|
);
|
||||||
};
|
};
|
||||||
const bankChangeHandler = (val: OptionType | OptionType[] | null) => {
|
const bankChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||||
setSelectedBank(val);
|
setSelectedBank(val);
|
||||||
setPendingFilters((prev) => ({
|
filterFormik.setFieldValue(
|
||||||
...prev,
|
'bank_ids',
|
||||||
bankIds: val
|
val
|
||||||
? Array.isArray(val)
|
? Array.isArray(val)
|
||||||
? val.map((item) => item.value).join(',')
|
? val.map((item) => item.value).join(',')
|
||||||
: (val.value as string)
|
: (val.value as string)
|
||||||
: '',
|
: ''
|
||||||
}));
|
);
|
||||||
};
|
};
|
||||||
const customerIdChangeHandler = (val: OptionType | OptionType[] | null) => {
|
const customerIdChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||||
setSelectedCustomerId(val);
|
setSelectedCustomerId(val);
|
||||||
setPendingFilters((prev) => ({
|
filterFormik.setFieldValue(
|
||||||
...prev,
|
'customer_ids',
|
||||||
customerIds: val
|
val
|
||||||
? Array.isArray(val)
|
? Array.isArray(val)
|
||||||
? val.map((item) => item.value).join(',')
|
? val.map((item) => item.value).join(',')
|
||||||
: (val.value as string)
|
: (val.value as string)
|
||||||
: '',
|
: ''
|
||||||
}));
|
);
|
||||||
};
|
};
|
||||||
const supplierIdChangeHandler = (val: OptionType | OptionType[] | null) => {
|
const supplierIdChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||||
setSelectedSupplierId(val);
|
setSelectedSupplierId(val);
|
||||||
setPendingFilters((prev) => ({
|
filterFormik.setFieldValue(
|
||||||
...prev,
|
'supplier_ids',
|
||||||
supplierIds: val
|
val
|
||||||
? Array.isArray(val)
|
? Array.isArray(val)
|
||||||
? val.map((item) => item.value).join(',')
|
? val.map((item) => item.value).join(',')
|
||||||
: (val.value as string)
|
: (val.value as string)
|
||||||
: '',
|
: ''
|
||||||
}));
|
);
|
||||||
};
|
};
|
||||||
const sortByChangeHandler = (val: OptionType | OptionType[] | null) => {
|
const sortByChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||||
setSelectedSortBy(val as OptionType);
|
setSelectedSortBy(val as OptionType);
|
||||||
setPendingFilters((prev) => ({
|
filterFormik.setFieldValue(
|
||||||
...prev,
|
'sort_by',
|
||||||
sortBy: val ? ((val as OptionType).value as string) : '',
|
val ? ((val as OptionType).value as string) : ''
|
||||||
}));
|
);
|
||||||
};
|
|
||||||
const startDateChangeHandler: ChangeEventHandler<HTMLInputElement> = (e) => {
|
|
||||||
setPendingFilters((prev) => ({ ...prev, startDate: e.target.value }));
|
|
||||||
};
|
|
||||||
const endDateChangeHandler: ChangeEventHandler<HTMLInputElement> = (e) => {
|
|
||||||
setPendingFilters((prev) => ({ ...prev, endDate: e.target.value }));
|
|
||||||
};
|
};
|
||||||
const pageSizeChangeHandler = (val: OptionType | OptionType[] | null) => {
|
const pageSizeChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||||
const newVal = val as OptionType;
|
const newVal = val as OptionType;
|
||||||
setPageSize(newVal.value as number);
|
setPageSize(newVal.value as number);
|
||||||
};
|
};
|
||||||
const submitFilterHandler = () => {
|
|
||||||
updateFilter('search', pendingFilters.search);
|
|
||||||
setSearchValue(pendingFilters.search);
|
|
||||||
updateFilter('transactionTypes', pendingFilters.transactionTypes);
|
|
||||||
updateFilter('bankIds', pendingFilters.bankIds);
|
|
||||||
updateFilter('customerIds', pendingFilters.customerIds);
|
|
||||||
updateFilter('supplierIds', pendingFilters.supplierIds);
|
|
||||||
updateFilter('sortBy', pendingFilters.sortBy);
|
|
||||||
updateFilter('startDate', pendingFilters.startDate);
|
|
||||||
updateFilter('endDate', pendingFilters.endDate);
|
|
||||||
};
|
|
||||||
const resetFilterHandler = () => {
|
const resetFilterHandler = () => {
|
||||||
setSelectedTransactionType(null);
|
setSelectedTransactionType(null);
|
||||||
setSelectedBank(null);
|
setSelectedBank(null);
|
||||||
@@ -322,17 +322,7 @@ const FinanceTable = () => {
|
|||||||
setSelectedSupplierId(null);
|
setSelectedSupplierId(null);
|
||||||
setSelectedSortBy(null);
|
setSelectedSortBy(null);
|
||||||
|
|
||||||
const emptyFilters = {
|
filterFormik.resetForm();
|
||||||
search: '',
|
|
||||||
transactionTypes: '',
|
|
||||||
bankIds: '',
|
|
||||||
customerIds: '',
|
|
||||||
supplierIds: '',
|
|
||||||
sortBy: '',
|
|
||||||
startDate: '',
|
|
||||||
endDate: '',
|
|
||||||
};
|
|
||||||
setPendingFilters(emptyFilters);
|
|
||||||
|
|
||||||
updateFilter('search', '');
|
updateFilter('search', '');
|
||||||
resetSearchValue();
|
resetSearchValue();
|
||||||
@@ -526,7 +516,7 @@ const FinanceTable = () => {
|
|||||||
<Button
|
<Button
|
||||||
color='primary'
|
color='primary'
|
||||||
className='min-w-24'
|
className='min-w-24'
|
||||||
onClick={submitFilterHandler}
|
onClick={() => filterFormik.handleSubmit()}
|
||||||
>
|
>
|
||||||
Cari
|
Cari
|
||||||
</Button>
|
</Button>
|
||||||
@@ -601,22 +591,34 @@ const FinanceTable = () => {
|
|||||||
isClearable
|
isClearable
|
||||||
/>
|
/>
|
||||||
<DateInput
|
<DateInput
|
||||||
name='startDate'
|
name='start_date'
|
||||||
label='Periode Tanggal (Mulai)'
|
label='Periode Tanggal (Mulai)'
|
||||||
value={pendingFilters.startDate}
|
value={filterFormik.values.start_date}
|
||||||
onChange={startDateChangeHandler}
|
onChange={filterFormik.handleChange}
|
||||||
|
errorMessage={
|
||||||
|
filterFormik.touched.start_date && filterFormik.errors.start_date
|
||||||
|
? filterFormik.errors.start_date
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
onBlur={filterFormik.handleBlur}
|
||||||
/>
|
/>
|
||||||
<DateInput
|
<DateInput
|
||||||
name='endDate'
|
name='end_date'
|
||||||
label='Periode Tanggal (Akhir)'
|
label='Periode Tanggal (Akhir)'
|
||||||
value={pendingFilters.endDate}
|
value={filterFormik.values.end_date}
|
||||||
onChange={endDateChangeHandler}
|
onChange={filterFormik.handleChange}
|
||||||
|
errorMessage={
|
||||||
|
filterFormik.touched.end_date && filterFormik.errors.end_date
|
||||||
|
? filterFormik.errors.end_date
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
onBlur={filterFormik.handleBlur}
|
||||||
/>
|
/>
|
||||||
<DebouncedTextInput
|
<DebouncedTextInput
|
||||||
name='search'
|
name='search'
|
||||||
label='Cari'
|
label='Cari'
|
||||||
placeholder='Cari'
|
placeholder='Cari'
|
||||||
value={pendingFilters.search}
|
value={filterFormik.values.search}
|
||||||
onChange={searchChangeHandler}
|
onChange={searchChangeHandler}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { OptionType } from '@/components/input/SelectInput';
|
||||||
|
import * as yup from 'yup';
|
||||||
|
|
||||||
|
export type FinanceTableFilterType = {
|
||||||
|
search: string;
|
||||||
|
transaction_types: string;
|
||||||
|
bank_ids: string;
|
||||||
|
customer_ids: string;
|
||||||
|
supplier_ids: string;
|
||||||
|
sort_by: string;
|
||||||
|
start_date: string;
|
||||||
|
end_date: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FinanceTableFilterSchema = yup.object({
|
||||||
|
search: yup.string().optional(),
|
||||||
|
transaction_types: yup.string().optional(),
|
||||||
|
bank_ids: yup.string().optional(),
|
||||||
|
customer_ids: yup.string().optional(),
|
||||||
|
supplier_ids: yup.string().optional(),
|
||||||
|
sort_by: yup.string().optional(),
|
||||||
|
start_date: yup.string().optional(),
|
||||||
|
end_date: yup
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.test(
|
||||||
|
'is-greater-than-start',
|
||||||
|
'Tanggal akhir tidak boleh masa lampau',
|
||||||
|
function (value) {
|
||||||
|
const { start_date } = this.parent;
|
||||||
|
if (!start_date || !value) return true;
|
||||||
|
return new Date(value) >= new Date(start_date);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}) as yup.ObjectSchema<FinanceTableFilterType>;
|
||||||
|
|
||||||
|
export type FinanceTableFilterValues = yup.InferType<
|
||||||
|
typeof FinanceTableFilterSchema
|
||||||
|
>;
|
||||||
Reference in New Issue
Block a user