feat(FE-170,175): implement payload creation for growing and laying recordings in RecordingForm

This commit is contained in:
rstubryan
2025-11-06 23:27:46 +07:00
parent 2e5530cf91
commit f032f71136
@@ -89,6 +89,9 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
const [recordingFormErrorMessage, setRecordingFormErrorMessage] =
useState('');
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const [newRecordingData, setNewRecordingData] = useState<Recording | null>(
null
);
const approveModal = useModal();
const rejectModal = useModal();
@@ -112,6 +115,71 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
);
}, []);
// ===== PAYLOAD CREATION HELPERS =====
const createGrowingPayload = useCallback(
(values: RecordingGrowingFormValues) => {
return {
project_flock_kandang_id: values.project_flock_kandang_id,
body_weights: (values.body_weights ?? []).map((bw) => {
const qty = Number(bw.qty) || 0;
const weight = Number(bw.weight) || 0;
const totalWeight = qty * weight;
return {
avg_weight:
typeof bw.avg_weight === 'number'
? bw.avg_weight
: parseFloat(String(bw.avg_weight)) || 0,
qty: qty,
total_weight: parseFloat(String(totalWeight)) || 0,
};
}),
stocks: (values.stocks ?? []).map((stock) => ({
product_warehouse_id: stock.product_warehouse_id,
qty: Number(stock.qty) || 0,
})),
depletions: (values.depletions ?? []).map((depletion) => ({
product_warehouse_id: depletion.product_warehouse_id,
qty: Number(depletion.qty) || 0,
})),
};
},
[]
);
const createLayingPayload = useCallback(
(values: RecordingLayingFormValues) => {
return {
project_flock_kandang_id: values.project_flock_kandang_id,
body_weights: (values.body_weights ?? []).map((bw) => {
const qty = Number(bw.qty) || 0;
const weight = Number(bw.weight) || 0;
const totalWeight = qty * weight;
return {
avg_weight:
typeof bw.avg_weight === 'number'
? bw.avg_weight
: parseFloat(String(bw.avg_weight)) || 0,
qty: qty,
total_weight: parseFloat(String(totalWeight)) || 0,
};
}),
stocks: (values.stocks ?? []).map((stock) => ({
product_warehouse_id: stock.product_warehouse_id,
qty: Number(stock.qty) || 0,
})),
depletions: (values.depletions ?? []).map((depletion) => ({
product_warehouse_id: depletion.product_warehouse_id,
qty: Number(depletion.qty) || 0,
})),
eggs: (values.eggs ?? []).map((egg) => ({
product_warehouse_id: egg.product_warehouse_id,
qty: Number(egg.qty) || 0,
})),
};
},
[]
);
// ===== FORM HANDLERS =====
const createRecordingHandler = useCallback(
async (
@@ -128,6 +196,35 @@ 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,
@@ -370,7 +467,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
const recordedProjectFlockKandangIds = useMemo(() => {
if (!isResponseSuccess(existingRecordings)) return new Set<number>();
const todayRecordings = existingRecordings?.data || [];
const todayRecordings = existingRecordings.data;
const recordedIds = new Set<number>();
todayRecordings.forEach((recording) => {
@@ -558,36 +655,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
onSubmit: async (values) => {
if (isLayingCategory) {
const layingValues = values as RecordingLayingFormValues;
const layingPayload = {
project_flock_kandang_id: layingValues.project_flock_kandang_id,
body_weights: (layingValues.body_weights ?? []).map((bw) => {
const qty = Number(bw.qty) || 0;
const weight = Number(bw.weight) || 0;
const totalWeight = qty * weight;
return {
avg_weight:
typeof bw.avg_weight === 'number'
? bw.avg_weight
: parseFloat(String(bw.avg_weight)) || 0,
qty: qty,
total_weight: parseFloat(String(totalWeight)) || 0,
};
}),
stocks: (layingValues.stocks ?? []).map((stock) => ({
product_warehouse_id: stock.product_warehouse_id,
qty: Number(stock.qty) || 0,
})),
depletions: (layingValues.depletions ?? []).map((depletion) => ({
product_warehouse_id: depletion.product_warehouse_id,
qty: Number(depletion.qty) || 0,
})),
eggs: (layingValues.eggs ?? []).map((egg) => ({
product_warehouse_id: egg.product_warehouse_id,
qty: Number(egg.qty) || 0,
})),
};
const layingPayload = createLayingPayload(layingValues);
switch (type) {
case 'add':
@@ -604,32 +672,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
}
} else {
const growingValues = values as RecordingGrowingFormValues;
const growingPayload = {
project_flock_kandang_id: growingValues.project_flock_kandang_id,
body_weights: (growingValues.body_weights ?? []).map((bw) => {
const qty = Number(bw.qty) || 0;
const weight = Number(bw.weight) || 0;
const totalWeight = qty * weight;
return {
avg_weight:
typeof bw.avg_weight === 'number'
? bw.avg_weight
: parseFloat(String(bw.avg_weight)) || 0,
qty: qty,
total_weight: parseFloat(String(totalWeight)) || 0,
};
}),
stocks: (growingValues.stocks ?? []).map((stock) => ({
product_warehouse_id: stock.product_warehouse_id,
qty: Number(stock.qty) || 0,
})),
depletions: (growingValues.depletions ?? []).map((depletion) => ({
product_warehouse_id: depletion.product_warehouse_id,
qty: Number(depletion.qty) || 0,
})),
};
const growingPayload = createGrowingPayload(growingValues);
switch (type) {
case 'add':
@@ -1243,6 +1286,9 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
} else {
setFormSteps(null);
}
if (type !== 'add') {
setNewRecordingData(null);
}
}, [isLayingCategory, type]);
const bodyWeightValues = useMemo(() => {
@@ -2464,13 +2510,22 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
type='button'
color='primary'
onClick={() => {
router.push(
`/production/recording/grading/add?recording_id=${initialValues?.id}`
);
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(initialValues) ||
hasGradingData(newRecordingData || undefined)
? 'Edit Grading'
: 'Lanjut ke Grading'}
</Button>
@@ -2536,20 +2591,45 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
formik.isSubmitting
}
onClick={async () => {
await formik.submitForm();
if (
formik.isValid &&
!formik.isSubmitting &&
!hasExceededStock
) {
toast.success(
'Recording berhasil disimpan! Mengalihkan ke form Grading...'
if (!formik.isValid) {
await formik.validateForm();
return;
}
setRecordingFormErrorMessage('');
formik.setSubmitting(true);
try {
if (isLayingCategory) {
const layingValues =
formik.values as RecordingLayingFormValues;
const layingPayload =
createLayingPayload(layingValues);
const recordingData =
await createRecordingHandlerWithRedirect(
layingPayload as CreateLayingRecordingPayload,
true
);
if (recordingData?.id) {
toast.success(
'Recording berhasil disimpan! Mengalihkan ke form Grading...'
);
setTimeout(() => {
router.push(
`/production/recording/grading/add?recording_id=${recordingData.id}`
);
}, 1000);
}
}
} catch (error) {
console.error('Error creating recording:', error);
toast.error(
'Gagal membuat recording. Silakan coba lagi.'
);
setTimeout(() => {
router.push(
`/production/recording/grading/add?recording_id=${initialValues?.id || ''}`
);
}, 1000);
} finally {
formik.setSubmitting(false);
}
}}
>