feat(FE-170,175): enhance GradingForm with total egg consumption display and validation for grading limits

This commit is contained in:
rstubryan
2025-11-06 14:42:17 +07:00
parent 62c595bdf6
commit 501222a4ee
@@ -15,6 +15,7 @@ import {
UpdateGradingPayload,
RecordingEgg,
GradingEgg,
Recording,
} from '@/types/api/production/recording';
import {
type FormStepStatus,
@@ -31,6 +32,7 @@ import toast from 'react-hot-toast';
import { RecordingApi } from '@/services/api/production';
import { isResponseError } from '@/lib/api-helper';
import { useModal } from '@/components/Modal';
import useSWR from 'swr';
import Card from '@/components/Card';
import StepItem from '@/components/steps/StepItem';
@@ -54,18 +56,36 @@ const GradingForm = ({ type = 'add', initialValues }: GradingFormProps) => {
const deleteModal = useModal();
// ===== API DATA FETCHING =====
// const existingGradingsUrl = useMemo(() => {
// const recordingEggIdToUse = recordingId || initialValues?.id?.toString();
// if (!recordingEggIdToUse) return null;
// return `${RecordingApi.basePath}/gradings?recording_egg_id=${recordingEggIdToUse}`;
// }, [recordingId, initialValues]);
const recordingUrl = useMemo(() => {
const recordingIdToUse = recordingId;
if (!recordingIdToUse) return null;
return `${RecordingApi.basePath}/${recordingIdToUse}`;
}, [recordingId]);
// const { data: existingGradings } = useSWR(
// existingGradingsUrl,
// existingGradingsUrl ? RecordingApi.getAllFetcher : null
// );
const { data: recordingData } = useSWR(
recordingUrl,
recordingUrl ? RecordingApi.getAllFetcher : null
);
// ===== DATA PROCESSING =====
const recording =
recordingData?.status === 'success'
? (recordingData.data as unknown as Recording)
: undefined;
const konsumsiBaikEggData = useMemo(() => {
if (!recording?.eggs) return null;
const konsumsiBaikEgg = recording.eggs.find((egg: RecordingEgg) =>
egg.product_warehouse?.product?.name
?.toLowerCase()
.includes('konsumsi baik')
);
return konsumsiBaikEgg || null;
}, [recording]);
const totalKonsumsiBaikEggs = konsumsiBaikEggData?.qty || 0;
// ===== FORM HANDLERS =====
const createGradingHandler = useCallback(
@@ -180,7 +200,14 @@ const GradingForm = ({ type = 'add', initialValues }: GradingFormProps) => {
},
});
// Grading Handlers
const currentGradingTotal = useMemo(() => {
return (formik.values.eggs_grading || []).reduce((total, grading) => {
return total + (Number(grading.qty) || 0);
}, 0);
}, [formik.values.eggs_grading]);
const isGradingExceedsAvailable = currentGradingTotal > totalKonsumsiBaikEggs;
const addGrading = () => {
let recordingEggId: number | undefined = initialValues?.id;
@@ -385,7 +412,7 @@ const GradingForm = ({ type = 'add', initialValues }: GradingFormProps) => {
className={
type === 'detail'
? 'flex flex-col gap-6'
: 'grid grid-cols-3 gap-4'
: 'grid grid-cols-2 gap-4'
}
>
{type === 'detail' && initialValues ? (
@@ -398,6 +425,32 @@ const GradingForm = ({ type = 'add', initialValues }: GradingFormProps) => {
{formik.values.eggs_grading?.[0]?.recording_egg_id || '-'}
</>
)}
{/* Total Telur Konsumsi Baik Info */}
<div>
<span className='text-sm text-gray-600'>
Total Telur Konsumsi Baik
</span>
<div className='flex items-center gap-2'>
<p className='font-semibold text-lg'>
{totalKonsumsiBaikEggs}
</p>
<span className='text-sm text-gray-500'>telur</span>
</div>
<div className='flex items-center gap-2 mt-1'>
<span className='text-sm'>Total yang digrading:</span>
<span
className={`font-semibold ${isGradingExceedsAvailable ? 'text-error' : 'text-success'}`}
>
{currentGradingTotal} / {totalKonsumsiBaikEggs}
</span>
</div>
{isGradingExceedsAvailable && (
<div className='text-error text-sm mt-1'>
Total grading melebihi available telur!
</div>
)}
</div>
</div>
</Card>
@@ -506,7 +559,6 @@ const GradingForm = ({ type = 'add', initialValues }: GradingFormProps) => {
{ value: 'Grade B', label: 'Grade B' },
{ value: 'Grade C', label: 'Grade C' },
{ value: 'Grade D', label: 'Grade D' },
{ value: 'Extra', label: 'Extra' },
]}
placeholder='Pilih Grade'
isError={
@@ -538,11 +590,14 @@ const GradingForm = ({ type = 'add', initialValues }: GradingFormProps) => {
decimalSeparator='.'
isError={
isRepeaterInputError('eggs_grading', 'qty', idx)
.isError
.isError || isGradingExceedsAvailable
}
errorMessage={
isRepeaterInputError('eggs_grading', 'qty', idx)
.errorMessage
.errorMessage ||
(isGradingExceedsAvailable
? `Total grading melebihi available telur (${totalKonsumsiBaikEggs})`
: undefined)
}
readOnly={type === 'detail'}
className={{
@@ -660,10 +715,20 @@ const GradingForm = ({ type = 'add', initialValues }: GradingFormProps) => {
color='primary'
className='px-4'
isLoading={formik.isSubmitting}
disabled={!formik.isValid || formik.isSubmitting}
disabled={
!formik.isValid ||
formik.isSubmitting ||
isGradingExceedsAvailable
}
>
Submit
</Button>
{isGradingExceedsAvailable && (
<div className='text-error text-sm mt-2 text-right'>
Total grading ({currentGradingTotal}) melebihi available
telur ({totalKonsumsiBaikEggs})
</div>
)}
</div>
)}
</div>