This commit is contained in:
2026-04-30 04:00:19 +03:30
parent 9946f01cca
commit 07240b03bb
18 changed files with 4295 additions and 62 deletions
+3
View File
@@ -38,6 +38,7 @@
"recommendation": "توصیه‌ها", "recommendation": "توصیه‌ها",
"irrigationRecommendation": "توصیه آبیاری", "irrigationRecommendation": "توصیه آبیاری",
"fertilizationRecommendation": "توصیه کوددهی", "fertilizationRecommendation": "توصیه کوددهی",
"fertilizationPlanParser": "برنامه آبیاری و کودهی",
"aiAssistant": "دستیار هوشمند", "aiAssistant": "دستیار هوشمند",
"farmAiAssistant": "دستیار هوشمند مزرعه", "farmAiAssistant": "دستیار هوشمند مزرعه",
"pestDetection": "تشخیص آفات گیاهی", "pestDetection": "تشخیص آفات گیاهی",
@@ -151,7 +152,9 @@
"yieldHarvest": "عملکرد و برداشت", "yieldHarvest": "عملکرد و برداشت",
"farmAlerts": "هشدارهای مزرعه", "farmAlerts": "هشدارهای مزرعه",
"pestDiseaseRisk": "ریسک آفات و بیماری", "pestDiseaseRisk": "ریسک آفات و بیماری",
"farmerTodos": "کارهای روزانه",
"economicOverview": "نمای اقتصادی", "economicOverview": "نمای اقتصادی",
"farmWallet": "کیف پول مزرعه",
"farmCalendar": "تقویم کشاورز", "farmCalendar": "تقویم کشاورز",
"sensorSection": "سنسورها", "sensorSection": "سنسورها",
"sensor7In1": "سنسور خاک 7 در 1" "sensor7In1": "سنسور خاک 7 در 1"
@@ -0,0 +1,7 @@
import EconomicOverviewPageWrapper from "@views/dashboards/farm/EconomicOverviewPageWrapper";
const EconomyPage = () => {
return <EconomicOverviewPageWrapper />;
};
export default EconomyPage;
@@ -0,0 +1,7 @@
import FarmerTodoPage from "@views/dashboards/farm/todos/FarmerTodoPage";
const FarmerTodos = () => {
return <FarmerTodoPage />;
};
export default FarmerTodos;
@@ -0,0 +1,7 @@
import FertilizationPlanParserPage from "@views/dashboards/farm/fertilizationPlanParser/FertilizationPlanParserPage";
const FertilizationPlanPage = () => {
return <FertilizationPlanParserPage />;
};
export default FertilizationPlanPage;
@@ -0,0 +1,7 @@
import FarmWalletPage from "@views/dashboards/farm/wallet/FarmWalletPage";
const WalletPage = () => {
return <FarmWalletPage />;
};
export default WalletPage;
+64 -26
View File
@@ -1,5 +1,5 @@
// React Imports // React Imports
import { useTranslations } from 'next-intl' import { useTranslations } from "next-intl";
// MUI Imports // MUI Imports
import { useTheme } from "@mui/material/styles"; import { useTheme } from "@mui/material/styles";
@@ -49,7 +49,7 @@ const RenderExpandIcon = ({
); );
const VerticalMenu = ({ scrollMenu }: Props) => { const VerticalMenu = ({ scrollMenu }: Props) => {
const t = useTranslations('navigation') const t = useTranslations("navigation");
const theme = useTheme(); const theme = useTheme();
const verticalNavOptions = useVerticalNav(); const verticalNavOptions = useVerticalNav();
@@ -92,53 +92,91 @@ const VerticalMenu = ({ scrollMenu }: Props) => {
href={`/dashboard`} href={`/dashboard`}
icon={<i className="tabler-smart-home" />} icon={<i className="tabler-smart-home" />}
> >
{t('dashboards')} {t("dashboards")}
</MenuItem> </MenuItem>
<MenuSection label={t('farmDomain')}> <MenuSection label={t("farmDomain")}>
<MenuItem href="/yield-harvest" icon={<i className="tabler-chart-line" />}> <MenuItem
{t('yieldHarvest')} href="/yield-harvest"
icon={<i className="tabler-chart-line" />}
>
{t("yieldHarvest")}
</MenuItem> </MenuItem>
<MenuItem href="/farm-alerts" icon={<i className="tabler-alert-triangle" />}> <MenuItem
{t('farmAlerts')} href="/farm-alerts"
icon={<i className="tabler-alert-triangle" />}
>
{t("farmAlerts")}
</MenuItem> </MenuItem>
<MenuItem href="/pest-risk" icon={<i className="tabler-bug" />}> <MenuItem href="/pest-risk" icon={<i className="tabler-bug" />}>
{t('pestDiseaseRisk')} {t("pestDiseaseRisk")}
</MenuItem> </MenuItem>
<MenuItem href="/farmer-calendar" icon={<i className="tabler-calendar-event" />}> <MenuItem
{t('farmCalendar')} href="/farmer-todos"
icon={<i className="tabler-checklist" />}
>
{t("farmerTodos")}
</MenuItem>
<MenuItem href="/wallet" icon={<i className="tabler-wallet" />}>
{t("farmWallet")}
</MenuItem>
<MenuItem
href="/farmer-calendar"
icon={<i className="tabler-calendar-event" />}
>
{t("farmCalendar")}
</MenuItem>
<MenuItem
href="/economy"
icon={<i className="tabler-cash-banknote" />}
>
{t("economicOverview")}
</MenuItem> </MenuItem>
</MenuSection> </MenuSection>
<MenuSection label={t('dataSection')}> <MenuSection label={t("dataSection")}>
<MenuItem href="/water-data" icon={<i className="tabler-droplet" />}> <MenuItem href="/water-data" icon={<i className="tabler-droplet" />}>
{t('waterData')} {t("waterData")}
</MenuItem> </MenuItem>
<MenuItem href="/soil-data" icon={<i className="tabler-seedling" />}> <MenuItem href="/soil-data" icon={<i className="tabler-seedling" />}>
{t('soilData')} {t("soilData")}
</MenuItem> </MenuItem>
<MenuItem href="/crop-zoning" icon={<i className="tabler-map-2" />}> <MenuItem href="/crop-zoning" icon={<i className="tabler-map-2" />}>
{t('cropZoning')} {t("cropZoning")}
</MenuItem> </MenuItem>
</MenuSection> </MenuSection>
<MenuSection label={t('sensorSection')}> <MenuSection label={t("sensorSection")}>
<MenuItem href="/solid-sensor" icon={<i className="tabler-sensor" />}> <MenuItem href="/solid-sensor" icon={<i className="tabler-sensor" />}>
{t('sensor7In1')} {t("sensor7In1")}
</MenuItem> </MenuItem>
</MenuSection> </MenuSection>
<MenuSection label={t('recommendation')}> <MenuSection label={t("recommendation")}>
<MenuItem href="/irrigation-recommendation" icon={<i className="tabler-droplet-half-2" />}> <MenuItem
{t('irrigationRecommendation')} href="/irrigation-recommendation"
icon={<i className="tabler-droplet-half-2" />}
>
{t("irrigationRecommendation")}
</MenuItem> </MenuItem>
<MenuItem href="/fertilization-recommendation" icon={<i className="tabler-atom-2" />}> <MenuItem
{t('fertilizationRecommendation')} href="/fertilization-recommendation"
icon={<i className="tabler-atom-2" />}
>
{t("fertilizationRecommendation")}
</MenuItem>
<MenuItem
href="/fertilization-plan"
icon={<i className="tabler-sparkles" />}
>
{t("fertilizationPlanParser")}
</MenuItem> </MenuItem>
</MenuSection> </MenuSection>
<MenuSection label={t('aiAssistant')}> <MenuSection label={t("aiAssistant")}>
<MenuItem href="/farm-ai-assistant" icon={<i className="tabler-robot" />}> <MenuItem
{t('farmAiAssistant')} href="/farm-ai-assistant"
icon={<i className="tabler-robot" />}
>
{t("farmAiAssistant")}
</MenuItem> </MenuItem>
</MenuSection> </MenuSection>
</Menu> </Menu>
{/* <Menu {/* <Menu
popoutMenuOffset={{ mainAxis: 23 }} popoutMenuOffset={{ mainAxis: 23 }}
+2
View File
@@ -109,7 +109,9 @@
"yieldHarvest": "الإنتاج والحصاد", "yieldHarvest": "الإنتاج والحصاد",
"farmAlerts": "تنبيهات المزرعة", "farmAlerts": "تنبيهات المزرعة",
"pestDiseaseRisk": "مخاطر الآفات والأمراض", "pestDiseaseRisk": "مخاطر الآفات والأمراض",
"farmerTodos": "مهام المزارع",
"economicOverview": "النظرة الاقتصادية", "economicOverview": "النظرة الاقتصادية",
"farmWallet": "محفظة المزرعة",
"farmCalendar": "تقويم المزارع", "farmCalendar": "تقويم المزارع",
"dataSection": "قسم البيانات", "dataSection": "قسم البيانات",
"waterData": "بيانات المياه", "waterData": "بيانات المياه",
+2
View File
@@ -109,7 +109,9 @@
"yieldHarvest": "Yield & Harvest", "yieldHarvest": "Yield & Harvest",
"farmAlerts": "Farm Alerts", "farmAlerts": "Farm Alerts",
"pestDiseaseRisk": "Pest & Disease Risk", "pestDiseaseRisk": "Pest & Disease Risk",
"farmerTodos": "Farmer Todos",
"economicOverview": "Economic Overview", "economicOverview": "Economic Overview",
"farmWallet": "Farm Wallet",
"farmCalendar": "Farmer Calendar", "farmCalendar": "Farmer Calendar",
"dataSection": "Data Section", "dataSection": "Data Section",
"waterData": "Water Data", "waterData": "Water Data",
+2
View File
@@ -109,7 +109,9 @@
"yieldHarvest": "عملکرد و برداشت", "yieldHarvest": "عملکرد و برداشت",
"farmAlerts": "هشدارهای مزرعه", "farmAlerts": "هشدارهای مزرعه",
"pestDiseaseRisk": "ریسک آفات و بیماری", "pestDiseaseRisk": "ریسک آفات و بیماری",
"farmerTodos": "کارهای روزانه",
"economicOverview": "نمای اقتصادی", "economicOverview": "نمای اقتصادی",
"farmWallet": "کیف پول مزرعه",
"farmCalendar": "تقویم کشاورز", "farmCalendar": "تقویم کشاورز",
"dataSection": "بخش داده‌ها", "dataSection": "بخش داده‌ها",
"waterData": "دیتاهای آب", "waterData": "دیتاهای آب",
+2
View File
@@ -109,7 +109,9 @@
"yieldHarvest": "Rendement et récolte", "yieldHarvest": "Rendement et récolte",
"farmAlerts": "Alertes ferme", "farmAlerts": "Alertes ferme",
"pestDiseaseRisk": "Risque ravageurs et maladies", "pestDiseaseRisk": "Risque ravageurs et maladies",
"farmerTodos": "Taches de l'agriculteur",
"economicOverview": "Aperçu économique", "economicOverview": "Aperçu économique",
"farmWallet": "Portefeuille agricole",
"farmCalendar": "Calendrier de l'agriculteur", "farmCalendar": "Calendrier de l'agriculteur",
"dataSection": "Section des données", "dataSection": "Section des données",
"waterData": "Données sur l'eau", "waterData": "Données sur l'eau",
@@ -70,6 +70,16 @@ const horizontalMenuData = (): HorizontalMenuDataType[] => [
icon: 'tabler-bug', icon: 'tabler-bug',
href: '/pest-risk' href: '/pest-risk'
}, },
{
label: 'farmerTodos',
icon: 'tabler-checklist',
href: '/farmer-todos'
},
{
label: 'farmWallet',
icon: 'tabler-wallet',
href: '/wallet'
},
{ {
label: 'economicOverview', label: 'economicOverview',
icon: 'tabler-cash-banknote', icon: 'tabler-cash-banknote',
@@ -126,6 +136,16 @@ const horizontalMenuData = (): HorizontalMenuDataType[] => [
icon: 'tabler-bug', icon: 'tabler-bug',
href: '/pest-risk' href: '/pest-risk'
}, },
{
label: 'farmerTodos',
icon: 'tabler-checklist',
href: '/farmer-todos'
},
{
label: 'farmWallet',
icon: 'tabler-wallet',
href: '/wallet'
},
{ {
label: 'economicOverview', label: 'economicOverview',
icon: 'tabler-cash-banknote', icon: 'tabler-cash-banknote',
+10
View File
@@ -74,6 +74,16 @@ const verticalMenuData = (): VerticalMenuDataType[] => [
icon: 'tabler-bug', icon: 'tabler-bug',
href: '/pest-risk' href: '/pest-risk'
}, },
{
label: 'farmerTodos',
icon: 'tabler-checklist',
href: '/farmer-todos'
},
{
label: 'farmWallet',
icon: 'tabler-wallet',
href: '/wallet'
},
{ {
label: 'economicOverview', label: 'economicOverview',
icon: 'tabler-cash-banknote', icon: 'tabler-cash-banknote',
@@ -0,0 +1,74 @@
import { apiClient } from "../client";
const PREFIX = "/api/fertilization";
interface ApiResponse<T> {
code: number;
msg: string;
data: T;
}
export type FertilizationPlanParserStatus = "completed" | "needs_clarification";
export interface FertilizationPlanQuestion {
id: string;
field: string;
question: string;
rationale: string;
}
export interface FertilizationPlanApplication {
fertilizer_name: string | null;
formula: string | null;
amount: string | null;
application_method: string | null;
timing: string | null;
interval_days: number | null;
purpose: string | null;
}
export interface FertilizationPlanData {
crop_name: string | null;
growth_stage: string | null;
objective: string | null;
applications: FertilizationPlanApplication[];
notes: string[];
}
export interface FertilizationPlanParserResult {
status: FertilizationPlanParserStatus;
status_fa: string;
summary: string;
missing_fields: string[];
questions: FertilizationPlanQuestion[];
collected_data: FertilizationPlanData;
final_plan: FertilizationPlanData | null;
}
export type FertilizationPlanAnswerValue = string | number | boolean | null;
export interface FertilizationPlanParserPayload {
message?: string;
answers?: Record<string, FertilizationPlanAnswerValue>;
partial_plan?: FertilizationPlanData;
farm_uuid?: string;
}
async function unwrap<T>(promise: Promise<ApiResponse<T>>): Promise<T> {
const response = await promise;
return response.data;
}
export const fertilizationPlanParserService = {
parseFromText(
payload: FertilizationPlanParserPayload,
): Promise<FertilizationPlanParserResult> {
return unwrap(
apiClient.post<ApiResponse<FertilizationPlanParserResult>>(
`${PREFIX}/plan-from-text/`,
payload,
),
);
},
};
@@ -0,0 +1,71 @@
import { apiClient } from "../client";
const PREFIX = "/api/irrigation";
interface ApiResponse<T> {
code: number;
msg: string;
data: T;
}
export type IrrigationPlanParserStatus = "completed" | "needs_clarification";
export interface IrrigationPlanQuestion {
id: string;
field: string;
question: string;
rationale: string;
}
export interface IrrigationPlanData {
crop_name: string | null;
growth_stage: string | null;
irrigation_method: string | null;
water_amount_per_event: string | null;
duration_minutes: number | null;
frequency_text: string | null;
interval_days: number | null;
preferred_time_of_day: string | null;
start_date: string | null;
target_area: string | null;
trigger_conditions: string[];
notes: string[];
}
export interface IrrigationPlanParserResult {
status: IrrigationPlanParserStatus;
status_fa: string;
summary: string;
missing_fields: string[];
questions: IrrigationPlanQuestion[];
collected_data: IrrigationPlanData;
final_plan: IrrigationPlanData | null;
}
export type IrrigationPlanAnswerValue = string | number | boolean | null;
export interface IrrigationPlanParserPayload {
message?: string;
answers?: Record<string, IrrigationPlanAnswerValue>;
partial_plan?: IrrigationPlanData;
farm_uuid?: string;
}
async function unwrap<T>(promise: Promise<ApiResponse<T>>): Promise<T> {
const response = await promise;
return response.data;
}
export const irrigationPlanParserService = {
parseFromText(
payload: IrrigationPlanParserPayload,
): Promise<IrrigationPlanParserResult> {
return unwrap(
apiClient.post<ApiResponse<IrrigationPlanParserResult>>(
`${PREFIX}/plan-from-text/`,
payload,
),
);
},
};
@@ -1,60 +1,722 @@
'use client' "use client";
import { useEffect, useState } from 'react' import { useEffect, useMemo, useState } from "react";
import { useTranslations } from "next-intl";
import Box from '@mui/material/Box' import Box from "@mui/material/Box";
import CircularProgress from '@mui/material/CircularProgress' import Button from "@mui/material/Button";
import Grid from '@mui/material/Grid2' import Card from "@mui/material/Card";
import CardContent from "@mui/material/CardContent";
import CardHeader from "@mui/material/CardHeader";
import Chip from "@mui/material/Chip";
import CircularProgress from "@mui/material/CircularProgress";
import Grid from "@mui/material/Grid2";
import LinearProgress from "@mui/material/LinearProgress";
import Typography from "@mui/material/Typography";
import { alpha, useTheme } from "@mui/material/styles";
import { useFarmHub } from '@/hooks/useFarmHub' import type { ThemeColor } from "@core/types";
import { economicOverviewService } from '@/libs/api/services/economicOverviewService'
import EconomicOverview from '@views/dashboards/farm/EconomicOverview' import { useFarmHub } from "@/hooks/useFarmHub";
import { economicOverviewService } from "@/libs/api/services/economicOverviewService";
import OptionMenu from "@core/components/option-menu";
import CustomAvatar from "@core/components/mui/Avatar";
import HorizontalWithAvatar from "@components/card-statistics/HorizontalWithAvatar";
import Link from "@components/Link";
import EconomicOverview from "@views/dashboards/farm/EconomicOverview";
const cardRowSx = { const cardRowSx = {
display: 'flex', display: "flex",
flexDirection: 'column', flexDirection: "column",
minHeight: 380, minHeight: 380,
'& > *': { flex: 1, minHeight: 0 } "& > *": { flex: 1, minHeight: 0 },
} };
type EconomicItem = {
title: string;
value: string;
subtitle: string;
avatarIcon: string;
avatarColor: ThemeColor;
};
type ChartSeriesItem = {
name: string;
data: number[];
};
type FertilizerProductItem = {
fertilizerCode: string;
fertilizerName: string;
productName: string;
storeName: string;
price: string;
packageSize: string;
storeUrl: string;
color: ThemeColor;
};
const fertilizerProductsMock: FertilizerProductItem[] = [
{
fertilizerCode: "NPK-20-20-20",
fertilizerName: "کود کامل 20-20-20",
productName: "NPK یونیورسال گرین پلاس",
storeName: "فروشگاه سبزینه",
price: "۱,۹۸۰,۰۰۰ تومان",
packageSize: "کیسه 25 کیلوگرم",
storeUrl: "/apps/ecommerce/products/list",
color: "primary",
},
{
fertilizerCode: "UREA-46",
fertilizerName: "اوره 46 درصد",
productName: "اوره دانه ای کشاورزی مهر",
storeName: "مارکت نهاده یار",
price: "۱,۴۲۰,۰۰۰ تومان",
packageSize: "کیسه 50 کیلوگرم",
storeUrl: "/apps/ecommerce/products/list",
color: "success",
},
{
fertilizerCode: "MAP-12-61",
fertilizerName: "مونوآمونیوم فسفات",
productName: "MAP خالص برای شروع رشد",
storeName: "فروشگاه آگرومال",
price: "۲,۳۵۰,۰۰۰ تومان",
packageSize: "کیسه 25 کیلوگرم",
storeUrl: "/apps/ecommerce/products/list",
color: "warning",
},
];
const EconomicOverviewPageWrapper = () => { const EconomicOverviewPageWrapper = () => {
const { farmHub } = useFarmHub() const t = useTranslations("farmDashboard");
const farmUuid = farmHub?.farm_uuid const theme = useTheme();
const [data, setData] = useState<Record<string, unknown>>({}) const { farmHub } = useFarmHub();
const [loading, setLoading] = useState(true) const farmUuid = farmHub?.farm_uuid;
const [data, setData] = useState<Record<string, unknown>>({});
const [loading, setLoading] = useState(true);
const economicData = (data?.economicData as EconomicItem[] | undefined) ?? [];
const chartSeries =
(data?.chartSeries as ChartSeriesItem[] | undefined) ?? [];
const headlineCards = useMemo(
() =>
economicData.slice(0, 3).map((item) => ({
stats: item.value,
title: item.title,
avatarIcon: item.avatarIcon,
avatarColor: item.avatarColor,
})),
[economicData],
);
const portfolioMix = useMemo(() => {
const fallbackColors: ThemeColor[] = [
"primary",
"info",
"success",
"warning",
];
return chartSeries.map((series, index) => {
const total = series.data.reduce((sum, current) => sum + current, 0);
const max = chartSeries.reduce(
(best, item) =>
Math.max(
best,
item.data.reduce((sum, current) => sum + current, 0),
),
0,
);
return {
name: series.name,
total,
share: max > 0 ? Math.round((total / max) * 100) : 0,
color: fallbackColors[index % fallbackColors.length],
};
});
}, [chartSeries]);
const completionValue = useMemo(() => {
const completed = economicData.filter(
(item) => item.value && item.value !== "-",
).length;
return economicData.length > 0
? Math.round((completed / economicData.length) * 100)
: 72;
}, [economicData]);
useEffect(() => { useEffect(() => {
if (!farmUuid) { if (!farmUuid) {
setData({}) setData({});
setLoading(false) setLoading(false);
return return;
} }
setLoading(true) setLoading(true);
economicOverviewService economicOverviewService
.getSummary(farmUuid) .getSummary(farmUuid)
.then(summary => setData((summary.economicOverview as Record<string, unknown>) ?? {})) .then((summary) =>
setData((summary.economicOverview as Record<string, unknown>) ?? {}),
)
.catch(() => setData({})) .catch(() => setData({}))
.finally(() => setLoading(false)) .finally(() => setLoading(false));
}, [farmUuid]) }, [farmUuid]);
if (loading) { if (loading) {
return ( return (
<Box display='flex' justifyContent='center' alignItems='center' minHeight={200}> <Box
display="flex"
justifyContent="center"
alignItems="center"
minHeight={200}
>
<CircularProgress /> <CircularProgress />
</Box> </Box>
) );
} }
return ( return (
<Box position='relative'> <Box position="relative">
<Grid container spacing={6}> <Grid container spacing={6}>
<Grid size={12} sx={cardRowSx}> <Grid size={12}>
<Card sx={{ overflow: "hidden" }}>
<CardContent
sx={{
position: "relative",
overflow: "hidden",
p: { xs: 4, md: 6 },
color: "common.white",
background: `linear-gradient(135deg, ${theme.palette.success.main} 0%, ${theme.palette.primary.main} 45%, ${theme.palette.info.main} 100%)`,
}}
>
<Box
sx={{
position: "absolute",
insetInlineEnd: -48,
insetBlockStart: -56,
inlineSize: 190,
blockSize: 190,
borderRadius: "50%",
backgroundColor: alpha(theme.palette.common.white, 0.12),
}}
/>
<Box
sx={{
position: "absolute",
insetInlineStart: "-10%",
insetBlockEnd: "-62%",
inlineSize: "42%",
blockSize: 260,
borderRadius: "50%",
backgroundColor: alpha(theme.palette.common.white, 0.08),
}}
/>
<Grid
container
spacing={5}
sx={{ position: "relative", zIndex: 1, alignItems: "center" }}
>
<Grid size={{ xs: 12, lg: 7 }}>
<div className="flex flex-col gap-4">
<Chip
label="Economy Snapshot"
size="small"
sx={{
width: "fit-content",
color: "common.white",
border: `1px solid ${alpha(theme.palette.common.white, 0.22)}`,
backgroundColor: alpha(
theme.palette.common.white,
0.14,
),
}}
/>
<div>
<Typography
variant="h4"
sx={{ color: "common.white", fontWeight: 800, mb: 1.5 }}
>
صفحه اقتصاد مزرعه با همان کامپوننت های مالی موجود
</Typography>
<Typography
sx={{
color: alpha(theme.palette.common.white, 0.82),
maxWidth: 760,
}}
>
خلاصه عملکرد اقتصادی، روند درآمد و هزینه، و چند نمای
سریع برای تصمیم گیری روزانه را در یک صفحه یکپارچه ببین.
</Typography>
</div>
<div className="flex flex-wrap gap-3">
<Box
sx={{
px: 2.5,
py: 1.75,
borderRadius: 4,
border: `1px solid ${alpha(theme.palette.common.white, 0.2)}`,
backgroundColor: alpha(
theme.palette.common.white,
0.12,
),
}}
>
<Typography
variant="body2"
sx={{
color: alpha(theme.palette.common.white, 0.78),
}}
>
وضعیت تصمیم گیری
</Typography>
<Typography
sx={{ color: "common.white", fontWeight: 700 }}
>
{headlineCards[0]?.stats ??
"در حال بارگذاری داده مالی"}
</Typography>
</Box>
<Box
sx={{
px: 2.5,
py: 1.75,
borderRadius: 4,
border: `1px solid ${alpha(theme.palette.common.white, 0.2)}`,
backgroundColor: alpha(
theme.palette.common.white,
0.12,
),
}}
>
<Typography
variant="body2"
sx={{
color: alpha(theme.palette.common.white, 0.78),
}}
>
تمرکز این صفحه
</Typography>
<Typography
sx={{ color: "common.white", fontWeight: 700 }}
>
هزینه، بازگشت سرمایه و سهم درآمد
</Typography>
</Box>
</div>
</div>
</Grid>
<Grid size={{ xs: 12, lg: 5 }}>
<Box
sx={{
p: 4,
borderRadius: 5,
border: `1px solid ${alpha(theme.palette.common.white, 0.18)}`,
backgroundColor: alpha(theme.palette.common.white, 0.14),
backdropFilter: "blur(14px)",
}}
>
<div className="flex items-center justify-between gap-4 mbe-3">
<div>
<Typography
sx={{
color: alpha(theme.palette.common.white, 0.76),
mb: 1,
}}
>
آمادگی داده های اقتصادی
</Typography>
<Typography
variant="h5"
sx={{ color: "common.white", fontWeight: 800 }}
>
{completionValue}% تکمیل
</Typography>
</div>
<CustomAvatar
skin="light-static"
color="success"
size={42}
>
<i className="tabler-chart-histogram text-xl" />
</CustomAvatar>
</div>
<LinearProgress
variant="determinate"
value={completionValue}
sx={{
mb: 3,
blockSize: 8,
borderRadius: 999,
backgroundColor: alpha(
theme.palette.common.white,
0.18,
),
"& .MuiLinearProgress-bar": {
borderRadius: 999,
backgroundColor: theme.palette.common.white,
},
}}
/>
<div className="flex flex-col gap-3">
{economicData.slice(0, 2).map((item) => (
<div
key={item.title}
className="flex items-center justify-between gap-3"
>
<div className="flex items-center gap-2">
<CustomAvatar
skin="light-static"
color={item.avatarColor}
size={34}
>
<i className={item.avatarIcon} />
</CustomAvatar>
<div>
<Typography
sx={{ color: "common.white", fontWeight: 700 }}
>
{item.title}
</Typography>
<Typography
variant="body2"
sx={{
color: alpha(
theme.palette.common.white,
0.72,
),
}}
>
{item.subtitle}
</Typography>
</div>
</div>
<Typography
sx={{ color: "common.white", fontWeight: 700 }}
>
{item.value}
</Typography>
</div>
))}
</div>
</Box>
</Grid>
</Grid>
</CardContent>
</Card>
</Grid>
{headlineCards.map((item) => (
<Grid key={item.title} size={{ xs: 12, md: 4 }}>
<HorizontalWithAvatar
stats={item.stats}
title={item.title}
avatarIcon={item.avatarIcon}
avatarColor={item.avatarColor}
avatarSkin="light"
avatarVariant="rounded"
avatarSize={46}
/>
</Grid>
))}
<Grid size={{ xs: 12, xl: 8 }} sx={cardRowSx}>
<EconomicOverview data={data} /> <EconomicOverview data={data} />
</Grid> </Grid>
<Grid size={{ xs: 12, xl: 4 }} sx={cardRowSx}>
<Card className="bs-full">
<CardHeader
title="ترکیب جریان مالی"
subheader={t("subheaders.costsAndRoi")}
action={
<OptionMenu
options={[
t("optionMenu.details"),
t("optionMenu.exportExcel"),
]}
/>
}
/>
<CardContent className="flex flex-col gap-4">
{portfolioMix.length > 0 ? (
portfolioMix.map((item) => (
<Box key={item.name}>
<div className="flex items-center justify-between gap-3 mbe-2">
<div className="flex items-center gap-2">
<CustomAvatar skin="light" color={item.color} size={34}>
<i className="tabler-coins text-lg" />
</CustomAvatar>
<Typography
color="text.primary"
className="font-medium"
>
{item.name}
</Typography>
</div>
<Typography
color="text.primary"
className="font-semibold"
>
{item.total.toLocaleString("fa-IR")}
</Typography>
</div>
<LinearProgress
variant="determinate"
value={Math.min(item.share, 100)}
color={item.color}
sx={{
blockSize: 8,
borderRadius: 999,
backgroundColor: alpha(
theme.palette[item.color].main,
0.14,
),
"& .MuiLinearProgress-bar": { borderRadius: 999 },
}}
/>
</Box>
))
) : (
<Typography variant="body2">
هنوز داده سری های اقتصادی برای نمایش سهم درآمد و هزینه در
دسترس نیست.
</Typography>
)}
</CardContent>
</Card>
</Grid>
<Grid size={{ xs: 12, lg: 6 }}>
<Card className="bs-full">
<CardHeader
title="شاخص های مالی کلیدی"
subheader="خلاصه سریع برای مرور قبل از تصمیم گیری"
/>
<CardContent className="flex flex-col gap-4">
{economicData.length > 0 ? (
economicData.map((item) => (
<Box
key={item.title}
sx={{
p: 3,
borderRadius: 4,
border: `1px solid ${alpha(theme.palette.divider, 0.9)}`,
backgroundColor: alpha(
theme.palette[item.avatarColor].main,
0.05,
),
}}
>
<div className="flex items-center justify-between gap-3">
<div className="flex items-center gap-3">
<CustomAvatar
skin="light"
color={item.avatarColor}
size={38}
>
<i className={item.avatarIcon} />
</CustomAvatar>
<div>
<Typography
color="text.primary"
className="font-semibold"
>
{item.title}
</Typography>
<Typography variant="body2">
{item.subtitle}
</Typography>
</div>
</div>
<Typography
color="text.primary"
className="font-semibold"
>
{item.value}
</Typography>
</div>
</Box>
))
) : (
<Typography variant="body2">
هنوز شاخص مالی برای این مزرعه دریافت نشده است.
</Typography>
)}
</CardContent>
</Card>
</Grid>
<Grid size={{ xs: 12, lg: 6 }}>
<Card className="bs-full">
<CardHeader
title="خرید محصول بر اساس کد کود"
subheader="بر اساس کود مصرفی، نزدیک ترین پیشنهاد خرید و قیمت نمایش داده می شود."
action={
<OptionMenu
options={[
"مرتب سازی بر اساس قیمت",
"فقط محصولات پیشنهادی",
"مشاهده همه فروشگاه ها",
]}
/>
}
/>
<CardContent className="flex flex-col gap-4">
{fertilizerProductsMock.map((item) => (
<Box
key={item.fertilizerCode}
sx={{
p: 3,
borderRadius: 4,
border: `1px solid ${alpha(theme.palette[item.color].main, 0.18)}`,
background: `linear-gradient(135deg, ${alpha(theme.palette[item.color].main, 0.08)} 0%, ${alpha(theme.palette.background.paper, 0.96)} 100%)`,
}}
>
<div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
<div className="flex items-start gap-3">
<CustomAvatar skin="light" color={item.color} size={42}>
<i className="tabler-shopping-bag text-xl" />
</CustomAvatar>
<div className="flex flex-col gap-2">
<div className="flex flex-wrap items-center gap-2">
<Typography
color="text.primary"
className="font-semibold"
>
{item.productName}
</Typography>
<Chip
label={item.fertilizerCode}
size="small"
color={item.color}
variant="tonal"
/>
</div>
<Typography variant="body2">
{item.fertilizerName}
</Typography>
<div className="flex flex-wrap gap-2">
<Chip
icon={
<i className="tabler-building-store text-sm" />
}
label={item.storeName}
size="small"
variant="outlined"
/>
<Chip
icon={<i className="tabler-package text-sm" />}
label={item.packageSize}
size="small"
variant="outlined"
/>
</div>
</div>
</div>
<Box
sx={{
minInlineSize: { xs: "100%", lg: 220 },
p: 2.5,
borderRadius: 4,
backgroundColor: alpha(
theme.palette[item.color].main,
0.08,
),
}}
>
<Typography variant="body2" className="mbe-1">
قیمت امروز
</Typography>
<Typography
color="text.primary"
variant="h6"
className="font-semibold mbe-3"
>
{item.price}
</Typography>
<Button
fullWidth
component={Link}
href={item.storeUrl}
variant="contained"
color={item.color}
endIcon={<i className="tabler-external-link text-lg" />}
>
لینک فروشگاه
</Button>
</Box>
</div>
</Box>
))}
</CardContent>
</Card>
</Grid>
<Grid size={{ xs: 12, lg: 6 }}>
<Card className="bs-full">
<CardHeader
title="یادداشت تحلیلی"
subheader="خروجی سبک برای مرور سریع مدیر مزرعه"
/>
<CardContent className="flex flex-col gap-4">
<Box
sx={{
p: 3,
borderRadius: 4,
border: `1px dashed ${alpha(theme.palette.primary.main, 0.24)}`,
backgroundColor: alpha(theme.palette.primary.main, 0.05),
}}
>
<div className="flex items-start gap-3">
<CustomAvatar skin="light" color="primary" size={38}>
<i className="tabler-sparkles text-lg" />
</CustomAvatar>
<div>
<Typography
color="text.primary"
className="font-semibold mbe-1"
>
جمع بندی سریع
</Typography>
<Typography variant="body2">
این صفحه با همان کامپوننت اقتصادی موجود ساخته شده و نمای
خلاصه، کارت های سریع و وضعیت ترکیب جریان مالی را در کنار
چارت اصلی نشان می دهد.
</Typography>
</div>
</div>
</Box>
<Box
sx={{
p: 3,
borderRadius: 4,
border: `1px solid ${alpha(theme.palette.success.main, 0.18)}`,
backgroundColor: alpha(theme.palette.success.main, 0.05),
}}
>
<Typography
color="text.primary"
className="font-semibold mbe-1"
>
پیشنهاد استفاده
</Typography>
<Typography variant="body2">
اگر خواستی مرحله بعدی می شود این صفحه را به داده های ریزتر مثل
هزینه آبیاری، حمل، کوددهی و درآمد محصول به تفکیک فصل وصل کرد.
</Typography>
</Box>
</CardContent>
</Card>
</Grid>
</Grid> </Grid>
</Box> </Box>
) );
} };
export default EconomicOverviewPageWrapper export default EconomicOverviewPageWrapper;
@@ -0,0 +1,665 @@
"use client";
import { useMemo, useState } from "react";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Card from "@mui/material/Card";
import CardContent from "@mui/material/CardContent";
import CardHeader from "@mui/material/CardHeader";
import Checkbox from "@mui/material/Checkbox";
import Chip from "@mui/material/Chip";
import CircularProgress from "@mui/material/CircularProgress";
import Divider from "@mui/material/Divider";
import Grid from "@mui/material/Grid2";
import MenuItem from "@mui/material/MenuItem";
import Typography from "@mui/material/Typography";
import { alpha, useTheme } from "@mui/material/styles";
import classnames from "classnames";
import type { ThemeColor } from "@core/types";
import OptionMenu from "@core/components/option-menu";
import CustomAvatar from "@core/components/mui/Avatar";
import CustomTextField from "@core/components/mui/TextField";
import HorizontalWithAvatar from "@components/card-statistics/HorizontalWithAvatar";
type TaskPriority = "زیاد" | "متوسط" | "کم";
type TaskStatus = "open" | "done";
type TaskSegment = "همه" | "امروز" | "فوری" | "انجام شده";
type FarmerTask = {
id: number;
title: string;
zone: string;
time: string;
priority: TaskPriority;
note: string;
tags: string[];
status: TaskStatus;
};
const initialTasks: FarmerTask[] = [
{
id: 1,
title: "بررسی رطوبت ردیف شمالی و تنظیم آبیاری قطره ای",
zone: "قطعه گندم - شمال مزرعه",
time: "06:30",
priority: "زیاد",
note: "اگر رطوبت کمتر از 28٪ بود، دور دوم آبیاری را 20 دقیقه جلو بینداز.",
tags: ["آبیاری", "صبح زود"],
status: "open",
},
{
id: 2,
title: "نمونه برداری خاک برای بخش سبزیجات",
zone: "گلخانه شماره 2",
time: "09:15",
priority: "متوسط",
note: "سه نقطه از بستر برداشت شود و برای آزمایش فسفر ثبت گردد.",
tags: ["خاک", "آزمایش"],
status: "open",
},
{
id: 3,
title: "هماهنگی با راننده برای ارسال بار جو",
zone: "انبار مرکزی",
time: "12:00",
priority: "کم",
note: "وزن نهایی بارنامه قبل از خروج با باسکول تطبیق داده شود.",
tags: ["لجستیک", "فروش"],
status: "done",
},
{
id: 4,
title: "بازدید سریع برای نشانه های آفت روی برگ های تازه",
zone: "باغچه آزمایشی غربی",
time: "17:40",
priority: "زیاد",
note: "فقط لکه های جدید را علامت بزن و برای تیم سمپاشی عکس بگیر.",
tags: ["آفت", "بازدید عصر"],
status: "open",
},
];
const priorityMeta: Record<TaskPriority, { color: ThemeColor; icon: string }> =
{
زیاد: { color: "error", icon: "tabler-alert-triangle" },
متوسط: { color: "warning", icon: "tabler-sun-high" },
کم: { color: "success", icon: "tabler-leaf" },
};
const segments: TaskSegment[] = ["همه", "امروز", "فوری", "انجام شده"];
const FarmerTodoPage = () => {
const theme = useTheme();
const [tasks, setTasks] = useState(initialTasks);
const [segment, setSegment] = useState<TaskSegment>("همه");
const [draftTitle, setDraftTitle] = useState("");
const [draftZone, setDraftZone] = useState("قطعه گندم - شمال مزرعه");
const [draftTime, setDraftTime] = useState("07:00");
const [draftPriority, setDraftPriority] = useState<TaskPriority>("متوسط");
const completedCount = useMemo(
() => tasks.filter((task) => task.status === "done").length,
[tasks],
);
const openCount = tasks.length - completedCount;
const urgentCount = useMemo(
() =>
tasks.filter((task) => task.priority === "زیاد" && task.status === "open")
.length,
[tasks],
);
const progressValue =
tasks.length === 0 ? 0 : Math.round((completedCount / tasks.length) * 100);
const filteredTasks = useMemo(() => {
switch (segment) {
case "فوری":
return tasks.filter(
(task) => task.priority === "زیاد" && task.status === "open",
);
case "انجام شده":
return tasks.filter((task) => task.status === "done");
case "امروز":
return tasks;
default:
return tasks;
}
}, [segment, tasks]);
const stats = [
{
stats: `${openCount} کار`,
title: "کارهای باز امروز",
avatarIcon: "tabler-plant-2",
avatarColor: "primary" as const,
},
{
stats: `${completedCount} مورد`,
title: "انجام شده تا الان",
avatarIcon: "tabler-circle-check",
avatarColor: "success" as const,
},
{
stats: `${urgentCount} تسک`,
title: "اولویت خیلی بالا",
avatarIcon: "tabler-bolt",
avatarColor: "error" as const,
},
];
const toggleTask = (taskId: number) => {
setTasks((currentTasks) =>
currentTasks.map((task) =>
task.id === taskId
? { ...task, status: task.status === "done" ? "open" : "done" }
: task,
),
);
};
const addTask = () => {
if (!draftTitle.trim()) return;
setTasks((currentTasks) => [
{
id: Date.now(),
title: draftTitle.trim(),
zone: draftZone,
time: draftTime,
priority: draftPriority,
note: "بعد از ثبت انجام، اگر موردی غیرعادی بود برای شیفت بعدی یادداشت بگذار.",
tags: [draftPriority === "زیاد" ? "فوری" : "روزانه", "ثبت دستی"],
status: "open",
},
...currentTasks,
]);
setDraftTitle("");
setDraftTime("07:00");
setDraftPriority("متوسط");
};
return (
<Grid container spacing={6}>
<Grid size={12}>
<Card sx={{ overflow: "hidden" }}>
<CardContent
sx={{
position: "relative",
p: { xs: 4, md: 6 },
overflow: "hidden",
background: `linear-gradient(135deg, ${theme.palette.success.main} 0%, ${theme.palette.primary.main} 52%, ${theme.palette.info.main} 100%)`,
}}
>
<Box
sx={{
position: "absolute",
insetInlineEnd: -50,
insetBlockStart: -60,
inlineSize: 200,
blockSize: 200,
borderRadius: "50%",
backgroundColor: alpha(theme.palette.common.white, 0.12),
}}
/>
<Box
sx={{
position: "absolute",
insetInlineStart: "-10%",
insetBlockEnd: "-58%",
inlineSize: "45%",
blockSize: 240,
borderRadius: "50%",
backgroundColor: alpha(theme.palette.common.white, 0.08),
}}
/>
<Grid
container
spacing={5}
sx={{ position: "relative", zIndex: 1, alignItems: "center" }}
>
<Grid size={{ xs: 12, lg: 8 }}>
<div className="flex flex-col gap-4">
<Chip
label="برنامه روز کشاورز"
size="small"
sx={{
width: "fit-content",
color: "common.white",
border: `1px solid ${alpha(theme.palette.common.white, 0.2)}`,
backgroundColor: alpha(theme.palette.common.white, 0.12),
}}
/>
<div>
<Typography
variant="h4"
sx={{ color: "common.white", fontWeight: 800, mb: 1.5 }}
>
تودولیست ساده، تمیز و کاربردی برای مدیریت کارهای مزرعه
</Typography>
<Typography
sx={{
color: alpha(theme.palette.common.white, 0.84),
maxWidth: 720,
}}
>
کارهای مهم روز، بازدیدهای میدانی و کارهای پیگیری را یکجا
نگه دار تا بین آبیاری، خاک، برداشت و هماهنگی تیم چیزی از
قلم نیفتد.
</Typography>
</div>
<div className="flex flex-wrap gap-3">
<Box
sx={{
px: 2.5,
py: 1.75,
borderRadius: 4,
border: `1px solid ${alpha(theme.palette.common.white, 0.2)}`,
backgroundColor: alpha(
theme.palette.common.white,
0.12,
),
}}
>
<Typography
variant="body2"
sx={{ color: alpha(theme.palette.common.white, 0.78) }}
>
شروع روز
</Typography>
<Typography
sx={{ color: "common.white", fontWeight: 700 }}
>
بازدید 06:30 از ردیف شمالی
</Typography>
</Box>
<Box
sx={{
px: 2.5,
py: 1.75,
borderRadius: 4,
border: `1px solid ${alpha(theme.palette.common.white, 0.2)}`,
backgroundColor: alpha(
theme.palette.common.white,
0.12,
),
}}
>
<Typography
variant="body2"
sx={{ color: alpha(theme.palette.common.white, 0.78) }}
>
تمرکز امروز
</Typography>
<Typography
sx={{ color: "common.white", fontWeight: 700 }}
>
آبیاری، آفت و هماهنگی بار خروجی
</Typography>
</Box>
</div>
</div>
</Grid>
<Grid size={{ xs: 12, lg: 4 }}>
<Box
sx={{
display: "flex",
flexDirection: "column",
gap: 2.5,
p: 4,
borderRadius: 5,
border: `1px solid ${alpha(theme.palette.common.white, 0.18)}`,
backgroundColor: alpha(theme.palette.common.white, 0.14),
backdropFilter: "blur(14px)",
}}
>
<div className="flex items-center justify-between gap-4">
<div>
<Typography
sx={{
color: alpha(theme.palette.common.white, 0.78),
mb: 1,
}}
>
پیشرفت امروز
</Typography>
<Typography
variant="h5"
sx={{ color: "common.white", fontWeight: 800 }}
>
{progressValue}% تکمیل شده
</Typography>
</div>
<Box sx={{ position: "relative", display: "inline-flex" }}>
<CircularProgress
variant="determinate"
value={progressValue}
size={74}
thickness={5}
sx={{ color: "common.white" }}
/>
<Box
sx={{
position: "absolute",
inset: 0,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<Typography
sx={{ color: "common.white", fontWeight: 700 }}
>
{progressValue}%
</Typography>
</Box>
</Box>
</div>
<Divider
sx={{
borderColor: alpha(theme.palette.common.white, 0.14),
}}
/>
<div className="flex items-center gap-3">
<CustomAvatar skin="light-static" color="success" size={42}>
<i className="tabler-sunrise text-xl" />
</CustomAvatar>
<div>
<Typography
sx={{ color: "common.white", fontWeight: 700 }}
>
پنجره طلایی صبح
</Typography>
<Typography
variant="body2"
sx={{ color: alpha(theme.palette.common.white, 0.78) }}
>
بهترین زمان برای آبیاری و بازدید سریع تا قبل از اوج
گرما.
</Typography>
</div>
</div>
</Box>
</Grid>
</Grid>
</CardContent>
</Card>
</Grid>
{stats.map((item) => (
<Grid key={item.title} size={{ xs: 12, md: 4 }}>
<HorizontalWithAvatar
stats={item.stats}
title={item.title}
avatarIcon={item.avatarIcon}
avatarColor={item.avatarColor}
avatarSkin="light"
avatarVariant="rounded"
avatarSize={46}
/>
</Grid>
))}
<Grid size={{ xs: 12, xl: 8 }}>
<Card>
<CardHeader
title="لیست کارهای امروز"
subheader="کارت ها را تیک بزن تا تمرکز تیم روی کارهای باقی مانده بماند."
action={
<OptionMenu
options={[
"نمای روز",
"مرتب سازی بر اساس ساعت",
"فقط موارد باز",
]}
/>
}
/>
<CardContent className="flex flex-col gap-4">
<div className="flex flex-wrap gap-2">
{segments.map((item) => (
<Chip
key={item}
clickable
label={item}
color={segment === item ? "primary" : "default"}
variant={segment === item ? "filled" : "tonal"}
onClick={() => setSegment(item)}
/>
))}
</div>
<div className="flex flex-col gap-3">
{filteredTasks.map((task) => {
const meta = priorityMeta[task.priority];
return (
<Box
key={task.id}
sx={{
p: 3,
borderRadius: 5,
border: `1px solid ${alpha(theme.palette.divider, 0.9)}`,
backgroundColor:
task.status === "done"
? alpha(theme.palette.success.main, 0.06)
: alpha(theme.palette.background.default, 0.7),
transition: "all .2s ease",
}}
>
<div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
<div className="flex items-start gap-3">
<Checkbox
checked={task.status === "done"}
onChange={() => toggleTask(task.id)}
sx={{ mt: -0.5 }}
/>
<div className="flex flex-col gap-2">
<div className="flex flex-wrap items-center gap-2">
<Typography
color="text.primary"
className={classnames("font-semibold", {
"line-through opacity-60":
task.status === "done",
})}
>
{task.title}
</Typography>
<Chip
label={task.priority}
size="small"
color={meta.color}
variant="tonal"
/>
</div>
<Typography variant="body2">{task.note}</Typography>
<div className="flex flex-wrap gap-2">
{task.tags.map((tag) => (
<Chip
key={tag}
label={tag}
size="small"
variant="outlined"
/>
))}
</div>
</div>
</div>
<Box
sx={{
minInlineSize: { xs: "100%", lg: 220 },
p: 2.5,
borderRadius: 4,
backgroundColor: alpha(
theme.palette[meta.color].main,
0.08,
),
}}
>
<div className="flex items-center gap-2 mbe-2">
<CustomAvatar
skin="light"
color={meta.color}
size={34}
>
<i className={classnames(meta.icon, "text-lg")} />
</CustomAvatar>
<div>
<Typography
color="text.primary"
className="font-semibold"
>
{task.time}
</Typography>
<Typography variant="body2">{task.zone}</Typography>
</div>
</div>
<Typography variant="body2">
{task.status === "done"
? "انجام شده و ثبت شده"
: "منتظر اقدام تیم مزرعه"}
</Typography>
</Box>
</div>
</Box>
);
})}
</div>
</CardContent>
</Card>
</Grid>
<Grid size={{ xs: 12, xl: 4 }}>
<div className="flex flex-col gap-6">
<Card>
<CardHeader
title="افزودن کار جدید"
subheader="خیلی سبک و سریع برای ثبت تسک های روزانه"
/>
<CardContent className="flex flex-col gap-4">
<CustomTextField
fullWidth
label="عنوان کار"
placeholder="مثلا بازدید پمپ جنوب"
value={draftTitle}
onChange={(event) => setDraftTitle(event.target.value)}
/>
<CustomTextField
select
fullWidth
label="محل اجرا"
value={draftZone}
onChange={(event) => setDraftZone(event.target.value)}
>
<MenuItem value="قطعه گندم - شمال مزرعه">
قطعه گندم - شمال مزرعه
</MenuItem>
<MenuItem value="گلخانه شماره 2">گلخانه شماره 2</MenuItem>
<MenuItem value="انبار مرکزی">انبار مرکزی</MenuItem>
<MenuItem value="باغچه آزمایشی غربی">
باغچه آزمایشی غربی
</MenuItem>
</CustomTextField>
<Grid container spacing={3}>
<Grid size={6}>
<CustomTextField
fullWidth
label="ساعت"
value={draftTime}
onChange={(event) => setDraftTime(event.target.value)}
/>
</Grid>
<Grid size={6}>
<CustomTextField
select
fullWidth
label="اولویت"
value={draftPriority}
onChange={(event) =>
setDraftPriority(event.target.value as TaskPriority)
}
>
<MenuItem value="زیاد">زیاد</MenuItem>
<MenuItem value="متوسط">متوسط</MenuItem>
<MenuItem value="کم">کم</MenuItem>
</CustomTextField>
</Grid>
</Grid>
<Button
variant="contained"
size="large"
startIcon={<i className="tabler-plus text-lg" />}
onClick={addTask}
>
ثبت در لیست امروز
</Button>
</CardContent>
</Card>
<Card>
<CardHeader
title="تابلوی تمرکز"
subheader="سه نکته کوتاه برای نظم بهتر روز مزرعه"
/>
<CardContent className="flex flex-col gap-4">
{[
{
title: "اول بازدیدها، بعد تماس ها",
text: "کارهای میدانی صبح را قبل از تماس ها و هماهنگی های اداری جمع کن.",
color: "primary" as const,
icon: "tabler-tractor",
},
{
title: "یادداشت های کوتاه ولی دقیق",
text: "برای هر کار فقط یک یادداشت عملی ثبت کن تا شیفت بعدی سریع متوجه شود.",
color: "info" as const,
icon: "tabler-notes",
},
{
title: "فوری ها را جدا نگه دار",
text: "اگر کاری روی کیفیت محصول یا آب تاثیر مستقیم دارد، آن را در دسته فوری نگه دار.",
color: "error" as const,
icon: "tabler-bolt",
},
].map((item) => (
<Box
key={item.title}
sx={{
p: 3,
borderRadius: 4,
border: `1px solid ${alpha(theme.palette[item.color].main, 0.18)}`,
backgroundColor: alpha(
theme.palette[item.color].main,
0.05,
),
}}
>
<div className="flex items-start gap-3">
<CustomAvatar skin="light" color={item.color} size={38}>
<i className={classnames(item.icon, "text-lg")} />
</CustomAvatar>
<div>
<Typography
color="text.primary"
className="font-semibold mbe-1"
>
{item.title}
</Typography>
<Typography variant="body2">{item.text}</Typography>
</div>
</div>
</Box>
))}
</CardContent>
</Card>
</div>
</Grid>
</Grid>
);
};
export default FarmerTodoPage;
File diff suppressed because it is too large Load Diff