mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
refactor(FE-174): enhance GradingForm and RecordingForm with improved error handling and modal integration for delete actions
This commit is contained in:
@@ -31,11 +31,10 @@ import {
|
||||
UpdateRecordingGrowingFormSchema,
|
||||
UpdateRecordingLayingFormSchema,
|
||||
} from './RecordingForm.schema';
|
||||
import { useRecordingFormHandlers } from './useRecordingFormHandlers';
|
||||
import { ProjectFlockApi } from '@/services/api/production';
|
||||
import { LocationApi } from '@/services/api/master-data';
|
||||
import { ProductWarehouseApi } from '@/services/api/inventory';
|
||||
import { isResponseSuccess } from '@/lib/api-helper';
|
||||
import { isResponseSuccess, isResponseError } from '@/lib/api-helper';
|
||||
import { cn } from '@/lib/helper';
|
||||
import { ProjectFlockKandangLookup } from '@/types/api/production/project-flock';
|
||||
import { useModal } from '@/components/Modal';
|
||||
@@ -77,9 +76,61 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
const [isApproveLoading, setIsApproveLoading] = useState(false);
|
||||
const [isRejectLoading, setIsRejectLoading] = useState(false);
|
||||
const [formSteps, setFormSteps] = useState<FormStepStatus[] | null>(null);
|
||||
const [recordingFormErrorMessage, setRecordingFormErrorMessage] =
|
||||
useState('');
|
||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||
|
||||
const approveModal = useModal();
|
||||
const rejectModal = useModal();
|
||||
const deleteModal = useModal();
|
||||
|
||||
// ===== FORM HANDLERS =====
|
||||
const createRecordingHandler = useCallback(
|
||||
async (
|
||||
payload: CreateGrowingRecordingPayload | CreateLayingRecordingPayload
|
||||
) => {
|
||||
const res = await RecordingApi.create(payload);
|
||||
if (isResponseError(res)) {
|
||||
setRecordingFormErrorMessage(res.message);
|
||||
return;
|
||||
}
|
||||
toast.success(res?.message as string);
|
||||
router.push('/production/recording');
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const updateRecordingHandler = useCallback(
|
||||
async (
|
||||
recordingId: number,
|
||||
payload: UpdateGrowingRecordingPayload | UpdateLayingRecordingPayload
|
||||
) => {
|
||||
const res = await RecordingApi.update(recordingId, payload);
|
||||
if (res?.status === 'error') {
|
||||
setRecordingFormErrorMessage(res.message);
|
||||
return;
|
||||
}
|
||||
toast.success(res?.message as string);
|
||||
router.refresh();
|
||||
router.push('/production/recording');
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const deleteRecordingClickHandler = useCallback(() => {
|
||||
deleteModal.openModal();
|
||||
}, [deleteModal]);
|
||||
|
||||
const confirmationModalDeleteClickHandler = useCallback(async () => {
|
||||
if (!initialValues?.id) return;
|
||||
|
||||
setIsDeleteLoading(true);
|
||||
await RecordingApi.delete(initialValues.id);
|
||||
deleteModal.closeModal();
|
||||
toast.success('Successfully delete Recording!');
|
||||
setIsDeleteLoading(false);
|
||||
router.push('/production/recording');
|
||||
}, [deleteModal, initialValues?.id, router]);
|
||||
|
||||
// ===== API DATA FETCHING =====
|
||||
const locationsUrl = `${LocationApi.basePath}?${new URLSearchParams({
|
||||
@@ -336,17 +387,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
return options;
|
||||
}, [eggProductsData]);
|
||||
|
||||
// ===== FORM HANDLERS =====
|
||||
const {
|
||||
deleteModal,
|
||||
recordingFormErrorMessage,
|
||||
isDeleteLoading,
|
||||
createRecordingHandler,
|
||||
updateRecordingHandler,
|
||||
deleteRecordingClickHandler,
|
||||
confirmationModalDeleteClickHandler,
|
||||
} = useRecordingFormHandlers(initialValues?.id);
|
||||
|
||||
const isLayingCategory =
|
||||
projectFlockKandangLookup?.project_flock?.category === 'LAYING';
|
||||
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { useModal } from '@/components/Modal';
|
||||
import { RecordingApi } from '@/services/api/production';
|
||||
import {
|
||||
CreateRecordingPayload,
|
||||
UpdateRecordingPayload,
|
||||
} from '@/types/api/production/recording';
|
||||
import { isResponseError } from '@/lib/api-helper';
|
||||
|
||||
export const useRecordingFormHandlers = (initialValuesId?: number) => {
|
||||
const router = useRouter();
|
||||
const deleteModal = useModal();
|
||||
const [recordingFormErrorMessage, setRecordingFormErrorMessage] =
|
||||
useState('');
|
||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||
|
||||
const createRecordingHandler = useCallback(
|
||||
async (payload: CreateRecordingPayload) => {
|
||||
const res = await RecordingApi.create(payload);
|
||||
if (isResponseError(res)) {
|
||||
setRecordingFormErrorMessage(res.message);
|
||||
return;
|
||||
}
|
||||
toast.success(res?.message as string);
|
||||
router.push('/production/recording');
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const updateRecordingHandler = useCallback(
|
||||
async (recordingId: number, payload: UpdateRecordingPayload) => {
|
||||
const res = await RecordingApi.update(recordingId, payload);
|
||||
if (res?.status === 'error') {
|
||||
setRecordingFormErrorMessage(res.message);
|
||||
return;
|
||||
}
|
||||
toast.success(res?.message as string);
|
||||
router.refresh();
|
||||
router.push('/production/recording');
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const deleteRecordingClickHandler = useCallback(() => {
|
||||
deleteModal.openModal();
|
||||
}, [deleteModal]);
|
||||
|
||||
const confirmationModalDeleteClickHandler = useCallback(async () => {
|
||||
if (!initialValuesId) return;
|
||||
|
||||
setIsDeleteLoading(true);
|
||||
await RecordingApi.delete(initialValuesId);
|
||||
deleteModal.closeModal();
|
||||
toast.success('Successfully delete Recording!');
|
||||
setIsDeleteLoading(false);
|
||||
router.push('/production/recording');
|
||||
}, [deleteModal, initialValuesId, router]);
|
||||
|
||||
return {
|
||||
deleteModal,
|
||||
recordingFormErrorMessage,
|
||||
isDeleteLoading,
|
||||
createRecordingHandler,
|
||||
updateRecordingHandler,
|
||||
deleteRecordingClickHandler,
|
||||
confirmationModalDeleteClickHandler,
|
||||
};
|
||||
};
|
||||
@@ -17,7 +17,10 @@ import {
|
||||
RecordingEgg,
|
||||
GradingEgg,
|
||||
} from '@/types/api/production/recording';
|
||||
import { type FormStepStatus } from '@/types/api/api-general';
|
||||
import {
|
||||
type FormStepStatus,
|
||||
type BaseApiResponse,
|
||||
} from '@/types/api/api-general';
|
||||
import {
|
||||
RecordingGradingFormSchema,
|
||||
RecordingGradingFormValues,
|
||||
@@ -26,10 +29,12 @@ import {
|
||||
} from '../../form/RecordingForm.schema';
|
||||
import { cn } from '@/lib/helper';
|
||||
import toast from 'react-hot-toast';
|
||||
import { RecordingApi } from '@/services/api/production';
|
||||
import { isResponseError } from '@/lib/api-helper';
|
||||
import { useModal } from '@/components/Modal';
|
||||
|
||||
import Card from '@/components/Card';
|
||||
import StepItem from '@/components/steps/StepItem';
|
||||
import { useGradingFormHandlers } from './useGradingFormHandlers';
|
||||
|
||||
interface GradingFormProps {
|
||||
type?: 'add' | 'edit' | 'detail';
|
||||
@@ -45,6 +50,9 @@ const GradingForm = ({ type = 'add', initialValues }: GradingFormProps) => {
|
||||
);
|
||||
|
||||
const [formSteps, setFormSteps] = useState<FormStepStatus[] | null>(null);
|
||||
const [gradingFormErrorMessage, setGradingFormErrorMessage] = useState('');
|
||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||
const deleteModal = useModal();
|
||||
|
||||
// ===== API DATA FETCHING =====
|
||||
// const existingGradingsUrl = useMemo(() => {
|
||||
@@ -61,15 +69,67 @@ const GradingForm = ({ type = 'add', initialValues }: GradingFormProps) => {
|
||||
// ===== DATA PROCESSING =====
|
||||
|
||||
// ===== FORM HANDLERS =====
|
||||
const {
|
||||
deleteModal,
|
||||
recordingFormErrorMessage,
|
||||
isDeleteLoading,
|
||||
createGradingHandler,
|
||||
updateGradingHandler,
|
||||
deleteRecordingClickHandler,
|
||||
confirmationModalDeleteClickHandler,
|
||||
} = useGradingFormHandlers(initialValues?.id);
|
||||
const createGradingHandler = useCallback(
|
||||
async (payload: CreateGradingPayload) => {
|
||||
const res = (await RecordingApi.createGrading(payload)) as
|
||||
| BaseApiResponse<unknown>
|
||||
| undefined;
|
||||
|
||||
if (!res || isResponseError(res)) {
|
||||
setGradingFormErrorMessage(res?.message || 'Failed to add Grading');
|
||||
return;
|
||||
}
|
||||
|
||||
toast.success(res?.message || 'Successfully added Grading!');
|
||||
router.push('/production/recording');
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const updateGradingHandler = useCallback(
|
||||
async (gradingId: number, payload: UpdateGradingPayload) => {
|
||||
const res = (await RecordingApi.updateGrading(gradingId, payload)) as
|
||||
| BaseApiResponse<unknown>
|
||||
| undefined;
|
||||
|
||||
if (!res || isResponseError(res)) {
|
||||
setGradingFormErrorMessage(res?.message || 'Failed to update Grading');
|
||||
return;
|
||||
}
|
||||
toast.success(res?.message || 'Successfully updated Grading!');
|
||||
router.refresh();
|
||||
router.push('/production/recording');
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const deleteRecordingClickHandler = useCallback(() => {
|
||||
deleteModal.openModal();
|
||||
}, [deleteModal]);
|
||||
|
||||
const confirmationModalDeleteClickHandler = useCallback(async () => {
|
||||
if (!initialValues?.id) return;
|
||||
|
||||
setIsDeleteLoading(true);
|
||||
try {
|
||||
const res = (await RecordingApi.deleteGrading(initialValues.id)) as
|
||||
| BaseApiResponse<unknown>
|
||||
| undefined;
|
||||
|
||||
if (!res || isResponseError(res)) {
|
||||
setGradingFormErrorMessage(res?.message || 'Failed to delete Grading');
|
||||
return;
|
||||
}
|
||||
deleteModal.closeModal();
|
||||
toast.success(res?.message || 'Successfully delete Grading!');
|
||||
router.push('/production/recording');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setGradingFormErrorMessage('Failed to delete Grading');
|
||||
} finally {
|
||||
setIsDeleteLoading(false);
|
||||
}
|
||||
}, [deleteModal, initialValues?.id, router]);
|
||||
|
||||
const formikInitialValues = useMemo(() => {
|
||||
let recordingEggId: number | undefined = initialValues?.id;
|
||||
@@ -599,14 +659,14 @@ const GradingForm = ({ type = 'add', initialValues }: GradingFormProps) => {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{recordingFormErrorMessage && (
|
||||
{gradingFormErrorMessage && (
|
||||
<div role='alert' className='alert alert-error'>
|
||||
<Icon
|
||||
icon='material-symbols:error-outline'
|
||||
width={24}
|
||||
height={24}
|
||||
/>
|
||||
<span>{recordingFormErrorMessage}</span>
|
||||
<span>{gradingFormErrorMessage}</span>
|
||||
</div>
|
||||
)}
|
||||
</form>
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { useModal } from '@/components/Modal';
|
||||
import { RecordingApi } from '@/services/api/production';
|
||||
import {
|
||||
CreateGradingPayload,
|
||||
UpdateGradingPayload,
|
||||
} from '@/types/api/production/recording';
|
||||
import { isResponseError } from '@/lib/api-helper';
|
||||
import { type BaseApiResponse } from '@/types/api/api-general';
|
||||
|
||||
export const useGradingFormHandlers = (gradingId?: number) => {
|
||||
const router = useRouter();
|
||||
const deleteModal = useModal();
|
||||
const [recordingFormErrorMessage, setRecordingFormErrorMessage] =
|
||||
useState('');
|
||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||
|
||||
const createGradingHandler = useCallback(
|
||||
async (payload: CreateGradingPayload) => {
|
||||
const res = (await RecordingApi.createGrading(payload)) as
|
||||
| BaseApiResponse<unknown>
|
||||
| undefined;
|
||||
|
||||
if (!res || isResponseError(res)) {
|
||||
setRecordingFormErrorMessage(res?.message || 'Failed to add Grading');
|
||||
return;
|
||||
}
|
||||
|
||||
toast.success(res?.message || 'Successfully added Grading!');
|
||||
router.push('/production/recording');
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const updateGradingHandler = useCallback(
|
||||
async (gradingId: number, payload: UpdateGradingPayload) => {
|
||||
const res = (await RecordingApi.updateGrading(gradingId, payload)) as
|
||||
| BaseApiResponse<unknown>
|
||||
| undefined;
|
||||
|
||||
if (!res || isResponseError(res)) {
|
||||
setRecordingFormErrorMessage(
|
||||
res?.message || 'Failed to update Grading'
|
||||
);
|
||||
return;
|
||||
}
|
||||
toast.success(res?.message || 'Successfully updated Grading!');
|
||||
router.refresh();
|
||||
router.push('/production/recording');
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const deleteRecordingClickHandler = useCallback(() => {
|
||||
deleteModal.openModal();
|
||||
}, [deleteModal]);
|
||||
|
||||
const confirmationModalDeleteClickHandler = useCallback(async () => {
|
||||
if (!gradingId) return;
|
||||
|
||||
setIsDeleteLoading(true);
|
||||
try {
|
||||
const res = (await RecordingApi.deleteGrading(gradingId)) as
|
||||
| BaseApiResponse<unknown>
|
||||
| undefined;
|
||||
|
||||
if (!res || isResponseError(res)) {
|
||||
setRecordingFormErrorMessage(
|
||||
res?.message || 'Failed to delete Grading'
|
||||
);
|
||||
return;
|
||||
}
|
||||
deleteModal.closeModal();
|
||||
toast.success(res?.message || 'Successfully delete Grading!');
|
||||
router.push('/production/recording');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setRecordingFormErrorMessage('Failed to delete Grading');
|
||||
} finally {
|
||||
setIsDeleteLoading(false);
|
||||
}
|
||||
}, [deleteModal, gradingId, router]);
|
||||
|
||||
return {
|
||||
deleteModal,
|
||||
recordingFormErrorMessage,
|
||||
isDeleteLoading,
|
||||
createGradingHandler,
|
||||
updateGradingHandler,
|
||||
deleteRecordingClickHandler,
|
||||
confirmationModalDeleteClickHandler,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user