feat(FE-208,212): enhance PurchaseOrder forms with onCancel functionality and UI improvements

This commit is contained in:
rstubryan
2025-11-11 15:05:05 +07:00
parent 8c17367fb6
commit ecb497430a
3 changed files with 544 additions and 505 deletions
@@ -10,6 +10,7 @@ import Table from '@/components/Table';
import DebouncedTextInput from '@/components/input/DebouncedTextInput';
import Button from '@/components/Button';
import { useModal } from '@/components/Modal';
import Modal from '@/components/Modal';
import ConfirmationModal from '@/components/modal/ConfirmationModal';
import SelectInput, {
OptionType,
@@ -21,6 +22,8 @@ import TextInput from '@/components/input/TextInput';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import { cn, formatDate, formatCurrency } from '@/lib/helper';
import PurchaseOrderStaffApprovalForm from '@/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm';
import PurchaseOrderAcceptApprovalForm from '@/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm';
import { isResponseSuccess } from '@/lib/api-helper';
import { useTableFilter } from '@/services/hooks/useTableFilter';
import { ROWS_OPTIONS } from '@/config/constant';
@@ -108,6 +111,8 @@ const PurchaseTable = () => {
// Modal hooks
const deleteModal = useModal();
const staffApprovalModal = useModal();
const acceptApprovalModal = useModal();
// Supplier modal
const {
@@ -282,6 +287,30 @@ const PurchaseTable = () => {
Tambah
</Button>
<Button
onClick={() => staffApprovalModal.openModal()}
variant='outline'
color='info'
className='w-full sm:w-fit'
>
<Icon icon='mdi:account-check-outline' width={24} height={24} />
Staff Approval
</Button>
<Button
onClick={() => acceptApprovalModal.openModal()}
variant='outline'
color='success'
className='w-full sm:w-fit'
>
<Icon
icon='mdi:package-variant-closed-check'
width={24}
height={24}
/>
Accept Approval
</Button>
{selectedRowIds.length > 0 && (
<Button
variant='outline'
@@ -418,6 +447,34 @@ const PurchaseTable = () => {
onClick: confirmationModalDeleteClickHandler,
}}
/>
{/* Staff Approval Modal */}
<Modal
ref={staffApprovalModal.ref}
closeOnBackdrop
className={{
modalBox: 'w-full max-w-6xl max-h-[90vh] overflow-y-auto'
}}
>
<PurchaseOrderStaffApprovalForm
type='add'
onCancel={staffApprovalModal.closeModal}
/>
</Modal>
{/* Accept Approval Modal */}
<Modal
ref={acceptApprovalModal.ref}
closeOnBackdrop
className={{
modalBox: 'w-full max-w-6xl max-h-[90vh] overflow-y-auto'
}}
>
<PurchaseOrderAcceptApprovalForm
type='add'
onCancel={acceptApprovalModal.closeModal}
/>
</Modal>
</>
);
};
@@ -23,16 +23,16 @@ import {
Purchase,
} from '@/types/api/purchase/purchase';
import Card from '@/components/Card';
interface PurchaseOrderAcceptApprovalFormProps {
type?: 'add' | 'edit';
initialValues?: Purchase;
onCancel?: () => void;
}
const PurchaseOrderAcceptApprovalForm = ({
type = 'add',
initialValues,
onCancel,
}: PurchaseOrderAcceptApprovalFormProps) => {
const searchParams = useSearchParams();
const [purchaseOrderFormErrorMessage, setPurchaseOrderFormErrorMessage] =
@@ -121,6 +121,7 @@ const PurchaseOrderAcceptApprovalForm = ({
return;
}
toast.success(res?.message as string);
onCancel?.();
},
[initialValues?.id, searchParams]
);
@@ -136,6 +137,7 @@ const PurchaseOrderAcceptApprovalForm = ({
return;
}
toast.success(res?.message as string);
onCancel?.();
window.location.href = '/purchase';
},
[]
@@ -330,10 +332,7 @@ const PurchaseOrderAcceptApprovalForm = ({
formik.setFieldTouched(`items.${idx}.warehouse`, true);
formik.setFieldValue(`items.${idx}.warehouse`, warehouse);
formik.setFieldTouched(`items.${idx}.warehouse_id`, true);
formik.setFieldValue(
`items.${idx}.warehouse_id`,
warehouse?.value || 0
);
formik.setFieldValue(`items.${idx}.warehouse_id`, warehouse?.value || 0);
};
const expeditionVendorChangeHandler = (
@@ -394,19 +393,11 @@ const PurchaseOrderAcceptApprovalForm = ({
};
return (
<>
<section className='w-full'>
<form
onSubmit={formik.handleSubmit}
className='w-full mt-8 flex flex-col gap-6'
>
<Card
title='Konfirmasi Penerimaan Produk'
className={{
wrapper: 'w-full mb-4 shadow',
title: 'mb-4',
}}
>
<form onSubmit={formik.handleSubmit} className='w-full flex flex-col gap-6'>
<div className='w-full'>
<h2 className='text-lg font-semibold mb-4'>
Konfirmasi Penerimaan Produk
</h2>
<div className='overflow-x-auto'>
<table className='table'>
<thead>
@@ -471,13 +462,10 @@ const PurchaseOrderAcceptApprovalForm = ({
isClearable={true}
value={item.purchase_item}
key={`purchase-item-${idx}`}
onChange={(val) =>
purchaseItemChangeHandler(idx, val)
}
onChange={(val) => purchaseItemChangeHandler(idx, val)}
options={getPurchaseItemOptions()}
isError={
getPurchaseItemError(idx, 'purchase_item_id')
.isError
getPurchaseItemError(idx, 'purchase_item_id').isError
}
errorMessage={
getPurchaseItemError(idx, 'purchase_item_id')
@@ -523,8 +511,8 @@ const PurchaseOrderAcceptApprovalForm = ({
typeof selectedPurchaseItem?.product
?.product_category === 'string'
? selectedPurchaseItem.product.product_category
: selectedPurchaseItem?.product
?.product_category?.name || ''
: selectedPurchaseItem?.product?.product_category
?.name || ''
}
readOnly={true}
placeholder='Pilih item terlebih dahulu'
@@ -557,9 +545,7 @@ const PurchaseOrderAcceptApprovalForm = ({
<TextInput
name={`items.${idx}.uom`}
type='text'
value={
selectedPurchaseItem?.product?.uom?.name || ''
}
value={selectedPurchaseItem?.product?.uom?.name || ''}
readOnly={true}
placeholder='Pilih item terlebih dahulu'
className={{
@@ -605,8 +591,7 @@ const PurchaseOrderAcceptApprovalForm = ({
getPurchaseItemError(idx, 'warehouse_id').isError
}
errorMessage={
getPurchaseItemError(idx, 'warehouse_id')
.errorMessage
getPurchaseItemError(idx, 'warehouse_id').errorMessage
}
placeholder='Pilih Gudang...'
className={{
@@ -681,8 +666,7 @@ const PurchaseOrderAcceptApprovalForm = ({
}
onBlur={formik.handleBlur}
isError={
getPurchaseItemError(idx, 'vehicle_number')
.isError
getPurchaseItemError(idx, 'vehicle_number').isError
}
errorMessage={
getPurchaseItemError(idx, 'vehicle_number')
@@ -740,8 +724,7 @@ const PurchaseOrderAcceptApprovalForm = ({
getPurchaseItemError(idx, 'received_qty').isError
}
errorMessage={
getPurchaseItemError(idx, 'received_qty')
.errorMessage
getPurchaseItemError(idx, 'received_qty').errorMessage
}
className={{
wrapper: 'min-w-32',
@@ -800,8 +783,7 @@ const PurchaseOrderAcceptApprovalForm = ({
decimalSeparator='.'
inputPrefix={'Rp'}
isError={
getPurchaseItemError(idx, 'transport_total')
.isError
getPurchaseItemError(idx, 'transport_total').isError
}
errorMessage={
getPurchaseItemError(idx, 'transport_total')
@@ -834,11 +816,14 @@ const PurchaseOrderAcceptApprovalForm = ({
{/* Action buttons */}
<div className='flex flex-row justify-between gap-2 flex-wrap mt-5'>
<div className='flex flex-row justify-end gap-2 w-full'>
<Link href='/purchase'>
<Button color='warning' className='px-4'>
<Button
type='button'
color='warning'
className='px-4'
onClick={onCancel}
>
Cancel
</Button>
</Link>
<Button
type='submit'
@@ -862,10 +847,8 @@ const PurchaseOrderAcceptApprovalForm = ({
<span>{purchaseOrderFormErrorMessage}</span>
</div>
)}
</Card>
</div>
</form>
</section>
</>
);
};
@@ -23,16 +23,17 @@ import {
Purchase,
} from '@/types/api/purchase/purchase';
import Card from '@/components/Card';
interface PurchaseOrderStaffApprovalFormProps {
type?: 'add' | 'edit';
initialValues?: Purchase;
onCancel?: () => void;
}
const PurchaseOrderStaffApprovalForm = ({
type = 'add',
initialValues,
onCancel,
}: PurchaseOrderStaffApprovalFormProps) => {
const searchParams = useSearchParams();
const [purchaseOrderFormErrorMessage, setPurchaseOrderFormErrorMessage] =
@@ -99,6 +100,7 @@ const PurchaseOrderStaffApprovalForm = ({
return;
}
toast.success(res?.message as string);
onCancel?.();
},
[initialValues?.id, searchParams]
);
@@ -117,6 +119,7 @@ const PurchaseOrderStaffApprovalForm = ({
return;
}
toast.success(res?.message as string);
onCancel?.();
window.location.href = '/purchase';
},
[]
@@ -299,18 +302,12 @@ const PurchaseOrderStaffApprovalForm = ({
return (
<>
<section className='w-full'>
<form
onSubmit={formik.handleSubmit}
className='w-full mt-8 flex flex-col gap-6'
>
<Card
title='Konfirmasi Approve Pembelian'
className={{
wrapper: 'w-full mb-4 shadow',
title: 'mb-4',
}}
className='w-full flex flex-col gap-6'
>
<div className='w-full'>
<h2 className='text-lg font-semibold mb-4'>Konfirmasi Approve Pembelian</h2>
<div className='overflow-x-auto'>
<table className='table'>
<thead>
@@ -525,11 +522,14 @@ const PurchaseOrderStaffApprovalForm = ({
{/* Action buttons */}
<div className='flex flex-row justify-between gap-2 flex-wrap mt-5'>
<div className='flex flex-row justify-end gap-2 w-full'>
<Link href='/purchase'>
<Button color='warning' className='px-4'>
<Button
type='button'
color='warning'
className='px-4'
onClick={onCancel}
>
Cancel
</Button>
</Link>
<Button
type='submit'
@@ -553,9 +553,8 @@ const PurchaseOrderStaffApprovalForm = ({
<span>{purchaseOrderFormErrorMessage}</span>
</div>
)}
</Card>
</div>
</form>
</section>
</>
);
};