mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-25 15:55:48 +00:00
feat(FE-170,174): refactor GradingForm to use grading form handlers and remove approval logic
This commit is contained in:
@@ -35,7 +35,7 @@ const AddGrading = () => {
|
|||||||
{(!recordingId ||
|
{(!recordingId ||
|
||||||
recordingId === 'new' ||
|
recordingId === 'new' ||
|
||||||
(!isLoadingRecording && recording && isResponseSuccess(recording))) && (
|
(!isLoadingRecording && recording && isResponseSuccess(recording))) && (
|
||||||
<GradingForm type='add' recordingData={isResponseSuccess(recording) ? recording.data : undefined} />
|
<GradingForm type='add' initialValues={isResponseSuccess(recording) ? recording.data?.recording_eggs?.[0] : undefined} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -41,8 +41,9 @@ const EditGrading = () => {
|
|||||||
{!isLoadingRecording && recording && isResponseSuccess(recording) && (
|
{!isLoadingRecording && recording && isResponseSuccess(recording) && (
|
||||||
<GradingForm
|
<GradingForm
|
||||||
type='edit'
|
type='edit'
|
||||||
initialValues={recording.data.recording_eggs?.find(egg => egg.id === parseInt(gradingId || '0'))}
|
initialValues={recording.data.recording_eggs?.find(
|
||||||
recordingData={recording.data}
|
(egg) => egg.id === parseInt(gradingId || '0')
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -40,8 +40,9 @@ const DetailGrading = () => {
|
|||||||
{!isLoadingGrading && grading && isResponseSuccess(grading) && (
|
{!isLoadingGrading && grading && isResponseSuccess(grading) && (
|
||||||
<GradingForm
|
<GradingForm
|
||||||
type='detail'
|
type='detail'
|
||||||
initialValues={grading.data.recording_eggs?.find(egg => egg.id === parseInt(gradingId))}
|
initialValues={grading.data.recording_eggs?.find(
|
||||||
recordingData={grading.data}
|
(egg) => egg.id === parseInt(gradingId)
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,39 +15,31 @@ import { FormHeader } from '@/components/helper/form/FormHeader';
|
|||||||
import { RecordingApi } from '@/services/api/production';
|
import { RecordingApi } from '@/services/api/production';
|
||||||
import {
|
import {
|
||||||
CreateGradingPayload,
|
CreateGradingPayload,
|
||||||
Recording,
|
UpdateGradingPayload,
|
||||||
RecordingEgg,
|
RecordingEgg,
|
||||||
GradingEgg,
|
GradingEgg,
|
||||||
} from '@/types/api/production/recording';
|
} from '@/types/api/production/recording';
|
||||||
import { type BaseApiResponse, FormStepStatus } from '@/types/api/api-general';
|
import { type FormStepStatus } from '@/types/api/api-general';
|
||||||
import {
|
import {
|
||||||
RecordingGradingFormSchema,
|
RecordingGradingFormSchema,
|
||||||
RecordingGradingFormValues,
|
RecordingGradingFormValues,
|
||||||
UpdateRecordingGradingFormSchema,
|
UpdateRecordingGradingFormSchema,
|
||||||
getRecordingGradingFormInitialValues,
|
getRecordingGradingFormInitialValues,
|
||||||
} from '../../form/RecordingForm.schema';
|
} from '../../form/RecordingForm.schema';
|
||||||
import { useRecordingFormHandlers } from '../../form/useRecordingFormHandlers';
|
|
||||||
import { ProductWarehouseApi } from '@/services/api/inventory';
|
|
||||||
import { isResponseSuccess } from '@/lib/api-helper';
|
|
||||||
import { cn } from '@/lib/helper';
|
import { cn } from '@/lib/helper';
|
||||||
import { useModal } from '@/components/Modal';
|
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
|
|
||||||
import Card from '@/components/Card';
|
import Card from '@/components/Card';
|
||||||
import Badge from '@/components/Badge';
|
|
||||||
import StepItem from '@/components/steps/StepItem';
|
import StepItem from '@/components/steps/StepItem';
|
||||||
|
import { useModal } from '@/components/Modal';
|
||||||
|
import { useGradingFormHandlers } from './useGradingFormHandlers';
|
||||||
|
|
||||||
interface GradingFormProps {
|
interface GradingFormProps {
|
||||||
type?: 'add' | 'edit' | 'detail';
|
type?: 'add' | 'edit' | 'detail';
|
||||||
initialValues?: RecordingEgg & { grading_eggs?: GradingEgg[] };
|
initialValues?: RecordingEgg & { grading_eggs?: GradingEgg[] };
|
||||||
recordingData?: Recording;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const GradingForm = ({
|
const GradingForm = ({ type = 'add', initialValues }: GradingFormProps) => {
|
||||||
type = 'add',
|
|
||||||
initialValues,
|
|
||||||
recordingData,
|
|
||||||
}: GradingFormProps) => {
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const recordingId = searchParams.get('recording_id');
|
const recordingId = searchParams.get('recording_id');
|
||||||
@@ -55,64 +47,45 @@ const GradingForm = ({
|
|||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
const [isApproveLoading, setIsApproveLoading] = useState(false);
|
|
||||||
const [isRejectLoading, setIsRejectLoading] = useState(false);
|
|
||||||
const [formSteps, setFormSteps] = useState<FormStepStatus[] | null>(null);
|
const [formSteps, setFormSteps] = useState<FormStepStatus[] | null>(null);
|
||||||
|
|
||||||
const approveModal = useModal();
|
|
||||||
const rejectModal = useModal();
|
|
||||||
|
|
||||||
// ===== API DATA FETCHING =====
|
// ===== API DATA FETCHING =====
|
||||||
const eggProductsUrl = useMemo(() => {
|
// Fetch existing gradings for the recording egg to show recorded data
|
||||||
if (!recordingData?.project_flock_kandangs_id) return null;
|
// Optional: Fetch existing gradings if needed for display purposes
|
||||||
const params = new URLSearchParams({
|
// const existingGradingsUrl = useMemo(() => {
|
||||||
search: '',
|
// const recordingEggIdToUse = recordingId || initialValues?.id?.toString();
|
||||||
location_id: recordingData.project_flock_kandangs_id.toString(),
|
// if (!recordingEggIdToUse) return null;
|
||||||
});
|
// return `${RecordingApi.basePath}/gradings?recording_egg_id=${recordingEggIdToUse}`;
|
||||||
return `${ProductWarehouseApi.basePath}?${params.toString()}`;
|
// }, [recordingId, initialValues]);
|
||||||
}, [recordingData]);
|
|
||||||
|
|
||||||
const { data: eggProductsData, isLoading: isLoadingEggProducts } = useSWR(
|
// const { data: existingGradings } = useSWR(
|
||||||
eggProductsUrl,
|
// existingGradingsUrl,
|
||||||
ProductWarehouseApi.getAllFetcher
|
// existingGradingsUrl ? RecordingApi.getAllFetcher : null
|
||||||
);
|
// );
|
||||||
|
|
||||||
// ===== DATA PROCESSING =====
|
// ===== DATA PROCESSING =====
|
||||||
const eggProducts = useMemo(() => {
|
// No data processing needed - grading form only needs recording_egg_id and grading data
|
||||||
const options: OptionType[] = [];
|
|
||||||
if (isResponseSuccess(eggProductsData)) {
|
|
||||||
eggProductsData.data.forEach((product) => {
|
|
||||||
const productName = product.product.name;
|
|
||||||
|
|
||||||
if (
|
|
||||||
productName.toLowerCase().includes('telur') ||
|
|
||||||
productName.toLowerCase().includes('egg')
|
|
||||||
) {
|
|
||||||
options.push({
|
|
||||||
value: product.id,
|
|
||||||
label: product.product.name,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}, [eggProductsData]);
|
|
||||||
|
|
||||||
// ===== FORM HANDLERS =====
|
// ===== FORM HANDLERS =====
|
||||||
const {
|
const {
|
||||||
deleteModal,
|
deleteModal,
|
||||||
recordingFormErrorMessage,
|
recordingFormErrorMessage,
|
||||||
isDeleteLoading,
|
isDeleteLoading,
|
||||||
createRecordingHandler,
|
createGradingHandler,
|
||||||
updateRecordingHandler,
|
updateGradingHandler,
|
||||||
deleteRecordingClickHandler,
|
deleteRecordingClickHandler,
|
||||||
confirmationModalDeleteClickHandler,
|
confirmationModalDeleteClickHandler,
|
||||||
} = useRecordingFormHandlers(initialValues?.id);
|
} = useGradingFormHandlers(initialValues?.id);
|
||||||
|
|
||||||
const formikInitialValues = useMemo(() => {
|
const formikInitialValues = useMemo(() => {
|
||||||
|
let recordingEggId: number | undefined = initialValues?.id;
|
||||||
|
|
||||||
|
if (!recordingEggId) {
|
||||||
|
recordingEggId = parseInt(recordingId || '0') || 0;
|
||||||
|
}
|
||||||
|
|
||||||
return getRecordingGradingFormInitialValues({
|
return getRecordingGradingFormInitialValues({
|
||||||
recording_egg_id: initialValues?.id || parseInt(recordingId || '0') || 0,
|
recording_egg_id: recordingEggId,
|
||||||
eggs_grading:
|
eggs_grading:
|
||||||
initialValues?.grading_eggs?.map((grading: GradingEgg) => ({
|
initialValues?.grading_eggs?.map((grading: GradingEgg) => ({
|
||||||
grade: grading.grade,
|
grade: grading.grade,
|
||||||
@@ -141,74 +114,19 @@ const GradingForm = ({
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'add':
|
case 'add':
|
||||||
await createRecordingHandler(gradingPayload as CreateGradingPayload);
|
await createGradingHandler(gradingPayload as CreateGradingPayload);
|
||||||
break;
|
break;
|
||||||
case 'edit':
|
case 'edit':
|
||||||
await updateRecordingHandler(
|
await updateGradingHandler(
|
||||||
initialValues?.id as number,
|
initialValues?.id as number,
|
||||||
gradingPayload as CreateGradingPayload
|
gradingPayload as UpdateGradingPayload
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// ===== EVENT HANDLERS =====
|
// Grading form doesn't need approval/reject handlers
|
||||||
const approveHandler = async () => {
|
|
||||||
setIsApproveLoading(true);
|
|
||||||
|
|
||||||
const approveResponse = await RecordingApi.customRequest<
|
|
||||||
BaseApiResponse<Recording[]>
|
|
||||||
>('approvals', {
|
|
||||||
method: 'POST',
|
|
||||||
payload: {
|
|
||||||
action: 'APPROVED',
|
|
||||||
approvable_ids: [initialValues?.id as number],
|
|
||||||
notes: 'Approved via Grading Form',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isResponseSuccess(approveResponse)) {
|
|
||||||
toast.success('Grading berhasil disetujui!');
|
|
||||||
approveModal.closeModal();
|
|
||||||
router.push('/production/recording');
|
|
||||||
} else {
|
|
||||||
toast.error(
|
|
||||||
(approveResponse?.message as string) || 'Gagal menyetujui grading'
|
|
||||||
);
|
|
||||||
approveModal.closeModal();
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsApproveLoading(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const rejectHandler = async () => {
|
|
||||||
setIsRejectLoading(true);
|
|
||||||
|
|
||||||
const rejectResponse = await RecordingApi.customRequest<
|
|
||||||
BaseApiResponse<Recording[]>
|
|
||||||
>('approvals', {
|
|
||||||
method: 'POST',
|
|
||||||
payload: {
|
|
||||||
action: 'REJECTED',
|
|
||||||
approvable_ids: [initialValues?.id as number],
|
|
||||||
notes: 'Rejected via Grading Form',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isResponseSuccess(rejectResponse)) {
|
|
||||||
toast.success('Grading berhasil ditolak!');
|
|
||||||
rejectModal.closeModal();
|
|
||||||
router.push('/production/recording');
|
|
||||||
} else {
|
|
||||||
toast.error(
|
|
||||||
(rejectResponse?.message as string) || 'Gagal menolak grading'
|
|
||||||
);
|
|
||||||
rejectModal.closeModal();
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsRejectLoading(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Grading Handlers
|
// Grading Handlers
|
||||||
const addGrading = () => {
|
const addGrading = () => {
|
||||||
@@ -309,6 +227,8 @@ const GradingForm = ({
|
|||||||
}
|
}
|
||||||
}, [formik]);
|
}, [formik]);
|
||||||
|
|
||||||
|
// Grading form doesn't need loading state since it only depends on recording_egg_id
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<section className='w-full'>
|
<section className='w-full'>
|
||||||
@@ -394,9 +314,9 @@ const GradingForm = ({
|
|||||||
: 'grid grid-cols-3 gap-4'
|
: 'grid grid-cols-3 gap-4'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{type === 'detail' && recordingData ? (
|
{type === 'detail' && initialValues ? (
|
||||||
<>
|
<>
|
||||||
<span>Recording ID</span>#{recordingData.id}
|
<span>Recording Egg ID</span>#{initialValues.id}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
@@ -641,40 +561,6 @@ const GradingForm = ({
|
|||||||
Edit
|
Edit
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{type === 'detail' && (
|
|
||||||
<>
|
|
||||||
<Button
|
|
||||||
type='button'
|
|
||||||
color='success'
|
|
||||||
onClick={() => approveModal.openModal()}
|
|
||||||
className='px-4'
|
|
||||||
isLoading={isApproveLoading}
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
icon='material-symbols:check-circle-outline'
|
|
||||||
width={24}
|
|
||||||
height={24}
|
|
||||||
className='justify-start text-sm'
|
|
||||||
/>
|
|
||||||
Approve
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type='button'
|
|
||||||
color='error'
|
|
||||||
onClick={() => rejectModal.openModal()}
|
|
||||||
className='px-4'
|
|
||||||
isLoading={isRejectLoading}
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
icon='material-symbols:cancel-outline'
|
|
||||||
width={24}
|
|
||||||
height={24}
|
|
||||||
className='justify-start text-sm'
|
|
||||||
/>
|
|
||||||
Reject
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{type !== 'detail' && (
|
{type !== 'detail' && (
|
||||||
@@ -735,42 +621,6 @@ const GradingForm = ({
|
|||||||
onClick: confirmationModalDeleteClickHandler,
|
onClick: confirmationModalDeleteClickHandler,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Approve Confirmation Modal */}
|
|
||||||
{type === 'detail' && (
|
|
||||||
<ConfirmationModal
|
|
||||||
ref={approveModal.ref}
|
|
||||||
type='success'
|
|
||||||
text='Apakah anda yakin ingin menyetujui data Grading ini?'
|
|
||||||
secondaryButton={{
|
|
||||||
text: 'Tidak',
|
|
||||||
}}
|
|
||||||
primaryButton={{
|
|
||||||
text: 'Ya',
|
|
||||||
color: 'success',
|
|
||||||
isLoading: isApproveLoading,
|
|
||||||
onClick: approveHandler,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Reject Confirmation Modal */}
|
|
||||||
{type === 'detail' && (
|
|
||||||
<ConfirmationModal
|
|
||||||
ref={rejectModal.ref}
|
|
||||||
type='error'
|
|
||||||
text='Apakah anda yakin ingin menolak data Grading ini?'
|
|
||||||
secondaryButton={{
|
|
||||||
text: 'Tidak',
|
|
||||||
}}
|
|
||||||
primaryButton={{
|
|
||||||
text: 'Ya',
|
|
||||||
color: 'error',
|
|
||||||
isLoading: isRejectLoading,
|
|
||||||
onClick: rejectHandler,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
Reference in New Issue
Block a user