diff --git a/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx b/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx index 15106c5e..d6ef5952 100644 --- a/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx +++ b/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx @@ -8,6 +8,7 @@ import { useSearchParams } from 'next/navigation'; import Button from '@/components/Button'; import TextInput from '@/components/input/TextInput'; import NumberInput from '@/components/input/NumberInput'; +import FileInput from '@/components/input/FileInput'; import SelectInput, { OptionType, useSelect, @@ -66,6 +67,7 @@ const PurchaseOrderAcceptApprovalForm = ({ | 'expedition_vendor_id' | 'received_qty' | 'transport_per_item' + | 'travel_documents' ): { isError: boolean; errorMessage: string } => { const touchedItem = formik.touched.items?.[idx]; const errorItem = formik.errors.items?.[idx] as @@ -185,6 +187,7 @@ const PurchaseOrderAcceptApprovalForm = ({ : formItem.transport_per_item || 0, }; }) || [], + travel_documents: values.travel_documents || [], }; switch (type) { @@ -236,15 +239,29 @@ const PurchaseOrderAcceptApprovalForm = ({ travel_document_path: item.travel_document_path || '', vehicle_number: item.vehicle_number || '', expedition_vendor: null, - expedition_vendor_id: 0, + expedition_vendor_id: item.expedition_vendor_id || 0, received_qty: item.total_qty || '', - transport_per_item: '', + transport_per_item: item.transport_per_item || '', }; }); formik.setFieldValue('items', updatedItems); } }, [purchaseItems, initialValues]); + useEffect(() => { + if ( + formik.values.travel_documents && + formik.values.travel_documents.length > 0 + ) { + const fileNames = formik.values.travel_documents + .map((file) => file.name) + .join(', '); + formik.values.items?.forEach((item, idx) => { + formik.setFieldValue(`items.${idx}.travel_document_path`, fileNames); + }); + } + }, [formik.values.travel_documents]); + // ===== HELPER FUNCTIONS ===== const getQuantityExceededError = useCallback( (idx: number, receivedQty: number) => { @@ -343,7 +360,7 @@ const PurchaseOrderAcceptApprovalForm = ({ No. Surat Jalan * - + Dokumen Surat Jalan * @@ -478,7 +495,7 @@ const PurchaseOrderAcceptApprovalForm = ({ }} /> - + -
+
+
+ { + const files = Array.from(e.target.files || []); + formik.setFieldValue('travel_documents', files); + }} + onBlur={formik.handleBlur} + bottomLabel={ + formik.values.travel_documents && + formik.values.travel_documents.length > 0 + ? `${formik.values.travel_documents.length} file(s) dipilih` + : undefined + } + isError={ + formik.touched.travel_documents && + Boolean(formik.errors.travel_documents) + } + errorMessage={formik.errors.travel_documents as string} + /> +
+ {/* Action buttons */}
diff --git a/src/components/pages/purchase/form/order/PurchaseOrderForm.schema.ts b/src/components/pages/purchase/form/order/PurchaseOrderForm.schema.ts index c7da956d..bb70053f 100644 --- a/src/components/pages/purchase/form/order/PurchaseOrderForm.schema.ts +++ b/src/components/pages/purchase/form/order/PurchaseOrderForm.schema.ts @@ -48,6 +48,7 @@ type PurchaseRequestAcceptApprovalFormSchemaType = { received_qty: number | string; transport_per_item: number | string; }[]; + travel_documents: File[]; }; export type PurchaseStaffApprovalItemSchema = { @@ -379,6 +380,11 @@ export const PurchaseRequestAcceptApprovalFormSchema: Yup.ObjectSchema().required()) + .required('Dokumen surat jalan wajib diupload!') + .min(1, 'Minimal upload 1 dokumen surat jalan!') + .typeError('Dokumen surat jalan wajib diupload!'), }); export const PurchaseRequestAcceptApprovalFormInitialValues: PurchaseRequestAcceptApprovalFormSchemaType = @@ -397,6 +403,7 @@ export const PurchaseRequestAcceptApprovalFormInitialValues: PurchaseRequestAcce transport_per_item: '', }, ], + travel_documents: [], }; export const PurchaseRequestAcceptApprovalFormDefaultValues = ( @@ -428,6 +435,7 @@ export const PurchaseRequestAcceptApprovalFormDefaultValues = ( transport_per_item: '', }, ], + travel_documents: [], }; }; diff --git a/src/services/api/purchase.ts b/src/services/api/purchase.ts index d0438e88..38ace6be 100644 --- a/src/services/api/purchase.ts +++ b/src/services/api/purchase.ts @@ -72,11 +72,29 @@ export const PurchaseApi = { purchaseRequestId: number, payload: CreateAcceptApprovalRequestPayload ): Promise | undefined> => { + const formData = new FormData(); + + formData.append('action', payload.action); + + if (payload.notes) { + formData.append('notes', payload.notes); + } + + if (payload.items) { + formData.append('items', JSON.stringify(payload.items)); + } + + if (payload.travel_documents) { + payload.travel_documents.forEach((file) => { + formData.append('travel_documents', file); + }); + } + return await basePurchaseApi.customRequest< BaseApiResponse<{ message: string }> >(`${purchaseRequestId}/receipts`, { method: 'POST', - payload, + payload: formData as unknown as Record, }); }, }, diff --git a/src/types/api/purchase/purchase.d.ts b/src/types/api/purchase/purchase.d.ts index e4de565b..7b698b74 100644 --- a/src/types/api/purchase/purchase.d.ts +++ b/src/types/api/purchase/purchase.d.ts @@ -118,6 +118,7 @@ export type CreateAcceptApprovalRequestPayload = { received_qty: number; transport_per_item: number; }[]; + travel_documents?: File[]; }; export type DeletePurchaseRequestItemPayload = {