feat(FE-149): integrate TransferToLayingForm to API

This commit is contained in:
ValdiANS
2025-11-12 13:34:25 +07:00
parent 1ff1e53e02
commit 569a8b495b
@@ -1,6 +1,6 @@
'use client'; 'use client';
import { useCallback, useEffect, useMemo, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { useFormik } from 'formik'; import { useFormik } from 'formik';
import { toast } from 'react-hot-toast'; import { toast } from 'react-hot-toast';
@@ -8,16 +8,23 @@ import useSWR from 'swr';
import { Icon } from '@iconify/react'; import { Icon } from '@iconify/react';
import Button from '@/components/Button'; import Button from '@/components/Button';
import TextInput from '@/components/input/TextInput';
import SelectInput, { import SelectInput, {
OptionType, OptionType,
// useSelect, useSelect,
} from '@/components/input/SelectInput'; } from '@/components/input/SelectInput';
import TextArea from '@/components/input/TextArea'; import TextArea from '@/components/input/TextArea';
import { useModal } from '@/components/Modal'; import { useModal } from '@/components/Modal';
import ConfirmationModal from '@/components/modal/ConfirmationModal'; import ConfirmationModal from '@/components/modal/ConfirmationModal';
import DateInput from '@/components/input/DateInput';
import NumberInput from '@/components/input/NumberInput';
import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes';
import ApprovalSteps, {
formatGroupedApprovalsToApprovalSteps,
} from '@/components/pages/ApprovalSteps';
import { import {
getFilledTransferToLayingFormInitialValues,
getTransferToLayingFormInitialValues,
TransferToLayingFormSchema, TransferToLayingFormSchema,
TransferToLayingFormValues, TransferToLayingFormValues,
UpdateTransferToLayingFormSchema, UpdateTransferToLayingFormSchema,
@@ -31,6 +38,8 @@ import {
import { cn } from '@/lib/helper'; import { cn } from '@/lib/helper';
import { TransferToLayingApi } from '@/services/api/production/transfer-to-laying'; import { TransferToLayingApi } from '@/services/api/production/transfer-to-laying';
import { ProjectFlock } from '@/types/api/production/project-flock';
import { TRANSFER_TO_LAYING_APPROVAL_LINE } from '@/config/approval-line';
interface TransferToLayingFormProps { interface TransferToLayingFormProps {
type?: 'add' | 'edit' | 'detail'; type?: 'add' | 'edit' | 'detail';
@@ -55,11 +64,23 @@ const TransferToLayingForm = ({
const [isApproveLoading, setIsApproveLoading] = useState(false); const [isApproveLoading, setIsApproveLoading] = useState(false);
const [isRejectLoading, setIsRejectLoading] = useState(false); const [isRejectLoading, setIsRejectLoading] = useState(false);
const { data: approvalHistory, isLoading: isLoadingApprovalHistory } = useSWR(
type === 'detail' && initialValues ? [String(initialValues.id)] : null,
([id]: string[]) => TransferToLayingApi.getApprovalHistory(Number(id))
);
const createTransferToLayingHandler = useCallback( const createTransferToLayingHandler = useCallback(
async (payload: CreateTransferToLayingPayload) => { async (payload: CreateTransferToLayingPayload) => {
console.log('Create transfer to laying:', { payload }); const createTransferToLayingRes =
await TransferToLayingApi.create(payload);
toast.success('Berhasil menambahkan data transfer ke laying!'); if (isResponseError(createTransferToLayingRes)) {
setFormErrorMessage(createTransferToLayingRes.message);
return;
}
toast.success(createTransferToLayingRes?.message as string);
router.push('/production/transfer-to-laying');
}, },
[router] [router]
); );
@@ -69,46 +90,30 @@ const TransferToLayingForm = ({
transferToLayingId: number, transferToLayingId: number,
payload: UpdateTransferToLayingPayload payload: UpdateTransferToLayingPayload
) => { ) => {
console.log( const updateKandangRes = await TransferToLayingApi.update(
`Update transfer to laying with ID of ${transferToLayingId}:`, transferToLayingId,
{ payload } payload
); );
toast.success('Berhasil mengubah data transfer ke laying!'); if (updateKandangRes?.status === 'error') {
setFormErrorMessage(updateKandangRes.message);
return;
}
toast.success(updateKandangRes?.message as string);
router.refresh();
router.push('/production/transfer-to-laying');
}, },
[router] [router]
); );
const formikInitialValues = useMemo<TransferToLayingFormValues>(() => { // const formikInitialValues = useMemo<TransferToLayingFormValues>(() => {
return { // return getTransferToLayingFormInitialValues(initialValues);
transfer_date: initialValues?.transfer_date ?? '', // }, [initialValues]);
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 const [formikInitialValues, setFormikInitialValues] = useState(
? initialValues.kandangs.map((kandang) => ({ getTransferToLayingFormInitialValues()
kandang: { );
value: kandang.kandang.id,
label: kandang.kandang.name,
},
quantity: kandang.quantity,
}))
: [],
reason: initialValues?.reason ?? undefined,
};
}, [initialValues]);
const formik = useFormik<TransferToLayingFormValues>({ const formik = useFormik<TransferToLayingFormValues>({
initialValues: formikInitialValues, initialValues: formikInitialValues,
@@ -117,23 +122,23 @@ const TransferToLayingForm = ({
? UpdateTransferToLayingFormSchema ? UpdateTransferToLayingFormSchema
: TransferToLayingFormSchema, : TransferToLayingFormSchema,
onSubmit: async (values) => { onSubmit: async (values) => {
console.log({ values });
setFormErrorMessage(''); setFormErrorMessage('');
const transferToLayingPayload: CreateTransferToLayingPayload = { const transferToLayingPayload: CreateTransferToLayingPayload = {
transfer_date: values.transfer_date as string, transfer_date: values.transfer_date as string,
flock_source_id: values.flockSource?.value as number, source_project_flock_id: values.flockSource?.value as number,
flock_destination_id: values.flockDestination?.value as number, target_project_flock_id: values.flockDestination?.value as number,
totalQuantity: values.totalQuantity as number, totalQuantity: values.totalQuantity as number,
kandangs: values.kandangs?.map((kandang) => ({ source_kandangs: values.flockSourceKandangs?.map((kandang) => ({
kandang_id: kandang.kandang.value, project_flock_kandang_id: kandang.kandang.value,
quantity: kandang.quantity, quantity: parseFloat(kandang.quantity as string),
})) as { })) as CreateTransferToLayingPayload['source_kandangs'],
kandang_id: number;
quantity: number; target_kandangs: values.flockDestinationKandangs?.map((kandang) => ({
}[], project_flock_kandang_id: kandang.kandang.value,
quantity: parseFloat(kandang.quantity as string),
})) as CreateTransferToLayingPayload['target_kandangs'],
reason: values.reason as string, reason: values.reason as string,
}; };
@@ -154,7 +159,11 @@ const TransferToLayingForm = ({
}); });
const { setValues: formikSetValues, values: formikValues } = formik; const { setValues: formikSetValues, values: formikValues } = formik;
const { kandangs: kandangsValue } = formikValues; const {
flockSourceKandangs: flockSourceKandangsValue,
flockDestinationKandangs: flockDestinationKandangsValue,
totalQuantity,
} = formikValues;
const deleteTransferToLayingClickHandler = () => { const deleteTransferToLayingClickHandler = () => {
deleteModal.openModal(); deleteModal.openModal();
@@ -172,24 +181,32 @@ const TransferToLayingForm = ({
const confirmationModalDeleteClickHandler = async () => { const confirmationModalDeleteClickHandler = async () => {
setIsDeleteLoading(true); setIsDeleteLoading(true);
// TODO: delete data and integrate to real API try {
deleteModal.closeModal(); await TransferToLayingApi.delete(initialValues?.id as number);
toast.success('Berhasil menghapus data transfer ke laying!');
setIsDeleteLoading(false); toast.success('Berhasil menghapus data transfer ke laying!');
router.push('/production/transfer-to-laying');
} catch (error) {
toast.success('Gagal menghapus data transfer ke laying!');
} finally {
deleteModal.closeModal();
setIsDeleteLoading(false);
}
}; };
const confirmationModalApproveClickHandler = async () => { const confirmationModalApproveClickHandler = async (notes: string) => {
setIsApproveLoading(true); setIsApproveLoading(true);
const approveResponse = await TransferToLayingApi.approve( const approveResponse = await TransferToLayingApi.approve(
initialValues?.id as number initialValues?.id as number,
notes
); );
if (isResponseSuccess(approveResponse)) { if (isResponseSuccess(approveResponse)) {
approveModal.closeModal(); approveModal.closeModal();
toast.success('Berhasil approve data transfer ke laying!'); toast.success('Berhasil approve data transfer ke laying!');
router.push('/production/transfer-to-laying');
} else { } else {
approveModal.closeModal(); approveModal.closeModal();
@@ -199,17 +216,19 @@ const TransferToLayingForm = ({
setIsApproveLoading(false); setIsApproveLoading(false);
}; };
const confirmationModalRejectClickHandler = async () => { const confirmationModalRejectClickHandler = async (notes: string) => {
setIsRejectLoading(true); setIsRejectLoading(true);
const rejectResponse = await TransferToLayingApi.reject( const rejectResponse = await TransferToLayingApi.reject(
initialValues?.id as number initialValues?.id as number,
notes
); );
if (isResponseSuccess(rejectResponse)) { if (isResponseSuccess(rejectResponse)) {
rejectModal.closeModal(); rejectModal.closeModal();
toast.success('Berhasil reject data transfer ke laying!'); toast.success('Berhasil reject data transfer ke laying!');
router.push('/production/transfer-to-laying');
} else { } else {
rejectModal.closeModal(); rejectModal.closeModal();
@@ -219,49 +238,47 @@ const TransferToLayingForm = ({
setIsRejectLoading(false); setIsRejectLoading(false);
}; };
const isRepeaterInputError = ( // flock source
column: keyof TransferToLayingFormValues['kandangs'][0], const isFlockSourceKandangsRepeaterInputError = (
column: keyof TransferToLayingFormValues['flockSourceKandangs'][0],
idx: number idx: number
) => { ) => {
return ( return (
formik.touched.kandangs?.[idx]?.[column] && formik.touched.flockSourceKandangs?.[idx]?.[column] &&
Boolean( Boolean(
formik.errors.kandangs?.[idx] instanceof Object && formik.errors.flockSourceKandangs?.[idx] instanceof Object &&
formik.errors.kandangs?.[idx]?.[column] formik.errors.flockSourceKandangs?.[idx]?.[column]
) )
); );
}; };
const repeaterInputErrorMessage = ( const flockSourceKandangsRepeaterInputErrorMessage = (
column: keyof TransferToLayingFormValues['kandangs'][0], column: keyof TransferToLayingFormValues['flockSourceKandangs'][0],
idx: number idx: number
) => { ) => {
return (formik.errors.kandangs?.[idx] as Record<string, string>)?.[column]; return (
formik.errors.flockSourceKandangs?.[idx] as Record<string, string>
)?.[column];
}; };
// TODO: remove dummy data and use real data const {
// Flock Source setInputValue: setFlockSourceInputValue,
// const { options: flockSourceOptions,
// inputValue: flockSourceInputValue, isLoadingOptions: isLoadingFlockSourceOptions,
// setInputValue: setFlockSourceInputValue, rawData: flockSources,
// options: flockSourceOptions, } = useSelect<ProjectFlock>(
// isLoadingOptions: isLoadingFlockSourceOptions, '/production/project-flocks',
// } = useSelect<FlockWithKandangs>('/transfer-to-laying/production/get-flock-source', 'id', 'name'); 'id',
'flock_name',
// TODO: remove this dummy data 'search',
const { data: flockSources, isLoading: isLoadingFlockSourceOptions } = useSWR( {
'test', category: 'GROWING',
() => TransferToLayingApi.getFlockSource() }
); );
const flockSourceOptions = isResponseSuccess(flockSources) const flockSourceChangeHandler = async (
? flockSources?.data.map((flockSource) => ({ val: OptionType | OptionType[] | null
value: flockSource.id, ) => {
label: flockSource.name,
}))
: [];
const flockSourceChangeHandler = (val: OptionType | OptionType[] | null) => {
// Get flock source data for total quantity and kandang // Get flock source data for total quantity and kandang
const flockSource = const flockSource =
isResponseSuccess(flockSources) && val !== null isResponseSuccess(flockSources) && val !== null
@@ -272,21 +289,38 @@ const TransferToLayingForm = ({
// Set total quantity and kandangs // Set total quantity and kandangs
if (flockSource) { if (flockSource) {
const mappedFlockKandangsAvailableQty =
await TransferToLayingApi.getMappedFlockKandangsAvailability(
flockSource.id
);
const formattedKandangs = flockSource.kandangs.map((item) => ({ const formattedKandangs = flockSource.kandangs.map((item) => ({
kandang: { kandang: {
value: item.kandang.id, value: item.project_flock_kandang_id,
label: item.kandang.name, label: item.name,
}, },
quantity: '', quantity: '',
maxQuantity: item.quantity, maxQuantity:
(mappedFlockKandangsAvailableQty &&
mappedFlockKandangsAvailableQty[item.project_flock_kandang_id]
.available_qty) ??
0,
})); }));
formik.setFieldValue('totalQuantity', flockSource.totalQuantity); let maxTotalQuantity = 0;
formik.setFieldValue('maxTotalQuantity', flockSource.totalQuantity); // flockSource.kandangs.forEach((item) => {
formik.setFieldValue('kandangs', formattedKandangs); // maxTotalQuantity += item.capacity;
// });
formattedKandangs.forEach((item) => {
maxTotalQuantity += item.maxQuantity;
});
formik.setFieldValue('totalQuantity', '');
formik.setFieldValue('maxTotalQuantity', maxTotalQuantity);
formik.setFieldValue('flockSourceKandangs', formattedKandangs);
} else { } else {
formik.setFieldValue('totalQuantity', undefined); formik.setFieldValue('totalQuantity', undefined);
formik.setFieldValue('kandangs', undefined); formik.setFieldValue('flockSourceKandangs', undefined);
formik.setFieldValue('reason', ''); formik.setFieldValue('reason', '');
} }
@@ -294,52 +328,137 @@ const TransferToLayingForm = ({
formik.setFieldValue('flockSource', val); formik.setFieldValue('flockSource', val);
}; };
// TODO: remove dummy data and use real data // flock destination
// Flock Destination const isFlockDestinationKandangsRepeaterInputError = (
// const { column: keyof TransferToLayingFormValues['flockDestinationKandangs'][0],
// inputValue: flockDestinationInputValue, idx: number
// setInputValue: setFlockDestinationInputValue, ) => {
// options: flockDestinationOptions, return (
// isLoadingOptions: isLoadingFlockDestinationOptions, formik.touched.flockDestinationKandangs?.[idx]?.[column] &&
// } = useSelect<FlockWithKandangs>('/transfer-to-laying/production/get-flock-destination', 'id', 'name'); Boolean(
formik.errors.flockDestinationKandangs?.[idx] instanceof Object &&
formik.errors.flockDestinationKandangs?.[idx]?.[column]
)
);
};
const flockDestinationKandangsRepeaterInputErrorMessage = (
column: keyof TransferToLayingFormValues['flockDestinationKandangs'][0],
idx: number
) => {
return (
formik.errors.flockDestinationKandangs?.[idx] as Record<string, string>
)?.[column];
};
// TODO: remove this dummy data
const { const {
data: flockDestinations, setInputValue: setFlockDestinationInputValue,
isLoading: isLoadingFlockDestinationOptions, options: flockDestinationOptions,
} = useSWR('test', () => TransferToLayingApi.getFlockSource()); isLoadingOptions: isLoadingFlockDestinationOptions,
rawData: flockDestinations,
const flockDestinationOptions = isResponseSuccess(flockDestinations) } = useSelect<ProjectFlock>(
? flockDestinations?.data.map((flockDestination) => ({ '/production/project-flocks',
value: flockDestination.id, 'id',
label: flockDestination.name, 'flock_name',
})) 'search',
: []; {
category: 'LAYING',
}
);
const flockDestinationChangeHandler = ( const flockDestinationChangeHandler = (
val: OptionType | OptionType[] | null val: OptionType | OptionType[] | null
) => { ) => {
// Get flock destination data for total quantity and kandang
const flockDestination =
isResponseSuccess(flockDestinations) && val !== null
? flockDestinations.data.find(
(item) => item.id === (val as OptionType).value
)
: undefined;
// Set total quantity and kandangs
if (flockDestination) {
const formattedKandangs = flockDestination.kandangs.map((item) => ({
kandang: {
value: item.project_flock_kandang_id,
label: item.name,
},
quantity: '',
// TODO: integrate this later to real kandang capacity API
// maxQuantity: item.capacity ?? 0,
maxQuantity: item.capacity ?? Infinity,
}));
formik.setFieldValue('flockDestinationKandangs', formattedKandangs);
}
formik.setFieldTouched('flockDestination', true); formik.setFieldTouched('flockDestination', true);
formik.setFieldValue('flockDestination', val); formik.setFieldValue('flockDestination', val);
}; };
const isShowApproveRejectButton =
initialValues &&
initialValues?.approval?.step_number === 1 &&
initialValues?.approval.action !== 'REJECTED';
const isShowDeleteButton =
initialValues &&
initialValues?.approval.action !== 'REJECTED' &&
initialValues?.approval.action !== 'APPROVED';
const isShowEditButton = isShowDeleteButton;
useEffect(() => {
const getFilledInitialValues = async () => {
if (initialValues) {
const filledInitialValues =
await getFilledTransferToLayingFormInitialValues(initialValues);
setFormikInitialValues(filledInitialValues);
}
};
getFilledInitialValues();
}, [initialValues, setFormikInitialValues]);
useEffect(() => { useEffect(() => {
formikSetValues(formikInitialValues); formikSetValues(formikInitialValues);
}, [formikSetValues, formikInitialValues]); }, [formikSetValues, formikInitialValues]);
useEffect(() => { useEffect(() => {
// calculate total quantity if kandangs quantity change // calculate total quantity if kandangs quantity change
if (kandangsValue && kandangsValue.length > 0) { if (flockSourceKandangsValue && flockSourceKandangsValue.length > 0) {
let newTotalQuantity = 0; let newTotalQuantity = 0;
kandangsValue.forEach((item) => { flockSourceKandangsValue.forEach((item) => {
newTotalQuantity += item.quantity as number; newTotalQuantity += parseFloat(item.quantity as string);
}); });
formik.setFieldValue('totalQuantity', newTotalQuantity); formik.setFieldValue('totalQuantity', newTotalQuantity);
formik.validateField('totalQuantity'); formik.validateField('totalQuantity');
} }
}, [formikSetValues, kandangsValue]); }, [formikSetValues, flockSourceKandangsValue]);
useEffect(() => {
// calculate total quantity if kandangs quantity change
if (
flockDestinationKandangsValue &&
flockDestinationKandangsValue.length > 0
) {
let destinationKandangsTotalQuantity = 0;
flockDestinationKandangsValue.forEach((item) => {
destinationKandangsTotalQuantity += parseFloat(item.quantity as string);
});
if (
destinationKandangsTotalQuantity > parseFloat(String(totalQuantity))
) {
}
}
}, [formikSetValues, flockDestinationKandangsValue]);
return ( return (
<> <>
@@ -361,30 +480,56 @@ const TransferToLayingForm = ({
</h1> </h1>
</header> </header>
<div className='w-full my-4 flex flex-row justify-end gap-2'> {type === 'detail' &&
initialValues &&
!isLoadingApprovalHistory &&
isResponseSuccess(approvalHistory) && (
<div className='w-full my-4'>
<ApprovalSteps
approvals={formatGroupedApprovalsToApprovalSteps(
TRANSFER_TO_LAYING_APPROVAL_LINE,
approvalHistory.data,
initialValues.approval
)}
/>
</div>
)}
<div className='w-full my-4 flex flex-row justify-between gap-2'>
{type === 'detail' && ( {type === 'detail' && (
<> <>
<Button {isShowApproveRejectButton && (
variant='outline' <div className='w-full flex flex-row justify-end gap-2'>
color='success' {/* TODO: apply RBAC */}
onClick={approveClickHandler} <Button
// disabled={selectedRowIds.length === 0} variant='outline'
className='w-full sm:w-fit' color='success'
> onClick={approveClickHandler}
<Icon icon='material-symbols:check' width={24} height={24} /> className='w-full sm:w-fit'
Approve >
</Button> <Icon
icon='material-symbols:check'
width={24}
height={24}
/>
Approve
</Button>
<Button <Button
variant='outline' variant='outline'
color='error' color='error'
onClick={rejectClickHandler} onClick={rejectClickHandler}
// disabled={selectedRowIds.length === 0} className='w-full sm:w-fit'
className='w-full sm:w-fit' >
> <Icon
<Icon icon='material-symbols:close' width={24} height={24} /> icon='material-symbols:close'
Reject width={24}
</Button> height={24}
/>
Reject
</Button>
</div>
)}
</> </>
)} )}
</div> </div>
@@ -395,13 +540,12 @@ const TransferToLayingForm = ({
className='w-full flex flex-col gap-6' className='w-full flex flex-col gap-6'
> >
<div className='flex flex-col gap-4'> <div className='flex flex-col gap-4'>
<TextInput <DateInput
required required
type='date'
label='Tanggal Transfer' label='Tanggal Transfer'
name='transfer_date' name='transfer_date'
placeholder='Masukkan tanggal transfer' placeholder='Masukkan tanggal transfer'
value={formik.values.transfer_date} value={formik.values.transfer_date ?? ''}
onChange={formik.handleChange} onChange={formik.handleChange}
onBlur={formik.handleBlur} onBlur={formik.handleBlur}
isError={ isError={
@@ -421,7 +565,7 @@ const TransferToLayingForm = ({
options={flockSourceOptions} options={flockSourceOptions}
onChange={flockSourceChangeHandler} onChange={flockSourceChangeHandler}
isLoading={isLoadingFlockSourceOptions} isLoading={isLoadingFlockSourceOptions}
// onInputChange={setFlockSourceInputValue} onInputChange={setFlockSourceInputValue}
isError={ isError={
formik.touched.flockSource && formik.touched.flockSource &&
Boolean(typeof formik.errors.flockSource === 'string') Boolean(typeof formik.errors.flockSource === 'string')
@@ -439,7 +583,7 @@ const TransferToLayingForm = ({
options={flockDestinationOptions} options={flockDestinationOptions}
onChange={flockDestinationChangeHandler} onChange={flockDestinationChangeHandler}
isLoading={isLoadingFlockDestinationOptions} isLoading={isLoadingFlockDestinationOptions}
// onInputChange={setFlockDestinationInputValue} onInputChange={setFlockDestinationInputValue}
isError={ isError={
formik.touched.flockDestination && formik.touched.flockDestination &&
Boolean(typeof formik.errors.flockDestination === 'string') Boolean(typeof formik.errors.flockDestination === 'string')
@@ -450,9 +594,8 @@ const TransferToLayingForm = ({
/> />
</div> </div>
<TextInput <NumberInput
required required
type='number'
name='totalQuantity' name='totalQuantity'
label='Jumlah Transfer' label='Jumlah Transfer'
bottomLabel={ bottomLabel={
@@ -461,7 +604,9 @@ const TransferToLayingForm = ({
: undefined : undefined
} }
placeholder='Masukkan jumlah transfer' placeholder='Masukkan jumlah transfer'
value={formik.values.totalQuantity ?? ''} value={
formik.values.totalQuantity ? formik.values.totalQuantity : ''
}
onChange={formik.handleChange} onChange={formik.handleChange}
onBlur={formik.handleBlur} onBlur={formik.handleBlur}
isError={ isError={
@@ -469,24 +614,22 @@ const TransferToLayingForm = ({
Boolean(formik.errors.totalQuantity) Boolean(formik.errors.totalQuantity)
} }
errorMessage={formik.errors.totalQuantity} errorMessage={formik.errors.totalQuantity}
// readOnly={type === 'detail'}
// disabled={Boolean(formik.errors.flockSource)}
disabled disabled
/> />
<div> <div className='flex flex-col gap-4'>
<div className='overflow-x-auto'> <div className='overflow-x-auto'>
<table className='table'> <table className='table'>
<thead> <thead>
<tr> <tr>
<th>Kandang</th> <th>Kandang Flock Asal</th>
<th>Kuantitas</th> <th>Kuantitas</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{(!formik.values.kandangs || {(!formik.values.flockSourceKandangs ||
formik.values.kandangs.length === 0) && ( formik.values.flockSourceKandangs.length === 0) && (
<tr> <tr>
<td colSpan={2}> <td colSpan={2}>
<p className='w-full text-center text-gray-400'> <p className='w-full text-center text-gray-400'>
@@ -496,8 +639,8 @@ const TransferToLayingForm = ({
</tr> </tr>
)} )}
{formik.values.kandangs && {formik.values.flockSourceKandangs &&
formik.values.kandangs.map((kandang, idx) => ( formik.values.flockSourceKandangs.map((kandang, idx) => (
<tr key={idx}> <tr key={idx}>
<td> <td>
<SelectInput <SelectInput
@@ -511,10 +654,9 @@ const TransferToLayingForm = ({
</td> </td>
<td> <td>
<TextInput <NumberInput
required required
type='number' name={`flockSourceKandangs[${idx}].quantity`}
name={`kandangs[${idx}].quantity`}
bottomLabel={ bottomLabel={
kandang.maxQuantity kandang.maxQuantity
? `Max: ${kandang.maxQuantity}` ? `Max: ${kandang.maxQuantity}`
@@ -524,8 +666,11 @@ const TransferToLayingForm = ({
value={kandang.quantity} value={kandang.quantity}
onChange={formik.handleChange} onChange={formik.handleChange}
onBlur={formik.handleBlur} onBlur={formik.handleBlur}
isError={isRepeaterInputError('quantity', idx)} isError={isFlockSourceKandangsRepeaterInputError(
errorMessage={repeaterInputErrorMessage( 'quantity',
idx
)}
errorMessage={flockSourceKandangsRepeaterInputErrorMessage(
'quantity', 'quantity',
idx idx
)} )}
@@ -540,6 +685,76 @@ const TransferToLayingForm = ({
</tbody> </tbody>
</table> </table>
</div> </div>
<div className='overflow-x-auto'>
<table className='table'>
<thead>
<tr>
<th>Kandang Flock Tujuan</th>
<th>Kuantitas</th>
</tr>
</thead>
<tbody>
{(!formik.values.flockDestinationKandangs ||
formik.values.flockDestinationKandangs.length === 0) && (
<tr>
<td colSpan={2}>
<p className='w-full text-center text-gray-400'>
Pilih flock tujuan terlebih dahulu!
</p>
</td>
</tr>
)}
{formik.values.flockDestinationKandangs &&
formik.values.flockDestinationKandangs.map(
(kandang, idx) => (
<tr key={idx}>
<td>
<SelectInput
value={kandang.kandang}
options={[]}
isDisabled
className={{
wrapper: 'min-w-52',
}}
/>
</td>
<td>
<NumberInput
required
name={`flockDestinationKandangs[${idx}].quantity`}
bottomLabel={
kandang.maxQuantity
? `Max: ${kandang.maxQuantity}`
: undefined
}
placeholder='Masukkan kuantitas'
value={kandang.quantity}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
isError={isFlockDestinationKandangsRepeaterInputError(
'quantity',
idx
)}
errorMessage={flockDestinationKandangsRepeaterInputErrorMessage(
'quantity',
idx
)}
readOnly={type === 'detail'}
className={{
wrapper: 'min-w-52',
}}
/>
</td>
</tr>
)
)}
</tbody>
</table>
</div>
</div> </div>
<TextArea <TextArea
@@ -558,25 +773,38 @@ const TransferToLayingForm = ({
/> />
</div> </div>
{formErrorMessage && (
<div role='alert' className='alert alert-error w-full'>
<Icon
icon='material-symbols:error-outline'
width={24}
height={24}
/>
<span>{formErrorMessage}</span>
</div>
)}
<div className='flex flex-row justify-between gap-2 flex-wrap'> <div className='flex flex-row justify-between gap-2 flex-wrap'>
{type !== 'add' && ( {type !== 'add' && (
<div className='flex flex-row justify-start gap-2'> <div className='flex flex-row justify-start gap-2'>
<Button {isShowDeleteButton && (
type='button' <Button
color='error' type='button'
onClick={deleteTransferToLayingClickHandler} color='error'
className='px-4' onClick={deleteTransferToLayingClickHandler}
> className='px-4'
<Icon >
icon='material-symbols:delete-outline-rounded' <Icon
width={24} icon='material-symbols:delete-outline-rounded'
height={24} width={24}
className='justify-start text-sm' height={24}
/> className='justify-start text-sm'
Delete />
</Button> Delete
</Button>
)}
{type !== 'edit' && ( {type !== 'edit' && isShowEditButton && (
<Button <Button
type='button' type='button'
color='warning' color='warning'
@@ -617,17 +845,6 @@ const TransferToLayingForm = ({
</div> </div>
)} )}
</div> </div>
{formErrorMessage && (
<div role='alert' className='alert alert-error'>
<Icon
icon='material-symbols:error-outline'
width={24}
height={24}
/>
<span>{formErrorMessage}</span>
</div>
)}
</form> </form>
</section> </section>
@@ -650,7 +867,7 @@ const TransferToLayingForm = ({
{type === 'detail' && ( {type === 'detail' && (
<> <>
<ConfirmationModal <ConfirmationModalWithNotes
ref={approveModal.ref} ref={approveModal.ref}
type='success' type='success'
text='Apakah anda yakin ingin approve data transfer ke laying ini?' text='Apakah anda yakin ingin approve data transfer ke laying ini?'
@@ -665,7 +882,7 @@ const TransferToLayingForm = ({
}} }}
/> />
<ConfirmationModal <ConfirmationModalWithNotes
ref={rejectModal.ref} ref={rejectModal.ref}
type='error' type='error'
text='Apakah anda yakin ingin reject data transfer ke laying ini?' text='Apakah anda yakin ingin reject data transfer ke laying ini?'