From 0eb109725e2ab6bdde0d81c00211565079af9f83 Mon Sep 17 00:00:00 2001 From: Mohammad Sajad Pourajam Date: Fri, 20 Feb 2026 23:48:14 +0330 Subject: [PATCH] Add plant simulator feature with Persian localization and UI enhancements - Introduced a new Plant Simulator section in the dashboard with a dedicated menu item. - Added Persian translations for plant growth metrics and chart titles. - Enhanced the GrowthChart component to utilize localized labels for better user experience. - Updated PlantSimulator component to display plant statistics and growth visualization. - Improved UI layout with Material-UI components for a more polished appearance. --- messages/fa.json | 31 ++ .../layout/vertical/VerticalMenu.tsx | 3 + .../farm/plantSimulator/PlantSimulator.tsx | 513 +++++++++--------- 3 files changed, 305 insertions(+), 242 deletions(-) diff --git a/messages/fa.json b/messages/fa.json index 486f50a..f62f745 100644 --- a/messages/fa.json +++ b/messages/fa.json @@ -37,6 +37,7 @@ "waterData": "دیتاهای آب", "soilData": "اطلاعات خاک", "cropZoning": "زون‌بندی کشت", + "plantSimulator": "شبیه‌ساز رشد گیاه", "dataSection": "بخش داده‌ها", "crm": "مدیریت ارتباط با مشتری", "analytics": "تحلیل‌ها", @@ -561,5 +562,35 @@ "forecastChart": "پیش‌بینی هوا", "forecastSubheader": "دما و رطوبت در ۷ روز آینده" } + }, + "plantSimulator": { + "title": "شبیه‌ساز رشد گیاه", + "height": "ارتفاع", + "leaves": "برگ", + "branches": "شاخه", + "fruits": "میوه", + "yield": "محصول (g)", + "yieldRate": "سرعت (g/s)", + "maxGrowthReached": "گیاه به حداکثر رشد رسید!", + "controls": "کنترل‌ها", + "stop": "توقف", + "start": "شروع", + "reset": "ریست", + "growthSpeed": "سرعت رشد", + "light": "نور", + "water": "آب", + "effectiveRate": "نرخ رشد مؤثر", + "chartTitle": "نمودار رشد گیاه", + "chartHeight": "ارتفاع", + "chartLeaves": "برگ", + "chartHeightPx": "ارتفاع (px)", + "chartLeafCount": "تعداد برگ", + "chartYield": "محصول (g)", + "chartYieldRate": "سرعت محصول (g/s)", + "progressGrowth": "پیشرفت رشد", + "lightStatus": "وضعیت نور", + "waterStatus": "وضعیت آب", + "yieldStatus": "محصول دهی", + "description": "این شبیه‌ساز رشد گیاه را بر اساس سرعت پایه، میزان نور خورشید و آب دریافتی محاسبه می‌کند. هر برگ به صورت تدریجی روی ساقه ظاهر شده و با حرکت طبیعی در باد نمایش داده می‌شود. محصول‌دهی (g) پس از ۲۰٪ رشد شروع شده و با تعداد برگ، نور و آب شتاب می‌گیرد. سرعت محصول (g/s) نشان‌دهنده نرخ لحظه‌ای تولید است. نمودار تغییرات همه شاخص‌ها را در طول زمان ثبت می‌کند." } } diff --git a/src/components/layout/vertical/VerticalMenu.tsx b/src/components/layout/vertical/VerticalMenu.tsx index d7f73fa..bc535d0 100644 --- a/src/components/layout/vertical/VerticalMenu.tsx +++ b/src/components/layout/vertical/VerticalMenu.tsx @@ -105,6 +105,9 @@ const VerticalMenu = ({ scrollMenu }: Props) => { }> {t('cropZoning')} + }> + {t('plantSimulator')} + diff --git a/src/views/dashboards/farm/plantSimulator/PlantSimulator.tsx b/src/views/dashboards/farm/plantSimulator/PlantSimulator.tsx index 70c7115..bdd9b0c 100644 --- a/src/views/dashboards/farm/plantSimulator/PlantSimulator.tsx +++ b/src/views/dashboards/farm/plantSimulator/PlantSimulator.tsx @@ -1,6 +1,7 @@ 'use client' import { useEffect, useRef, useState, useCallback, memo } from 'react' +import { useTranslations } from 'next-intl' import { Chart as ChartJS, LineElement, @@ -13,6 +14,12 @@ import { Filler } from 'chart.js' import { Line } from 'react-chartjs-2' +import Card from '@mui/material/Card' +import CardContent from '@mui/material/CardContent' +import Typography from '@mui/material/Typography' +import Box from '@mui/material/Box' +import Grid from '@mui/material/Grid2' +import Button from '@mui/material/Button' ChartJS.register(LineElement, PointElement, LinearScale, CategoryScale, Title, Tooltip, Legend, Filler) @@ -393,59 +400,6 @@ function PlantSVG({ plant, tick, running }: { plant: PlantState; tick: number; r // ─── Growth Chart ───────────────────────────────────────────────────────────── -const CHART_OPTIONS = { - responsive: true, - animation: { duration: 0 }, - plugins: { - legend: { labels: { color: '#e2e8f0', font: { size: 11 } } }, - title: { - display: true, - text: 'نمودار رشد گیاه', - color: '#e2e8f0', - font: { size: 14 } - } - }, - scales: { - x: { - ticks: { color: '#94a3b8', maxTicksLimit: 8 }, - grid: { color: 'rgba(148,163,184,0.1)' } - }, - yHeight: { - type: 'linear' as const, - position: 'left' as const, - min: 0, - max: MAX_HEIGHT, - ticks: { color: '#4a7c59' }, - grid: { color: 'rgba(148,163,184,0.1)' }, - title: { display: true, text: 'ارتفاع', color: '#4a7c59' } - }, - yLeaf: { - type: 'linear' as const, - position: 'right' as const, - min: 0, - max: MAX_LEAVES, - ticks: { color: '#f9c74f' }, - grid: { display: false }, - title: { display: true, text: 'برگ', color: '#f9c74f' } - }, - yYield: { - type: 'linear' as const, - position: 'left' as const, - min: 0, - max: MAX_YIELD, - display: false, - grid: { display: false } - }, - yYieldRate: { - type: 'linear' as const, - position: 'right' as const, - min: 0, - display: false, - grid: { display: false } - } - } -} - const GrowthChart = memo(function GrowthChart({ heightHistory, leafHistory, @@ -457,13 +411,63 @@ const GrowthChart = memo(function GrowthChart({ yieldHistory: number[] yieldRateHistory: number[] }) { + const t = useTranslations('plantSimulator') + + const chartOptions = { + responsive: true, + animation: { duration: 0 }, + plugins: { + legend: { labels: { font: { size: 11 } } }, + title: { + display: true, + text: t('chartTitle'), + font: { size: 14 } + } + }, + scales: { + x: { + ticks: { maxTicksLimit: 8 } + }, + yHeight: { + type: 'linear' as const, + position: 'left' as const, + min: 0, + max: MAX_HEIGHT, + title: { display: true, text: t('chartHeight') } + }, + yLeaf: { + type: 'linear' as const, + position: 'right' as const, + min: 0, + max: MAX_LEAVES, + grid: { display: false }, + title: { display: true, text: t('chartLeaves') } + }, + yYield: { + type: 'linear' as const, + position: 'left' as const, + min: 0, + max: MAX_YIELD, + display: false, + grid: { display: false } + }, + yYieldRate: { + type: 'linear' as const, + position: 'right' as const, + min: 0, + display: false, + grid: { display: false } + } + } + } + const labels = heightHistory.map((_, i) => `${i}s`) const data = { labels, datasets: [ { - label: 'ارتفاع (px)', + label: t('chartHeightPx'), data: heightHistory, borderColor: '#4a7c59', backgroundColor: 'rgba(74,124,89,0.10)', @@ -473,7 +477,7 @@ const GrowthChart = memo(function GrowthChart({ yAxisID: 'yHeight' }, { - label: 'تعداد برگ', + label: t('chartLeafCount'), data: leafHistory, borderColor: '#f9c74f', backgroundColor: 'rgba(249,199,79,0.10)', @@ -483,7 +487,7 @@ const GrowthChart = memo(function GrowthChart({ yAxisID: 'yLeaf' }, { - label: 'محصول (g)', + label: t('chartYield'), data: yieldHistory, borderColor: '#f97316', backgroundColor: 'rgba(249,115,22,0.10)', @@ -493,7 +497,7 @@ const GrowthChart = memo(function GrowthChart({ yAxisID: 'yYield' }, { - label: 'سرعت محصول (g/s)', + label: t('chartYieldRate'), data: yieldRateHistory, borderColor: '#a78bfa', backgroundColor: 'rgba(167,139,250,0.10)', @@ -506,7 +510,7 @@ const GrowthChart = memo(function GrowthChart({ ] } - return + return }) // ─── Main Component ─────────────────────────────────────────────────────────── @@ -698,207 +702,232 @@ export default function PlantSimulator() { } }, [running]) + const t = useTranslations('plantSimulator') const isFinished = plant.height >= MAX_HEIGHT + const statItems: { value: string | number; label: string; color: 'success' | 'warning' | 'error' | 'secondary' }[] = [ + { value: Math.round(plant.height), label: t('height'), color: 'success' }, + { value: plant.leaves.length, label: t('leaves'), color: 'warning' }, + { value: plant.branches.length, label: t('branches'), color: 'success' }, + { value: plant.fruits.length, label: t('fruits'), color: 'error' }, + { value: plant.yield.toFixed(1), label: t('yield'), color: 'warning' }, + { value: plant.yieldRate.toFixed(2), label: t('yieldRate'), color: 'secondary' } + ] + return ( -
-

- 🌱 شبیه‌ساز رشد گیاه -

- -
+ + + 🌱 {t('title')} + + {/* ── Left: Plant visualization ── */} -
-
- + + + + - {/* Stats */} -
-
-
{Math.round(plant.height)}
-
ارتفاع
-
-
-
{plant.leaves.length}
-
برگ
-
-
-
{plant.branches.length}
-
شاخه
-
-
-
{plant.fruits.length}
-
میوه
-
-
-
{plant.yield.toFixed(1)}
-
محصول (g)
-
-
-
{plant.yieldRate.toFixed(2)}
-
سرعت (g/s)
-
-
+ + {statItems.map((item, idx) => ( + + + + {item.value} + + + {item.label} + + + + ))} + - {isFinished && ( -
- 🌼 گیاه به حداکثر رشد رسید! -
- )} -
+ {isFinished && ( + + 🌼 {t('maxGrowthReached')} + + )} + + {/* Controls */} -
-

کنترل‌ها

+ + + + {t('controls')} + - {/* Start / Stop / Reset */} -
- - -
+ + + + - {/* Speed slider */} -
- - setSpeed(Number(e.target.value))} - className='w-full accent-green-500' - /> -
+ + + {t('growthSpeed')} + {speed.toFixed(1)}× + + setSpeed(Number(e.target.value))} + className='w-full' + /> + - {/* Light */} -
- - setEnv(prev => ({ ...prev, light: Number(e.target.value) }))} - className='w-full accent-yellow-400' - /> -
+ + + ☀️ {t('light')} + {env.light}% + + setEnv(prev => ({ ...prev, light: Number(e.target.value) }))} + className='w-full' + /> + - {/* Water */} -
- - setEnv(prev => ({ ...prev, water: Number(e.target.value) }))} - className='w-full accent-blue-400' - /> -
+ + + 💧 {t('water')} + {env.water}% + + setEnv(prev => ({ ...prev, water: Number(e.target.value) }))} + className='w-full' + /> + - {/* Effective rate indicator */} -
- نرخ رشد مؤثر:{' '} - - {growthRate(env, speed).toFixed(2)}× - -
-
-
+ + + {t('effectiveRate')}{' '} + + {growthRate(env, speed).toFixed(2)}× + + + + + +
{/* ── Right: Chart ── */} -
- + + + + - {/* Info cards */} -
-
-
پیشرفت رشد
-
-
-
-
- {Math.round((plant.height / MAX_HEIGHT) * 100)}% -
-
+ + + + + {t('progressGrowth')} + + + + + + {Math.round((plant.height / MAX_HEIGHT) * 100)}% + + + + + + + {t('lightStatus')} + + + + + + {env.light}% + + + + + + + {t('waterStatus')} + + + + + + {env.water}% + + + + + + + {t('yieldStatus')} + + + + + + + {plant.yield.toFixed(1)}g + + + {plant.yieldRate.toFixed(3)} g/s + + + + + -
-
وضعیت نور
-
-
-
-
{env.light}%
-
- -
-
وضعیت آب
-
-
-
-
{env.water}%
-
- -
-
محصول دهی
-
-
-
-
- {plant.yield.toFixed(1)}g - {plant.yieldRate.toFixed(3)} g/s -
-
-
- - {/* Description */} -
-

- این شبیه‌ساز رشد گیاه را بر اساس سرعت پایه، میزان نور خورشید و آب دریافتی - محاسبه می‌کند. هر برگ به صورت تدریجی روی ساقه ظاهر شده و با حرکت طبیعی - در باد نمایش داده می‌شود. محصول‌دهی (g) پس از ۲۰٪ رشد شروع شده - و با تعداد برگ، نور و آب شتاب می‌گیرد. سرعت محصول (g/s) نشان‌دهنده - نرخ لحظه‌ای تولید است. نمودار تغییرات همه شاخص‌ها را در طول زمان ثبت می‌کند. -

-
-
- -
-
+ + + {t('description')} + + + + + + + ) }