feat(FE-316): Add Uniformity result drawer and flow

This commit is contained in:
rstubryan
2025-12-27 21:25:06 +07:00
parent 549a710a8d
commit 819b709f7e
5 changed files with 228 additions and 5 deletions
@@ -37,6 +37,7 @@ import { type BaseApiResponse } from '@/types/api/api-general';
import { ProjectFlockKandangLookup } from '@/types/api/production/project-flock';
import { Kandang } from '@/types/api/master-data/kandang';
import UniformityPreviewForm from '@/components/pages/uniformity/form/UniformityPreviewForm';
import UniformityResultForm from '@/components/pages/uniformity/form/UniformityResultForm';
import useSWR from 'swr';
import { cn } from '@/lib/helper';
@@ -63,6 +64,9 @@ const UniformityForm = ({
const setVerifyUniformityResult = useUiStore(
(s) => s.setVerifyUniformityResult
);
const setUniformityFormData = useUiStore((s) => s.setUniformityFormData);
const uniformityStep = useUiStore((s) => s.uniformityStep);
const setUniformityStep = useUiStore((s) => s.setUniformityStep);
const [uniformityFormErrorMessage, setUniformityFormErrorMessage] =
useState('');
@@ -230,6 +234,12 @@ const UniformityForm = ({
return;
}
setUniformityFormData({
date: values.date,
project_flock_kandang_id: projectFlockKandangId,
files: values.files as File,
});
const payload: VerifyUniformityPayload = {
project_flock_kandang_id: projectFlockKandangId,
files: values.files as File,
@@ -251,6 +261,7 @@ const UniformityForm = ({
if (formType === 'add') {
setIsNextStep(true);
setExpandedDrawerOpen(true);
setUniformityStep('preview');
} else {
router.push('/uniformity');
}
@@ -361,11 +372,15 @@ const UniformityForm = ({
useEffect(() => {
if (expandedDrawerOpen) {
setExpandedDrawerContent(<UniformityPreviewForm />);
if (uniformityStep === 'preview') {
setExpandedDrawerContent(<UniformityPreviewForm />);
} else if (uniformityStep === 'result') {
setExpandedDrawerContent(<UniformityResultForm />);
}
} else {
setExpandedDrawerContent(null);
}
}, [expandedDrawerOpen, setExpandedDrawerContent]);
}, [expandedDrawerOpen, uniformityStep, setExpandedDrawerContent]);
return (
<>
@@ -19,11 +19,17 @@ type BodyWeightData = {
const UniformityPreviewForm = () => {
const setExpandedDrawerOpen = useUiStore((s) => s.setExpandedDrawerOpen);
const setIsNextStep = useUiStore((s) => s.setIsNextStep);
const setUniformityStep = useUiStore((s) => s.setUniformityStep);
const verifyUniformityResult = useUiStore((s) => s.verifyUniformityResult);
const handleClose = () => {
setExpandedDrawerOpen(false);
setIsNextStep(false);
setUniformityStep('preview');
};
const handleNext = () => {
setUniformityStep('result');
};
const tableData = useMemo(() => {
@@ -87,9 +93,14 @@ const UniformityPreviewForm = () => {
<Table<BodyWeightData>
data={tableData}
columns={columns}
pageSize={20}
className={{ containerClassName: 'mb-10' }}
pageSize={15}
className={{ containerClassName: 'mb-5' }}
/>
<RequirePermission permissions='lti.production.uniformity.create'>
<Button color='primary' onClick={handleNext} className='mb-10'>
Next
</Button>
</RequirePermission>
</div>
) : (
<div className='flex flex-col items-center justify-center py-10 text-gray-400'>
@@ -0,0 +1,178 @@
'use client';
import React, { useMemo } from 'react';
import { Icon } from '@iconify/react';
import { ColumnDef } from '@tanstack/react-table';
import Button from '@/components/Button';
import Tooltip from '@/components/Tooltip';
import DrawerHeader from '@/components/helper/drawer/DrawerHeader';
import { useUiStore } from '@/stores/ui/ui.store';
import RequirePermission from '@/components/helper/RequirePermission';
import Table from '@/components/Table';
import { useRouter } from 'next/navigation';
import toast from 'react-hot-toast';
import { UniformityApi } from '@/services/api/uniformity';
import { isResponseError } from '@/lib/api-helper';
type BodyWeightData = {
id: string;
number: number;
weight: number;
};
const UniformityResultForm = () => {
const router = useRouter();
const setExpandedDrawerOpen = useUiStore((s) => s.setExpandedDrawerOpen);
const setIsNextStep = useUiStore((s) => s.setIsNextStep);
const setUniformityStep = useUiStore((s) => s.setUniformityStep);
const verifyUniformityResult = useUiStore((s) => s.verifyUniformityResult);
const setVerifyUniformityResult = useUiStore(
(s) => s.setVerifyUniformityResult
);
const uniformityFormData = useUiStore((s) => s.uniformityFormData);
const [isSubmitting, setIsSubmitting] = React.useState(false);
const handleClose = () => {
setExpandedDrawerOpen(false);
setIsNextStep(false);
setUniformityStep('preview');
setVerifyUniformityResult(null);
};
const handleBack = () => {
setUniformityStep('preview');
};
const handleSubmit = async () => {
if (!uniformityFormData || !uniformityFormData.files) {
toast.error('Form data is missing. Please try again.');
return;
}
setIsSubmitting(true);
try {
const payload = {
date: uniformityFormData.date,
project_flock_kandang_id: uniformityFormData.project_flock_kandang_id,
files: uniformityFormData.files,
};
const res = await UniformityApi.createUniformity(payload);
if (isResponseError(res)) {
toast.error(res.message);
return;
}
toast.success('Uniformity created successfully!');
setExpandedDrawerOpen(false);
setIsNextStep(false);
setUniformityStep('preview');
setVerifyUniformityResult(null);
router.push('/uniformity');
} finally {
setIsSubmitting(false);
}
};
const tableData = useMemo(() => {
if (!verifyUniformityResult) return [];
return verifyUniformityResult.body_weights.map((weight, index) => ({
id: `weight-${index}`,
number: index + 1,
weight: weight,
}));
}, [verifyUniformityResult]);
const columns: ColumnDef<BodyWeightData>[] = useMemo(
() => [
{
accessorKey: 'number',
header: 'No',
cell: (props) => props.row.original.number,
},
{
accessorKey: 'weight',
header: 'Weight (g)',
cell: (props) => (
<span className='font-medium'>{props.row.original.weight}</span>
),
},
],
[]
);
return (
<section className='w-full h-full bg-white border-l border-gray-200'>
{/* Header */}
<DrawerHeader
leftIcon='mdi:arrow-left'
leftIconSize={24}
leftIconOnClick={handleBack}
leftIconClassName='hover:text-gray-400 cursor-pointer'
subtitle='Uniformity Result'
subtitleClassName='text-sm text-neutral'
showDivider
>
<RequirePermission permissions='lti.production.uniformity.delete'>
<Button
variant='link'
className='p-0 text-error'
onClick={handleClose}
>
<Tooltip content='Tutup' position='bottom'>
<Icon icon='mdi:close' width={20} height={20} />
</Tooltip>
</Button>
</RequirePermission>
</DrawerHeader>
{/* Form Section */}
<div className='divider mt-3'></div>
<section className='w-full px-6'>
{verifyUniformityResult ? (
<div className='flex flex-col gap-4'>
<div className='mt-4'>
<Table<BodyWeightData>
data={tableData}
columns={columns}
pageSize={15}
className={{ containerClassName: 'mb-5' }}
/>
</div>
{/* Action Buttons */}
<RequirePermission permissions='lti.production.uniformity.create'>
<Button
color='primary'
onClick={handleSubmit}
isLoading={isSubmitting}
disabled={!uniformityFormData}
className='mb-10'
>
Submit
</Button>
</RequirePermission>
</div>
) : (
<div className='flex flex-col items-center justify-center py-10 text-gray-400'>
<Icon
icon='mdi:file-document-outline'
width={64}
height={64}
className='mb-4'
/>
<p className='text-lg'>No data available</p>
<p className='text-sm'>Upload a file to verify uniformity</p>
</div>
)}
</section>
</section>
);
};
export default UniformityResultForm;
+6
View File
@@ -52,4 +52,10 @@ export const createDrawerUISlice: StateCreator<
verifyUniformityResult: null,
setVerifyUniformityResult: (result) =>
set({ verifyUniformityResult: result }),
uniformityStep: 'preview',
setUniformityStep: (step) => set({ uniformityStep: step }),
uniformityFormData: null,
setUniformityFormData: (data) => set({ uniformityFormData: data }),
});
+14 -1
View File
@@ -1,11 +1,20 @@
import type { ReactNode } from 'react';
import type { VerifyUniformityResponse } from '@/types/api/uniformity/uniformity';
import type {
VerifyUniformityResponse,
CreateUniformityPayload,
} from '@/types/api/uniformity/uniformity';
type MainUiSlice = {
mainDrawerOpen: boolean;
setMainDrawerOpen: (open: boolean) => void;
};
type UniformityFormData = {
date: string;
project_flock_kandang_id: number;
files: File | null;
};
type DrawerUISlice = {
triggerValidate: boolean;
toggleValidate: () => void;
@@ -21,6 +30,10 @@ type DrawerUISlice = {
setIsNextStep: (v: boolean) => void;
verifyUniformityResult: VerifyUniformityResponse | null;
setVerifyUniformityResult: (result: VerifyUniformityResponse | null) => void;
uniformityStep: 'preview' | 'result';
setUniformityStep: (step: 'preview' | 'result') => void;
uniformityFormData: UniformityFormData | null;
setUniformityFormData: (data: UniformityFormData | null) => void;
};
export type UIStore = MainUiSlice & DrawerUISlice;