mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
feat(FE): Add travel document upload to purchase form
This commit is contained in:
@@ -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
|
||||
<span className='text-error'>*</span>
|
||||
</th>
|
||||
<th>
|
||||
<th className='hidden'>
|
||||
Dokumen Surat Jalan
|
||||
<span className='text-error'>*</span>
|
||||
</th>
|
||||
@@ -478,7 +495,7 @@ const PurchaseOrderAcceptApprovalForm = ({
|
||||
}}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<td className='hidden'>
|
||||
<TextInput
|
||||
required
|
||||
name={`items.${idx}.travel_document_path`}
|
||||
@@ -636,7 +653,7 @@ const PurchaseOrderAcceptApprovalForm = ({
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className={'col-span-2'}>
|
||||
<div className={'col-span-2 my-2'}>
|
||||
<TextInput
|
||||
label='Notes'
|
||||
name='notes'
|
||||
@@ -649,6 +666,31 @@ const PurchaseOrderAcceptApprovalForm = ({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={'col-span-2 my-2'}>
|
||||
<FileInput
|
||||
required
|
||||
name='travel_documents'
|
||||
label='Dokumen Surat Jalan'
|
||||
accept='.pdf,.jpg,.jpeg,.png'
|
||||
onChange={(e) => {
|
||||
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}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Action buttons */}
|
||||
<div className='flex flex-row justify-between gap-2 flex-wrap mt-5'>
|
||||
<div className='flex flex-row justify-end gap-2 w-full'>
|
||||
|
||||
@@ -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<PurchaseR
|
||||
.min(1, 'Minimal harus ada 1 item pembelian!')
|
||||
.required('Item pembelian wajib diisi!')
|
||||
.typeError('Item pembelian wajib diisi!'),
|
||||
travel_documents: Yup.array()
|
||||
.of(Yup.mixed<File>().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: [],
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -72,11 +72,29 @@ export const PurchaseApi = {
|
||||
purchaseRequestId: number,
|
||||
payload: CreateAcceptApprovalRequestPayload
|
||||
): Promise<BaseApiResponse<{ message: string }> | 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<string, unknown>,
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
Vendored
+1
@@ -118,6 +118,7 @@ export type CreateAcceptApprovalRequestPayload = {
|
||||
received_qty: number;
|
||||
transport_per_item: number;
|
||||
}[];
|
||||
travel_documents?: File[];
|
||||
};
|
||||
|
||||
export type DeletePurchaseRequestItemPayload = {
|
||||
|
||||
Reference in New Issue
Block a user