feat(FE-316): Save and preview uniformity verification

This commit is contained in:
rstubryan
2025-12-27 21:00:07 +07:00
parent ec8ae7561d
commit 549a710a8d
6 changed files with 88 additions and 6 deletions
@@ -60,6 +60,9 @@ const UniformityForm = ({
); );
const isNextStep = useUiStore((s) => s.isNextStep); const isNextStep = useUiStore((s) => s.isNextStep);
const setIsNextStep = useUiStore((s) => s.setIsNextStep); const setIsNextStep = useUiStore((s) => s.setIsNextStep);
const setVerifyUniformityResult = useUiStore(
(s) => s.setVerifyUniformityResult
);
const [uniformityFormErrorMessage, setUniformityFormErrorMessage] = const [uniformityFormErrorMessage, setUniformityFormErrorMessage] =
useState(''); useState('');
@@ -239,6 +242,10 @@ const UniformityForm = ({
return; return;
} }
if (isResponseSuccess(res) && res.data) {
setVerifyUniformityResult(res.data);
}
toast.success(res?.message as string); toast.success(res?.message as string);
if (formType === 'add') { if (formType === 'add') {
@@ -1,21 +1,59 @@
'use client'; 'use client';
import { useMemo } from 'react';
import { Icon } from '@iconify/react'; import { Icon } from '@iconify/react';
import { ColumnDef } from '@tanstack/react-table';
import Button from '@/components/Button'; import Button from '@/components/Button';
import Tooltip from '@/components/Tooltip'; import Tooltip from '@/components/Tooltip';
import DrawerHeader from '@/components/helper/drawer/DrawerHeader'; import DrawerHeader from '@/components/helper/drawer/DrawerHeader';
import { useUiStore } from '@/stores/ui/ui.store'; import { useUiStore } from '@/stores/ui/ui.store';
import RequirePermission from '@/components/helper/RequirePermission'; import RequirePermission from '@/components/helper/RequirePermission';
import Table from '@/components/Table';
type BodyWeightData = {
id: string;
number: number;
weight: number;
};
const UniformityPreviewForm = () => { const UniformityPreviewForm = () => {
const setExpandedDrawerOpen = useUiStore((s) => s.setExpandedDrawerOpen); const setExpandedDrawerOpen = useUiStore((s) => s.setExpandedDrawerOpen);
const setIsNextStep = useUiStore((s) => s.setIsNextStep); const setIsNextStep = useUiStore((s) => s.setIsNextStep);
const verifyUniformityResult = useUiStore((s) => s.verifyUniformityResult);
const handleClose = () => { const handleClose = () => {
setExpandedDrawerOpen(false); setExpandedDrawerOpen(false);
setIsNextStep(false); setIsNextStep(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 ( return (
<section className='w-full h-full bg-white border-l border-gray-200'> <section className='w-full h-full bg-white border-l border-gray-200'>
{/* Header */} {/* Header */}
@@ -43,7 +81,29 @@ const UniformityPreviewForm = () => {
{/* Form Section */} {/* Form Section */}
<div className='divider mt-3'></div> <div className='divider mt-3'></div>
<section className='w-full px-6'></section> <section className='w-full px-6'>
{verifyUniformityResult ? (
<div className='flex flex-col gap-4'>
<Table<BodyWeightData>
data={tableData}
columns={columns}
pageSize={20}
className={{ containerClassName: 'mb-10' }}
/>
</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> </section>
); );
}; };
+9 -5
View File
@@ -2,6 +2,7 @@ import { BaseApiService } from '@/services/api/base';
import { BaseApiResponse } from '@/types/api/api-general'; import { BaseApiResponse } from '@/types/api/api-general';
import { import {
VerifyUniformityPayload, VerifyUniformityPayload,
VerifyUniformityResponse,
Uniformity, Uniformity,
CreateUniformityPayload, CreateUniformityPayload,
} from '@/types/api/uniformity/uniformity'; } from '@/types/api/uniformity/uniformity';
@@ -38,7 +39,7 @@ export class UniformityApiService extends BaseApiService<
async verifyUniformity( async verifyUniformity(
payload: VerifyUniformityPayload payload: VerifyUniformityPayload
): Promise<BaseApiResponse<Uniformity> | undefined> { ): Promise<BaseApiResponse<VerifyUniformityResponse> | undefined> {
const formData = new FormData(); const formData = new FormData();
formData.append( formData.append(
'project_flock_kandang_id', 'project_flock_kandang_id',
@@ -49,10 +50,13 @@ export class UniformityApiService extends BaseApiService<
formData.append('file', payload.files); formData.append('file', payload.files);
} }
return await this.customRequest<BaseApiResponse<Uniformity>>('/verify', { return await this.customRequest<BaseApiResponse<VerifyUniformityResponse>>(
method: 'POST', '/verify',
payload: formData as unknown as Record<string, unknown>, {
}); method: 'POST',
payload: formData as unknown as Record<string, unknown>,
}
);
} }
} }
+4
View File
@@ -48,4 +48,8 @@ export const createDrawerUISlice: StateCreator<
isNextStep: false, isNextStep: false,
setIsNextStep: (isNextStep: boolean) => set({ isNextStep }), setIsNextStep: (isNextStep: boolean) => set({ isNextStep }),
verifyUniformityResult: null,
setVerifyUniformityResult: (result) =>
set({ verifyUniformityResult: result }),
}); });
+4
View File
@@ -23,3 +23,7 @@ export type VerifyUniformityPayload = {
project_flock_kandang_id: number; project_flock_kandang_id: number;
files: File; files: File;
}; };
export type VerifyUniformityResponse = {
body_weights: number[];
};
+3
View File
@@ -1,4 +1,5 @@
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import type { VerifyUniformityResponse } from '@/types/api/uniformity/uniformity';
type MainUiSlice = { type MainUiSlice = {
mainDrawerOpen: boolean; mainDrawerOpen: boolean;
@@ -18,6 +19,8 @@ type DrawerUISlice = {
setExpandedDrawerContent: (content: ReactNode) => void; setExpandedDrawerContent: (content: ReactNode) => void;
isNextStep: boolean; isNextStep: boolean;
setIsNextStep: (v: boolean) => void; setIsNextStep: (v: boolean) => void;
verifyUniformityResult: VerifyUniformityResponse | null;
setVerifyUniformityResult: (result: VerifyUniformityResponse | null) => void;
}; };
export type UIStore = MainUiSlice & DrawerUISlice; export type UIStore = MainUiSlice & DrawerUISlice;