'use client'; import { useState } from 'react'; import toast from 'react-hot-toast'; import { useRouter } from 'next/navigation'; import { useFormik } from 'formik'; import Link from 'next/link'; import { Icon } from '@iconify/react'; import Button from '@/components/Button'; import { useModal } from '@/components/Modal'; import ConfirmationModal from '@/components/modal/ConfirmationModal'; import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes'; import RealizationStatusBadge from '@/components/pages/expense/RealizationStatusBadge'; import ExpenseStatusBadge from '@/components/pages/expense/ExpenseStatusBadge'; import DropFileInput from '@/components/input/DropFileInput'; import { Expense } from '@/types/api/expense'; import { formatCurrency, formatDate } from '@/lib/helper'; import { ExpenseApi } from '@/services/api/expense'; import { isResponseSuccess } from '@/lib/api-helper'; import { ACCEPTED_FILE_TYPE } from '@/config/constant'; import { UploadRequestDocumentsFormSchema, UploadRequestDocumentsFormValues, } from '@/components/pages/expense/form/ExpenseRequestForm.schema'; interface ExpenseDetailProps { initialValues?: Expense; } const ExpenseDetail: React.FC = ({ initialValues }) => { const router = useRouter(); // Modal hooks const deleteModal = useModal(); const approveModal = useModal(); const rejectModal = useModal(); // Modal loading state const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [isApproveLoading, setIsApproveLoading] = useState(false); const [isRejectLoading, setIsRejectLoading] = useState(false); const isLatestApprovalRejectedOrDone = initialValues?.approval && (initialValues.approval.action === 'REJECTED' || initialValues.approval.step_number === 5); const formik = useFormik({ initialValues: { request_documents: [], }, validationSchema: UploadRequestDocumentsFormSchema, onSubmit: async (values) => { const addRequestDocumentsRes = await ExpenseApi.uploadRequestDocuments( initialValues?.id as number, values.request_documents ); if (isResponseSuccess(addRequestDocumentsRes)) { toast.success(addRequestDocumentsRes.message); window.location.reload(); } else { toast.error(String(addRequestDocumentsRes?.message)); } }, }); const deleteExpenseClickHandler = () => { deleteModal.openModal(); }; const approveClickHandler = () => { approveModal.openModal(); }; const rejectClickHandler = () => { rejectModal.openModal(); }; // Modal confirm click handler const confirmationModalDeleteClickHandler = async () => { setIsDeleteLoading(true); try { await ExpenseApi.delete(initialValues?.id as number); toast.success('Berhasil menghapus data biaya operasional!'); router.push('/expense'); } catch (error) { toast.error('Gagal menghapus data biaya operasional!'); } finally { deleteModal.closeModal(); setIsDeleteLoading(false); } }; const confirmationModalApproveClickHandler = async (notes: string) => { setIsApproveLoading(true); const approveResponse = await ExpenseApi.approve( initialValues?.id as number, notes ); if (isResponseSuccess(approveResponse)) { approveModal.closeModal(); toast.success('Berhasil approve pengajuan biaya operasional!'); router.push('/expense'); } else { approveModal.closeModal(); toast.error('Gagal approve pengajuan biaya operasional!'); } setIsApproveLoading(false); }; const confirmationModalRejectClickHandler = async (notes: string) => { setIsRejectLoading(true); const rejectResponse = await ExpenseApi.reject( initialValues?.id as number, notes ); if (isResponseSuccess(rejectResponse)) { rejectModal.closeModal(); toast.success('Berhasil reject pengajuan biaya operasional!'); router.push('/expense'); } else { rejectModal.closeModal(); toast.error('Gagal reject pengajuan biaya operasional!'); } setIsRejectLoading(false); }; const requestDocumentsChangeHandler = (val: File[]) => { formik.setFieldTouched('request_documents', true); formik.setFieldValue('request_documents', val); }; const requestDocumentsDeleteHandler = (deletedFileIdx: number) => { const newRequestDocuments = formik.values.request_documents; newRequestDocuments?.splice(deletedFileIdx, 1); formik.setFieldValue('request_documents', newRequestDocuments); }; return ( <>

Detail Biaya Operasional

{/* TODO: apply RBAC */} {!isLatestApprovalRejectedOrDone && (
)} {/* TODO: add and integrate ApprovalSteps component with API */}
Nomor PO : {initialValues?.po_number ?? '-'}
Nomor Referensi : {initialValues?.reference_number}
Lokasi : {initialValues?.location.name}
Kandang : {initialValues?.kandangs .map((item) => item.name) .join(', ')}
Vendor : {initialValues?.vendor.name}
Tanggal Transaksi : {formatDate( initialValues?.transaction_date, 'DD MMMM YYYY' )}
Tanggal Realisasi : {initialValues?.realization_date ? formatDate( initialValues?.realization_date, 'DD MMMM YYYY' ) : '-'}
Nama Pengaju : {initialValues?.created_user.name}
Nominal Biaya : {formatCurrency(initialValues?.nominal ?? 0)}
Nominal Sudah Bayar : {formatCurrency(initialValues?.paid ?? 0)}
Nominal Sisa Bayar : {formatCurrency(initialValues?.remaining_cost ?? 0)}
Status Pencairan :
Status Biaya :
Dokumen Pengajuan :
{initialValues?.request_documents.length === 0 && '-'} {initialValues?.request_documents && initialValues?.request_documents.length > 0 && (
    {initialValues?.request_documents.map( (requestDocument, requestDocumentIdx) => (
  • {requestDocument.name}{' '}
  • ) )}
)}
{formik.values.request_documents && formik.values.request_documents.length > 0 && ( )}

Rincian Pengajuan Biaya Operasional

{initialValues?.kandang_expenses.map( (kandangExpense, kandangExpenseIdx) => { let expenseGrandTotal = 0; kandangExpense.expenses.forEach( (item) => (expenseGrandTotal += item.total_expense) ); return (
{kandangExpense.expenses.map( (expenseItem, expenseIdx) => ( ) )}
Biaya {kandangExpense.kandang.name}
Nonstock Total Kuantitas Total Biaya Catatan
{expenseItem.nonstock.name} {expenseItem.total_quantity} {formatCurrency(expenseItem.total_expense)} {expenseItem.notes ?? '-'}
Total Biaya Keseluruhan: {formatCurrency(expenseGrandTotal)}
); } )}
); }; export default ExpenseDetail;