diff --git a/src/app/uniformity/add/page.tsx b/src/app/uniformity/add/page.tsx index 9931eebe..7c12cc72 100644 --- a/src/app/uniformity/add/page.tsx +++ b/src/app/uniformity/add/page.tsx @@ -1,5 +1,3 @@ -'use client'; - import UniformityForm from '@/components/pages/uniformity/form/UniformityForm'; const AddUniformity = () => { diff --git a/src/app/uniformity/detail/page.tsx b/src/app/uniformity/detail/page.tsx new file mode 100644 index 00000000..a2e9402e --- /dev/null +++ b/src/app/uniformity/detail/page.tsx @@ -0,0 +1,47 @@ +'use client'; + +import UniformityDetail from '@/components/pages/uniformity/detail/UniformityDetail'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; +import { UniformityApi } from '@/services/api/uniformity'; +import { useRouter, useSearchParams } from 'next/navigation'; +import useSWR from 'swr'; + +const UniformityDetailPage = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + + const uniformityId = searchParams.get('uniformityId'); + + const { data: uniformity, isLoading: isLoadingUniformity } = useSWR( + uniformityId, + (id: string) => UniformityApi.getUniformityDetail(parseInt(id)) + ); + + if (!uniformityId) { + router.back(); + + return ( +
+ +
+ ); + } + + if (!isLoadingUniformity && (!uniformity || isResponseError(uniformity))) { + router.replace('/404'); + return; + } + + return ( +
+ {isLoadingUniformity && ( + + )} + {isResponseSuccess(uniformity) && ( + + )} +
+ ); +}; + +export default UniformityDetailPage; diff --git a/src/app/uniformity/page.tsx b/src/app/uniformity/page.tsx index dd0e4466..24a31482 100644 --- a/src/app/uniformity/page.tsx +++ b/src/app/uniformity/page.tsx @@ -1,5 +1,7 @@ +import UniformityTable from '@/components/pages/uniformity/UniformityTable'; + const Uniformity = () => { - return <>; + return ; }; export default Uniformity; diff --git a/src/components/pages/uniformity/UniformityTable.tsx b/src/components/pages/uniformity/UniformityTable.tsx index 27365e40..efa8dd66 100644 --- a/src/components/pages/uniformity/UniformityTable.tsx +++ b/src/components/pages/uniformity/UniformityTable.tsx @@ -1,6 +1,7 @@ 'use client'; import React, { useCallback, useState, useEffect, useMemo } from 'react'; +import { useRouter } from 'next/navigation'; import useSWR from 'swr'; import { Icon } from '@iconify/react'; import { ColumnDef, SortingState } from '@tanstack/react-table'; @@ -59,6 +60,7 @@ const isUniformityLocked = (uniformity: Uniformity): boolean => { }; const UniformityTable = ({ refresh }: { refresh?: () => void }) => { + const router = useRouter(); const isSuccess = useUniformityStore((s) => s.isSuccess); const setIsSuccess = useUniformityStore((s) => s.setIsSuccess); @@ -200,6 +202,14 @@ const UniformityTable = ({ refresh }: { refresh?: () => void }) => { setRowSelection({}); }, []); + const handleViewDetail = useCallback( + (uniformity: Uniformity) => { + router.push(`/uniformity/detail?uniformityId=${uniformity.id}`); + setRowSelection({}); + }, + [router] + ); + const handleBulkApprove = useCallback(() => { bulkApproveModal.openModal(); }, [bulkApproveModal]); @@ -980,6 +990,19 @@ const UniformityTable = ({ refresh }: { refresh?: () => void }) => { {/* Floating Actions Button */} = ({ + initialValues, +}) => { + const router = useRouter(); + + const handleClose = () => { + router.back(); + }; + + const infoUmumTableData: DetailOptionType[] = useMemo(() => { + if (!initialValues) return []; + + return [ + { + id: 'tanggal', + value: 'tanggal', + label: 'Tanggal', + }, + { + id: 'lokasi-farm', + value: 'lokasi-farm', + label: 'Lokasi Farm', + }, + { + id: 'project-flock', + value: 'project-flock', + label: 'Project Flock', + }, + { + id: 'kandang', + value: 'kandang', + label: 'Kandang', + }, + { + id: 'file-name', + value: 'file-name', + label: 'File Name', + }, + ]; + }, [initialValues]); + + const columnsInfoUmum: ColumnDef[] = useMemo( + () => [ + { + accessorKey: 'label', + header: 'Label', + cell: (props) => props.row.original.label, + }, + { + accessorKey: 'value', + header: 'Value', + cell: (props) => { + const id = props.row.original.id; + const { info_umum } = initialValues!; + + const valueMap: Record = { + tanggal: info_umum.tanggal, + 'lokasi-farm': info_umum.lokasi_farm, + 'project-flock': info_umum.project_flock, + kandang: info_umum.kandang, + 'file-name': info_umum.file_name, + }; + + return {valueMap[id] || '-'}; + }, + }, + ], + [initialValues] + ); + + const samplingTableData: DetailOptionType[] = useMemo(() => { + if (!initialValues) return []; + + return [ + { + id: 'sampling-size', + value: 'sampling-size', + label: 'Sampling size', + }, + { + id: 'mean-weight', + value: 'mean-weight', + label: 'Mean Weight', + }, + { + id: 'min-limit', + value: 'min-limit', + label: 'Min Limit (-10%)', + }, + { + id: 'max-limit', + value: 'max-limit', + label: 'Max Limit (+10%)', + }, + ]; + }, [initialValues]); + + const columnsSampling: ColumnDef[] = useMemo( + () => [ + { + accessorKey: 'label', + header: 'Label', + cell: (props) => props.row.original.label, + }, + { + accessorKey: 'value', + header: 'Value', + cell: (props) => { + const id = props.row.original.id; + const { sampling } = initialValues!; + + const valueMap: Record = { + 'sampling-size': `${formatNumber(sampling.chick_qty_of_weight)} of Birds`, + 'mean-weight': `${formatNumber(sampling.mean_weight)} g`, + 'min-limit': `${formatNumber(sampling.mean_down)} g`, + 'max-limit': `${formatNumber(sampling.mean_up)} g`, + }; + + return {valueMap[id] || '-'}; + }, + }, + ], + [initialValues] + ); + + const resultTableData: DetailOptionType[] = useMemo(() => { + if (!initialValues) return []; + + return [ + { + id: 'ideal-birds', + value: 'ideal-birds', + label: 'Ideal Birds', + }, + { + id: 'outside-range', + value: 'outside-range', + label: 'Outside Range', + }, + { + id: 'uniformity', + value: 'uniformity', + label: 'Uniformity', + }, + { + id: 'cv', + value: 'cv', + label: 'CV', + }, + ]; + }, [initialValues]); + + const columnsResult: ColumnDef[] = useMemo( + () => [ + { + accessorKey: 'label', + header: 'Label', + cell: (props) => props.row.original.label, + }, + { + accessorKey: 'value', + header: 'Value', + cell: (props) => { + const id = props.row.original.id; + const { result } = initialValues!; + + const valueMap: Record = { + 'ideal-birds': `${formatNumber(result.uniform_qty)} of Birds`, + 'outside-range': `${formatNumber(result.outside_qty)} of Birds`, + uniformity: `${result.uniformity} %`, + cv: `${result.cv}`, + }; + + return {valueMap[id] || '-'}; + }, + }, + ], + [initialValues] + ); + + return ( +
+ {/* Header */} + + + + + {/* Form Section */} +
+
+ {initialValues ? ( +
+ {/* Info Umum */} +
+

Informasi Umum

+ + data={infoUmumTableData} + columns={columnsInfoUmum} + pageSize={5} + className={{ + containerClassName: 'mb-0', + paginationClassName: 'hidden', + }} + /> +
+ + {/* Sampling */} +
+

Sampling and Range

+ + data={samplingTableData} + columns={columnsSampling} + pageSize={4} + className={{ + containerClassName: 'mb-0', + paginationClassName: 'hidden', + }} + /> +
+ + {/* Result */} +
+

Result

+ + data={resultTableData} + columns={columnsResult} + pageSize={4} + className={{ + containerClassName: 'mb-0', + paginationClassName: 'hidden', + }} + /> +
+
+ ) : ( +
+ +

No data available

+

Uniformity detail not found

+
+ )} +
+
+ ); +}; + +export default UniformityDetail; diff --git a/src/services/api/uniformity.ts b/src/services/api/uniformity.ts index 4728e3e7..892192b6 100644 --- a/src/services/api/uniformity.ts +++ b/src/services/api/uniformity.ts @@ -1,9 +1,10 @@ import { BaseApiService } from '@/services/api/base'; import { BaseApiResponse } from '@/types/api/api-general'; import { + Uniformity, + UniformityDetail, VerifyUniformityPayload, VerifyUniformityResponse, - Uniformity, CreateUniformityPayload, } from '@/types/api/uniformity/uniformity'; @@ -20,6 +21,14 @@ export class UniformityApiService extends BaseApiService< return await this.customRequest>(''); } + async getUniformityDetail( + id: number + ): Promise | undefined> { + return await this.customRequest>( + `/${id}` + ); + } + async createUniformity( payload: CreateUniformityPayload ): Promise | undefined> {