feat(FE-62): implement bulk removal functionality for selected products and ekspedisi in MovementForm

This commit is contained in:
rstubryan
2025-10-10 13:14:39 +07:00
parent 57831646d9
commit 157235433e
@@ -38,6 +38,8 @@ interface MovementFormProps {
const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
const [, setMovementFormErrorMessage] = useState('');
const [selectedProducts, setSelectedProducts] = useState<number[]>([]);
const [selectedEkspedisi, setSelectedEkspedisi] = useState<number[]>([]);
const {
deleteModal,
@@ -120,6 +122,15 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
[formik]
);
const bulkRemoveProduct = useCallback(() => {
const updatedProducts =
formik.values.product?.filter(
(_, idx) => !selectedProducts.includes(idx)
) ?? [];
formik.setFieldValue('product', updatedProducts);
setSelectedProducts([]);
}, [formik, selectedProducts]);
const addEkspedisi = () => {
const newEkspedisi = [
...(formik.values.ekspedisi || []),
@@ -157,6 +168,15 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
[formik]
);
const bulkRemoveEkspedisi = useCallback(() => {
const updatedEkspedisi =
formik.values.ekspedisi?.filter(
(_, idx) => !selectedEkspedisi.includes(idx)
) ?? [];
formik.setFieldValue('ekspedisi', updatedEkspedisi);
setSelectedEkspedisi([]);
}, [formik, selectedEkspedisi]);
const isRepeaterInputError = <T extends 'product' | 'ekspedisi'>(
arrayName: T,
column: T extends 'product' ? keyof ProductSchema : keyof EkspedisiSchema,
@@ -333,6 +353,29 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
<table className='table'>
<thead>
<tr>
{type !== 'detail' && (
<th>
<input
type='checkbox'
className='checkbox'
checked={
formik.values.product?.length ===
selectedProducts.length &&
formik.values.product?.length > 0
}
onChange={(e) => {
if (e.target.checked) {
setSelectedProducts(
formik.values.product?.map((_, idx) => idx) ??
[]
);
} else {
setSelectedProducts([]);
}
}}
/>
</th>
)}
<th>Produk</th>
<th>Qty</th>
{type !== 'detail' && <th>Aksi</th>}
@@ -341,6 +384,27 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
<tbody>
{formik.values.product?.map((product, idx) => (
<tr key={`product-row-${idx}-${product.product_id}`}>
{type !== 'detail' && (
<td>
<input
type='checkbox'
className='checkbox'
checked={selectedProducts.includes(idx)}
onChange={(e) => {
if (e.target.checked) {
setSelectedProducts([
...selectedProducts,
idx,
]);
} else {
setSelectedProducts(
selectedProducts.filter((i) => i !== idx)
);
}
}}
/>
</td>
)}
<td>
<SelectInput
required
@@ -407,15 +471,32 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
</table>
</div>
{type !== 'detail' && (
<Button
type='button'
color='success'
onClick={addProduct}
className='w-fit mx-auto mt-4'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah Produk
</Button>
<div className='flex justify-center items-center mt-4 gap-4'>
{selectedProducts.length > 0 && (
<Button
type='button'
color='error'
onClick={bulkRemoveProduct}
className='w-fit'
>
<Icon
icon='material-symbols:delete-outline-rounded'
width={24}
height={24}
/>
Hapus Produk Terpilih ({selectedProducts.length})
</Button>
)}
<Button
type='button'
color='success'
onClick={addProduct}
className='w-fit'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah Produk
</Button>
</div>
)}
</div>
</div>
@@ -428,6 +509,30 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
<table className='table'>
<thead>
<tr>
{type !== 'detail' && (
<th>
<input
type='checkbox'
className='checkbox'
checked={
formik.values.ekspedisi?.length ===
selectedEkspedisi.length &&
formik.values.ekspedisi?.length > 0
}
onChange={(e) => {
if (e.target.checked) {
setSelectedEkspedisi(
formik.values.ekspedisi?.map(
(_, idx) => idx
) ?? []
);
} else {
setSelectedEkspedisi([]);
}
}}
/>
</th>
)}
<th>Produk</th>
<th>Qty</th>
<th>Supplier</th>
@@ -444,6 +549,27 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
<tr
key={`ekspedisi-row-${idx}-${ekspedisi.product_id}-${ekspedisi.supplier_id}`}
>
{type !== 'detail' && (
<td>
<input
type='checkbox'
className='checkbox'
checked={selectedEkspedisi.includes(idx)}
onChange={(e) => {
if (e.target.checked) {
setSelectedEkspedisi([
...selectedEkspedisi,
idx,
]);
} else {
setSelectedEkspedisi(
selectedEkspedisi.filter((i) => i !== idx)
);
}
}}
/>
</td>
)}
<td>
<SelectInput
required
@@ -634,15 +760,33 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
</table>
</div>
{type !== 'detail' && (
<Button
type='button'
color='success'
onClick={addEkspedisi}
className='w-fit mx-auto mt-4'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah Ekspedisi
</Button>
<div className='flex justify-center items-center mt-4 gap-4'>
{selectedEkspedisi.length > 0 && (
<Button
type='button'
color='error'
onClick={bulkRemoveEkspedisi}
disabled={selectedEkspedisi.length === 0}
className='w-fit'
>
<Icon
icon='material-symbols:delete-outline-rounded'
width={24}
height={24}
/>
Hapus Ekspedisi Terpilih ({selectedEkspedisi.length})
</Button>
)}
<Button
type='button'
color='success'
onClick={addEkspedisi}
className='w-fit'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah Ekspedisi
</Button>
</div>
)}
</div>
</div>