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 MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
const [, setMovementFormErrorMessage] = useState(''); const [, setMovementFormErrorMessage] = useState('');
const [selectedProducts, setSelectedProducts] = useState<number[]>([]);
const [selectedEkspedisi, setSelectedEkspedisi] = useState<number[]>([]);
const { const {
deleteModal, deleteModal,
@@ -120,6 +122,15 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
[formik] [formik]
); );
const bulkRemoveProduct = useCallback(() => {
const updatedProducts =
formik.values.product?.filter(
(_, idx) => !selectedProducts.includes(idx)
) ?? [];
formik.setFieldValue('product', updatedProducts);
setSelectedProducts([]);
}, [formik, selectedProducts]);
const addEkspedisi = () => { const addEkspedisi = () => {
const newEkspedisi = [ const newEkspedisi = [
...(formik.values.ekspedisi || []), ...(formik.values.ekspedisi || []),
@@ -157,6 +168,15 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
[formik] [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'>( const isRepeaterInputError = <T extends 'product' | 'ekspedisi'>(
arrayName: T, arrayName: T,
column: T extends 'product' ? keyof ProductSchema : keyof EkspedisiSchema, column: T extends 'product' ? keyof ProductSchema : keyof EkspedisiSchema,
@@ -333,6 +353,29 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
<table className='table'> <table className='table'>
<thead> <thead>
<tr> <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>Produk</th>
<th>Qty</th> <th>Qty</th>
{type !== 'detail' && <th>Aksi</th>} {type !== 'detail' && <th>Aksi</th>}
@@ -341,6 +384,27 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
<tbody> <tbody>
{formik.values.product?.map((product, idx) => ( {formik.values.product?.map((product, idx) => (
<tr key={`product-row-${idx}-${product.product_id}`}> <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> <td>
<SelectInput <SelectInput
required required
@@ -407,15 +471,32 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
</table> </table>
</div> </div>
{type !== 'detail' && ( {type !== 'detail' && (
<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 <Button
type='button' type='button'
color='success' color='success'
onClick={addProduct} onClick={addProduct}
className='w-fit mx-auto mt-4' className='w-fit'
> >
<Icon icon='ic:round-plus' width={24} height={24} /> <Icon icon='ic:round-plus' width={24} height={24} />
Tambah Produk Tambah Produk
</Button> </Button>
</div>
)} )}
</div> </div>
</div> </div>
@@ -428,6 +509,30 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
<table className='table'> <table className='table'>
<thead> <thead>
<tr> <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>Produk</th>
<th>Qty</th> <th>Qty</th>
<th>Supplier</th> <th>Supplier</th>
@@ -444,6 +549,27 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
<tr <tr
key={`ekspedisi-row-${idx}-${ekspedisi.product_id}-${ekspedisi.supplier_id}`} 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> <td>
<SelectInput <SelectInput
required required
@@ -634,15 +760,33 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
</table> </table>
</div> </div>
{type !== 'detail' && ( {type !== 'detail' && (
<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 <Button
type='button' type='button'
color='success' color='success'
onClick={addEkspedisi} onClick={addEkspedisi}
className='w-fit mx-auto mt-4' className='w-fit'
> >
<Icon icon='ic:round-plus' width={24} height={24} /> <Icon icon='ic:round-plus' width={24} height={24} />
Tambah Ekspedisi Tambah Ekspedisi
</Button> </Button>
</div>
)} )}
</div> </div>
</div> </div>