From 126346dc52a52715a2f7195b0587b9b8328b66bd Mon Sep 17 00:00:00 2001 From: randy-ar Date: Sat, 10 Jan 2026 08:09:29 +0700 Subject: [PATCH] feat(FE): slicing ui dashboard, API integration with dummy data and form validation --- .../pages/dashboard/DashboardProduction.tsx | 102 ++- .../dashboard/chart/DashboardLineChart.tsx | 8 +- .../pages/dashboard/chart/DashboardStats.tsx | 5 +- .../DashboardProductionFilter.schema.ts | 110 ++- .../dashboard.comparasion.kandang.dummy.json | 705 +++++++++--------- .../dashboard/dashboard.production.dummy.ts | 21 +- src/types/api/dashboard/dashboard.d.ts | 10 + 7 files changed, 574 insertions(+), 387 deletions(-) diff --git a/src/components/pages/dashboard/DashboardProduction.tsx b/src/components/pages/dashboard/DashboardProduction.tsx index a293e287..5ee4ea4e 100644 --- a/src/components/pages/dashboard/DashboardProduction.tsx +++ b/src/components/pages/dashboard/DashboardProduction.tsx @@ -20,13 +20,19 @@ import Alert from '@/components/Alert'; import { DashboardFilterSchema, DashboardFilterType, + getDashboardFilterSchema, } from '@/components/pages/dashboard/filter/DashboardProductionFilter.schema'; import DashboardLineChart from '@/components/pages/dashboard/chart/DashboardLineChart'; import DashboardLineChartSkeleton from '@/components/pages/dashboard/skeleton/DashboardLineChartSkeleton'; import { RadioGroup, RadioGroupItem } from '@/components/input/RadioInput'; -import { DashboardFilter } from '@/types/api/dashboard/dashboard'; +import { + DashboardFilter, + DashboardMeta, +} from '@/types/api/dashboard/dashboard'; import DashboardStats from '@/components/pages/dashboard/chart/DashboardStats'; import { isResponseSuccess } from '@/lib/api-helper'; +import AlertErrorList from '@/components/helper/form/FormErrors'; +import { getUniqueFormikErrors } from '@/lib/formik-helper'; // Helper function to normalize values to array const normalizeToArray = ( @@ -46,6 +52,7 @@ const DashboardProduction = () => { ); const [endpointUrl, setEndpointUrl] = useState('/dashboard'); const [selectedLocationIds, setSelectedLocationIds] = useState([]); + const [formErrorList, setFormErrorList] = useState([]); // ===== FETCH DATA ===== const { @@ -78,7 +85,7 @@ const DashboardProduction = () => { location_id: selectedLocationIds ? selectedLocationIds.toString() : '', }); const comparedByOptions = [ - { value: 'LOCATION', label: 'Location' }, + { value: 'LOCATION', label: 'Farm' }, { value: 'FLOCK', label: 'Flock' }, { value: 'KANDANG', label: 'Kandang' }, ]; @@ -97,7 +104,7 @@ const DashboardProduction = () => { flockIds: [], kandangIds: [], } as DashboardFilterType, - validationSchema: DashboardFilterSchema, + validationSchema: getDashboardFilterSchema(analysisMode), onSubmit: (values) => { console.log(values); @@ -117,6 +124,7 @@ const DashboardProduction = () => { setAnalysisMode('OVERVIEW'); setEndpointUrl('/dashboard'); }; + const handleApplyFilter = (values: DashboardFilter) => { console.log(values); @@ -140,6 +148,23 @@ const DashboardProduction = () => { formik.resetForm(); }; + const handleValidateForm = async () => { + const errors = await formik.validateForm(); + + if (Object.keys(errors).length > 0) { + // Parse and display errors + const errorMessages = getUniqueFormikErrors(errors); + setFormErrorList(errorMessages); + return; // Stop submission + } + }; + + const handleFormSubmit = (e: React.FormEvent) => { + e.preventDefault(); + handleValidateForm(); + formik.handleSubmit(); + }; + if (isLoadingDashboardProductionData) { return (
@@ -155,11 +180,53 @@ const DashboardProduction = () => {
-
+ {/* Rentang Waktu */}
@@ -259,6 +338,7 @@ const DashboardProduction = () => { value={formik.values.analysisMode} onChange={(e) => { formik.handleChange(e); + setAnalysisMode(e.target.value as 'OVERVIEW' | 'COMPARISON'); // Reset all dependent fields when analysis mode changes formik.setFieldValue('location', []); formik.setFieldValue('flock', []); @@ -395,6 +475,14 @@ const DashboardProduction = () => {
)} + {/* Error List Alert */} + {formErrorList.length > 0 && ( + setFormErrorList([])} + /> + )} + {/* Action Buttons */}