mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-24 15:25:46 +00:00
refactor(FE-Storyless): remove UpdateMovementPayload type and related schema, streamline MovementForm handling
This commit is contained in:
@@ -133,8 +133,6 @@ export const MovementFormSchema = Yup.object({
|
|||||||
.required('Pengiriman wajib diisi!'),
|
.required('Pengiriman wajib diisi!'),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const UpdateMovementFormSchema = MovementFormSchema;
|
|
||||||
|
|
||||||
export type MovementFormValues = Yup.InferType<typeof MovementFormSchema>;
|
export type MovementFormValues = Yup.InferType<typeof MovementFormSchema>;
|
||||||
|
|
||||||
export const getMovementFormInitialValues = (
|
export const getMovementFormInitialValues = (
|
||||||
|
|||||||
@@ -13,19 +13,19 @@ import {
|
|||||||
CreateMovementPayload,
|
CreateMovementPayload,
|
||||||
Movement,
|
Movement,
|
||||||
} from '@/types/api/inventory/movement';
|
} from '@/types/api/inventory/movement';
|
||||||
import { isResponseSuccess } from '@/lib/api-helper';
|
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
import {
|
import {
|
||||||
MovementFormSchema,
|
MovementFormSchema,
|
||||||
MovementFormValues,
|
MovementFormValues,
|
||||||
UpdateMovementFormSchema,
|
|
||||||
getMovementFormInitialValues,
|
getMovementFormInitialValues,
|
||||||
ProductSchema,
|
ProductSchema,
|
||||||
DeliverySchema,
|
DeliverySchema,
|
||||||
} from '@/components/pages/inventory/movement/form/MovementForm.schema';
|
} from '@/components/pages/inventory/movement/form/MovementForm.schema';
|
||||||
import { useMovementFormHandlers } from './useMovementFormHandlers';
|
|
||||||
import { SupplierApi, WarehouseApi } from '@/services/api/master-data';
|
import { SupplierApi, WarehouseApi } from '@/services/api/master-data';
|
||||||
import { ProductWarehouseApi } from '@/services/api/inventory';
|
import { ProductWarehouseApi } from '@/services/api/inventory';
|
||||||
import { toast } from 'react-hot-toast';
|
import { toast } from 'react-hot-toast';
|
||||||
|
import { MovementApi } from '@/services/api/inventory';
|
||||||
import FileInput from '@/components/input/FileInput';
|
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';
|
||||||
@@ -36,8 +36,10 @@ interface MovementFormProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
// ===== STATE MANAGEMENT =====
|
// ===== STATE MANAGEMENT =====
|
||||||
const [, setMovementFormErrorMessage] = useState('');
|
const [movementFormErrorMessage, setMovementFormErrorMessage] = useState('');
|
||||||
const [
|
const [
|
||||||
productWarehouseSelectInputValue,
|
productWarehouseSelectInputValue,
|
||||||
setProductWarehouseSelectInputValue,
|
setProductWarehouseSelectInputValue,
|
||||||
@@ -49,11 +51,26 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
|||||||
const [supplierSelectInputValue, setSupplierSelectInputValue] = useState('');
|
const [supplierSelectInputValue, setSupplierSelectInputValue] = useState('');
|
||||||
|
|
||||||
// ===== FORM HANDLERS =====
|
// ===== FORM HANDLERS =====
|
||||||
const {
|
const createMovementHandler = useCallback(
|
||||||
movementFormErrorMessage,
|
async (payload: CreateMovementPayload, documents: File[] = []) => {
|
||||||
createMovementHandler,
|
const formData = new FormData();
|
||||||
updateMovementHandler,
|
formData.append('data', JSON.stringify(payload));
|
||||||
} = useMovementFormHandlers(initialValues?.id);
|
documents.forEach((file, index) => {
|
||||||
|
formData.append(`documents[${index}]`, file);
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await MovementApi.create(
|
||||||
|
formData as unknown as CreateMovementPayload
|
||||||
|
);
|
||||||
|
if (isResponseError(res)) {
|
||||||
|
setMovementFormErrorMessage(res.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toast.success(res?.message as string);
|
||||||
|
router.push('/inventory/movement');
|
||||||
|
},
|
||||||
|
[router]
|
||||||
|
);
|
||||||
|
|
||||||
// ===== INTERFACES =====
|
// ===== INTERFACES =====
|
||||||
interface WarehouseOptionType extends OptionType {
|
interface WarehouseOptionType extends OptionType {
|
||||||
@@ -139,8 +156,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
|||||||
|
|
||||||
const formik = useFormik<MovementFormValues>({
|
const formik = useFormik<MovementFormValues>({
|
||||||
initialValues: formikInitialValues,
|
initialValues: formikInitialValues,
|
||||||
validationSchema:
|
validationSchema: MovementFormSchema,
|
||||||
type === 'edit' ? UpdateMovementFormSchema : MovementFormSchema,
|
|
||||||
validateOnChange: true,
|
validateOnChange: true,
|
||||||
validateOnBlur: true,
|
validateOnBlur: true,
|
||||||
validateOnMount: false,
|
validateOnMount: false,
|
||||||
@@ -148,7 +164,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
|||||||
onSubmit: async (values) => {
|
onSubmit: async (values) => {
|
||||||
setMovementFormErrorMessage('');
|
setMovementFormErrorMessage('');
|
||||||
const documents: File[] = [];
|
const documents: File[] = [];
|
||||||
const deliveriesPayload = values.deliveries.map((d, idx) => {
|
const deliveriesPayload = values.deliveries.map((d) => {
|
||||||
let documentIndex = 0;
|
let documentIndex = 0;
|
||||||
|
|
||||||
if (d.document && d.document instanceof File) {
|
if (d.document && d.document instanceof File) {
|
||||||
@@ -187,13 +203,6 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
|||||||
case 'add':
|
case 'add':
|
||||||
await createMovementHandler(payload, documents);
|
await createMovementHandler(payload, documents);
|
||||||
break;
|
break;
|
||||||
case 'edit':
|
|
||||||
await updateMovementHandler(
|
|
||||||
initialValues?.id as number,
|
|
||||||
payload,
|
|
||||||
documents
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -1591,49 +1600,9 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
|||||||
|
|
||||||
{/* Action buttons */}
|
{/* Action buttons */}
|
||||||
<div className='flex flex-row justify-between gap-2 flex-wrap'>
|
<div className='flex flex-row justify-between gap-2 flex-wrap'>
|
||||||
{type !== 'add' && (
|
|
||||||
<div className='flex flex-row justify-start gap-2'>
|
|
||||||
<Button
|
|
||||||
type='button'
|
|
||||||
color='error'
|
|
||||||
onClick={() => console.log('Delete clicked')}
|
|
||||||
className='px-4'
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
icon='material-symbols:delete-outline-rounded'
|
|
||||||
width={24}
|
|
||||||
height={24}
|
|
||||||
className='justify-start text-sm'
|
|
||||||
/>
|
|
||||||
Delete
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
{type !== 'edit' && (
|
|
||||||
<Button
|
|
||||||
type='button'
|
|
||||||
color='warning'
|
|
||||||
href={`/inventory/movement/detail/edit/?movementId=${initialValues?.id}`}
|
|
||||||
className='px-4'
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
icon='material-symbols:edit-outline'
|
|
||||||
width={24}
|
|
||||||
height={24}
|
|
||||||
className='justify-start text-sm'
|
|
||||||
/>
|
|
||||||
Edit
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{type !== 'detail' && (
|
{type !== 'detail' && (
|
||||||
<div className='flex flex-row justify-end gap-2 w-full'>
|
<div className='flex flex-row justify-end gap-2 w-full'>
|
||||||
<Button
|
<Button type='reset' color='warning' className='px-4'>
|
||||||
type='reset'
|
|
||||||
color='warning'
|
|
||||||
className='px-4'
|
|
||||||
>
|
|
||||||
Reset
|
Reset
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
@@ -1642,7 +1611,12 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
|||||||
color='primary'
|
color='primary'
|
||||||
className='px-4'
|
className='px-4'
|
||||||
isLoading={formik.isSubmitting}
|
isLoading={formik.isSubmitting}
|
||||||
disabled={hasInvalidQty || hasExceededStock || !formik.isValid || formik.isSubmitting}
|
disabled={
|
||||||
|
hasInvalidQty ||
|
||||||
|
hasExceededStock ||
|
||||||
|
!formik.isValid ||
|
||||||
|
formik.isSubmitting
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
import { useCallback, useState } from 'react';
|
|
||||||
import { useRouter } from 'next/navigation';
|
|
||||||
import { toast } from 'react-hot-toast';
|
|
||||||
import { useModal } from '@/components/Modal';
|
|
||||||
import { MovementApi } from '@/services/api/inventory';
|
|
||||||
import {
|
|
||||||
CreateMovementPayload,
|
|
||||||
UpdateMovementPayload,
|
|
||||||
} from '@/types/api/inventory/movement';
|
|
||||||
import { isResponseError } from '@/lib/api-helper';
|
|
||||||
|
|
||||||
export const useMovementFormHandlers = (initialValuesId?: number) => {
|
|
||||||
const router = useRouter();
|
|
||||||
const deleteModal = useModal();
|
|
||||||
const [movementFormErrorMessage, setMovementFormErrorMessage] = useState('');
|
|
||||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
|
||||||
|
|
||||||
const createMovementHandler = useCallback(
|
|
||||||
async (payload: CreateMovementPayload, documents: File[] = []) => {
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('data', JSON.stringify(payload));
|
|
||||||
documents.forEach((file, index) => {
|
|
||||||
formData.append(`documents[${index}]`, file);
|
|
||||||
});
|
|
||||||
|
|
||||||
const res = await MovementApi.create(
|
|
||||||
formData as unknown as CreateMovementPayload
|
|
||||||
);
|
|
||||||
if (isResponseError(res)) {
|
|
||||||
setMovementFormErrorMessage(res.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
toast.success(res?.message as string);
|
|
||||||
router.push('/inventory/movement');
|
|
||||||
},
|
|
||||||
[router]
|
|
||||||
);
|
|
||||||
|
|
||||||
const updateMovementHandler = useCallback(
|
|
||||||
async (
|
|
||||||
movementId: number,
|
|
||||||
payload: UpdateMovementPayload,
|
|
||||||
documents: File[] = []
|
|
||||||
) => {
|
|
||||||
let finalPayload: UpdateMovementPayload | FormData;
|
|
||||||
|
|
||||||
if (documents.length > 0) {
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('data', JSON.stringify(payload));
|
|
||||||
documents.forEach((file, index) => {
|
|
||||||
formData.append(`documents[${index}]`, file);
|
|
||||||
});
|
|
||||||
|
|
||||||
finalPayload = formData as unknown as UpdateMovementPayload;
|
|
||||||
} else {
|
|
||||||
finalPayload = payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await MovementApi.update(movementId, finalPayload);
|
|
||||||
if (res?.status === 'error') {
|
|
||||||
setMovementFormErrorMessage(res.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
toast.success(res?.message as string);
|
|
||||||
router.refresh();
|
|
||||||
router.push('/inventory/movement');
|
|
||||||
},
|
|
||||||
[router]
|
|
||||||
);
|
|
||||||
|
|
||||||
const deleteMovementClickHandler = useCallback(() => {
|
|
||||||
deleteModal.openModal();
|
|
||||||
}, [deleteModal]);
|
|
||||||
|
|
||||||
const confirmationModalDeleteClickHandler = useCallback(async () => {
|
|
||||||
if (!initialValuesId) return;
|
|
||||||
|
|
||||||
setIsDeleteLoading(true);
|
|
||||||
await MovementApi.delete(initialValuesId);
|
|
||||||
deleteModal.closeModal();
|
|
||||||
toast.success('Successfully delete Movement!');
|
|
||||||
setIsDeleteLoading(false);
|
|
||||||
router.push('/inventory/movement');
|
|
||||||
}, [deleteModal, initialValuesId, router]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
deleteModal,
|
|
||||||
movementFormErrorMessage,
|
|
||||||
isDeleteLoading,
|
|
||||||
createMovementHandler,
|
|
||||||
updateMovementHandler,
|
|
||||||
deleteMovementClickHandler,
|
|
||||||
confirmationModalDeleteClickHandler,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
import {
|
import {
|
||||||
CreateMovementPayload,
|
CreateMovementPayload,
|
||||||
Movement,
|
Movement,
|
||||||
UpdateMovementPayload,
|
|
||||||
} from '@/types/api/inventory/movement';
|
} from '@/types/api/inventory/movement';
|
||||||
import {
|
import {
|
||||||
CreateInventoryAdjustmentPayload,
|
CreateInventoryAdjustmentPayload,
|
||||||
@@ -23,7 +22,7 @@ export const ProductWarehouseApi = new BaseApiService<
|
|||||||
export const MovementApi = new BaseApiService<
|
export const MovementApi = new BaseApiService<
|
||||||
Movement,
|
Movement,
|
||||||
CreateMovementPayload,
|
CreateMovementPayload,
|
||||||
UpdateMovementPayload
|
unknown
|
||||||
>('/inventory/transfers');
|
>('/inventory/transfers');
|
||||||
|
|
||||||
export const inventoryAdjustmentApi = new BaseApiService<
|
export const inventoryAdjustmentApi = new BaseApiService<
|
||||||
|
|||||||
-2
@@ -71,5 +71,3 @@ export type CreateMovementPayload = {
|
|||||||
}[];
|
}[];
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UpdateMovementPayload = CreateMovementPayload;
|
|
||||||
|
|||||||
Reference in New Issue
Block a user