'use client'; import Button from '@/components/Button'; import { Icon } from '@iconify/react'; import Modal, { useModal } from '@/components/Modal'; import DateInput from '@/components/input/DateInput'; import SelectInput, { OptionType, useSelect, } from '@/components/input/SelectInput'; import { useState, useEffect } from 'react'; import useSWR from 'swr'; import { DashboardApi } from '@/services/api/dashboard'; import { useFormik } from 'formik'; import { ProjectFlockApi } from '@/services/api/production'; import { KandangApi, LocationApi } from '@/services/api/master-data'; import { 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, 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 { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; import ButtonFilter from '@/components/helper/ButtonFilter'; import toast from 'react-hot-toast'; import Dropdown from '@/components/Dropdown'; import Menu from '@/components/menu/Menu'; import MenuItem from '@/components/menu/MenuItem'; // Helper function to normalize values to array const normalizeToArray = ( value: OptionType | OptionType[] | null | undefined ): number[] => { if (!value) return []; if (Array.isArray(value)) { return value.map((v) => Number(v.value)); } return [Number(value.value)]; }; const DashboardProduction = () => { const filterModal = useModal(); const [analysisMode, setAnalysisMode] = useState<'OVERVIEW' | 'COMPARISON'>( 'OVERVIEW' ); const [endpointUrl, setEndpointUrl] = useState('/dashboards'); const [selectedLocationIds, setSelectedLocationIds] = useState([]); const [exporting, setExporting] = useState(false); // ===== FETCH DATA ===== const { data: dashboardProductionResponse, isLoading: isLoadingDashboardProductionData, mutate: refreshDashboardProductionData, } = useSWR(endpointUrl, () => DashboardApi.getDashboardProductionFetcher(endpointUrl) ); const dashboardProductionData = isResponseSuccess(dashboardProductionResponse) ? dashboardProductionResponse.data : undefined; // ===== SELECT ===== const { setInputValue: setInputValueFlock, options: flockOptions, isLoadingOptions: isLoadingFlockOptions, loadMore: loadMoreFlock, } = useSelect(ProjectFlockApi.basePath, 'id', 'flock_name', '', { limit: 'limit', location_id: selectedLocationIds ? selectedLocationIds.toString() : '', }); const { setInputValue: setInputValueLocation, options: locationOptions, isLoadingOptions: isLoadingLocationOptions, loadMore: loadMoreLocation, } = useSelect(LocationApi.basePath, 'id', 'name', '', { limit: 'limit', }); const { setInputValue: setInputValueKandang, options: kandangOptions, isLoadingOptions: isLoadingKandangOptions, loadMore: loadMoreKandang, } = useSelect(KandangApi.basePath, 'id', 'name', '', { limit: 'limit', location_id: selectedLocationIds ? selectedLocationIds.toString() : '', }); const comparisonTypeOptions = [ { value: 'FARM', label: 'Farm' }, { value: 'FLOCK', label: 'Flock' }, { value: 'KANDANG', label: 'Kandang' }, ]; // ===== FORMIK ===== const formik = useFormik({ initialValues: { startDate: '', endDate: '', flock: [] as OptionType[], location: [] as OptionType[], kandang: [] as OptionType[], analysisMode: analysisMode, comparisonType: '', lokasiIds: [], flockIds: [], kandangIds: [], } as DashboardFilterType, validationSchema: getDashboardFilterSchema(analysisMode), onSubmit: (values) => { console.log(values); handleApplyFilter({ start_date: values.startDate || '', end_date: values.endDate || '', analysis_mode: values.analysisMode as 'OVERVIEW' | 'COMPARISON', location_ids: normalizeToArray(values.location), flock_ids: normalizeToArray(values.flock), kandang_ids: normalizeToArray(values.kandang), comparison_type: values.comparisonType, }); }, }); const handleResetFilter = () => { formik.resetForm(); setAnalysisMode('OVERVIEW'); setEndpointUrl('/dashboards'); }; const handleApplyFilter = (values: DashboardFilter) => { console.log(values); // Build query params object, only include non-empty values const params: Record = {}; if (values.start_date) params.start_date = values.start_date; if (values.end_date) params.end_date = values.end_date; if (values.analysis_mode) params.analysis_mode = values.analysis_mode; if (values.location_ids.length > 0) params.location_ids = values.location_ids.toString(); if (values.flock_ids.length > 0) params.flock_ids = values.flock_ids.toString(); if (values.kandang_ids.length > 0) params.kandang_ids = values.kandang_ids.toString(); if (values.comparison_type) params.comparison_type = values.comparison_type; setEndpointUrl(`/dashboards?${new URLSearchParams(params).toString()}`); console.log(endpointUrl); filterModal.closeModal(); refreshDashboardProductionData(); }; // ===== Formik Error List ===== const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); // ===== Export PDF ===== const handleExportPDF = () => { setExporting(true); }; // Wait for state to render, then trigger print useEffect(() => { if (exporting) { const timer = setTimeout(() => { window.print(); setExporting(false); }, 100); return () => clearTimeout(timer); } }, [exporting]); if (isLoadingDashboardProductionData) { return (
); } return ( <>
filterModal.openModal()} /> Export } className={{ content: 'w-full', }} >
{/* Dashboard Stats */} {/* Use DashboardLineChart component or skeleton */} {isLoadingDashboardProductionData ? ( ) : dashboardProductionData && dashboardProductionData.charts && Object.keys(dashboardProductionData.charts).length > 0 ? ( ) : ( )}
{/* Modal Header */}

Filter Data

{/* Rentang Waktu */}
{/* Analysis Mode */}
{ formik.handleChange(e); setAnalysisMode(e.target.value as 'OVERVIEW' | 'COMPARISON'); // Reset all dependent fields when analysis mode changes formik.setFieldValue('location', []); formik.setFieldValue('flock', []); formik.setFieldValue('kandang', []); formik.setFieldValue('comparisonType', ''); setSelectedLocationIds([]); }} color='primary' className={{ wrapper: 'w-full my-6 font-semibold text-neutral-500', }} >
{formik.values.analysisMode === 'COMPARISON' && (
option.value === formik.values.comparisonType )} onChange={(selected) => formik.setFieldValue( 'comparisonType', selected ? (selected as OptionType).value : '' ) } errorMessage={formik.errors.comparisonType as string} options={comparisonTypeOptions} isLoading={isLoadingLocationOptions} isError={ Boolean(formik.errors.comparisonType) && Boolean(formik.touched.comparisonType) } />
)} {/* Location */}
{ formik.setFieldValue('location', selected); // Update selectedLocationIds for kandang filter setSelectedLocationIds(normalizeToArray(selected)); // Reset dependent fields when location changes formik.setFieldValue('flock', []); formik.setFieldValue('kandang', []); }} errorMessage={formik.errors.location as string} options={locationOptions} isLoading={isLoadingLocationOptions} isMulti={ comparisonTypeOptions.find( (option) => option.value === formik.values.comparisonType )?.value === 'FARM' } isError={ Boolean(formik.errors.location) && Boolean(formik.touched.location) } />
{/* Flock */} {!( formik.values.analysisMode === 'COMPARISON' && !( formik.values.comparisonType === 'FLOCK' || formik.values.comparisonType === 'KANDANG' ) ) && (
formik.setFieldValue('flock', selected) } errorMessage={formik.errors.flock as string} onInputChange={setInputValueFlock} onMenuScrollToBottom={loadMoreFlock} options={flockOptions} isLoading={isLoadingFlockOptions} isMulti={ comparisonTypeOptions.find( (option) => option.value === formik.values.comparisonType )?.value === 'FLOCK' } isError={ Boolean(formik.errors.flock) && Boolean(formik.touched.flock) } />
)} {/* Kandang */} {!( formik.values.analysisMode === 'COMPARISON' && !(formik.values.comparisonType === 'KANDANG') ) && (
formik.setFieldValue('kandang', selected) } errorMessage={formik.errors.kandang as string} onInputChange={setInputValueKandang} onMenuScrollToBottom={loadMoreKandang} options={kandangOptions} isLoading={isLoadingKandangOptions} isMulti={ comparisonTypeOptions.find( (option) => option.value === formik.values.comparisonType )?.value === 'KANDANG' } isError={ Boolean(formik.errors.kandang) && Boolean(formik.touched.kandang) } />
)}
{/* Action Buttons */}
); }; export default DashboardProduction;