'use client'; import { useCallback, useMemo, useState } from 'react'; import { ColumnDef, SortingState } from '@tanstack/react-table'; import ApprovalSteps, { useApprovalSteps, } from '@/components/pages/ApprovalSteps'; import Table from '@/components/Table'; import Button from '@/components/Button'; import { Icon } from '@iconify/react'; import { useModal } from '@/components/Modal'; import CheckboxInput from '@/components/input/CheckboxInput'; import Modal from '@/components/Modal'; import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes'; import ConfirmationModal from '@/components/modal/ConfirmationModal'; import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; import PurchaseOrderStaffApprovalForm from '@/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm'; import PurchaseOrderAcceptApprovalForm from '@/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm'; import PurchaseOrderInvoice from '@/components/pages/purchase/order/PurchaseOrderInvoice'; import Card from '@/components/Card'; import { CreateManagerApprovalRequestPayload, Purchase, PurchaseItem, } from '@/types/api/purchase/purchase'; import { ManagerApprovalApi, PurchaseDeleteItemsApi, } from '@/services/api/purchase'; import { isResponseError } from '@/lib/api-helper'; import { toast } from 'react-hot-toast'; import { useSearchParams } from 'next/navigation'; import { formatCurrency, formatNumber, formatDate } from '@/lib/helper'; import { PURCHASE_ORDER_APPROVAL_LINE } from '@/config/approval-line'; const ItemPembelianDropdown = ({ onEdit }: { onEdit: () => void }) => { return ( ); }; const PenerimaanBarangDropdown = ({ onEdit }: { onEdit: () => void }) => { return ( ); }; interface PurchaseOrderDetailProps { type?: 'detail' | 'edit'; initialValues?: Purchase; } const PurchaseOrderDetail = ({ type = 'detail', initialValues, }: PurchaseOrderDetailProps) => { // ===== MODAL HOOKS ===== const searchParams = useSearchParams(); const confirmationModalWithNotes = useModal(); const staffApprovalModal = useModal(); const acceptApprovalModal = useModal(); const editModal = useModal(); const penerimaanBarangModal = useModal(); const deleteModal = useModal(); // ===== STATE MANAGEMENT ===== const [sorting, setSorting] = useState([]); const [rowSelection, setRowSelection] = useState>({}); const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [selectedItem, setSelectedItem] = useState(null); const selectedRowIds = Object.keys(rowSelection).map((item) => parseInt(item) ); // ===== COMPUTED VALUES ===== const purchaseOrderItems = useMemo( () => initialValues?.items || [], [initialValues?.items] ); const goodsReceiptItems = useMemo(() => { return purchaseOrderItems.filter((item) => item.received_date); }, [purchaseOrderItems]); const canUpdatePurchaseItems = useMemo(() => { if (!initialValues?.approval) return false; const currentStep = initialValues.approval.step_number; return currentStep >= 4; }, [initialValues?.approval]); const { approvals, isLoading: approvalsLoading, rawDataApprovals, refresh: refreshApprovals, } = useApprovalSteps({ latestApproval: initialValues?.approval, approvalLines: PURCHASE_ORDER_APPROVAL_LINE, moduleName: 'PURCHASES', moduleId: initialValues?.id?.toString() ?? '', params: { limit: 100, group_step_number: true, }, }); const totalBeforeTax = useMemo(() => { return purchaseOrderItems.reduce( (sum, item) => sum + (item.total_price || 0), 0 ); }, [purchaseOrderItems]); // ===== SUBMISSION HANDLER ===== const createManagerApprovalHandler = useCallback( async (payload: CreateManagerApprovalRequestPayload) => { const purchaseRequestId = searchParams.get('purchaseId') ? parseInt(searchParams.get('purchaseId')!) : initialValues?.id || 1; if (!purchaseRequestId) { toast.error('Purchase Request ID is required'); return; } const res = await ManagerApprovalApi.createManagerApproval( purchaseRequestId, payload ); if (isResponseError(res)) { toast.error(res.message); return; } toast.success(res?.message as string); }, [initialValues?.id, searchParams] ); // ===== DELETE HANDLER ===== const deleteItemsHandler = useCallback(async () => { const purchaseRequestId = searchParams.get('purchaseId') ? parseInt(searchParams.get('purchaseId')!) : initialValues?.id || 1; if (!purchaseRequestId) { toast.error('Purchase Request ID is required'); return; } const itemIdsToDelete = selectedItem ? [selectedItem.id] : selectedRowIds; if (itemIdsToDelete.length === 0) { toast.error('Pilih minimal 1 item untuk dihapus'); return; } setIsDeleteLoading(true); try { const res = await PurchaseDeleteItemsApi.deleteItems(purchaseRequestId, { item_ids: itemIdsToDelete, }); if (isResponseError(res)) { toast.error(res.message || 'Gagal menghapus item pembelian'); return; } 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); } }, [initialValues?.id, searchParams, selectedItem, selectedRowIds]); if (!initialValues) { return null; } const purchaseData = initialValues; const purchaseOrderColumns: ColumnDef[] = [ { id: 'select', header: ({ table }) => (
), cell: ({ row }) => { return (
); }, }, { header: 'No', cell: (props) => props.row.index + 1, }, { accessorKey: 'product.name', header: 'Produk', cell: (props) => props.row.original.product?.name || '-', }, { accessorKey: 'product.product_category', header: 'Jenis Produk', cell: (props) => { const category = props.row.original.product?.product_category; if (typeof category === 'string') { return category; } return category?.name || '-'; }, }, { accessorKey: 'sub_qty', header: 'Jumlah', cell: (props) => formatNumber(props.getValue() as number), }, { accessorKey: 'product.uom.name', header: 'Satuan', cell: (props) => { const uom = props.row.original.product?.uom; if (uom && typeof uom === 'object' && uom.name) { return uom.name; } return uom || '-'; }, }, { accessorKey: 'price', header: 'Harga Satuan', cell: (props) => formatCurrency(props.getValue() as number), }, { accessorKey: 'total_price', header: 'Total (Rp.)', cell: (props) => formatCurrency(props.getValue() as number), }, { header: 'Aksi', cell: (props) => { const deleteClickHandler = () => { setSelectedItem(props.row.original); setRowSelection({}); deleteModal.openModal(); }; return ( ); }, }, ]; const goodsReceiptColumns: ColumnDef[] = [ { header: 'Header Placeholder untuk tiap Produk Penerimaan Barang', columns: [ { header: 'No', cell: (props) => props.row.index + 1, }, { accessorKey: 'received_date', header: 'Tanggal Penerimaan', cell: (props) => props.row.original.received_date ? formatDate(props.row.original.received_date, 'DD MMM YYYY') : '-', }, { accessorKey: 'warehouse.name', header: 'Gudang Tujuan', cell: (props) => { const warehouse = props.row.original.warehouse; return warehouse?.name || '-'; }, }, { accessorKey: 'travel_number', header: 'No. Surat Jalan', cell: (props) => props.row.original.travel_number || '-', }, { accessorKey: 'travel_document_path', header: 'Dokumen Surat Jalan', cell: (props) => { const documentPath = props.row.original.travel_document_path; return documentPath ? ( ) : ( '-' ); }, }, { accessorKey: 'vehicle_number', header: 'No. Armada', cell: (props) => props.row.original.vehicle_number || '-', }, { accessorKey: 'total_qty', header: 'Jumlah Total', cell: (props) => formatNumber(props.getValue() as number), }, { accessorKey: 'sub_qty', header: 'Jumlah Diterima', cell: (props) => formatNumber(props.getValue() as number), }, { accessorKey: 'price', header: 'Transport /Item', cell: (props) => formatCurrency(props.getValue() as number), }, { accessorKey: 'total_price', header: 'Transport Total', cell: (props) => formatCurrency(props.getValue() as number), }, ], }, ]; const summaryData = [ { label: 'Total Sebelum Pajak', value: totalBeforeTax, }, { label: 'Total Pembayaran', value: totalBeforeTax, }, ]; const summaryColumns: ColumnDef<(typeof summaryData)[0]>[] = [ { accessorKey: 'label', header: '', cell: (props) => ( {props.getValue() as string} ), }, { accessorKey: 'value', header: '', cell: (props) => ( {formatCurrency(props.getValue() as number)} ), }, ]; return (
{/* Approval and Action Buttons */}
{/* Steps */} {approvals && !approvalsLoading && (
)} {/* Detail Purchase Order */} {/* Order Information */}

Informasi Pesanan

{/* Kolom 1 */}
Area : {purchaseData.items?.[0]?.warehouse?.area?.name || '-'}
Lokasi :{' '} {purchaseData.items?.[0]?.warehouse?.type === 'LOKASI' && purchaseData.items?.[0]?.warehouse?.location?.name ? purchaseData.items[0].warehouse.location.name : '-'}
Gudang : {purchaseData.items?.[0]?.warehouse?.name || '-'}
{/* Kolom 2 */}
Nama Vendor : {purchaseData.supplier?.name || '-'} ( {purchaseData.supplier?.alias || ''})
Kategori Vendor : {purchaseData.supplier?.category || '-'}
Tgl. Jatuh Tempo : {formatDate(purchaseData.due_date, 'D MMM YYYY')} ( {purchaseData.credit_term} hari)
Nomor : {purchaseData.pr_number}
Nomor PO
{canUpdatePurchaseItems && purchaseData.po_number && purchaseData.po_number !== 'Belum dibuat' ? ( ) : ( <> : Belum dibuat )}
{/* Item Pembelian Section */}

Item Pembelian

{canUpdatePurchaseItems && ( )}
{/* Product Table */}
data={purchaseOrderItems} columns={purchaseOrderColumns} isLoading={false} sorting={sorting} setSorting={setSorting} rowSelection={rowSelection} setRowSelection={setRowSelection} enableRowSelection={() => true} className={{ containerClassName: 'm-0', tableWrapperClassName: 'overflow-x-auto', tableClassName: 'w-full table-auto', headerRowClassName: 'bg-gray-50 border-b border-gray-200', headerColumnClassName: 'px-6 py-4 text-sm font-semibold text-gray-700 text-left', bodyRowClassName: 'border-b border-gray-100 hover:bg-gray-50 transition-colors', bodyColumnClassName: 'px-6 py-4 text-sm text-gray-900', paginationClassName: 'hidden', }} />
{/* Bulk Action Buttons */} {selectedRowIds.length > 0 && (
)} {/* Bottom Section - Catatan dan Total */}
{/* Catatan Section */}

Catatan

{purchaseData.notes || 'Tidak ada catatan'}
{/* Summary Section */}
{/* Penerimaan Barang */} {/* Detail Penerimaan Barang Section */}

Informasi Penerimaan Barang

data={goodsReceiptItems} columns={goodsReceiptColumns} isLoading={false} className={{ containerClassName: 'm-0', tableWrapperClassName: 'overflow-x-auto', tableClassName: 'w-full table-auto', headerRowClassName: 'bg-gray-50 border-b border-gray-200', headerColumnClassName: 'px-4 py-3 text-sm font-semibold text-gray-700 text-left whitespace-nowrap', bodyRowClassName: 'border-b border-gray-100 hover:bg-gray-50 transition-colors', bodyColumnClassName: 'px-4 py-3 text-sm text-gray-900 whitespace-nowrap', paginationClassName: 'hidden', }} />
{/* Confirmation Modal with Notes */} { const payload: CreateManagerApprovalRequestPayload = { notes: notes || null, }; await createManagerApprovalHandler(payload); confirmationModalWithNotes.closeModal(); }, }} secondaryButton={{ text: 'Batal', }} /> {/* Staff Approval Modal */} {/* Accept Approval Modal */} {/* Edit Modal */} {/* Penerimaan Barang Modal */} {/* Delete Confirmation Modal */} { await deleteItemsHandler(); }, }} secondaryButton={{ text: 'Batal', }} /> ); }; export default PurchaseOrderDetail;