refactor(FE-318,319): Remove egg grading schema and UI logic

This commit is contained in:
rstubryan
2025-12-08 23:37:20 +07:00
parent 012fe800bc
commit 6ee5bc3f1b
2 changed files with 38 additions and 241 deletions
@@ -4,7 +4,6 @@ import {
CreateGrowingRecordingPayload,
CreateLayingRecordingPayload,
CreateEggPayload,
CreateGradingPayload,
} from '@/types/api/production/recording';
type RecordingGrowingFormSchemaType = {
@@ -36,14 +35,6 @@ type RecordingLayingFormSchemaType = RecordingGrowingFormSchemaType & {
}[];
};
type RecordingGradingFormSchemaType = {
eggs_grading: {
recording_egg_id: number;
grade: string;
qty: number | string;
}[];
};
export type BodyWeightSchema = {
weight: number | string;
avg_weight: number | string;
@@ -196,30 +187,6 @@ export const UpdateRecordingLayingFormSchema = RecordingLayingFormSchema.shape({
.required('Project Flock Kandang wajib diisi!'),
});
export const RecordingGradingFormSchema: Yup.ObjectSchema<RecordingGradingFormSchemaType> =
Yup.object({
eggs_grading: Yup.array()
.of(
Yup.object({
recording_egg_id: Yup.number()
.required('Recording Egg ID wajib diisi!')
.min(1, 'Recording Egg ID minimal 1!')
.typeError('Recording Egg ID harus berupa angka!'),
grade: Yup.string()
.required('Grade telur wajib diisi!')
.typeError('Grade telur harus berupa string!'),
qty: Yup.number()
.required('Jumlah telur wajib diisi!')
.min(1, 'Jumlah telur minimal 1!')
.typeError('Jumlah telur harus berupa angka!'),
})
)
.min(1, 'Minimal harus ada 1 data grading telur!')
.required('Data grading telur wajib diisi!'),
});
export const UpdateRecordingGradingFormSchema = RecordingGradingFormSchema;
export type RecordingGrowingFormValues = Yup.InferType<
typeof RecordingGrowingFormSchema
>;
@@ -228,10 +195,6 @@ export type RecordingLayingFormValues = Yup.InferType<
typeof RecordingLayingFormSchema
>;
export type RecordingGradingFormValues = Yup.InferType<
typeof RecordingGradingFormSchema
>;
type RecordingFormData = Partial<Recording> & {
body_weights?: CreateGrowingRecordingPayload['body_weights'];
stocks?: CreateGrowingRecordingPayload['stocks'] | Recording['stocks'];
@@ -310,19 +273,3 @@ export const getRecordingLayingFormInitialValues = (
},
],
});
export const getRecordingGradingFormInitialValues = (
initialValues?: Partial<CreateGradingPayload> & { recording_egg_id?: number }
): RecordingGradingFormValues => ({
eggs_grading: initialValues?.eggs_grading?.map((grading) => ({
recording_egg_id: grading.recording_egg_id,
grade: grading.grade,
qty: grading.qty,
})) ?? [
{
recording_egg_id: initialValues?.recording_egg_id ?? 0,
grade: '',
qty: '',
},
],
});
@@ -16,7 +16,6 @@ import CheckboxInput from '@/components/input/CheckboxInput';
import ConfirmationModal from '@/components/modal/ConfirmationModal';
import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes';
import { useModal } from '@/components/Modal';
import Tooltip from '@/components/Tooltip';
import {
ProjectFlockKandangApi,
@@ -98,9 +97,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
const [recordingFormErrorMessage, setRecordingFormErrorMessage] =
useState('');
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const [newRecordingData, setNewRecordingData] = useState<Recording | null>(
null
);
const [, setNewRecordingData] = useState<Recording | null>(null);
const [nextDayRecording, setNextDayRecording] =
useState<NextDayRecording | null>(null);
@@ -111,18 +108,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
const isRecordingApproved = useCallback((recording?: Recording) => {
return (
recording?.approval?.action === 'APPROVED' &&
recording?.approval?.step_name === 'Disetujui' &&
recording?.approval?.step_number === 2
);
}, []);
const hasGradingData = useCallback((recording?: Recording) => {
if (!recording || !recording.eggs) return false;
return recording.eggs.some(
(egg) =>
egg.gradings &&
egg.gradings.length > 0 &&
egg.gradings.some((grading) => grading.qty > 0)
recording?.approval?.step_name === 'Disetujui'
);
}, []);
@@ -207,35 +193,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
[router]
);
const createRecordingHandlerWithRedirect = useCallback(
async (
payload: CreateGrowingRecordingPayload | CreateLayingRecordingPayload,
redirectToGrading: boolean = false
) => {
const res = await RecordingApi.create(payload);
if (isResponseError(res)) {
setRecordingFormErrorMessage(res.message);
return null;
}
toast.success(res?.message as string);
if (res?.status === 'success' && res.data) {
setNewRecordingData(res.data);
return res.data;
}
if (redirectToGrading) {
toast.error(
'Gagal mendapatkan ID recording. Silakan coba dari halaman list.'
);
router.push('/production/recording');
}
return null;
},
[router]
);
const updateRecordingHandler = useCallback(
async (
recordingId: number,
@@ -654,7 +611,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
const hasPakanFlag = product.product.flags?.includes('PAKAN');
const hasOvkFlag = product.product.flags?.includes('OVK');
// Only include products that are in the same location as the selected kandang
if (hasPakanFlag || hasOvkFlag) {
options.push({
value: product.id,
@@ -694,7 +650,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
depletionProductsData.data.forEach((product) => {
const productName = product.product.name;
// Filter for depletion-related products (culling, mati, afkir)
if (
productName.toLowerCase().includes('culling') ||
productName.toLowerCase().includes('mati') ||
@@ -736,7 +691,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
eggProductsData.data.forEach((product) => {
const productName = product.product.name;
// Filter for egg-related products
if (
productName.toLowerCase().includes('telur') ||
productName.toLowerCase().includes('egg') ||
@@ -1023,54 +977,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
);
}, [formik.values.stocks, getStockUsageError, type]);
const hasConsumableEggs = useMemo(() => {
if (!isLayingCategory) return false;
const layingValues = formik.values as RecordingLayingFormValues;
if (!layingValues.eggs || layingValues.eggs.length === 0) return false;
return layingValues.eggs.some((egg) => {
if (!egg.product_warehouse_id || Number(egg.qty) <= 0) return false;
const product = eggProducts.find(
(opt) => opt.value === egg.product_warehouse_id
);
if (!product) return false;
const productName = product.label.toLowerCase();
return (
productName.includes('konsumsi') &&
productName.includes('baik') &&
Number(egg.qty) > 0
);
});
}, [isLayingCategory, formik.values, eggProducts]);
const hasConsumableEggsInRecording = useCallback((recording?: Recording) => {
if (!recording || !recording.eggs || recording.eggs.length === 0)
return false;
return recording.eggs.some((egg) => {
if (!egg.product_warehouse || !egg.product_warehouse.product)
return false;
if (Number(egg.qty) <= 0) return false;
const productName = egg.product_warehouse.product.name.toLowerCase();
return (
productName.includes('konsumsi') &&
productName.includes('baik') &&
Number(egg.qty) > 0
);
});
}, []);
const hasConsumableEggsInCurrentRecording = useMemo(() => {
return (
hasConsumableEggsInRecording(initialValues) ||
hasConsumableEggsInRecording(newRecordingData || undefined)
);
}, [initialValues, newRecordingData, hasConsumableEggsInRecording]);
const isRepeaterInputError = (
arrayName: 'body_weights' | 'stocks' | 'depletions' | 'eggs',
column: string,
@@ -1282,7 +1188,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
setIsRejectLoading(false);
};
// Body Weights Handlers
const addBodyWeight = () => {
const newBodyWeights = [
...(formik.values.body_weights || []),
@@ -1401,7 +1306,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
setSelectedBodyWeights([]);
};
// Stocks Handlers
const addStock = () => {
const newStocks = [
...(formik.values.stocks || []),
@@ -1434,7 +1338,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
setSelectedStocks([]);
};
// Depletions Handlers
const addDepletion = () => {
const newDepletions = [
...(formik.values.depletions || []),
@@ -1469,7 +1372,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
setSelectedDepletions([]);
};
// Eggs Handlers
const addEgg = () => {
const newEggs = [
...((formik.values as RecordingLayingFormValues).eggs || []),
@@ -1581,47 +1483,37 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
Kembali
</Button>
{type === 'detail' &&
!isRecordingApproved(initialValues) &&
(!isLayingCategory || hasGradingData(initialValues)) && (
<div className='flex flex-row gap-2'>
<Button
variant='outline'
color='success'
onClick={() => {
setApprovalNotes('');
approveModal.openModal();
}}
isLoading={isApproveLoading}
className='w-full sm:w-fit'
>
<Icon
icon='material-symbols:check'
width={24}
height={24}
/>
Approve
</Button>
{type === 'detail' && !isRecordingApproved(initialValues) && (
<div className='flex flex-row gap-2'>
<Button
variant='outline'
color='success'
onClick={() => {
setApprovalNotes('');
approveModal.openModal();
}}
isLoading={isApproveLoading}
className='w-full sm:w-fit'
>
<Icon icon='material-symbols:check' width={24} height={24} />
Approve
</Button>
<Button
variant='outline'
color='error'
onClick={() => {
setApprovalNotes('');
rejectModal.openModal();
}}
isLoading={isRejectLoading}
className='w-full sm:w-fit'
>
<Icon
icon='material-symbols:close'
width={24}
height={24}
/>
Reject
</Button>
</div>
)}
<Button
variant='outline'
color='error'
onClick={() => {
setApprovalNotes('');
rejectModal.openModal();
}}
isLoading={isRejectLoading}
className='w-full sm:w-fit'
>
<Icon icon='material-symbols:close' width={24} height={24} />
Reject
</Button>
</div>
)}
</div>
<h1 className='text-2xl font-bold text-center'>
@@ -1928,7 +1820,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
{formik.values.body_weights?.map((bw, idx) => (
<tr key={`body-weight-${idx}`}>
{(type as 'add' | 'edit' | 'detail') !== 'detail' && (
<td className='!align-middle'>
<td className='align-middle!'>
<CheckboxInput
name={`body-weight-${idx}`}
checked={selectedBodyWeights.includes(idx)}
@@ -2178,7 +2070,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
{formik.values.stocks?.map((stock, idx) => (
<tr key={`stock-${idx}`}>
{(type as 'add' | 'edit' | 'detail') !== 'detail' && (
<td className='!align-middle'>
<td className='align-middle!'>
<CheckboxInput
name={`stock-${idx}`}
checked={selectedStocks.includes(idx)}
@@ -2398,7 +2290,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
{formik.values.depletions?.map((depletion, idx) => (
<tr key={`depletion-${idx}`}>
{(type as 'add' | 'edit' | 'detail') !== 'detail' && (
<td className='!align-middle'>
<td className='align-middle!'>
<CheckboxInput
name={`depletion-${idx}`}
checked={selectedDepletions.includes(idx)}
@@ -2618,7 +2510,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
(egg, idx) => (
<tr key={`egg-${idx}`}>
{(type as 'add' | 'edit' | 'detail') !== 'detail' && (
<td className='!align-middle'>
<td className='align-middle!'>
<CheckboxInput
name={`egg-${idx}`}
checked={selectedEggs.includes(idx)}
@@ -2823,46 +2715,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
</div>
{/* Right side actions */}
<div className='flex flex-col sm:flex-row sm:justify-end gap-2 w-full sm:w-auto'>
{type === 'detail' && isLayingCategory && (
<Tooltip
content={
hasConsumableEggsInCurrentRecording
? 'Lanjut ke proses grading untuk telur konsumsi baik'
: 'Hanya bisa melanjutkan ke grading jika ada Telur Konsumsi Baik'
}
position='left'
color={
hasConsumableEggsInCurrentRecording ? 'info' : 'warning'
}
>
<Button
type='button'
color='primary'
disabled={!hasConsumableEggsInCurrentRecording}
className='w-full sm:w-auto'
onClick={() => {
const recordingId =
newRecordingData?.id || initialValues?.id;
if (recordingId) {
router.push(
`/production/recording/grading/add?recording_id=${recordingId}`
);
} else {
toast.error(
'Recording ID tidak ditemukan. Silakan refresh halaman.'
);
}
}}
>
<Icon icon='material-symbols:egg' width={24} height={24} />
{hasGradingData(initialValues) ||
hasGradingData(newRecordingData || undefined)
? 'Edit Grading'
: 'Lanjut ke Grading'}
</Button>
</Tooltip>
)}
{type === 'edit' && (
<div className='flex flex-col sm:flex-row gap-2 w-full sm:w-auto'>
<Button
@@ -2951,8 +2803,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
{/* Approve Confirmation Modal */}
{(type as 'add' | 'edit' | 'detail') === 'detail' &&
!isRecordingApproved(initialValues) &&
(!isLayingCategory || hasGradingData(initialValues)) && (
!isRecordingApproved(initialValues) && (
<ConfirmationModalWithNotes
ref={approveModal.ref}
type='success'
@@ -2974,8 +2825,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
{/* Reject Confirmation Modal */}
{(type as 'add' | 'edit' | 'detail') === 'detail' &&
!isRecordingApproved(initialValues) &&
(!isLayingCategory || hasGradingData(initialValues)) && (
!isRecordingApproved(initialValues) && (
<ConfirmationModalWithNotes
ref={rejectModal.ref}
type='error'