@@ -3116,7 +3240,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
text='Apakah anda yakin ingin menyetujui data Recording ini?'
secondaryButton={{
text: 'Tidak',
- onClick: () => setApprovalNotes(''),
+ onClick: () => {
+ setApprovalNotes('');
+ approveModal.closeModal();
+ },
}}
primaryButton={{
text: 'Ya',
@@ -3138,7 +3265,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
text='Apakah anda yakin ingin menolak data Recording ini?'
secondaryButton={{
text: 'Tidak',
- onClick: () => setApprovalNotes(''),
+ onClick: () => {
+ setApprovalNotes('');
+ rejectModal.closeModal();
+ },
}}
primaryButton={{
text: 'Ya',
diff --git a/src/components/pages/production/transfer-to-laying/TransferToLayingFormModal.tsx b/src/components/pages/production/transfer-to-laying/TransferToLayingFormModal.tsx
index 399468c7..78de70e1 100644
--- a/src/components/pages/production/transfer-to-laying/TransferToLayingFormModal.tsx
+++ b/src/components/pages/production/transfer-to-laying/TransferToLayingFormModal.tsx
@@ -99,6 +99,7 @@ const TransferToLayingFormModal = () => {
{
category: 'GROWING',
transfer_context: 'transfer_to_laying',
+ is_approved: 'true',
}
);
@@ -116,6 +117,7 @@ const TransferToLayingFormModal = () => {
'search',
{
category: 'LAYING',
+ is_approved: 'true',
}
);
diff --git a/src/components/pages/production/uniformity/UniformityTable.tsx b/src/components/pages/production/uniformity/UniformityTable.tsx
index a3530032..39112b47 100644
--- a/src/components/pages/production/uniformity/UniformityTable.tsx
+++ b/src/components/pages/production/uniformity/UniformityTable.tsx
@@ -1058,7 +1058,7 @@ const UniformityTable = () => {
iconPosition='left'
text='Data Berhasil Ditambahkan'
subtitleText='Data uniformity telah berhasil disimpan.'
- closeOnBackdrop={false}
+ closeOnBackdrop={true}
primaryButton={{
text: 'Ok',
color: 'primary',
@@ -1089,6 +1089,7 @@ const UniformityTable = () => {
ref={singleDeleteModal.ref}
type='error'
iconPosition='left'
+ closeOnBackdrop={true}
text={`Delete This Data?`}
subtitleText='Are you sure you want to delete this data?'
secondaryButton={{
@@ -1113,6 +1114,7 @@ const UniformityTable = () => {
ref={singleApproveModal.ref}
type='success'
iconPosition='left'
+ closeOnBackdrop={true}
text='Approve This Submission?'
subtitleText='Are you sure you want to approve this submission?'
secondaryButton={{
@@ -1129,15 +1131,12 @@ const UniformityTable = () => {
}}
>
- {selectedRowIds.length === 1 ? (
+ {selectedUniformities.map((uniformity) => (
- ) : (
-
- {selectedRowIds.length} data dipilih
-
- )}
+ ))}
@@ -1145,8 +1144,13 @@ const UniformityTable = () => {
ref={bulkApproveModal.ref}
type='success'
iconPosition='left'
+ closeOnBackdrop={true}
text={`Approve This Submission?`}
- subtitleText={`Are you sure you want to approve this submission? (${selectedRowIds.length} data)`}
+ subtitleText={
+ selectedRowIds.length === 1
+ ? 'Are you sure you want to approve this submission?'
+ : `Are you sure you want to approve these submissions? (${selectedRowIds.length} data)`
+ }
secondaryButton={{
text: 'Cancel',
}}
@@ -1161,7 +1165,12 @@ const UniformityTable = () => {
}}
>
-
+ {selectedUniformities.map((uniformity) => (
+
+ ))}
@@ -1169,6 +1178,7 @@ const UniformityTable = () => {
ref={singleRejectModal.ref}
type='error'
iconPosition='left'
+ closeOnBackdrop={true}
text='Reject This Submission?'
subtitleText='Are you sure you want to reject this submission?'
secondaryButton={{
@@ -1185,15 +1195,12 @@ const UniformityTable = () => {
}}
>
- {selectedRowIds.length === 1 ? (
+ {selectedUniformities.map((uniformity) => (
- ) : (
-
- {selectedRowIds.length} data dipilih
-
- )}
+ ))}
@@ -1201,8 +1208,13 @@ const UniformityTable = () => {
ref={bulkRejectModal.ref}
type='error'
iconPosition='left'
+ closeOnBackdrop={true}
text={`Reject This Submission?`}
- subtitleText={`Are you sure you want to reject this submission? (${selectedRowIds.length} data)`}
+ subtitleText={
+ selectedRowIds.length === 1
+ ? 'Are you sure you want to reject this submission?'
+ : `Are you sure you want to reject these submissions? (${selectedRowIds.length} data)`
+ }
secondaryButton={{
text: 'Cancel',
}}
@@ -1217,15 +1229,12 @@ const UniformityTable = () => {
}}
>
- {selectedRowIds.length === 1 ? (
+ {selectedUniformities.map((uniformity) => (
- ) : (
-
- {selectedRowIds.length} data dipilih
-
- )}
+ ))}
diff --git a/src/components/pages/purchase/PurchaseTable.tsx b/src/components/pages/purchase/PurchaseTable.tsx
index 9af19b42..2c08f726 100644
--- a/src/components/pages/purchase/PurchaseTable.tsx
+++ b/src/components/pages/purchase/PurchaseTable.tsx
@@ -16,7 +16,8 @@ import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import RequirePermission from '@/components/helper/RequirePermission';
-import Badge from '@/components/Badge';
+import StatusBadge from '@/components/helper/StatusBadge';
+import PurchaseOrderInvoice from '@/components/pages/purchase/order/PurchaseOrderInvoice';
import { cn, formatDate } from '@/lib/helper';
import { isResponseSuccess } from '@/lib/api-helper';
@@ -25,6 +26,44 @@ import { useTableFilter } from '@/services/hooks/useTableFilter';
import { ROWS_OPTIONS } from '@/config/constant';
import { Purchase } from '@/types/api/purchase/purchase';
import { PurchaseApi } from '@/services/api/purchase';
+import { Color } from '@/types/theme';
+
+// ===== STATUS BADGE UTILITIES =====
+const statusTextMap: Record
= {
+ APPROVED: 'Disetujui',
+ Disetujui: 'Disetujui',
+ REJECTED: 'Ditolak',
+ Ditolak: 'Ditolak',
+ CREATED: 'Dibuat',
+ UPDATED: 'Diperbarui',
+};
+
+const getStatusText = (status: string): string => {
+ return statusTextMap[status] || status;
+};
+
+const statusBadgeColorMap: Record = {
+ APPROVED: 'success',
+ Disetujui: 'success',
+ approved: 'success',
+ disetujui: 'success',
+ REJECTED: 'error',
+ Ditolak: 'error',
+ rejected: 'error',
+ ditolak: 'error',
+ CREATED: 'neutral',
+ Dibuat: 'neutral',
+ created: 'neutral',
+ dibuat: 'neutral',
+ UPDATED: 'warning',
+ Diperbarui: 'warning',
+ updated: 'warning',
+ diperbarui: 'warning',
+};
+
+const getStatusBadgeColor = (status: string): Color => {
+ return statusBadgeColorMap[status] || 'neutral';
+};
// ===== INTERFACES =====
interface RowOptionsMenuProps {
@@ -120,6 +159,27 @@ const PurchaseTable = () => {
PurchaseApi.getAllFetcher
);
+ const [isDownloadingInvoice, setIsDownloadingInvoice] = useState(false);
+ const [invoicePurchaseData, setInvoicePurchaseData] =
+ useState(null);
+
+ const handleDownloadInvoice = async (purchaseId: number) => {
+ setIsDownloadingInvoice(true);
+ try {
+ const response = await PurchaseApi.getSingle(purchaseId);
+ if (isResponseSuccess(response) && response.data) {
+ setInvoicePurchaseData(response.data);
+ setTimeout(() => {
+ setInvoicePurchaseData(null);
+ }, 1000);
+ }
+ } catch {
+ toast.error('Gagal mengambil data purchase order.');
+ } finally {
+ setIsDownloadingInvoice(false);
+ }
+ };
+
// ===== TABLE COLUMNS DEFINITION =====
const purchaseColumns: ColumnDef[] = [
{
@@ -130,10 +190,66 @@ const PurchaseTable = () => {
},
},
{
- accessorKey: 'supplier',
+ accessorKey: 'po_expedition',
+ header: 'PO Ekspedisi',
+ cell: (props) => {
+ const purchase = props.row.original;
+
+ if (!purchase.po_number || purchase.po_number === 'Belum dibuat') {
+ return -;
+ }
+
+ return (
+
+ );
+ },
+ },
+ {
+ accessorKey: 'supplier.name',
header: 'Vendor',
cell: (props) => props.row.original.supplier.name,
},
+ {
+ accessorKey: 'requester_name',
+ header: 'Nama Pengaju',
+ cell: (props) => props.row.original.requester_name || '-',
+ },
+ {
+ accessorKey: 'products.name',
+ header: 'Produk',
+ cell: (props) => {
+ const products = props.row.original.products;
+ if (!products || products.length === 0) return '-';
+ return (
+
+ {products.map((product, index) => (
+ - {product.name}
+ ))}
+
+ );
+ },
+ },
+ {
+ accessorKey: 'location.name',
+ header: 'Lokasi',
+ cell: (props) => props.row.original.location?.name || '-',
+ },
{
accessorKey: 'po_date',
header: 'Tgl. PO',
@@ -142,6 +258,14 @@ const PurchaseTable = () => {
? 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) => {
@@ -160,48 +284,42 @@ const PurchaseTable = () => {
const approval = props.row.original.latest_approval;
if (!approval) return '-';
- const isRejected = approval.action === 'REJECTED';
+ const status = approval.action;
- let statusColor:
- | 'warning'
- | 'success'
- | 'neutral'
- | 'error'
- | 'primary'
- | 'info' = 'neutral';
+ let statusColor: Color = 'neutral';
- switch (approval.step_number) {
- case 1:
- statusColor = 'neutral';
- break;
- case 2:
- statusColor = 'primary';
- break;
- case 3:
- statusColor = 'info';
- break;
- case 4:
- statusColor = 'warning';
- break;
- case 5:
- statusColor = 'success';
- break;
+ if (status === 'REJECTED') {
+ statusColor = getStatusBadgeColor(status);
+ } else {
+ switch (approval.step_number) {
+ case 1:
+ statusColor = 'neutral';
+ break;
+ case 2:
+ statusColor = 'primary';
+ break;
+ case 3:
+ statusColor = 'info';
+ break;
+ case 4:
+ statusColor = 'warning';
+ break;
+ case 5:
+ statusColor = 'success';
+ break;
+ }
}
- if (isRejected) {
- statusColor = 'error';
- }
+ const statusText = approval.step_name || getStatusText(status);
return (
-
- {isRejected ? 'Ditolak' : approval.step_name}
-
+ />
);
},
},
@@ -287,23 +405,32 @@ const PurchaseTable = () => {
+ }
className={{
- wrapper: 'sm:max-w-3xs',
+ wrapper: 'w-full min-w-24 max-w-3xs',
+ inputWrapper: 'rounded-xl! shadow-button-soft',
+ input:
+ 'placeholder:font-semibold placeholder:text-base-content/50',
}}
/>