From cb29828a69a9dad0a3c49829674328ba1a4e107c Mon Sep 17 00:00:00 2001 From: Mohammad Sajad Pourajam Date: Sat, 21 Feb 2026 22:05:47 +0330 Subject: [PATCH] Remove deprecated dashboard pages and update vertical menu links for streamlined navigation - Deleted unused pages for crop zoning, farm AI assistant, fertilization recommendation, irrigation recommendation, pest detection, plant simulator, soil data, and water data. - Updated the vertical menu to reflect the removal of these pages, ensuring a cleaner and more efficient user experience. --- .../{dashboard => }/crop-zoning/page.tsx | 0 .../farm-ai-assistant/page.tsx | 0 .../fertilization-recommendation/page.tsx | 0 .../irrigation-recommendation/page.tsx | 0 .../{dashboard => }/pest-detection/page.tsx | 0 .../{dashboard => }/plant-simulator/page.tsx | 0 .../{dashboard => }/soil-data/page.tsx | 0 .../{dashboard => }/water-data/page.tsx | 0 .../layout/vertical/VerticalMenu.tsx | 30 +++-- .../farm/SoilDataDashboardWrapper.tsx | 47 ++++---- .../farm/WaterDataDashboardWrapper.tsx | 45 +++++--- .../farm/cropZoning/CropZoningMap.tsx | 65 +++++++---- .../cropZoning/CropZoningWeatherSection.tsx | 105 ++++++++++-------- .../farm/cropZoning/CropZoningWrapper.tsx | 5 +- .../farm/cropZoning/cropZoningMockData.ts | 23 ++++ .../farm/plantSimulator/PlantSimulator.tsx | 14 ++- 16 files changed, 208 insertions(+), 126 deletions(-) rename src/app/(dashboard)/(private)/{dashboard => }/crop-zoning/page.tsx (100%) rename src/app/(dashboard)/(private)/{dashboard => }/farm-ai-assistant/page.tsx (100%) rename src/app/(dashboard)/(private)/{dashboard => }/fertilization-recommendation/page.tsx (100%) rename src/app/(dashboard)/(private)/{dashboard => }/irrigation-recommendation/page.tsx (100%) rename src/app/(dashboard)/(private)/{dashboard => }/pest-detection/page.tsx (100%) rename src/app/(dashboard)/(private)/{dashboard => }/plant-simulator/page.tsx (100%) rename src/app/(dashboard)/(private)/{dashboard => }/soil-data/page.tsx (100%) rename src/app/(dashboard)/(private)/{dashboard => }/water-data/page.tsx (100%) create mode 100644 src/views/dashboards/farm/cropZoning/cropZoningMockData.ts diff --git a/src/app/(dashboard)/(private)/dashboard/crop-zoning/page.tsx b/src/app/(dashboard)/(private)/crop-zoning/page.tsx similarity index 100% rename from src/app/(dashboard)/(private)/dashboard/crop-zoning/page.tsx rename to src/app/(dashboard)/(private)/crop-zoning/page.tsx diff --git a/src/app/(dashboard)/(private)/dashboard/farm-ai-assistant/page.tsx b/src/app/(dashboard)/(private)/farm-ai-assistant/page.tsx similarity index 100% rename from src/app/(dashboard)/(private)/dashboard/farm-ai-assistant/page.tsx rename to src/app/(dashboard)/(private)/farm-ai-assistant/page.tsx diff --git a/src/app/(dashboard)/(private)/dashboard/fertilization-recommendation/page.tsx b/src/app/(dashboard)/(private)/fertilization-recommendation/page.tsx similarity index 100% rename from src/app/(dashboard)/(private)/dashboard/fertilization-recommendation/page.tsx rename to src/app/(dashboard)/(private)/fertilization-recommendation/page.tsx diff --git a/src/app/(dashboard)/(private)/dashboard/irrigation-recommendation/page.tsx b/src/app/(dashboard)/(private)/irrigation-recommendation/page.tsx similarity index 100% rename from src/app/(dashboard)/(private)/dashboard/irrigation-recommendation/page.tsx rename to src/app/(dashboard)/(private)/irrigation-recommendation/page.tsx diff --git a/src/app/(dashboard)/(private)/dashboard/pest-detection/page.tsx b/src/app/(dashboard)/(private)/pest-detection/page.tsx similarity index 100% rename from src/app/(dashboard)/(private)/dashboard/pest-detection/page.tsx rename to src/app/(dashboard)/(private)/pest-detection/page.tsx diff --git a/src/app/(dashboard)/(private)/dashboard/plant-simulator/page.tsx b/src/app/(dashboard)/(private)/plant-simulator/page.tsx similarity index 100% rename from src/app/(dashboard)/(private)/dashboard/plant-simulator/page.tsx rename to src/app/(dashboard)/(private)/plant-simulator/page.tsx diff --git a/src/app/(dashboard)/(private)/dashboard/soil-data/page.tsx b/src/app/(dashboard)/(private)/soil-data/page.tsx similarity index 100% rename from src/app/(dashboard)/(private)/dashboard/soil-data/page.tsx rename to src/app/(dashboard)/(private)/soil-data/page.tsx diff --git a/src/app/(dashboard)/(private)/dashboard/water-data/page.tsx b/src/app/(dashboard)/(private)/water-data/page.tsx similarity index 100% rename from src/app/(dashboard)/(private)/dashboard/water-data/page.tsx rename to src/app/(dashboard)/(private)/water-data/page.tsx diff --git a/src/components/layout/vertical/VerticalMenu.tsx b/src/components/layout/vertical/VerticalMenu.tsx index 306a705..9d690bc 100644 --- a/src/components/layout/vertical/VerticalMenu.tsx +++ b/src/components/layout/vertical/VerticalMenu.tsx @@ -95,36 +95,34 @@ const VerticalMenu = ({ scrollMenu }: Props) => { {t('dashboards')} - - }> + }> {t('waterData')} - }> + }> {t('soilData')} - }> + }> {t('cropZoning')} - - - }> + + + }> {t('plantSimulator')} - - - - }> + + + }> {t('irrigationRecommendation')} - }> + }> {t('fertilizationRecommendation')} - - - }> + + + }> {t('farmAiAssistant')} - }> + }> {t('pestDetection')} diff --git a/src/views/dashboards/farm/SoilDataDashboardWrapper.tsx b/src/views/dashboards/farm/SoilDataDashboardWrapper.tsx index d3bb7a2..7f54d4c 100644 --- a/src/views/dashboards/farm/SoilDataDashboardWrapper.tsx +++ b/src/views/dashboards/farm/SoilDataDashboardWrapper.tsx @@ -18,19 +18,18 @@ import AnomalyDetectionCard from '@views/dashboards/farm/AnomalyDetectionCard' // Service import { farmDashboardService } from '@/libs/api/services/farmDashboardService' import type { CardId } from '@views/dashboards/farm/farmDashboardConfig' -import { CARD_GRID_SIZE } from '@views/dashboards/farm/farmDashboardConfig' -const SOIL_CARD_IDS: CardId[] = [ - 'soilMoistureHeatmap', - 'sensorValuesList', - 'sensorRadarChart', - 'sensorComparisonChart', - 'anomalyDetectionCard' +/** هر ردیف: آرایهٔ کارت‌ها؛ در هر ردیف فضا مساوی بین گریدها تقسیم می‌شود (جمع = ۱۲) */ +const SOIL_ROWS: CardId[][] = [ + ['soilMoistureHeatmap'], + ['sensorValuesList', 'sensorRadarChart'], + ['sensorComparisonChart', 'anomalyDetectionCard'] ] const cardRowSx = { display: 'flex', flexDirection: 'column', + minHeight: 380, '& > *': { flex: 1, minHeight: 0 } } @@ -65,18 +64,28 @@ const SoilDataDashboardWrapper = () => { return ( - - {SOIL_CARD_IDS.map(cardId => { - const size = CARD_GRID_SIZE[cardId] - const Component = CARD_COMPONENTS[cardId] - if (!Component) return null - return ( - - - - ) - })} - + {SOIL_ROWS.map((rowCards, rowIndex) => { + const sizePerCard = 12 / rowCards.length + return ( + + {rowCards.map(cardId => { + const Component = CARD_COMPONENTS[cardId] + if (!Component) return null + return ( + + + + ) + })} + + ) + })} ) diff --git a/src/views/dashboards/farm/WaterDataDashboardWrapper.tsx b/src/views/dashboards/farm/WaterDataDashboardWrapper.tsx index f953973..1c49aa9 100644 --- a/src/views/dashboards/farm/WaterDataDashboardWrapper.tsx +++ b/src/views/dashboards/farm/WaterDataDashboardWrapper.tsx @@ -17,18 +17,17 @@ import SensorValuesList from '@views/dashboards/farm/SensorValuesList' // Service import { farmDashboardService } from '@/libs/api/services/farmDashboardService' import type { CardId } from '@views/dashboards/farm/farmDashboardConfig' -import { CARD_GRID_SIZE } from '@views/dashboards/farm/farmDashboardConfig' -const WATER_CARD_IDS: CardId[] = [ - 'farmWeatherCard', - 'farmAlertsTimeline', - 'waterNeedPrediction', - 'sensorValuesList' +/** هر ردیف: آرایهٔ کارت‌ها؛ در هر ردیف فضا مساوی بین گریدها تقسیم می‌شود (جمع = ۱۲) */ +const WATER_ROWS: CardId[][] = [ + ['farmWeatherCard', 'farmAlertsTimeline', 'waterNeedPrediction'], + ['sensorValuesList'] ] const cardRowSx = { display: 'flex', flexDirection: 'column', + minHeight: 380, '& > *': { flex: 1, minHeight: 0 } } @@ -62,18 +61,28 @@ const WaterDataDashboardWrapper = () => { return ( - - {WATER_CARD_IDS.map(cardId => { - const size = CARD_GRID_SIZE[cardId] - const Component = CARD_COMPONENTS[cardId] - if (!Component) return null - return ( - - - - ) - })} - + {WATER_ROWS.map((rowCards, rowIndex) => { + const sizePerCard = 12 / rowCards.length + return ( + + {rowCards.map(cardId => { + const Component = CARD_COMPONENTS[cardId] + if (!Component) return null + return ( + + + + ) + })} + + ) + })} ) diff --git a/src/views/dashboards/farm/cropZoning/CropZoningMap.tsx b/src/views/dashboards/farm/cropZoning/CropZoningMap.tsx index 313fb12..2969106 100644 --- a/src/views/dashboards/farm/cropZoning/CropZoningMap.tsx +++ b/src/views/dashboards/farm/cropZoning/CropZoningMap.tsx @@ -19,6 +19,10 @@ type CropZoningMapProps = { onZoneClick?: (zone: ZoneFeatureProperties) => void optimizationKey?: number className?: string + /** منطقهٔ اولیه از دیتای ماک؛ وقتی مقدار دارد نقشه فقط نمایشی است و کاربر نمیتواند منطقه را تغییر دهد */ + initialAreaGeoJson?: MapDrawGeoJSON | null + /** غیرفعال کردن رسم و ویرایش منطقه توسط کاربر */ + readOnly?: boolean } export default function CropZoningMap({ @@ -29,7 +33,9 @@ export default function CropZoningMap({ onAreaChange, onZoneClick, optimizationKey = 0, - className = '' + className = '', + initialAreaGeoJson = null, + readOnly = false }: CropZoningMapProps) { const mapRef = useRef(null) const mapInstanceRef = useRef(null) @@ -124,21 +130,22 @@ export default function CropZoningMap({ const drawnItems = L.featureGroup().addTo(map) drawnItemsRef.current = drawnItems - const drawControl = new L.Control.Draw({ - position: 'topright', - draw: { - polygon: { shapeOptions: { color: '#3388ff' } }, - rectangle: { shapeOptions: { color: '#3388ff' } }, - circle: false, - circlemarker: false, - marker: false, - polyline: false - }, - edit: { featureGroup: drawnItems, remove: true } - }) - - map.addControl(drawControl) - drawControlRef.current = drawControl + if (!readOnly) { + const drawControl = new L.Control.Draw({ + position: 'topright', + draw: { + polygon: { shapeOptions: { color: '#3388ff' } }, + rectangle: { shapeOptions: { color: '#3388ff' } }, + circle: false, + circlemarker: false, + marker: false, + polyline: false + }, + edit: { featureGroup: drawnItems, remove: true } + }) + map.addControl(drawControl) + drawControlRef.current = drawControl + } const getGeoJsonFromDrawn = (): MapDrawGeoJSON => { const geojson = drawnItems.toGeoJSON() @@ -159,6 +166,12 @@ export default function CropZoningMap({ } } + if (readOnly && initialAreaGeoJson && initialAreaGeoJson.geometry && (initialAreaGeoJson.geometry as { type: string }).type === 'Polygon') { + drawnItems.clearLayers() + L.geoJSON(initialAreaGeoJson as Feature).eachLayer((layer) => drawnItems.addLayer(layer)) + emitAndRender() + } + const onCreated = (e: L.LeafletEvent) => { const event = e as L.DrawEvents.Created drawnItems.clearLayers() @@ -175,17 +188,23 @@ export default function CropZoningMap({ } } - map.on(L.Draw.Event.CREATED, onCreated) - map.on(L.Draw.Event.EDITED, onEdited) - map.on(L.Draw.Event.DELETED, onDeleted) + if (!readOnly) { + map.on(L.Draw.Event.CREATED, onCreated) + map.on(L.Draw.Event.EDITED, onEdited) + map.on(L.Draw.Event.DELETED, onDeleted) + } mapInstanceRef.current = map cleanupFn = () => { - map.off(L.Draw.Event.CREATED, onCreated) - map.off(L.Draw.Event.EDITED, onEdited) - map.off(L.Draw.Event.DELETED, onDeleted) - map.removeControl(drawControl) + if (!readOnly) { + map.off(L.Draw.Event.CREATED, onCreated) + map.off(L.Draw.Event.EDITED, onEdited) + map.off(L.Draw.Event.DELETED, onDeleted) + if (drawControlRef.current) { + map.removeControl(drawControlRef.current) + } + } if (zonesLayerRef.current) map.removeLayer(zonesLayerRef.current) map.remove() mapInstanceRef.current = null diff --git a/src/views/dashboards/farm/cropZoning/CropZoningWeatherSection.tsx b/src/views/dashboards/farm/cropZoning/CropZoningWeatherSection.tsx index 445496f..90d6d49 100644 --- a/src/views/dashboards/farm/cropZoning/CropZoningWeatherSection.tsx +++ b/src/views/dashboards/farm/cropZoning/CropZoningWeatherSection.tsx @@ -96,64 +96,77 @@ export default function CropZoningWeatherSection() { const humidity = (weatherData.humidity as number) ?? 45 const windSpeed = (weatherData.windSpeed as number) ?? 12 + const cardRowSx = { + display: 'flex', + flexDirection: 'column' as const, + minHeight: 200, + '& > *': { flex: 1, minHeight: 0 } + } + return ( {t('title')} - - + {/* Row 1: Weather + 3 KPI cards — equal width (3 each on md+) */} + + + + + + + + + + {t('temperature')} + + + {temp} + {weatherData.unit ?? '°C'} + + + + + + + + + + {t('humidity')} + + {humidity}% + + + + + + + + + {t('windSpeed')} + + + {windSpeed} {(weatherData.windUnit as string) ?? 'km/h'} + + + + - - - - - - {t('temperature')} - - - {temp} - {weatherData.unit ?? '°C'} - - - - - - - - - - - {t('humidity')} - - {humidity}% - - - - - - - - - - {t('windSpeed')} - - - {windSpeed} {(weatherData.windUnit as string) ?? 'km/h'} - - - - - - - + {/* Row 2: Forecast chart — full width */} + + - + Promise.resolve(CropZoningMap), { export default function CropZoningWrapper() { const t = useTranslations('cropZoning') - const [areaGeoJson, setAreaGeoJson] = useState(null) + const [areaGeoJson, setAreaGeoJson] = useState(MOCK_AREA_GEOJSON) const [activeLayer, setActiveLayer] = useState('crops') const [selectedZone, setSelectedZone] = useState(null) const [panelOpen, setPanelOpen] = useState(false) @@ -58,6 +59,8 @@ export default function CropZoningWrapper() { onZoneClick={handleZoneClick} optimizationKey={optimizationKey} className='min-bs-[400px]' + initialAreaGeoJson={MOCK_AREA_GEOJSON} + readOnly /> diff --git a/src/views/dashboards/farm/cropZoning/cropZoningMockData.ts b/src/views/dashboards/farm/cropZoning/cropZoningMockData.ts new file mode 100644 index 0000000..b0e8d43 --- /dev/null +++ b/src/views/dashboards/farm/cropZoning/cropZoningMockData.ts @@ -0,0 +1,23 @@ +import type { MapDrawGeoJSON } from './CropZoningMap' + +/** + * منطقهٔ ثابت برای نمایش روی نقشه (دیتای ماک). + * کاربر امکان تغییر یا رسم منطقهٔ جدید را ندارد. + * مختصات: یک چندضلعی حول تهران [35.6892, 51.389] — در GeoJSON به صورت [lng, lat]. + */ +export const MOCK_AREA_GEOJSON: MapDrawGeoJSON = { + type: 'Feature', + properties: {}, + geometry: { + type: 'Polygon', + coordinates: [ + [ + [51.38, 35.68], + [51.40, 35.68], + [51.40, 35.70], + [51.38, 35.70], + [51.38, 35.68] + ] + ] + } +} as MapDrawGeoJSON diff --git a/src/views/dashboards/farm/plantSimulator/PlantSimulator.tsx b/src/views/dashboards/farm/plantSimulator/PlantSimulator.tsx index bdd9b0c..e2aee09 100644 --- a/src/views/dashboards/farm/plantSimulator/PlantSimulator.tsx +++ b/src/views/dashboards/farm/plantSimulator/PlantSimulator.tsx @@ -415,6 +415,7 @@ const GrowthChart = memo(function GrowthChart({ const chartOptions = { responsive: true, + maintainAspectRatio: false, animation: { duration: 0 }, plugins: { legend: { labels: { font: { size: 11 } } }, @@ -510,7 +511,14 @@ const GrowthChart = memo(function GrowthChart({ ] } - return + return ( + + + + ) }) // ─── Main Component ─────────────────────────────────────────────────────────── @@ -715,12 +723,12 @@ export default function PlantSimulator() { ] return ( - + 🌱 {t('title')} - + {/* ── Left: Plant visualization ── */}