refactor(FE): Support MovementDocument in movement form

This commit is contained in:
rstubryan
2026-01-02 14:22:57 +07:00
parent 1c77deeee7
commit 57fa67c05a
3 changed files with 61 additions and 28 deletions
@@ -1,5 +1,5 @@
import * as Yup from 'yup'; import * as Yup from 'yup';
import { Movement } from '@/types/api/inventory/movement'; import { Movement, MovementDocument } from '@/types/api/inventory/movement';
type MovementFormSchemaType = { type MovementFormSchemaType = {
transfer_reason: string; transfer_reason: string;
@@ -29,7 +29,7 @@ type MovementFormSchemaType = {
deliveries: { deliveries: {
delivery_cost?: number | string; delivery_cost?: number | string;
delivery_cost_per_item?: number | string; delivery_cost_per_item?: number | string;
document?: File | string | null; document?: File | MovementDocument | null;
document_path?: string | null; document_path?: string | null;
driver_name: string; driver_name: string;
vehicle_plate: string; vehicle_plate: string;
@@ -61,7 +61,7 @@ export type ProductSchema = {
export type DeliverySchema = { export type DeliverySchema = {
delivery_cost?: number | string; delivery_cost?: number | string;
delivery_cost_per_item?: number | string; delivery_cost_per_item?: number | string;
document?: File | string | null; document?: File | MovementDocument | null;
document_path?: string | null; document_path?: string | null;
driver_name: string; driver_name: string;
vehicle_plate: string; vehicle_plate: string;
@@ -129,13 +129,12 @@ const DeliveryObjectSchema: Yup.ObjectSchema<DeliverySchema> = Yup.object({
}), }),
document_path: Yup.string().optional(), document_path: Yup.string().optional(),
document_index: Yup.number().optional(), document_index: Yup.number().optional(),
document: Yup.mixed<File | string>() document: Yup.mixed<File | MovementDocument>()
.nullable() .nullable()
.test('fileSize', 'Ukuran dokumen maksimal 2 MB', (value) => { .test('fileSize', 'Ukuran dokumen maksimal 2 MB', (value) => {
if (!value) return true; if (!value) return true;
if (typeof value === 'string') return true;
if (value instanceof File) return value.size <= 2 * 1024 * 1024; if (value instanceof File) return value.size <= 2 * 1024 * 1024;
return false; return true;
}), }),
driver_name: Yup.string().required('Nama sopir wajib diisi!'), driver_name: Yup.string().required('Nama sopir wajib diisi!'),
vehicle_plate: Yup.string().required('Plat nomor wajib diisi!'), vehicle_plate: Yup.string().required('Plat nomor wajib diisi!'),
@@ -241,7 +240,7 @@ export const getMovementFormInitialValues = (
delivery_cost: d.shipping_cost_total ?? undefined, delivery_cost: d.shipping_cost_total ?? undefined,
delivery_cost_per_item: d.shipping_cost_item ?? undefined, delivery_cost_per_item: d.shipping_cost_item ?? undefined,
document_number: d.document_number ?? '', document_number: d.document_number ?? '',
document: d.document_path ?? null, document: d.document ?? null,
document_path: d.document_path ?? null, document_path: d.document_path ?? null,
driver_name: d.driver_name ?? '', driver_name: d.driver_name ?? '',
vehicle_plate: d.vehicle_plate ?? '', vehicle_plate: d.vehicle_plate ?? '',
@@ -35,6 +35,7 @@ import FileInput from '@/components/input/FileInput';
import CheckboxInput from '@/components/input/CheckboxInput'; import CheckboxInput from '@/components/input/CheckboxInput';
import Badge from '@/components/Badge'; import Badge from '@/components/Badge';
import Card from '@/components/Card'; import Card from '@/components/Card';
import { S3_PUBLIC_BASE_URL } from '@/config/constant';
interface MovementFormProps { interface MovementFormProps {
type?: 'add' | 'edit' | 'detail'; type?: 'add' | 'edit' | 'detail';
@@ -1532,27 +1533,51 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
{type === 'detail' ? ( {type === 'detail' ? (
<> <>
<div className='flex flex-col items-start gap-2'> <div className='flex flex-col items-start gap-2'>
<Button {delivery.document_path ? (
color='primary' <Button
className='w-full min-w-52 flex items-center justify-center gap-2' color='primary'
disabled={!delivery.document_path} className='w-full min-w-52 flex items-center justify-center gap-2'
href={delivery.document_path ?? undefined} href={`${S3_PUBLIC_BASE_URL}/${delivery.document_path.startsWith('/') ? delivery.document_path.slice(1) : delivery.document_path}`}
target='_blank' target='_blank'
rel='noopener noreferrer' rel='noopener noreferrer'
> >
{delivery.document_path ? ( <Icon
<> icon='material-symbols:file-open-outline'
<Icon width={20}
icon='material-symbols:file-open-outline' height={20}
width={20} />
height={20} Lihat Dokumen
/> </Button>
Lihat Dokumen ) : delivery.document &&
</> delivery.document instanceof File === false ? (
) : ( <Button
'-' color='primary'
)} className='w-full min-w-52 flex items-center justify-center gap-2'
</Button> href={`${S3_PUBLIC_BASE_URL}/${delivery.document.path.startsWith('/') ? delivery.document.path.slice(1) : delivery.document.path}`}
target='_blank'
rel='noopener noreferrer'
>
<Icon
icon='material-symbols:file-open-outline'
width={20}
height={20}
/>
{delivery.document.name}
</Button>
) : (
<Button
color='neutral'
className='w-full min-w-52 flex items-center justify-center gap-2 cursor-not-allowed'
disabled
>
<Icon
icon='material-symbols:description'
width={20}
height={20}
/>
Tidak ada dokumen
</Button>
)}
</div> </div>
</> </>
) : ( ) : (
+9
View File
@@ -14,6 +14,14 @@ type MovementWarehouse = {
}; };
}; };
export type MovementDocument = {
id: number;
path: string;
name: string;
ext: string;
size: number;
};
export type BaseMovement = { export type BaseMovement = {
id: number; id: number;
transfer_reason: string; transfer_reason: string;
@@ -39,6 +47,7 @@ export type BaseMovement = {
document_path: string; document_path: string;
shipping_cost_item: number; shipping_cost_item: number;
shipping_cost_total: number; shipping_cost_total: number;
document?: MovementDocument;
items: { items: {
id: number; id: number;
stock_transfer_detail_id: number; stock_transfer_detail_id: number;