From 24499d110aaf5f6a89ccac9db70ce6bbbfe8cef2 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Tue, 6 Jan 2026 08:36:23 +0700 Subject: [PATCH] refactor(FE): Refactor Uniformity charts to use API data --- .../production/uniformity/UniformityChart.tsx | 156 +++++++----------- .../production/uniformity/UniformityTable.tsx | 50 +++++- .../uniformity/chart/UniformityBarChart.tsx | 19 +++ 3 files changed, 125 insertions(+), 100 deletions(-) diff --git a/src/components/pages/production/uniformity/UniformityChart.tsx b/src/components/pages/production/uniformity/UniformityChart.tsx index 58a8f9c8..77d1608d 100644 --- a/src/components/pages/production/uniformity/UniformityChart.tsx +++ b/src/components/pages/production/uniformity/UniformityChart.tsx @@ -4,89 +4,20 @@ import UniformityBarChart from '@/components/pages/production/uniformity/chart/U import UniformityGaugeChart from '@/components/pages/production/uniformity/chart/UniformityGaugeChart'; import UniformityBarChartSkeleton from '@/components/pages/production/uniformity/skeleton/UniformityBarChartSkeleton'; import UniformityGaugeChartSkeleton from '@/components/pages/production/uniformity/skeleton/UniformityGaugeChartSkeleton'; -import { UniformityDetailItem } from '@/types/api/production/uniformity'; - -interface BarChartData { - name: string; - uv: number; - isIdeal?: boolean; -} - -interface GaugeChartData { - value: number; - label: string; - kandang?: string; - week?: string; - currentValue?: number; - totalValue?: number; -} +import { + UniformityDetailItem, + Uniformity, +} from '@/types/api/production/uniformity'; interface UniformityChartProps { - barChartData?: BarChartData[]; - gaugeChartData?: GaugeChartData; + uniformityData?: Uniformity | null; uniformityDetails?: UniformityDetailItem[]; } const UniformityChart = ({ - barChartData: initialBarChartData, - gaugeChartData: initialGaugeChartData, + uniformityData, uniformityDetails, }: UniformityChartProps) => { - const defaultBarChartData: BarChartData[] = [ - { - name: '48-52', - uv: 80, - }, - { - name: '52-56', - uv: 120, - }, - { - name: '56-60', - uv: 160, - }, - { - name: '60-64', - uv: 200, - }, - { - name: '64-68', - uv: 160, - }, - { - name: '68-72', - uv: 120, - }, - { - name: '72-76', - uv: 80, - }, - { - name: '76-80', - uv: 120, - }, - { - name: '84-88', - uv: 160, - }, - { - name: '88-92', - uv: 200, - }, - { - name: '92-96', - uv: 160, - }, - ]; - - const defaultGaugeChartData: GaugeChartData = { - value: 52, - label: 'Uniformity', - week: 'Week 2', - currentValue: 512, - totalValue: 1024, - }; - const defaultUniformityDetails: UniformityDetailItem[] = [ { id: 1, weight: 61, range: 'Ideal' }, { id: 2, weight: 62, range: 'Ideal' }, @@ -100,34 +31,63 @@ const UniformityChart = ({ const detailsToUse = uniformityDetails || defaultUniformityDetails; const barChartData = useMemo(() => { - const dataToProcess = initialBarChartData || defaultBarChartData; - - if (!detailsToUse || detailsToUse.length === 0) { - return dataToProcess; + if (!uniformityData) { + return []; } - return dataToProcess.map((bar) => { - const rangeMatch = bar.name.match(/(\d+)-(\d+)/); - if (!rangeMatch) return bar; + if (!detailsToUse || detailsToUse.length === 0) { + return []; + } - const minWeight = parseInt(rangeMatch[1], 10); - const maxWeight = parseInt(rangeMatch[2], 10); + const weights = detailsToUse.map((d) => d.weight); + const minWeight = Math.floor(Math.min(...weights) / 5) * 5; + const maxWeight = Math.ceil(Math.max(...weights) / 5) * 5; - const hasIdealWeight = detailsToUse.some((detail) => { - const weight = detail.weight; - return ( - detail.range === 'Ideal' && weight >= minWeight && weight <= maxWeight - ); - }); + const rangeSize = maxWeight - minWeight < 11 ? 4 : 5; + const ranges: string[] = []; + + for (let start = minWeight; start <= maxWeight; start += rangeSize) { + const end = start + rangeSize; + ranges.push(`${start}-${end}`); + } + + const totalIdealCount = detailsToUse.filter( + (d) => d.range === 'Ideal' + ).length; + + return ranges.map((range) => { + const [minStr, maxStr] = range.split('-').map(Number); + const min = minStr; + const max = maxStr; + + const birdsInRange = detailsToUse.filter( + (d) => d.weight >= min && d.weight < max + ).length; + + const hasIdeal = detailsToUse.some( + (d) => d.range === 'Ideal' && d.weight >= min && d.weight < max + ); return { - ...bar, - isIdeal: hasIdealWeight, + name: range, + uv: birdsInRange, + isIdeal: hasIdeal, + idealCount: hasIdeal ? totalIdealCount : undefined, }; }); - }, [initialBarChartData, detailsToUse]); + }, [uniformityData, detailsToUse]); - const gaugeChartData = initialGaugeChartData || defaultGaugeChartData; + const gaugeChartData = useMemo(() => { + if (!uniformityData) return undefined; + + return { + value: uniformityData.uniformity, + label: 'Uniformity', + week: `Week ${uniformityData.week}`, + currentValue: uniformityData.uniform_qty, + totalValue: uniformityData.chick_qty_of_weight, + }; + }, [uniformityData]); return (
@@ -140,14 +100,14 @@ const UniformityChart = ({ }} >
- {barChartData.length === 0 ? ( + {!uniformityData || barChartData.length === 0 ? ( ) : ( )}
- {gaugeChartData && gaugeChartData.value === 0 ? ( + {!uniformityData || !gaugeChartData ? ( - ) : gaugeChartData ? ( + ) : ( - ) : null} + )}
); }; diff --git a/src/components/pages/production/uniformity/UniformityTable.tsx b/src/components/pages/production/uniformity/UniformityTable.tsx index 0a7483f2..e031e2c4 100644 --- a/src/components/pages/production/uniformity/UniformityTable.tsx +++ b/src/components/pages/production/uniformity/UniformityTable.tsx @@ -13,6 +13,7 @@ import { UniformityApi } from '@/services/api/uniformity'; import { DetailOptionType, type Uniformity, + type UniformityDetail, } from '@/types/api/production/uniformity'; import { isResponseSuccess } from '@/lib/api-helper'; import { type BaseApiResponse } from '@/types/api/api-general'; @@ -79,7 +80,7 @@ const UniformityConfirmationPreview = ({ { id: 'file-uniformity', label: 'File Uniformity', - value: '-', // File name tidak tersedia di GET ALL response + value: '-', }, { id: 'status', @@ -136,6 +137,51 @@ const UniformityConfirmationPreview = ({ ); }; +const UniformityChartWrapper = ({ + uniformitySwrKey, +}: { + uniformitySwrKey: string; +}) => { + const { data: uniformities } = useSWR( + uniformitySwrKey, + UniformityApi.getAllFetcher + ); + + const uniformityData = useMemo(() => { + if (isResponseSuccess(uniformities) && uniformities?.data?.length > 0) { + return uniformities.data[0]; + } + return null; + }, [uniformities]); + + const shouldFetchDetails = !!uniformityData; + const uniformityDetailSwrKey = useMemo(() => { + if (!uniformityData) return null; + return `${UniformityApi.basePath}/${uniformityData.id}?with_details=true`; + }, [uniformityData]); + + const { data: uniformityDetailResponse } = useSWR( + uniformityDetailSwrKey, + shouldFetchDetails ? UniformityApi.getAllFetcher : null + ); + + const uniformityDetails = useMemo(() => { + if (shouldFetchDetails && isResponseSuccess(uniformityDetailResponse)) { + const detailData = + uniformityDetailResponse.data as unknown as UniformityDetail; + return detailData.uniformity_details; + } + return undefined; + }, [shouldFetchDetails, uniformityDetailResponse]); + + return ( + + ); +}; + const UniformityTable = () => { const router = useRouter(); const searchParams = useSearchParams(); @@ -830,7 +876,7 @@ const UniformityTable = () => {
- +
+

Uniformity 2025

+
+
+
+ {chartData.idealCount} of Birds +
+ {labelStr} +
+ + ); + } + return (

Uniformity 2025