mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
refactor(FE-208,213): enhance PurchaseOrderDetail and PurchaseOrderStaffApprovalForm components with initialValues prop and clean up unused code
This commit is contained in:
@@ -91,7 +91,6 @@ const PurchaseTable = () => {
|
||||
null
|
||||
);
|
||||
const [sorting, setSorting] = useState<SortingState>([]);
|
||||
const [rowSelection, setRowSelection] = useState<Record<string, boolean>>({});
|
||||
|
||||
// ===== TABLE FILTER STATE =====
|
||||
const {
|
||||
@@ -134,104 +133,94 @@ const PurchaseTable = () => {
|
||||
PurchaseRequestApi.getAllFetcher
|
||||
);
|
||||
|
||||
// ===== COMPUTED VALUES =====
|
||||
const selectedRowIds = useMemo(
|
||||
() => Object.keys(rowSelection).map((item) => parseInt(item)),
|
||||
[rowSelection]
|
||||
);
|
||||
|
||||
// ===== TABLE COLUMNS DEFINITION =====
|
||||
const purchaseColumns: ColumnDef<Purchase>[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
header: 'No. PR/PO',
|
||||
cell: (props) => {
|
||||
const { pr_number, po_number } = props.row.original;
|
||||
return po_number ? po_number : pr_number;
|
||||
},
|
||||
const purchaseColumns: ColumnDef<Purchase>[] = [
|
||||
{
|
||||
header: 'No. PR/PO',
|
||||
cell: (props) => {
|
||||
const { pr_number, po_number } = props.row.original;
|
||||
return po_number ? po_number : pr_number;
|
||||
},
|
||||
{
|
||||
accessorKey: 'supplier',
|
||||
header: 'Vendor',
|
||||
cell: (props) => props.row.original.supplier.name,
|
||||
},
|
||||
{
|
||||
accessorKey: 'supplier',
|
||||
header: 'Vendor',
|
||||
cell: (props) => props.row.original.supplier.name,
|
||||
},
|
||||
{
|
||||
accessorKey: 'po_date',
|
||||
header: 'Tgl. PO',
|
||||
cell: (props) =>
|
||||
props.row.original.po_date
|
||||
? formatDate(props.row.original.po_date, 'DD MMM YYYY')
|
||||
: '-',
|
||||
},
|
||||
{
|
||||
accessorKey: 'due_date',
|
||||
header: 'Jatuh Tempo',
|
||||
cell: (props) =>
|
||||
props.row.original.due_date
|
||||
? formatDate(props.row.original.due_date, 'DD MMM YYYY')
|
||||
: '-',
|
||||
},
|
||||
{
|
||||
header: 'Aging',
|
||||
cell: (props) => {
|
||||
const purchase = props.row.original;
|
||||
if (!purchase.po_date) return '-';
|
||||
const poDate = new Date(purchase.po_date);
|
||||
const today = new Date();
|
||||
const diffTime = Math.abs(today.getTime() - poDate.getTime());
|
||||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
||||
return `${diffDays} hari`;
|
||||
},
|
||||
{
|
||||
accessorKey: 'po_date',
|
||||
header: 'Tgl. PO',
|
||||
cell: (props) =>
|
||||
props.row.original.po_date
|
||||
? formatDate(props.row.original.po_date, 'DD MMM YYYY')
|
||||
: '-',
|
||||
},
|
||||
{
|
||||
accessorKey: 'due_date',
|
||||
header: 'Jatuh Tempo',
|
||||
cell: (props) =>
|
||||
props.row.original.due_date
|
||||
? formatDate(props.row.original.due_date, 'DD MMM YYYY')
|
||||
: '-',
|
||||
},
|
||||
{
|
||||
header: 'Aging',
|
||||
cell: (props) => {
|
||||
const purchase = props.row.original;
|
||||
if (!purchase.po_date) return '-';
|
||||
const poDate = new Date(purchase.po_date);
|
||||
const today = new Date();
|
||||
const diffTime = Math.abs(today.getTime() - poDate.getTime());
|
||||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
||||
return `${diffDays} hari`;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'grand_total',
|
||||
header: 'Total (Rp.)',
|
||||
cell: (props) => formatCurrency(props.row.original.grand_total),
|
||||
},
|
||||
{
|
||||
header: 'Aksi',
|
||||
cell: (props) => {
|
||||
const currentPageSize =
|
||||
props.table.getPaginationRowModel().rows.length;
|
||||
const currentPageRows = props.table.getPaginationRowModel().flatRows;
|
||||
const currentRowRelativeIndex =
|
||||
currentPageRows.findIndex((r) => r.id === props.row.id) + 1;
|
||||
},
|
||||
{
|
||||
accessorKey: 'grand_total',
|
||||
header: 'Total (Rp.)',
|
||||
cell: (props) => formatCurrency(props.row.original.grand_total),
|
||||
},
|
||||
{
|
||||
header: 'Aksi',
|
||||
cell: (props) => {
|
||||
const currentPageSize = props.table.getPaginationRowModel().rows.length;
|
||||
const currentPageRows = props.table.getPaginationRowModel().flatRows;
|
||||
const currentRowRelativeIndex =
|
||||
currentPageRows.findIndex((r) => r.id === props.row.id) + 1;
|
||||
|
||||
const isLast2Rows = currentRowRelativeIndex > currentPageSize - 2;
|
||||
const isLast2Rows = currentRowRelativeIndex > currentPageSize - 2;
|
||||
|
||||
const deleteClickHandler = () => {
|
||||
setSelectedPurchase(props.row.original);
|
||||
deleteModal.openModal();
|
||||
};
|
||||
const deleteClickHandler = () => {
|
||||
setSelectedPurchase(props.row.original);
|
||||
deleteModal.openModal();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{currentPageSize > 2 && (
|
||||
<RowDropdownOptions isLast2Rows={isLast2Rows}>
|
||||
<RowOptionsMenu
|
||||
type='dropdown'
|
||||
props={props}
|
||||
deleteClickHandler={deleteClickHandler}
|
||||
/>
|
||||
</RowDropdownOptions>
|
||||
)}
|
||||
return (
|
||||
<>
|
||||
{currentPageSize > 2 && (
|
||||
<RowDropdownOptions isLast2Rows={isLast2Rows}>
|
||||
<RowOptionsMenu
|
||||
type='dropdown'
|
||||
props={props}
|
||||
deleteClickHandler={deleteClickHandler}
|
||||
/>
|
||||
</RowDropdownOptions>
|
||||
)}
|
||||
|
||||
{currentPageSize <= 2 && (
|
||||
<RowCollapseOptions>
|
||||
<RowOptionsMenu
|
||||
type='collapse'
|
||||
props={props}
|
||||
deleteClickHandler={deleteClickHandler}
|
||||
/>
|
||||
</RowCollapseOptions>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
},
|
||||
{currentPageSize <= 2 && (
|
||||
<RowCollapseOptions>
|
||||
<RowOptionsMenu
|
||||
type='collapse'
|
||||
props={props}
|
||||
deleteClickHandler={deleteClickHandler}
|
||||
/>
|
||||
</RowCollapseOptions>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
},
|
||||
];
|
||||
|
||||
// ===== EVENT HANDLERS =====
|
||||
const confirmationModalDeleteClickHandler = useCallback(async () => {
|
||||
@@ -287,7 +276,7 @@ const PurchaseTable = () => {
|
||||
<div className='w-full p-0 sm:p-4'>
|
||||
<div className='flex flex-col gap-2 mb-4'>
|
||||
<div className='w-full flex flex-col xl:flex-row justify-between items-end xl:items-center gap-2'>
|
||||
<div className='w-full sm:w-fit flex flex-col sm:flex-row self-start gap-2'>
|
||||
<div className='w-full flex flex-row gap-2'>
|
||||
<Button
|
||||
href='/purchase/add'
|
||||
variant='outline'
|
||||
@@ -297,32 +286,6 @@ const PurchaseTable = () => {
|
||||
<Icon icon='ic:round-plus' width={24} height={24} />
|
||||
Tambah
|
||||
</Button>
|
||||
|
||||
{selectedRowIds.length > 0 && (
|
||||
<Button
|
||||
variant='outline'
|
||||
color='error'
|
||||
onClick={() => {
|
||||
setSelectedPurchase(
|
||||
isResponseSuccess(purchaseRequests)
|
||||
? purchaseRequests?.data?.find((p: Purchase) =>
|
||||
selectedRowIds.includes(p.id)
|
||||
) || null
|
||||
: null
|
||||
);
|
||||
deleteModal.openModal();
|
||||
}}
|
||||
disabled={selectedRowIds.length === 0}
|
||||
className='w-full sm:w-fit'
|
||||
>
|
||||
<Icon
|
||||
icon='material-symbols:delete-outline-rounded'
|
||||
width={24}
|
||||
height={24}
|
||||
/>
|
||||
Hapus ({selectedRowIds.length})
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<DebouncedTextInput
|
||||
@@ -400,8 +363,6 @@ const PurchaseTable = () => {
|
||||
isLoading={isLoading}
|
||||
sorting={sorting}
|
||||
setSorting={setSorting}
|
||||
rowSelection={rowSelection}
|
||||
setRowSelection={setRowSelection}
|
||||
className={{
|
||||
containerClassName: cn({
|
||||
'mb-20':
|
||||
|
||||
@@ -170,7 +170,7 @@ const PurchaseOrderStaffApprovalForm = ({
|
||||
if (initialValues?.items) {
|
||||
return initialValues.items.map((item) => ({
|
||||
value: item.id,
|
||||
label: `${item.product.name} (${item.quantity} ${item.product.uom?.name || 'unit'})`,
|
||||
label: `${item.product.name} ${item.quantity}`,
|
||||
id: item.id,
|
||||
quantity: item.quantity,
|
||||
product: {
|
||||
@@ -184,57 +184,8 @@ const PurchaseOrderStaffApprovalForm = ({
|
||||
}));
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
value: 1,
|
||||
label: 'SEALYTE SPARK 1 x 87 gr (14 SACHET)',
|
||||
id: 1,
|
||||
quantity: 14,
|
||||
product: {
|
||||
name: 'SEALYTE SPARK 1 x 87 gr',
|
||||
product_category: 'Bahan Baku',
|
||||
uom: {
|
||||
name: 'SACHET',
|
||||
},
|
||||
},
|
||||
warehouse: {
|
||||
name: 'GUDANG CIANGSANA 1 (ARCA P15)',
|
||||
},
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: 'CID-2000 @ 5 KG (2 KILOGRAM)',
|
||||
id: 2,
|
||||
quantity: 2,
|
||||
product: {
|
||||
name: 'CID-2000 @ 5 KG',
|
||||
product_category: 'Bahan Baku',
|
||||
uom: {
|
||||
name: 'Kilogram',
|
||||
},
|
||||
},
|
||||
warehouse: {
|
||||
name: 'GUDANG CIANGSANA 2 (ARCA P15)',
|
||||
},
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: 'VITAMIN AYAM (10 DOSIS)',
|
||||
id: 3,
|
||||
quantity: 10,
|
||||
product: {
|
||||
name: 'VITAMIN AYAM',
|
||||
product_category: 'Bahan Baku',
|
||||
uom: {
|
||||
name: 'DOSIS',
|
||||
},
|
||||
},
|
||||
warehouse: {
|
||||
name: 'GUDANG CIANGSANA 3 (ARCA P15)',
|
||||
},
|
||||
},
|
||||
];
|
||||
}, [initialValues?.items, searchParams]);
|
||||
return [];
|
||||
}, [initialValues?.items]);
|
||||
|
||||
const getPurchaseItemOptions = useCallback(() => {
|
||||
return purchaseItems;
|
||||
|
||||
@@ -758,6 +758,7 @@ const PurchaseOrderDetail = ({
|
||||
>
|
||||
<PurchaseOrderStaffApprovalForm
|
||||
type='add'
|
||||
initialValues={purchaseData}
|
||||
onCancel={staffApprovalModal.closeModal}
|
||||
/>
|
||||
</Modal>
|
||||
|
||||
Reference in New Issue
Block a user