mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
feat(FE-170,175): enhance GradingForm with total egg consumption display and validation for grading limits
This commit is contained in:
@@ -15,6 +15,7 @@ import {
|
|||||||
UpdateGradingPayload,
|
UpdateGradingPayload,
|
||||||
RecordingEgg,
|
RecordingEgg,
|
||||||
GradingEgg,
|
GradingEgg,
|
||||||
|
Recording,
|
||||||
} from '@/types/api/production/recording';
|
} from '@/types/api/production/recording';
|
||||||
import {
|
import {
|
||||||
type FormStepStatus,
|
type FormStepStatus,
|
||||||
@@ -31,6 +32,7 @@ import toast from 'react-hot-toast';
|
|||||||
import { RecordingApi } from '@/services/api/production';
|
import { RecordingApi } from '@/services/api/production';
|
||||||
import { isResponseError } from '@/lib/api-helper';
|
import { isResponseError } from '@/lib/api-helper';
|
||||||
import { useModal } from '@/components/Modal';
|
import { useModal } from '@/components/Modal';
|
||||||
|
import useSWR from 'swr';
|
||||||
|
|
||||||
import Card from '@/components/Card';
|
import Card from '@/components/Card';
|
||||||
import StepItem from '@/components/steps/StepItem';
|
import StepItem from '@/components/steps/StepItem';
|
||||||
@@ -54,18 +56,36 @@ const GradingForm = ({ type = 'add', initialValues }: GradingFormProps) => {
|
|||||||
const deleteModal = useModal();
|
const deleteModal = useModal();
|
||||||
|
|
||||||
// ===== API DATA FETCHING =====
|
// ===== API DATA FETCHING =====
|
||||||
// const existingGradingsUrl = useMemo(() => {
|
const recordingUrl = useMemo(() => {
|
||||||
// const recordingEggIdToUse = recordingId || initialValues?.id?.toString();
|
const recordingIdToUse = recordingId;
|
||||||
// if (!recordingEggIdToUse) return null;
|
if (!recordingIdToUse) return null;
|
||||||
// return `${RecordingApi.basePath}/gradings?recording_egg_id=${recordingEggIdToUse}`;
|
return `${RecordingApi.basePath}/${recordingIdToUse}`;
|
||||||
// }, [recordingId, initialValues]);
|
}, [recordingId]);
|
||||||
|
|
||||||
// const { data: existingGradings } = useSWR(
|
const { data: recordingData } = useSWR(
|
||||||
// existingGradingsUrl,
|
recordingUrl,
|
||||||
// existingGradingsUrl ? RecordingApi.getAllFetcher : null
|
recordingUrl ? RecordingApi.getAllFetcher : null
|
||||||
// );
|
);
|
||||||
|
|
||||||
// ===== DATA PROCESSING =====
|
// ===== 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 =====
|
// ===== FORM HANDLERS =====
|
||||||
const createGradingHandler = useCallback(
|
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 = () => {
|
const addGrading = () => {
|
||||||
let recordingEggId: number | undefined = initialValues?.id;
|
let recordingEggId: number | undefined = initialValues?.id;
|
||||||
|
|
||||||
@@ -385,7 +412,7 @@ const GradingForm = ({ type = 'add', initialValues }: GradingFormProps) => {
|
|||||||
className={
|
className={
|
||||||
type === 'detail'
|
type === 'detail'
|
||||||
? 'flex flex-col gap-6'
|
? 'flex flex-col gap-6'
|
||||||
: 'grid grid-cols-3 gap-4'
|
: 'grid grid-cols-2 gap-4'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{type === 'detail' && initialValues ? (
|
{type === 'detail' && initialValues ? (
|
||||||
@@ -398,6 +425,32 @@ const GradingForm = ({ type = 'add', initialValues }: GradingFormProps) => {
|
|||||||
{formik.values.eggs_grading?.[0]?.recording_egg_id || '-'}
|
{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>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
@@ -506,7 +559,6 @@ const GradingForm = ({ type = 'add', initialValues }: GradingFormProps) => {
|
|||||||
{ value: 'Grade B', label: 'Grade B' },
|
{ value: 'Grade B', label: 'Grade B' },
|
||||||
{ value: 'Grade C', label: 'Grade C' },
|
{ value: 'Grade C', label: 'Grade C' },
|
||||||
{ value: 'Grade D', label: 'Grade D' },
|
{ value: 'Grade D', label: 'Grade D' },
|
||||||
{ value: 'Extra', label: 'Extra' },
|
|
||||||
]}
|
]}
|
||||||
placeholder='Pilih Grade'
|
placeholder='Pilih Grade'
|
||||||
isError={
|
isError={
|
||||||
@@ -538,11 +590,14 @@ const GradingForm = ({ type = 'add', initialValues }: GradingFormProps) => {
|
|||||||
decimalSeparator='.'
|
decimalSeparator='.'
|
||||||
isError={
|
isError={
|
||||||
isRepeaterInputError('eggs_grading', 'qty', idx)
|
isRepeaterInputError('eggs_grading', 'qty', idx)
|
||||||
.isError
|
.isError || isGradingExceedsAvailable
|
||||||
}
|
}
|
||||||
errorMessage={
|
errorMessage={
|
||||||
isRepeaterInputError('eggs_grading', 'qty', idx)
|
isRepeaterInputError('eggs_grading', 'qty', idx)
|
||||||
.errorMessage
|
.errorMessage ||
|
||||||
|
(isGradingExceedsAvailable
|
||||||
|
? `Total grading melebihi available telur (${totalKonsumsiBaikEggs})`
|
||||||
|
: undefined)
|
||||||
}
|
}
|
||||||
readOnly={type === 'detail'}
|
readOnly={type === 'detail'}
|
||||||
className={{
|
className={{
|
||||||
@@ -660,10 +715,20 @@ const GradingForm = ({ type = 'add', initialValues }: GradingFormProps) => {
|
|||||||
color='primary'
|
color='primary'
|
||||||
className='px-4'
|
className='px-4'
|
||||||
isLoading={formik.isSubmitting}
|
isLoading={formik.isSubmitting}
|
||||||
disabled={!formik.isValid || formik.isSubmitting}
|
disabled={
|
||||||
|
!formik.isValid ||
|
||||||
|
formik.isSubmitting ||
|
||||||
|
isGradingExceedsAvailable
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
|
{isGradingExceedsAvailable && (
|
||||||
|
<div className='text-error text-sm mt-2 text-right'>
|
||||||
|
Total grading ({currentGradingTotal}) melebihi available
|
||||||
|
telur ({totalKonsumsiBaikEggs})
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user