feat(FE-208,212): implement bulk delete functionality for purchase order items with confirmation modal

This commit is contained in:
rstubryan
2025-11-17 13:21:43 +07:00
parent 7ec4105454
commit 283c2b2a44
@@ -175,6 +175,67 @@ const dummyPurchaseData: Purchase = {
vehicle_number: null,
warehouse: dummyWarehouses[0],
},
{
id: 2,
purchase_id: 2,
product: {
id: 1,
name: 'CP Vaksin',
brand: '',
sku: '',
product_price: 0,
selling_price: 0,
tax: 0,
expiry_period: 0,
uom: {
id: 1,
name: 'Ekor',
created_user: {
id: 1,
id_user: 1,
email: 'hello@gmail.com',
name: 'Admin',
},
created_at: '2025-01-01T00:00:00Z',
updated_at: '2025-01-01T00:00:00Z',
},
product_category: {
id: 1,
code: 'DOC',
name: 'DOC',
created_user: {
id: 1,
id_user: 1,
email: 'hello@gmail.com',
name: 'Admin',
},
created_at: '2025-01-01T00:00:00Z',
updated_at: '2025-01-01T00:00:00Z',
},
suppliers: [],
flags: [],
created_user: {
id: 1,
id_user: 1,
email: 'hello@gmail.com',
name: 'Admin',
},
created_at: '2025-01-01T00:00:00Z',
updated_at: '2025-01-01T00:00:00Z',
},
product_warehouse: dummyProductWarehouses[0],
quantity: 10000,
sub_qty: 10000,
total_qty: 10000,
total_used: 0,
price: 6500,
total_price: 65000000,
received_date: null,
travel_number: null,
travel_number_docs: null,
vehicle_number: null,
warehouse: dummyWarehouses[0],
},
],
created_at: '2025-01-10T00:00:00Z',
updated_at: '2025-01-10T00:00:00Z',
@@ -184,7 +245,6 @@ const dummyPurchaseData: Purchase = {
warehouse: dummyWarehouses[0],
};
// Goods Receipt data - using items from PurchaseItem with received data
const dummyGoodsReceiptItems: PurchaseItem[] = [
{
id: 1,
@@ -356,6 +416,10 @@ const PurchaseOrderDetail = ({
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const [selectedItem, setSelectedItem] = useState<PurchaseItem | null>(null);
const selectedRowIds = Object.keys(rowSelection).map((item) =>
parseInt(item)
);
// ===== STATIC DATA =====
const purchaseData = data || dummyPurchaseData;
const purchaseOrderItems = useMemo(
@@ -394,7 +458,7 @@ const PurchaseOrderDetail = ({
);
// ===== DELETE HANDLER =====
const deleteItemHandler = useCallback(async () => {
const deleteItemsHandler = useCallback(async () => {
const purchaseRequestId = searchParams.get('purchaseId')
? parseInt(searchParams.get('purchaseId')!)
: purchaseData?.id || 1;
@@ -404,8 +468,10 @@ const PurchaseOrderDetail = ({
return;
}
if (!selectedItem) {
toast.error('Item tidak valid');
const itemIdsToDelete = selectedItem ? [selectedItem.id] : selectedRowIds;
if (itemIdsToDelete.length === 0) {
toast.error('Pilih minimal 1 item untuk dihapus');
return;
}
@@ -413,7 +479,7 @@ const PurchaseOrderDetail = ({
try {
const res = await PurchaseDeleteItemsApi.deleteItems(purchaseRequestId, {
item_ids: [selectedItem.id],
item_ids: itemIdsToDelete,
});
if (isResponseError(res)) {
@@ -421,16 +487,21 @@ const PurchaseOrderDetail = ({
return;
}
toast.success('Berhasil menghapus item pembelian');
const successMessage = selectedItem
? 'Berhasil menghapus item pembelian'
: `Berhasil menghapus ${itemIdsToDelete.length} item pembelian`;
toast.success(successMessage);
deleteModal.closeModal();
setSelectedItem(null);
setRowSelection({});
} catch (error) {
toast.error('Terjadi kesalahan saat menghapus item pembelian');
} finally {
setIsDeleteLoading(false);
}
}, [purchaseData?.id, searchParams, selectedItem]);
}, [purchaseData?.id, searchParams, selectedItem, selectedRowIds]);
// ===== COMPUTED VALUES =====
const approvalSteps = useMemo(() => {
@@ -522,6 +593,7 @@ const PurchaseOrderDetail = ({
cell: (props) => {
const deleteClickHandler = () => {
setSelectedItem(props.row.original);
setRowSelection({}); // Clear row selection when doing single delete
deleteModal.openModal();
};
@@ -857,6 +929,25 @@ const PurchaseOrderDetail = ({
/>
</div>
{/* Bulk Action Buttons */}
{selectedRowIds.length > 0 && (
<div className='flex justify-center items-center mt-4 gap-4 px-6 py-4 bg-gray-50 border-t border-gray-200'>
<Button
type='button'
color='error'
onClick={() => {
setSelectedItem(null);
deleteModal.openModal();
}}
disabled={selectedRowIds.length === 0}
className='w-fit text-sm'
>
<Icon icon='mdi:trash-can' width={16} height={16} />
Hapus Terpilih ({selectedRowIds.length})
</Button>
</div>
)}
{/* Bottom Section - Catatan dan Total */}
<div className='border-t border-gray-200 grid grid-cols-1 lg:grid-cols-5 divide-x divide-gray-200'>
{/* Catatan Section */}
@@ -1024,14 +1115,18 @@ const PurchaseOrderDetail = ({
<ConfirmationModal
ref={deleteModal.ref}
type='error'
text='Apakah Anda yakin ingin menghapus item pembelian ini?'
text={`Apakah Anda yakin ingin menghapus ${
selectedItem
? 'item pembelian ini?'
: `${selectedRowIds.length} item pembelian yang dipilih?`
}`}
closeOnBackdrop
primaryButton={{
text: 'Ya, Hapus',
color: 'error',
isLoading: isDeleteLoading,
onClick: async () => {
await deleteItemHandler();
await deleteItemsHandler();
},
}}
secondaryButton={{