'use client' import { useState, useCallback, useEffect } from 'react' import dynamic from 'next/dynamic' import { useTranslations } from 'next-intl' import Box from '@mui/material/Box' import CircularProgress from '@mui/material/CircularProgress' import Button from '@mui/material/Button' import CropZoningMap from './CropZoningMap' import ZoneLegend from './ZoneLegend' import LayerControl from './LayerControl' import ZoneDetailPanel from './ZoneDetailPanel' import CropZoningWeatherSection from './CropZoningWeatherSection' import { createGridFromPolygon } from './cropZoningUtils' import { cropZoningService, type Product, type ZoneInitialData, type ZoneDetailData } from '@/libs/api/services/cropZoningService' import type { LayerType } from './cropZoningTypes' import type { MapDrawGeoJSON } from './CropZoningMap' const MapComponent = dynamic(() => Promise.resolve(CropZoningMap), { ssr: false, loading: () => ( ) }) function isPolygon(geojson: MapDrawGeoJSON): geojson is MapDrawGeoJSON & { geometry: { type: 'Polygon'; coordinates: unknown[] } } { return !!geojson?.geometry && (geojson.geometry as { type: string }).type === 'Polygon' } export default function CropZoningWrapper() { const t = useTranslations('cropZoning') const [areaGeoJson, setAreaGeoJson] = useState(null) const [areaLoading, setAreaLoading] = useState(true) const [zonesData, setZonesData] = useState(null) const [products, setProducts] = useState([]) const [productsLoading, setProductsLoading] = useState(true) const [zonesLoading, setZonesLoading] = useState(false) const [activeLayer, setActiveLayer] = useState('crops') const [selectedZone, setSelectedZone] = useState(null) const [panelOpen, setPanelOpen] = useState(false) const [zoneDetailLoading, setZoneDetailLoading] = useState(false) const [optimizationKey, setOptimizationKey] = useState(0) const productLabels = Object.fromEntries(products.map(p => [p.id, p.label])) useEffect(() => { cropZoningService .getProducts() .then(res => setProducts(res.products)) .catch(() => setProducts([])) .finally(() => setProductsLoading(false)) }, []) useEffect(() => { setAreaLoading(true) cropZoningService .getArea() .then(res => setAreaGeoJson(res.area as unknown as MapDrawGeoJSON)) .catch(() => setAreaGeoJson(null)) .finally(() => setAreaLoading(false)) }, []) const fetchZones = useCallback((geojson: MapDrawGeoJSON) => { if (!isPolygon(geojson)) { setZonesData(null) return } setZonesLoading(true) const grid = createGridFromPolygon(geojson as unknown as import('geojson').Feature) cropZoningService .getZonesInitial({ zones: grid }) .then(res => setZonesData(res.zones)) .catch(() => setZonesData(null)) .finally(() => setZonesLoading(false)) }, []) useEffect(() => { if (isPolygon(areaGeoJson)) { fetchZones(areaGeoJson) } else { setZonesData(null) } }, [areaGeoJson, optimizationKey, fetchZones]) const handleAreaChange = useCallback((geojson: MapDrawGeoJSON) => { setAreaGeoJson(geojson) }, []) const handleZoneClick = useCallback((zone: ZoneInitialData) => { setZoneDetailLoading(true) setPanelOpen(true) setSelectedZone(null) cropZoningService .getZoneDetails(zone.zoneId) .then(details => setSelectedZone(details)) .catch(() => setSelectedZone(null)) .finally(() => setZoneDetailLoading(false)) }, []) const handleOptimize = useCallback(() => { setOptimizationKey(k => k + 1) }, []) return ( {areaGeoJson ? ( ) : ( )} {(areaLoading || zonesLoading) && ( )} {areaGeoJson && ( )} setPanelOpen(false)} zone={selectedZone} products={products} loading={zoneDetailLoading} /> ) }