'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 && (
}
onClick={handleOptimize}
disabled={zonesLoading}
className='rounded-xl shadow-lg'
>
{t('optimizeAgain')}
)}
setPanelOpen(false)}
zone={selectedZone}
products={products}
loading={zoneDetailLoading}
/>
)
}