refactor(FE-62,63,65): refactor Movement and ProductWarehouse APIs, update MovementForm schema, and enhance MovementTable functionality

This commit is contained in:
rstubryan
2025-10-16 14:33:49 +07:00
parent aa21088e99
commit c6a0c542aa
7 changed files with 277 additions and 556 deletions
@@ -13,7 +13,7 @@ export type ProductSchema = {
export type DeliverySchema = {
delivery_cost: number;
delivery_cost_per_item?: number | undefined;
document: string | File;
document?: File | string | null;
driver_name: string;
vehicle_plate: string;
supplier: {
@@ -64,23 +64,15 @@ const DeliveryObjectSchema: Yup.ObjectSchema<DeliverySchema> = Yup.object({
.transform((value) => (isNaN(value) ? undefined : value))
.min(0, 'Biaya per item minimal 0!')
.typeError('Biaya per item harus berupa angka!'),
document: Yup.mixed<string | File>()
.required('Dokumen wajib diisi!')
.test(
'fileType',
'Mohon upload file berformat PDF atau JPEG/JPG.',
(value) =>
typeof value === 'string' ||
(value instanceof File &&
['application/pdf', 'image/jpeg', 'image/jpg'].includes(value.type))
)
.test(
'fileSize',
'Ukuran dokumen maksimal 2 MB!',
(value) =>
typeof value === 'string' ||
(value instanceof File && value.size <= 2 * 1024 * 1024)
),
document_index: Yup.number().optional(),
document: Yup.mixed<File | string>()
.nullable()
.test('fileSize', 'Ukuran dokumen maksimal 2 MB', (value) => {
if (!value) return true;
if (typeof value === 'string') return true;
if (value instanceof File) return value.size <= 2 * 1024 * 1024;
return false;
}),
driver_name: Yup.string().required('Nama sopir wajib diisi!'),
vehicle_plate: Yup.string().required('Plat nomor wajib diisi!'),
supplier: Yup.object({
@@ -145,24 +137,25 @@ export const getMovementFormInitialValues = (
: null,
destination_warehouse_id: initialValues?.destination_warehouse?.id ?? 0,
products:
initialValues?.products?.map((p) => ({
product: { value: p.product.id, label: p.product.name },
product_id: p.product.id,
product_qty: p.product_qty,
initialValues?.details?.map((p) => ({
product: { value: p.product_id, label: '' },
product_id: p.product_id,
product_qty: p.quantity,
})) ?? [],
deliveries:
initialValues?.deliveries?.map((d) => ({
delivery_cost: d.delivery_cost,
delivery_cost_per_item: d.delivery_cost_per_item,
document: d.document,
delivery_cost: d.shipping_cost_total,
delivery_cost_per_item: d.shipping_cost_item,
document_index: 0,
document: d.document_path || null,
driver_name: d.driver_name,
vehicle_plate: d.vehicle_plate,
supplier: { value: d.supplier.id, label: d.supplier.name },
supplier_id: d.supplier.id,
products: d.products.map((p) => ({
product: { value: p.product.id, label: p.product.name },
product_id: p.product.id,
product_qty: p.product_qty,
supplier_id: d.supplier_id,
products: d.items.map((p) => ({
product: { value: 0, label: '' },
product_id: 0,
product_qty: p.quantity,
})),
})) ?? [],
});
@@ -8,7 +8,6 @@ import {
UpdateMovementPayload,
} from '@/types/api/inventory/movement';
import { isResponseError } from '@/lib/api-helper';
import { containsFile, toFormData } from '@/lib/form-data';
export const useMovementFormHandlers = (initialValuesId?: number) => {
const router = useRouter();
@@ -17,13 +16,44 @@ export const useMovementFormHandlers = (initialValuesId?: number) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const createMovementHandler = useCallback(
async (payload: CreateMovementPayload) => {
const finalPayload = containsFile(payload)
? (toFormData(payload) as unknown as CreateMovementPayload)
: payload;
async (payload: CreateMovementPayload, documents: File[] = []) => {
console.log('=== CREATE HANDLER DEBUG ===');
console.log('1. Received payload:', payload);
console.log('2. Documents count:', documents.length);
let finalPayload: CreateMovementPayload | FormData;
if (documents.length > 0) {
// Ada dokumen: kirim sebagai FormData dengan "data" field
console.log('3. Creating FormData (has documents)');
const formData = new FormData();
formData.append('data', JSON.stringify(payload));
documents.forEach((file, index) => {
formData.append(`documents[${index}]`, file);
});
console.log('4. FormData entries:');
for (const [key, value] of formData.entries()) {
if (value instanceof File) {
console.log(` ${key}: [File] ${value.name} (${value.size} bytes)`);
} else {
console.log(` ${key}: ${value}`);
}
}
finalPayload = formData as unknown as CreateMovementPayload;
} else {
// Tidak ada dokumen: kirim sebagai JSON biasa
console.log('3. Sending as JSON (no documents)');
console.log('4. Payload:', JSON.stringify(payload, null, 2));
finalPayload = payload;
}
console.log('=== END CREATE HANDLER DEBUG ===');
const res = await MovementApi.create(finalPayload);
if (isResponseError(res)) {
console.error('API Error:', res);
setMovementFormErrorMessage(res.message);
return;
}
@@ -34,13 +64,45 @@ export const useMovementFormHandlers = (initialValuesId?: number) => {
);
const updateMovementHandler = useCallback(
async (movementId: number, payload: UpdateMovementPayload) => {
const finalPayload = containsFile(payload)
? (toFormData(payload) as unknown as UpdateMovementPayload)
: payload;
async (movementId: number, payload: UpdateMovementPayload, documents: File[] = []) => {
console.log('=== UPDATE HANDLER DEBUG ===');
console.log('1. Received payload:', payload);
console.log('2. Movement ID:', movementId);
console.log('3. Documents count:', documents.length);
let finalPayload: UpdateMovementPayload | FormData;
if (documents.length > 0) {
// Ada dokumen: kirim sebagai FormData dengan "data" field
console.log('4. Creating FormData (has documents)');
const formData = new FormData();
formData.append('data', JSON.stringify(payload));
documents.forEach((file, index) => {
formData.append(`documents[${index}]`, file);
});
console.log('5. FormData entries:');
for (const [key, value] of formData.entries()) {
if (value instanceof File) {
console.log(` ${key}: [File] ${value.name} (${value.size} bytes)`);
} else {
console.log(` ${key}: ${value}`);
}
}
finalPayload = formData as unknown as UpdateMovementPayload;
} else {
// Tidak ada dokumen: kirim sebagai JSON biasa
console.log('4. Sending as JSON (no documents)');
console.log('5. Payload:', JSON.stringify(payload, null, 2));
finalPayload = payload;
}
console.log('=== END UPDATE HANDLER DEBUG ===');
const res = await MovementApi.update(movementId, finalPayload);
if (res?.status === 'error') {
console.error('API Error:', res);
setMovementFormErrorMessage(res.message);
return;
}