From d9fa685ae627dd29632dc23d0bcd27400136702a Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Tue, 21 Oct 2025 15:08:11 +0700 Subject: [PATCH] feat(FE-113): create Transfer to Laying Create Form --- .../form/TransferToLayingForm.tsx | 562 ++++++++++++++++++ 1 file changed, 562 insertions(+) create mode 100644 src/components/pages/production/transfer-to-laying/form/TransferToLayingForm.tsx diff --git a/src/components/pages/production/transfer-to-laying/form/TransferToLayingForm.tsx b/src/components/pages/production/transfer-to-laying/form/TransferToLayingForm.tsx new file mode 100644 index 00000000..c4428a72 --- /dev/null +++ b/src/components/pages/production/transfer-to-laying/form/TransferToLayingForm.tsx @@ -0,0 +1,562 @@ +'use client'; + +import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useRouter } from 'next/navigation'; +import { useFormik } from 'formik'; +import { toast } from 'react-hot-toast'; +import useSWR from 'swr'; + +import { Icon } from '@iconify/react'; +import Button from '@/components/Button'; +import TextInput from '@/components/input/TextInput'; +import SelectInput, { + OptionType, + // useSelect, +} from '@/components/input/SelectInput'; +import TextArea from '@/components/input/TextArea'; +import { useModal } from '@/components/Modal'; +import ConfirmationModal from '@/components/modal/ConfirmationModal'; + +import { + TransferToLayingFormSchema, + TransferToLayingFormValues, + UpdateTransferToLayingFormSchema, +} from '@/components/pages/production/transfer-to-laying/form/TransferToLayingForm.schema'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; +import { + TransferToLaying, + CreateTransferToLayingPayload, + UpdateTransferToLayingPayload, +} from '@/types/api/production/transfer-to-laying'; +import { cn } from '@/lib/helper'; + +import { TransferToLayingApi } from '@/services/api/production/transfer-to-laying'; + +interface TransferToLayingFormProps { + type?: 'add' | 'edit' | 'detail'; + initialValues?: TransferToLaying; +} + +const TransferToLayingForm = ({ + type = 'add', + initialValues, +}: TransferToLayingFormProps) => { + const router = useRouter(); + const deleteModal = useModal(); + + const [formErrorMessage, setFormErrorMessage] = useState(''); + const [isDeleteLoading, setIsDeleteLoading] = useState(false); + + const createTransferToLayingHandler = useCallback( + async (payload: CreateTransferToLayingPayload) => { + console.log('Create transfer to laying:', { payload }); + + toast.success('Berhasil menambahkan data transfer ke laying!'); + }, + [router] + ); + + const updateTransferToLayingHandler = useCallback( + async ( + transferToLayingId: number, + payload: UpdateTransferToLayingPayload + ) => { + console.log( + `Update transfer to laying with ID of ${transferToLayingId}:`, + { payload } + ); + + toast.success('Berhasil mengubah data transfer ke laying!'); + }, + [router] + ); + + const formikInitialValues = useMemo(() => { + return { + transfer_date: initialValues?.transfer_date ?? '', + flockSource: initialValues?.flock_source + ? { + value: initialValues?.flock_source.id, + label: initialValues?.flock_source.name, + } + : undefined, + flockDestination: initialValues?.flock_destination + ? { + value: initialValues?.flock_destination.id, + label: initialValues?.flock_destination.name, + } + : undefined, + totalQuantity: initialValues?.quantity ?? undefined, + + kandangs: initialValues?.kandangs + ? initialValues.kandangs.map((kandang) => ({ + kandang: { + value: kandang.kandang.id, + label: kandang.kandang.name, + }, + quantity: kandang.quantity, + })) + : [], + + reason: initialValues?.reason ?? undefined, + }; + }, [initialValues]); + + const formik = useFormik({ + initialValues: formikInitialValues, + validationSchema: + type === 'edit' + ? UpdateTransferToLayingFormSchema + : TransferToLayingFormSchema, + onSubmit: async (values) => { + console.log({ values }); + + setFormErrorMessage(''); + + const transferToLayingPayload: CreateTransferToLayingPayload = { + transfer_date: values.transfer_date as string, + flock_source_id: values.flockSource?.value as number, + flock_destination_id: values.flockDestination?.value as number, + totalQuantity: values.totalQuantity as number, + + kandangs: values.kandangs?.map((kandang) => ({ + kandang_id: kandang.kandang.value, + quantity: kandang.quantity, + })) as { + kandang_id: number; + quantity: number; + }[], + + reason: values.reason as string, + }; + + switch (type) { + case 'add': + await createTransferToLayingHandler(transferToLayingPayload); + break; + + case 'edit': + await updateTransferToLayingHandler( + initialValues?.id as number, + transferToLayingPayload + ); + break; + } + }, + }); + + const { setValues: formikSetValues, values: formikValues } = formik; + const { kandangs: kandangsValue } = formikValues; + + const deleteTransferToLayingClickHandler = () => { + deleteModal.openModal(); + }; + + const confirmationModalDeleteClickHandler = async () => { + setIsDeleteLoading(true); + + deleteModal.closeModal(); + toast.success('Successfully delete TransferToLaying!'); + + setIsDeleteLoading(false); + }; + + const isRepeaterInputError = ( + column: keyof TransferToLayingFormValues['kandangs'][0], + idx: number + ) => { + return ( + formik.touched.kandangs?.[idx]?.[column] && + Boolean( + formik.errors.kandangs?.[idx] instanceof Object && + formik.errors.kandangs?.[idx]?.[column] + ) + ); + }; + + const repeaterInputErrorMessage = ( + column: keyof TransferToLayingFormValues['kandangs'][0], + idx: number + ) => { + return (formik.errors.kandangs?.[idx] as Record)?.[column]; + }; + + // TODO: remove dummy data and use real data + // Flock Source + // const { + // inputValue: flockSourceInputValue, + // setInputValue: setFlockSourceInputValue, + // options: flockSourceOptions, + // isLoadingOptions: isLoadingFlockSourceOptions, + // } = useSelect('/transfer-to-laying/production/get-flock-source', 'id', 'name'); + + // TODO: remove this dummy data + const { data: flockSources, isLoading: isLoadingFlockSourceOptions } = useSWR( + 'test', + () => TransferToLayingApi.getFlockSource() + ); + + const flockSourceOptions = isResponseSuccess(flockSources) + ? flockSources?.data.map((flockSource) => ({ + value: flockSource.id, + label: flockSource.name, + })) + : []; + + const flockSourceChangeHandler = (val: OptionType | OptionType[] | null) => { + // Get flock source data for total quantity and kandang + const flockSource = + isResponseSuccess(flockSources) && val !== null + ? flockSources.data.find( + (item) => item.id === (val as OptionType).value + ) + : undefined; + + // Set total quantity and kandangs + if (flockSource) { + const formattedKandangs = flockSource.kandangs.map((item) => ({ + kandang: { + value: item.kandang.id, + label: item.kandang.name, + }, + quantity: '', + maxQuantity: item.quantity, + })); + + formik.setFieldValue('totalQuantity', flockSource.totalQuantity); + formik.setFieldValue('maxTotalQuantity', flockSource.totalQuantity); + formik.setFieldValue('kandangs', formattedKandangs); + } else { + formik.setFieldValue('totalQuantity', undefined); + formik.setFieldValue('kandangs', undefined); + formik.setFieldValue('reason', ''); + } + + formik.setFieldTouched('flockSource', true); + formik.setFieldValue('flockSource', val); + }; + + // TODO: remove dummy data and use real data + // Flock Destination + // const { + // inputValue: flockDestinationInputValue, + // setInputValue: setFlockDestinationInputValue, + // options: flockDestinationOptions, + // isLoadingOptions: isLoadingFlockDestinationOptions, + // } = useSelect('/transfer-to-laying/production/get-flock-destination', 'id', 'name'); + + // TODO: remove this dummy data + const { + data: flockDestinations, + isLoading: isLoadingFlockDestinationOptions, + } = useSWR('test', () => TransferToLayingApi.getFlockSource()); + + const flockDestinationOptions = isResponseSuccess(flockDestinations) + ? flockDestinations?.data.map((flockDestination) => ({ + value: flockDestination.id, + label: flockDestination.name, + })) + : []; + + const flockDestinationChangeHandler = ( + val: OptionType | OptionType[] | null + ) => { + formik.setFieldTouched('flockDestination', true); + formik.setFieldValue('flockDestination', val); + }; + + useEffect(() => { + formikSetValues(formikInitialValues); + }, [formikSetValues, formikInitialValues]); + + useEffect(() => { + // calculate total quantity if kandangs quantity change + if (kandangsValue && kandangsValue.length > 0) { + let newTotalQuantity = 0; + + kandangsValue.forEach((item) => { + newTotalQuantity += item.quantity as number; + }); + + formik.setFieldValue('totalQuantity', newTotalQuantity); + formik.validateField('totalQuantity'); + } + }, [formikSetValues, kandangsValue]); + + return ( + <> +
+
+ + +

+ {type === 'add' && 'Tambah Transfer ke Laying'} + {type === 'edit' && 'Edit Transfer ke Laying'} + {type === 'detail' && 'Detail Transfer ke Laying'} +

+
+ +
+
+ + +
+ + + +
+ + + +
+
+ + + + + + + + + + {(!formik.values.kandangs || + formik.values.kandangs.length === 0) && ( + + + + )} + + {formik.values.kandangs && + formik.values.kandangs.map((kandang, idx) => ( + + + + + + ))} + +
KandangKuantitas
+

+ Pilih flock asal terlebih dahulu! +

+
+ + + +
+
+
+ +