This commit is contained in:
2026-04-18 01:23:37 +03:30
parent d43bd74a06
commit 80ba238713
16 changed files with 98 additions and 70 deletions
@@ -1,8 +0,0 @@
// Components Imports
import PlantPestDetection from '@views/dashboards/farm/pestDetection/PlantPestDetection'
const PestDetectionPage = async () => {
return <PlantPestDetection />
}
export default PestDetectionPage
@@ -1,7 +1,7 @@
import PestRiskPageWrapper from '@views/dashboards/farm/PestRiskPageWrapper' import PestManagementPage from '@views/dashboards/farm/PestManagementPage'
const PestRiskPage = async () => { const PestRiskPage = () => {
return <PestRiskPageWrapper /> return <PestManagementPage />
} }
export default PestRiskPage export default PestRiskPage
@@ -1,7 +0,0 @@
import PlantSimulator from '@views/dashboards/farm/plantSimulator/PlantSimulator'
const PlantSimulatorPage = () => {
return <PlantSimulator />
}
export default PlantSimulatorPage
@@ -1,7 +1,7 @@
import YieldHarvestPageWrapper from '@views/dashboards/farm/YieldHarvestPageWrapper' import PlantProductionPage from '@views/dashboards/farm/PlantProductionPage'
const YieldHarvestPage = async () => { const YieldHarvestPage = () => {
return <YieldHarvestPageWrapper /> return <PlantProductionPage />
} }
export default YieldHarvestPage export default YieldHarvestPage
+3 -3
View File
@@ -19,8 +19,8 @@ const CardStatsVertical = (props: CardStatsVerticalProps) => {
props props
return ( return (
<Card> <Card sx={{ height: '100%', display: 'flex', width: '100%' }}>
<CardContent className='flex flex-col gap-y-3 items-start'> <CardContent className='flex flex-col gap-y-3 items-start' sx={{ flex: 1 }}>
<CustomAvatar variant='rounded' skin={avatarSkin} size={avatarSize} color={avatarColor}> <CustomAvatar variant='rounded' skin={avatarSkin} size={avatarSize} color={avatarColor}>
<i className={classnames(avatarIcon, 'text-[28px]')} /> <i className={classnames(avatarIcon, 'text-[28px]')} />
</CustomAvatar> </CustomAvatar>
@@ -29,7 +29,7 @@ const CardStatsVertical = (props: CardStatsVerticalProps) => {
<Typography color='text.disabled'>{subtitle}</Typography> <Typography color='text.disabled'>{subtitle}</Typography>
<Typography color='text.primary'>{stats}</Typography> <Typography color='text.primary'>{stats}</Typography>
</div> </div>
<Chip label={chipText} color={chipColor} variant={chipVariant} size='small' /> <Chip label={chipText} color={chipColor} variant={chipVariant} size='small' sx={{ marginTop: 'auto' }} />
</CardContent> </CardContent>
</Card> </Card>
) )
@@ -128,11 +128,6 @@ const VerticalMenu = ({ scrollMenu }: Props) => {
</MenuItem> </MenuItem>
</MenuSection> </MenuSection>
<MenuSection label={t('simulator')}>
<MenuItem href="/plant-simulator" icon={<i className="tabler-flower" />}>
{t('plantSimulator')}
</MenuItem>
</MenuSection>
<MenuSection label={t('recommendation')}> <MenuSection label={t('recommendation')}>
<MenuItem href="/irrigation-recommendation" icon={<i className="tabler-droplet-half-2" />}> <MenuItem href="/irrigation-recommendation" icon={<i className="tabler-droplet-half-2" />}>
{t('irrigationRecommendation')} {t('irrigationRecommendation')}
@@ -145,9 +140,6 @@ const VerticalMenu = ({ scrollMenu }: Props) => {
<MenuItem href="/farm-ai-assistant" icon={<i className="tabler-robot" />}> <MenuItem href="/farm-ai-assistant" icon={<i className="tabler-robot" />}>
{t('farmAiAssistant')} {t('farmAiAssistant')}
</MenuItem> </MenuItem>
<MenuItem href="/pest-detection" icon={<i className="tabler-bug" />}>
{t('pestDetection')}
</MenuItem>
</MenuSection> </MenuSection>
</Menu> </Menu>
@@ -65,11 +65,6 @@ const horizontalMenuData = (): HorizontalMenuDataType[] => [
icon: 'tabler-chart-line', icon: 'tabler-chart-line',
href: '/yield-harvest' href: '/yield-harvest'
}, },
{
label: 'plantSimulator',
icon: 'tabler-seeding',
href: '/plant-simulator'
},
{ {
label: 'farmAlerts', label: 'farmAlerts',
icon: 'tabler-alert-triangle', icon: 'tabler-alert-triangle',
@@ -126,11 +121,6 @@ const horizontalMenuData = (): HorizontalMenuDataType[] => [
icon: 'tabler-chart-line', icon: 'tabler-chart-line',
href: '/yield-harvest' href: '/yield-harvest'
}, },
{
label: 'plantSimulator',
icon: 'tabler-seeding',
href: '/plant-simulator'
},
{ {
label: 'farmAlerts', label: 'farmAlerts',
icon: 'tabler-alert-triangle', icon: 'tabler-alert-triangle',
-5
View File
@@ -69,11 +69,6 @@ const verticalMenuData = (): VerticalMenuDataType[] => [
icon: 'tabler-chart-line', icon: 'tabler-chart-line',
href: '/yield-harvest' href: '/yield-harvest'
}, },
{
label: 'plantSimulator',
icon: 'tabler-seeding',
href: '/plant-simulator'
},
{ {
label: 'farmAlerts', label: 'farmAlerts',
icon: 'tabler-alert-triangle', icon: 'tabler-alert-triangle',
+12 -3
View File
@@ -25,12 +25,21 @@ const FarmOverviewKPIs = ({ data }: FarmOverviewKPIsProps) => {
const kpis = (data?.kpis as KpiItem[] | undefined) ?? [] const kpis = (data?.kpis as KpiItem[] | undefined) ?? []
if (kpis.length === 0) return null if (kpis.length === 0) return null
const getGridSize = (count) => {
if (count === 1) return { xs: 12 };
if (count === 2) return { xs: 12, md: 6 };
if (count === 3) return { xs: 12, sm: 6, md: 4 };
if (count === 4) return { xs: 12, sm: 6, md: 3 };
return { xs: 12, sm: 6, md: 4, lg: 2 };
};
return ( return (
<> <>
{kpis.map((kpi) => ( {kpis.map((kpi) => (
<Grid key={kpi.id} size={{ xs: 12, sm: 6, md: 4, lg: 2 }}> <Grid
<CardStatsVertical key={kpi.id}
size={getGridSize(kpis.length)}
sx={{ display: "flex" }}
> <CardStatsVertical
title={kpi.title} title={kpi.title}
subtitle={kpi.subtitle} subtitle={kpi.subtitle}
stats={kpi.stats} stats={kpi.stats}
@@ -26,7 +26,7 @@ const HarvestPredictionCard = ({ data }: HarvestPredictionCardProps) => {
const description = (data?.description as string) ?? '' const description = (data?.description as string) ?? ''
return ( return (
<Card> <Card sx={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
<CardHeader <CardHeader
avatar={ avatar={
<CustomAvatar skin='light' color='success' size={44}> <CustomAvatar skin='light' color='success' size={44}>
@@ -37,18 +37,16 @@ const HarvestPredictionCard = ({ data }: HarvestPredictionCardProps) => {
subheader={t('subheaders.aiEstimatedDate')} subheader={t('subheaders.aiEstimatedDate')}
action={<OptionMenu options={[t('optionMenu.details'), t('optionMenu.adjust'), t('optionMenu.export')]} />} action={<OptionMenu options={[t('optionMenu.details'), t('optionMenu.adjust'), t('optionMenu.export')]} />}
/> />
<CardContent className='flex flex-col gap-4'> <CardContent className='flex flex-col gap-4' sx={{ flex: 1, justifyContent: 'space-between' }}>
<div className='flex items-center gap-4'> <div className='flex items-center gap-4'>
<Typography variant='h3'>{harvestDate}</Typography> <Typography variant='h3'>{harvestDate}</Typography>
{daysLeftFormatted && ( {daysLeftFormatted && (
<Chip label={daysLeftFormatted} color='info' size='small' variant='tonal' /> <Chip label={daysLeftFormatted} color='info' size='small' variant='tonal' />
)} )}
</div> </div>
{description && ( <Typography variant='body2' color='text.secondary'>
<Typography variant='body2' color='text.secondary'> {description}
{description} </Typography>
</Typography>
)}
</CardContent> </CardContent>
</Card> </Card>
) )
@@ -0,0 +1,24 @@
'use client'
import Grid from '@mui/material/Grid2'
import PestRiskPageWrapper from '@views/dashboards/farm/PestRiskPageWrapper'
import PlantPestDetection from '@views/dashboards/farm/pestDetection/PlantPestDetection'
const PestManagementPage = () => {
return (
<Grid container sx={{
width:"100%"
}} spacing={6} alignItems='stretch'>
<Grid size={{ xs: 12, xl: 12 }}>
<PestRiskPageWrapper />
</Grid>
<Grid size={{ xs: 12, xl: 12 }}>
<PlantPestDetection />
</Grid>
</Grid>
)
}
export default PestManagementPage
@@ -6,12 +6,20 @@ import { useFarmHub } from '@/hooks/useFarmHub'
import Grid from '@mui/material/Grid2' import Grid from '@mui/material/Grid2'
import Box from '@mui/material/Box' import Box from '@mui/material/Box'
import CircularProgress from '@mui/material/CircularProgress' import CircularProgress from '@mui/material/CircularProgress'
import Typography from '@mui/material/Typography'
import FarmOverviewKPIs from '@views/dashboards/farm/FarmOverviewKPIs' import FarmOverviewKPIs from '@views/dashboards/farm/FarmOverviewKPIs'
import { pestDetectionDomainService } from '@/libs/api/services/pestDetectionDomainService' import { pestDetectionDomainService } from '@/libs/api/services/pestDetectionDomainService'
import type { PestRiskSummary } from '@/libs/api/services/pestDetectionDomainService' import type { PestRiskSummary } from '@/libs/api/services/pestDetectionDomainService'
const sectionSx = {
display: 'flex',
flexDirection: 'column',
gap: 3,
minHeight: '100%'
}
const PestRiskPageWrapper = () => { const PestRiskPageWrapper = () => {
const { farmHub } = useFarmHub() const { farmHub } = useFarmHub()
const farmUuid = farmHub?.farm_uuid const farmUuid = farmHub?.farm_uuid
@@ -42,16 +50,21 @@ const PestRiskPageWrapper = () => {
} }
return ( return (
<Box position='relative'> <Box position='relative' sx={{ width: '100%' }}>
<Grid container spacing={6}> <Grid container spacing={6} alignItems='stretch'>
{data.disease_risk && ( {data.disease_risk && (
<Grid size={12} container spacing={6}> <Grid size={{ xs: 12, md: 6 }} sx={sectionSx}>
<FarmOverviewKPIs data={data.disease_risk as Record<string, unknown>} /> <Grid container spacing={6} alignItems='stretch'>
<FarmOverviewKPIs data={data.disease_risk as Record<string, unknown>} />
</Grid>
</Grid> </Grid>
)} )}
{data.pest_risk && ( {data.pest_risk && (
<Grid size={12} container spacing={6}> <Grid size={{ xs: 12, md: 6 }} sx={sectionSx}>
<FarmOverviewKPIs data={data.pest_risk as Record<string, unknown>} /> <Grid container spacing={6} alignItems='stretch'>
<FarmOverviewKPIs data={data.pest_risk as Record<string, unknown>} />
</Grid>
</Grid> </Grid>
)} )}
</Grid> </Grid>
@@ -0,0 +1,22 @@
'use client'
import Grid from '@mui/material/Grid2'
import YieldHarvestPageWrapper from '@views/dashboards/farm/YieldHarvestPageWrapper'
import PlantSimulator from '@views/dashboards/farm/plantSimulator/PlantSimulator'
const PlantProductionPage = () => {
return (
<Grid container spacing={6} alignItems='stretch'>
<Grid size={{ xs: 12, xl: 12 }} sx={{ display: 'flex' }}>
<PlantSimulator />
</Grid>
<Grid size={{ xs: 12, xl: 12 }} sx={{ display: 'flex' }}>
<YieldHarvestPageWrapper />
</Grid>
</Grid>
)
}
export default PlantProductionPage
@@ -51,10 +51,10 @@ const YieldHarvestPageWrapper = () => {
} }
return ( return (
<Box position='relative'> <Box position='relative' sx={{ width: '100%' }}>
<Grid container spacing={6}> <Grid container spacing={6} alignItems='stretch'>
{data.yield_prediction && ( {data.yield_prediction && (
<Grid size={12} container spacing={6}> <Grid size={12} container spacing={6} alignItems='stretch'>
<FarmOverviewKPIs data={data.yield_prediction as Record<string, unknown>} /> <FarmOverviewKPIs data={data.yield_prediction as Record<string, unknown>} />
</Grid> </Grid>
)} )}
@@ -90,16 +90,16 @@ const YieldPredictionChart = ({ data }: YieldPredictionChartProps) => {
} }
return ( return (
<Card> <Card sx={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
<CardHeader <CardHeader
title={t('cards.yieldPredictionChart')} title={t('cards.yieldPredictionChart')}
subheader={t('subheaders.thisYearVsLastYear')} subheader={t('subheaders.thisYearVsLastYear')}
action={<OptionMenu options={[t('optionMenu.export'), t('optionMenu.compare'), t('optionMenu.details')]} />} action={<OptionMenu options={[t('optionMenu.export'), t('optionMenu.compare'), t('optionMenu.details')]} />}
/> />
<CardContent className='flex flex-col gap-4'> <CardContent className='flex flex-col gap-4' sx={{ flex: 1 }}>
<AppReactApexCharts type='line' height={280} width='100%' series={series} options={options} /> <AppReactApexCharts type='line' height={280} width='100%' series={series} options={options} />
{summary.length > 0 && ( {summary.length > 0 && (
<div className='flex flex-col gap-4'> <div className='flex flex-col gap-4' style={{ marginTop: 'auto' }}>
{summary.map((item, index) => ( {summary.map((item, index) => (
<div key={index} className='flex items-center gap-4'> <div key={index} className='flex items-center gap-4'>
<CustomAvatar skin='light' variant='rounded' color={item.avatarColor as 'primary'} size={38}> <CustomAvatar skin='light' variant='rounded' color={item.avatarColor as 'primary'} size={38}>
@@ -75,7 +75,7 @@ export default function PlantPestDetection() {
return ( return (
<Box <Box
className={classnames(commonLayoutClasses.contentHeightFixed, 'flex flex-col is-full overflow-hidden rounded')} className={classnames(commonLayoutClasses.contentHeightFixed, 'flex flex-col is-full overflow-hidden rounded')}
sx={{ minHeight: '100%' }} sx={{ minHeight: '100%', width: '100%' }}
> >
<Box className="is-full py-6 sm:py-8 flex flex-col"> <Box className="is-full py-6 sm:py-8 flex flex-col">
{/* Header */} {/* Header */}