Enhance dashboard components with theme integration and UI improvements

- Updated FarmAiAssistantChat, PlantPestDetection, SmartFertilizationRecommendation, and SmartIrrigationRecommendation components to utilize theme-based styling for better consistency and visual appeal.
- Refactored background gradients, box shadows, and hover effects to align with the primary color palette.
- Improved layout classes for better responsiveness and user experience across various dashboard sections.
- Added new button styles and loading indicators to enhance interactivity and feedback during user actions.
This commit is contained in:
2026-02-21 22:21:31 +03:30
parent cb29828a69
commit 83b0f88d6e
4 changed files with 276 additions and 239 deletions
@@ -8,7 +8,13 @@ import Card from '@mui/material/Card'
import IconButton from '@mui/material/IconButton'
import TextField from '@mui/material/TextField'
import Collapse from '@mui/material/Collapse'
import { useTheme } from '@mui/material/styles'
import { alpha } from '@mui/material/styles'
import classnames from 'classnames'
// Util Imports
import { commonLayoutClasses } from '@layouts/utils/layoutClasses'
import type { FarmContext, FarmAIMessage, AIResponseSection } from './farmAiAssistantTypes'
// ─── Constants ─────────────────────────────────────────────────────────────
@@ -62,6 +68,7 @@ const DEMO_AI_RESPONSE_SECTIONS: AIResponseSection[] = [
export default function FarmAiAssistantChat() {
const t = useTranslations('farmAiAssistant')
const theme = useTheme()
const [messages, setMessages] = useState<FarmAIMessage[]>([])
const [inputValue, setInputValue] = useState('')
const [isContextExpanded, setIsContextExpanded] = useState(true)
@@ -71,6 +78,7 @@ export default function FarmAiAssistantChat() {
const scrollRef = useRef<HTMLDivElement>(null)
const farmContext = DEFAULT_FARM_CONTEXT
const { primary, info, warning } = theme.palette
// Scroll to bottom on new messages
useEffect(() => {
@@ -127,35 +135,36 @@ export default function FarmAiAssistantChat() {
return (
<Box
className='flex flex-col min-bs-screen max-w-md mx-auto'
className={classnames(commonLayoutClasses.contentHeightFixed, 'flex flex-col is-full overflow-hidden rounded')}
sx={{
background: 'linear-gradient(180deg, #f8fcf8 0%, #f0f7f4 30%, #e8f4ef 100%)',
minHeight: '100dvh'
background: `linear-gradient(180deg, ${theme.palette.background.default} 0%, ${alpha(primary.main, 0.04)} 30%, ${alpha(primary.main, 0.08)} 100%)`,
minHeight: '100%'
}}
>
{/* 1) Smart Header */}
<Box
className='flex items-center gap-3 px-4 pt-4 pb-3 flex-shrink-0'
sx={{
background: 'linear-gradient(135deg, rgba(34, 197, 94, 0.06) 0%, rgba(14, 165, 233, 0.06) 100%)',
borderBottom: '1px solid rgba(34, 197, 94, 0.12)'
background: `linear-gradient(135deg, ${alpha(primary.main, 0.06)} 0%, ${alpha(info.main, 0.06)} 100%)`,
borderBottom: `1px solid ${alpha(primary.main, 0.12)}`
}}
>
<Box
className='w-12 h-12 rounded-2xl flex items-center justify-center shrink-0'
sx={{
background: 'linear-gradient(145deg, #22c55e 0%, #0ea5e9 100%)',
boxShadow: '0 4px 12px rgba(34, 197, 94, 0.3)'
background: `linear-gradient(145deg, ${primary.main} 0%, ${info.main} 100%)`,
boxShadow: `0 4px 12px ${alpha(primary.main, 0.3)}`,
color: 'primary.contrastText'
}}
>
<i className='tabler-leaf text-2xl text-white' />
<i className='tabler-leaf text-2xl' style={{ color: 'inherit' }} />
</Box>
<Box className='min-w-0 flex-1'>
<Typography
variant='h6'
className='font-bold truncate'
sx={{
background: 'linear-gradient(135deg, #16a34a 0%, #0ea5e9 100%)',
background: `linear-gradient(135deg, ${primary.dark} 0%, ${info.main} 100%)`,
backgroundClip: 'text',
WebkitBackgroundClip: 'text',
color: 'transparent',
@@ -174,9 +183,9 @@ export default function FarmAiAssistantChat() {
<Box
className='mx-4 mt-3 flex-shrink-0 rounded-2xl overflow-hidden'
sx={{
background: 'linear-gradient(145deg, #ffffff 0%, rgba(34, 197, 94, 0.04) 100%)',
border: '1px solid rgba(34, 197, 94, 0.15)',
boxShadow: '0 2px 12px rgba(0,0,0,0.04)'
background: `linear-gradient(145deg, ${theme.palette.background.paper} 0%, ${alpha(primary.main, 0.04)} 100%)`,
border: `1px solid ${alpha(primary.main, 0.15)}`,
boxShadow: theme.shadows[1]
}}
>
<Box
@@ -185,7 +194,7 @@ export default function FarmAiAssistantChat() {
onClick={() => setIsContextExpanded(!isContextExpanded)}
className='w-full flex items-center justify-between px-4 py-3 text-start'
sx={{
'&:hover': { bgcolor: 'rgba(34, 197, 94, 0.04)' },
'&:hover': { bgcolor: alpha(primary.main, 0.04) },
transition: 'background 0.2s'
}}
>
@@ -193,9 +202,10 @@ export default function FarmAiAssistantChat() {
{t('context.title')}
</Typography>
<i
className={classnames('tabler-chevron-down text-xl text-[#22c55e] transition-transform duration-300', {
className={classnames('tabler-chevron-down text-xl transition-transform duration-300', {
'rotate-180': isContextExpanded
})}
style={{ color: primary.main }}
/>
</Box>
<Collapse in={isContextExpanded}>
@@ -225,10 +235,10 @@ export default function FarmAiAssistantChat() {
<Box
className='w-20 h-20 rounded-3xl flex items-center justify-center mb-4'
sx={{
background: 'linear-gradient(145deg, rgba(34, 197, 94, 0.1) 0%, rgba(14, 165, 233, 0.1) 100%)'
background: `linear-gradient(145deg, ${alpha(primary.main, 0.1)} 0%, ${alpha(info.main, 0.1)} 100%)`
}}
>
<i className='tabler-message-circle text-4xl text-[#22c55e]' />
<i className='tabler-message-circle text-4xl' style={{ color: primary.main }} />
</Box>
<Typography variant='body1' color='text.secondary' className='mb-1'>
{t('emptyState.title')}
@@ -255,17 +265,18 @@ export default function FarmAiAssistantChat() {
<Box
className='w-9 h-9 rounded-xl flex items-center justify-center shrink-0'
sx={{
background: 'linear-gradient(145deg, #22c55e 0%, #0ea5e9 100%)'
background: `linear-gradient(145deg, ${primary.main} 0%, ${info.main} 100%)`,
color: 'primary.contrastText'
}}
>
<i className='tabler-leaf text-lg text-white' />
<i className='tabler-leaf text-lg' style={{ color: 'inherit' }} />
</Box>
<Box
className='px-4 py-3 rounded-2xl rounded-tl-md'
sx={{
background: 'linear-gradient(145deg, #ffffff 0%, rgba(34, 197, 94, 0.05) 100%)',
border: '1px solid rgba(34, 197, 94, 0.15)',
boxShadow: '0 2px 12px rgba(0,0,0,0.04)'
background: `linear-gradient(145deg, ${theme.palette.background.paper} 0%, ${alpha(primary.main, 0.05)} 100%)`,
border: `1px solid ${alpha(primary.main, 0.15)}`,
boxShadow: theme.shadows[1]
}}
>
<TypingIndicator />
@@ -290,14 +301,12 @@ export default function FarmAiAssistantChat() {
sx={{
background:
selectedChip === chip.id
? 'linear-gradient(135deg, #22c55e 0%, #16a34a 100%)'
: 'linear-gradient(145deg, #ffffff 0%, rgba(34, 197, 94, 0.08) 100%)',
color: selectedChip === chip.id ? '#ffffff' : 'text.primary',
border: selectedChip === chip.id ? 'none' : '1px solid rgba(34, 197, 94, 0.2)',
? `linear-gradient(135deg, ${primary.main} 0%, ${primary.dark} 100%)`
: `linear-gradient(145deg, ${theme.palette.background.paper} 0%, ${alpha(primary.main, 0.08)} 100%)`,
color: selectedChip === chip.id ? 'primary.contrastText' : 'text.primary',
border: selectedChip === chip.id ? 'none' : `1px solid ${alpha(primary.main, 0.2)}`,
boxShadow:
selectedChip === chip.id
? '0 4px 12px rgba(34, 197, 94, 0.35)'
: '0 2px 8px rgba(0,0,0,0.04)'
selectedChip === chip.id ? `0 4px 12px ${alpha(primary.main, 0.35)}` : theme.shadows[1]
}}
>
{t(chip.labelKey)}
@@ -310,17 +319,17 @@ export default function FarmAiAssistantChat() {
<Box
className='px-4 py-3 pb-6 flex-shrink-0'
sx={{
background: 'linear-gradient(to top, rgba(248,252,248,0.98) 0%, rgba(248,252,248,0.9) 70%, transparent 100%)',
background: `linear-gradient(to top, ${alpha(theme.palette.background.default, 0.98)} 0%, ${alpha(theme.palette.background.default, 0.9)} 70%, transparent 100%)`,
backdropFilter: 'blur(12px)'
}}
>
<Box
className='flex items-end gap-2'
sx={{
background: '#ffffff',
bgcolor: 'background.paper',
borderRadius: '24px',
border: '1px solid rgba(34, 197, 94, 0.2)',
boxShadow: '0 4px 20px rgba(34, 197, 94, 0.08)',
border: `1px solid ${alpha(primary.main, 0.2)}`,
boxShadow: `0 4px 20px ${alpha(primary.main, 0.08)}`,
p: 1
}}
>
@@ -331,7 +340,7 @@ export default function FarmAiAssistantChat() {
className='shrink-0'
sx={{
color: 'text.secondary',
'&:hover': { color: '#22c55e', bgcolor: 'rgba(34, 197, 94, 0.08)' }
'&:hover': { color: 'primary.main', bgcolor: 'primary.lighterOpacity' }
}}
>
<i className='tabler-camera text-xl' />
@@ -342,7 +351,7 @@ export default function FarmAiAssistantChat() {
className='shrink-0'
sx={{
color: 'text.secondary',
'&:hover': { color: '#0ea5e9', bgcolor: 'rgba(14, 165, 233, 0.08)' }
'&:hover': { color: 'info.main', bgcolor: 'info.lighterOpacity' }
}}
>
<i className='tabler-microphone text-xl' />
@@ -377,13 +386,13 @@ export default function FarmAiAssistantChat() {
className='shrink-0'
sx={{
background: inputValue.trim()
? 'linear-gradient(135deg, #22c55e 0%, #16a34a 100%)'
? `linear-gradient(135deg, ${primary.main} 0%, ${primary.dark} 100%)`
: 'action.disabledBackground',
color: inputValue.trim() ? '#ffffff' : 'action.disabled',
color: inputValue.trim() ? 'primary.contrastText' : 'action.disabled',
'&:hover': inputValue.trim()
? {
background: 'linear-gradient(135deg, #16a34a 0%, #15803d 100%)',
boxShadow: '0 4px 12px rgba(34, 197, 94, 0.4)'
background: `linear-gradient(135deg, ${primary.dark} 0%, ${primary.dark} 100%)`,
boxShadow: `0 4px 12px ${alpha(primary.main, 0.4)}`
}
: {},
'&.Mui-disabled': { background: 'action.disabledBackground', color: 'action.disabled' }
@@ -410,15 +419,18 @@ function ContextBadge({
value: string
colSpan?: number
}) {
const theme = useTheme()
const primary = theme.palette.primary
return (
<Box
className={classnames('flex items-center gap-2 px-3 py-2 rounded-xl', colSpan === 2 ? 'col-span-2' : '')}
sx={{
background: 'rgba(34, 197, 94, 0.06)',
border: '1px solid rgba(34, 197, 94, 0.12)'
background: alpha(primary.main, 0.06),
border: `1px solid ${alpha(primary.main, 0.12)}`
}}
>
<i className={`${icon} text-lg text-[#22c55e] shrink-0`} />
<i className={`${icon} text-lg shrink-0`} style={{ color: primary.main }} />
<Box className='min-w-0'>
<Typography variant='caption' color='text.secondary' display='block' lineHeight={1.2}>
{label}
@@ -442,6 +454,8 @@ function MessageBubble({
onToggleExplanation: (id: string) => void
t: (key: string) => string
}) {
const theme = useTheme()
const { primary, info } = theme.palette
const isUser = message.role === 'user'
if (isUser) {
@@ -450,8 +464,8 @@ function MessageBubble({
<Box
className='max-w-[85%] px-4 py-2.5 rounded-2xl rounded-tr-md'
sx={{
background: 'linear-gradient(145deg, rgba(34, 197, 94, 0.15) 0%, rgba(34, 197, 94, 0.08) 100%)',
border: '1px solid rgba(34, 197, 94, 0.2)'
background: `linear-gradient(145deg, ${alpha(primary.main, 0.15)} 0%, ${alpha(primary.main, 0.08)} 100%)`,
border: `1px solid ${alpha(primary.main, 0.2)}`
}}
>
<Typography variant='body2' color='text.primary'>
@@ -468,10 +482,11 @@ function MessageBubble({
<Box
className='w-9 h-9 rounded-xl flex items-center justify-center shrink-0'
sx={{
background: 'linear-gradient(145deg, #22c55e 0%, #0ea5e9 100%)'
background: `linear-gradient(145deg, ${primary.main} 0%, ${info.main} 100%)`,
color: 'primary.contrastText'
}}
>
<i className='tabler-leaf text-lg text-white' />
<i className='tabler-leaf text-lg' style={{ color: 'inherit' }} />
</Box>
<Box className='flex-1 min-w-0 space-y-3'>
{message.sections?.map((section, idx) => (
@@ -505,6 +520,8 @@ function AISectionCard({
idx: number
t: (key: string) => string
}) {
const theme = useTheme()
const { primary, warning: warningPalette } = theme.palette
const expId = `${messageId}-exp-${idx}`
const iconMap = {
@@ -523,14 +540,14 @@ function AISectionCard({
className='overflow-hidden'
sx={{
borderRadius: '20px',
background: 'linear-gradient(160deg, #ffffff 0%, rgba(34, 197, 94, 0.06) 100%)',
border: '1px solid rgba(34, 197, 94, 0.2)',
boxShadow: '0 4px 20px rgba(34, 197, 94, 0.12)'
background: `linear-gradient(160deg, ${theme.palette.background.paper} 0%, ${alpha(primary.main, 0.06)} 100%)`,
border: `1px solid ${alpha(primary.main, 0.2)}`,
boxShadow: `0 4px 20px ${alpha(primary.main, 0.12)}`
}}
>
<Box className='p-4'>
<Box className='flex items-center gap-2 mb-3'>
<i className={`${iconClass} text-xl text-[#22c55e]`} />
<i className={`${iconClass} text-xl`} style={{ color: primary.main }} />
<Typography variant='subtitle2' fontWeight={700} color='primary'>
{section.title}
</Typography>
@@ -574,7 +591,7 @@ function AISectionCard({
type='button'
onClick={() => onToggleExplanation(expId)}
className='flex items-center gap-1 text-sm font-medium'
sx={{ color: '#22c55e', '&:hover': { color: '#16a34a' } }}
sx={{ color: 'primary.main', '&:hover': { color: 'primary.dark' } }}
>
{t('recommendation.whyThis')}
<i
@@ -600,12 +617,15 @@ function AISectionCard({
<Box
className='p-4 rounded-2xl'
sx={{
background: 'linear-gradient(135deg, rgba(251, 191, 36, 0.15) 0%, rgba(245, 158, 11, 0.08) 100%)',
border: '1px solid rgba(251, 191, 36, 0.35)'
background: `linear-gradient(135deg, ${alpha(warningPalette.main, 0.15)} 0%, ${alpha(warningPalette.main, 0.08)} 100%)`,
border: `1px solid ${alpha(warningPalette.main, 0.35)}`
}}
>
<Box className='flex gap-2'>
<i className='tabler-alert-triangle text-xl text-amber-600 shrink-0 mt-0.5' />
<i
className='tabler-alert-triangle text-xl shrink-0 mt-0.5'
style={{ color: warningPalette.dark }}
/>
<Box>
{section.title && (
<Typography variant='subtitle2' fontWeight={600} color='warning.dark' className='mb-1'>
@@ -626,13 +646,13 @@ function AISectionCard({
<Box
className='p-4 rounded-2xl'
sx={{
background: 'linear-gradient(145deg, #ffffff 0%, rgba(34, 197, 94, 0.04) 100%)',
border: '1px solid rgba(34, 197, 94, 0.15)'
background: `linear-gradient(145deg, ${theme.palette.background.paper} 0%, ${alpha(primary.main, 0.04)} 100%)`,
border: `1px solid ${alpha(primary.main, 0.15)}`
}}
>
{section.title && (
<Box className='flex items-center gap-2 mb-2'>
<i className={`${iconClass} text-lg text-[#22c55e]`} />
<i className={`${iconClass} text-lg`} style={{ color: primary.main }} />
<Typography variant='subtitle2' fontWeight={600} color='text.primary'>
{section.title}
</Typography>
@@ -660,8 +680,9 @@ function TypingIndicator() {
{[0, 1, 2].map(i => (
<Box
key={i}
className='w-2 h-2 rounded-full bg-[#22c55e]'
className='w-2 h-2 rounded-full'
sx={{
bgcolor: 'primary.main',
animation: `typing-bounce 1.4s ease-in-out ${i * 0.16}s infinite both`
}}
/>
@@ -9,6 +9,13 @@ import Typography from '@mui/material/Typography'
import Button from '@mui/material/Button'
import CircularProgress from '@mui/material/CircularProgress'
import Collapse from '@mui/material/Collapse'
import { useTheme } from '@mui/material/styles'
import { alpha } from '@mui/material/styles'
import classnames from 'classnames'
// Util Imports
import { commonLayoutClasses } from '@layouts/utils/layoutClasses'
import UploadBox from './components/UploadBox'
import ResultCard from './components/ResultCard'
import type { UploadedFile } from './components/UploadBox'
@@ -16,6 +23,8 @@ import type { PestResult } from './components/ResultCard'
export default function PlantPestDetection() {
const t = useTranslations('pestDetection')
const theme = useTheme()
const primary = theme.palette.primary
const [file, setFile] = useState<UploadedFile | null>(null)
const [result, setResult] = useState<PestResult | null>(null)
const [loading, setLoading] = useState(false)
@@ -58,19 +67,17 @@ export default function PlantPestDetection() {
return (
<Box
className="min-bs-screen pb-24"
sx={{
minHeight: '100vh',
}}
className={classnames(commonLayoutClasses.contentHeightFixed, 'flex flex-col is-full overflow-hidden rounded')}
sx={{ minHeight: '100%' }}
>
<Box className="max-w-2xl mx-auto px-4 py-6 sm:py-8">
<Box className="is-full py-6 sm:py-8 flex flex-col">
{/* Header */}
<Box className="mb-8">
<Typography
variant="h4"
className="font-bold tracking-tight"
sx={{
background: 'linear-gradient(135deg, #22c55e 0%, #16a34a 50%, #15803d 100%)',
background: `linear-gradient(135deg, ${primary.main} 0%, ${primary.dark} 50%, ${primary.dark} 100%)`,
backgroundClip: 'text',
WebkitBackgroundClip: 'text',
color: 'transparent',
@@ -90,9 +97,9 @@ export default function PlantPestDetection() {
className="mb-6 overflow-hidden transition-all duration-300 hover:shadow-lg"
sx={{
borderRadius: '24px',
background: 'linear-gradient(145deg, #ffffff 0%, #f8fcf8 100%)',
boxShadow: '0 4px 24px rgba(34, 197, 94, 0.08), 0 1px 3px rgba(0,0,0,0.04)',
border: '1px solid rgba(34, 197, 94, 0.12)',
background: `linear-gradient(145deg, ${theme.palette.background.paper} 0%, ${alpha(primary.main, 0.04)} 100%)`,
boxShadow: `0 4px 24px ${alpha(primary.main, 0.08)}, ${theme.shadows[1]}`,
border: `1px solid ${alpha(primary.main, 0.12)}`,
}}
>
<CardContent className="p-5 sm:p-6">
@@ -111,18 +118,18 @@ export default function PlantPestDetection() {
onClick={handleAnalyze}
startIcon={
loading ? (
<CircularProgress size={20} color="inherit" sx={{ color: 'white' }} />
<CircularProgress size={20} color="inherit" />
) : (
<i className="tabler-scan text-xl" />
)
}
className="rounded-xl py-3 px-8 font-semibold shadow-md transition-all duration-300 hover:shadow-lg hover:scale-[1.02] active:scale-[0.98]"
sx={{
background: 'linear-gradient(135deg, #22c55e 0%, #16a34a 50%, #15803d 100%)',
boxShadow: '0 4px 20px rgba(34, 197, 94, 0.35)',
background: `linear-gradient(135deg, ${primary.main} 0%, ${primary.dark} 50%, ${primary.dark} 100%)`,
boxShadow: `0 4px 20px ${alpha(primary.main, 0.35)}`,
'&:hover': {
background: 'linear-gradient(135deg, #4ade80 0%, #22c55e 50%, #16a34a 100%)',
boxShadow: '0 6px 24px rgba(34, 197, 94, 0.45)',
background: `linear-gradient(135deg, ${primary.light} 0%, ${primary.main} 50%, ${primary.dark} 100%)`,
boxShadow: `0 6px 24px ${alpha(primary.main, 0.45)}`,
},
'&:disabled': {
background: 'action.disabledBackground',
@@ -162,13 +169,13 @@ export default function PlantPestDetection() {
className="mb-6"
sx={{
borderRadius: '24px',
background: 'linear-gradient(160deg, #ffffff 0%, #f0fdf4 100%)',
boxShadow: '0 8px 32px rgba(34, 197, 94, 0.1)',
border: '1px solid rgba(34, 197, 94, 0.12)',
background: `linear-gradient(160deg, ${theme.palette.background.paper} 0%, ${alpha(primary.main, 0.06)} 100%)`,
boxShadow: `0 8px 32px ${alpha(primary.main, 0.1)}`,
border: `1px solid ${alpha(primary.main, 0.12)}`,
}}
>
<CardContent className="p-12 flex flex-col items-center gap-4">
<CircularProgress size={48} sx={{ color: '#22c55e' }} />
<CircularProgress size={48} sx={{ color: 'primary.main' }} />
<Typography variant="body2" color="text.secondary">
{t('analyzing')}
</Typography>
@@ -8,6 +8,7 @@ import CardContent from '@mui/material/CardContent'
import Typography from '@mui/material/Typography'
import Button from '@mui/material/Button'
import Collapse from '@mui/material/Collapse'
import { useTheme, alpha } from '@mui/material/styles'
// Types
interface FarmData {
@@ -77,6 +78,11 @@ function generateFertilizationPlan(
export default function SmartFertilizationRecommendation() {
const t = useTranslations('fertilization')
const theme = useTheme()
const primaryMain = theme.palette.primary.main
const primaryLight = theme.palette.primary.light
const primaryDark = theme.palette.primary.dark
const paperBg = theme.palette.background.paper
const [farmData] = useState<FarmData>(DEFAULT_FARM_DATA)
const [growthStage, setGrowthStage] = useState<string>(GROWTH_STAGES[0].id)
const [selectedCrop, setSelectedCrop] = useState<string | null>(null)
@@ -101,10 +107,10 @@ export default function SmartFertilizationRecommendation() {
return (
<Box
className='min-bs-screen pb-28'
className='min-bs-screen'
sx={{
background:
'linear-gradient(165deg, #f0fdf4 0%, #ecfdf5 25%, #faf5ff 60%, var(--mui-palette-background-default) 100%)',
background: (th) =>
`linear-gradient(165deg, ${alpha(th.palette.primary.main, 0.08)} 0%, ${alpha(th.palette.primary.main, 0.05)} 25%, ${alpha(th.palette.primary.main, 0.03)} 60%, ${th.palette.background.default} 100%)`,
minHeight: '100vh'
}}
>
@@ -115,8 +121,7 @@ export default function SmartFertilizationRecommendation() {
variant='h4'
className='font-bold tracking-tight'
sx={{
background:
'linear-gradient(135deg, #16a34a 0%, #22c55e 40%, #7c3aed 100%)',
background: `linear-gradient(135deg, ${primaryDark} 0%, ${primaryMain} 40%, ${primaryLight} 100%)`,
backgroundClip: 'text',
WebkitBackgroundClip: 'text',
color: 'transparent',
@@ -140,11 +145,9 @@ export default function SmartFertilizationRecommendation() {
className='mb-6 overflow-hidden transition-all duration-300 hover:shadow-lg animate-fade-in'
sx={{
borderRadius: '28px',
background:
'linear-gradient(145deg, #ffffff 0%, #faf5ff 50%, #f0fdf4 100%)',
boxShadow:
'0 4px 24px rgba(34, 197, 94, 0.08), 0 4px 12px rgba(124, 58, 237, 0.04), 0 1px 3px rgba(0,0,0,0.04)',
border: '1px solid rgba(34, 197, 94, 0.12)'
background: `linear-gradient(145deg, ${paperBg} 0%, ${alpha(primaryMain, 0.06)} 50%, ${alpha(primaryMain, 0.04)} 100%)`,
boxShadow: `0 4px 24px ${alpha(primaryMain, 0.08)}, 0 4px 12px ${alpha(primaryMain, 0.04)}, 0 1px 3px rgba(0,0,0,0.04)`,
border: `1px solid ${alpha(primaryMain, 0.12)}`
}}
>
<CardContent className='p-5'>
@@ -155,10 +158,9 @@ export default function SmartFertilizationRecommendation() {
<Box
className='px-2.5 py-1 rounded-full text-xs font-medium flex items-center gap-1.5'
sx={{
background:
'linear-gradient(135deg, #22c55e 0%, #16a34a 100%)',
background: (th) => `linear-gradient(135deg, ${th.palette.success.main} 0%, ${th.palette.success.dark} 100%)`,
color: 'white',
boxShadow: '0 2px 8px rgba(34, 197, 94, 0.3)'
boxShadow: (th) => `0 2px 8px ${alpha(th.palette.success.main, 0.3)}`
}}
>
<i className='tabler-circle-check text-sm' />
@@ -193,18 +195,18 @@ export default function SmartFertilizationRecommendation() {
onClick={() => setGrowthStage(stage.id)}
className='flex flex-col items-center gap-1.5 px-4 py-3 rounded-2xl shrink-0 transition-all duration-300 ease-out border-2 cursor-pointer min-w-[72px]'
sx={{
borderColor: isSelected ? '#22c55e' : 'transparent',
borderColor: isSelected ? primaryMain : 'transparent',
background: isSelected
? 'linear-gradient(145deg, rgba(34, 197, 94, 0.15) 0%, rgba(124, 58, 237, 0.06) 100%)'
: 'linear-gradient(145deg, #ffffff 0%, #faf5ff 100%)',
? `linear-gradient(145deg, ${alpha(primaryMain, 0.15)} 0%, ${alpha(primaryMain, 0.06)} 100%)`
: `linear-gradient(145deg, ${paperBg} 0%, ${alpha(primaryMain, 0.04)} 100%)`,
boxShadow: isSelected
? '0 4px 20px rgba(34, 197, 94, 0.2), inset 0 1px 0 rgba(255,255,255,0.8)'
? `0 4px 20px ${alpha(primaryMain, 0.2)}, inset 0 1px 0 rgba(255,255,255,0.8)`
: '0 2px 8px rgba(0,0,0,0.04)',
'&:hover': {
transform: 'translateY(-2px)',
boxShadow: isSelected
? '0 6px 24px rgba(34, 197, 94, 0.25)'
: '0 4px 16px rgba(124, 58, 237, 0.1)'
? `0 6px 24px ${alpha(primaryMain, 0.25)}`
: `0 4px 16px ${alpha(primaryMain, 0.1)}`
}
}}
>
@@ -212,23 +214,22 @@ export default function SmartFertilizationRecommendation() {
className='w-10 h-10 rounded-xl flex items-center justify-center transition-all duration-300'
sx={{
background: isSelected
? 'linear-gradient(135deg, #22c55e 0%, #16a34a 100%)'
? `linear-gradient(135deg, ${primaryMain} 0%, ${primaryDark} 100%)`
: isPast
? 'linear-gradient(145deg, rgba(34, 197, 94, 0.2) 0%, rgba(34, 197, 94, 0.1) 100%)'
: 'rgba(124, 58, 237, 0.08)'
? `linear-gradient(145deg, ${alpha(primaryMain, 0.2)} 0%, ${alpha(primaryMain, 0.1)} 100%)`
: alpha(primaryMain, 0.08)
}}
>
<i
className={`${stage.icon} text-xl transition-colors duration-300 ${
isSelected ? 'text-white' : isPast ? 'text-emerald-600' : 'text-violet-500'
}`}
className={`${stage.icon} text-xl transition-colors duration-300 ${isSelected ? 'text-white' : ''}`}
style={!isSelected ? { color: primaryMain } : undefined}
/>
</Box>
<Typography
variant='caption'
fontWeight={600}
sx={{
color: isSelected ? '#16a34a' : 'text.secondary',
color: isSelected ? 'primary.main' : 'text.secondary',
textAlign: 'center',
lineHeight: 1.2
}}
@@ -244,7 +245,7 @@ export default function SmartFertilizationRecommendation() {
<Typography variant='subtitle2' fontWeight={600} color='text.secondary' className='mbe-3'>
{t('plantSelection.title')}
</Typography>
<Box className='flex flex-wrap gap-3 mb-8'>
<Box className='flex flex-wrap gap-3 mb-6'>
{CROP_OPTIONS.map(crop => (
<CropCard
key={crop.id}
@@ -258,6 +259,33 @@ export default function SmartFertilizationRecommendation() {
))}
</Box>
{/* 5) Primary CTA Button - End of form */}
<Box className='mb-8'>
<Button
fullWidth
variant='contained'
disabled={!selectedCrop || loading}
onClick={handleGenerate}
startIcon={<i className='tabler-sparkles text-xl' />}
className='rounded-2xl py-3.5 text-base font-semibold shadow-lg transition-all duration-300 hover:shadow-xl hover:scale-[1.01] active:scale-[0.99]'
sx={{
background: `linear-gradient(135deg, ${primaryLight} 0%, ${primaryMain} 50%, ${primaryDark} 100%)`,
boxShadow: `0 4px 20px ${alpha(primaryMain, 0.4)}`,
'&:hover': {
background: `linear-gradient(135deg, ${primaryLight} 0%, ${primaryMain} 50%, ${primaryDark} 100%)`,
boxShadow: `0 6px 28px ${alpha(primaryMain, 0.5)}`,
filter: 'brightness(1.05)'
},
'&:disabled': {
background: 'action.disabledBackground',
color: 'action.disabled'
}
}}
>
{t('generateCta')}
</Button>
</Box>
{/* 6) Result Section - Prescription style */}
{plan && (
<Box className='mb-6 animate-fade-in'>
@@ -265,17 +293,15 @@ export default function SmartFertilizationRecommendation() {
elevation={0}
sx={{
borderRadius: '28px',
background:
'linear-gradient(160deg, #ffffff 0%, #faf5ff 40%, #f0fdf4 100%)',
boxShadow:
'0 8px 32px rgba(34, 197, 94, 0.12), 0 4px 16px rgba(124, 58, 237, 0.06), 0 2px 8px rgba(0,0,0,0.04)',
border: '1px solid rgba(34, 197, 94, 0.15)',
background: `linear-gradient(160deg, ${paperBg} 0%, ${alpha(primaryMain, 0.06)} 40%, ${alpha(primaryMain, 0.04)} 100%)`,
boxShadow: `0 8px 32px ${alpha(primaryMain, 0.12)}, 0 4px 16px ${alpha(primaryMain, 0.06)}, 0 2px 8px rgba(0,0,0,0.04)`,
border: `1px solid ${alpha(primaryMain, 0.15)}`,
overflow: 'visible'
}}
>
<CardContent className='p-6'>
<Box className='flex items-center gap-2 mbe-5'>
<i className='tabler-prescription text-2xl text-emerald-600' />
<i className='tabler-prescription text-2xl' style={{ color: primaryMain }} />
<Typography variant='h6' fontWeight={700} color='text.primary'>
{t('result.title')}
</Typography>
@@ -308,8 +334,8 @@ export default function SmartFertilizationRecommendation() {
<Box
className='mt-5 rounded-2xl overflow-hidden transition-all duration-300'
sx={{
border: '1px solid rgba(34, 197, 94, 0.15)',
background: 'rgba(34, 197, 94, 0.04)'
border: `1px solid ${alpha(primaryMain, 0.15)}`,
background: alpha(primaryMain, 0.04)
}}
>
<Box
@@ -317,18 +343,19 @@ export default function SmartFertilizationRecommendation() {
type='button'
onClick={() => setReasoningExpanded(!reasoningExpanded)}
className='w-full flex items-center justify-between px-4 py-3 text-start cursor-pointer'
sx={{ '&:hover': { bgcolor: 'rgba(34, 197, 94, 0.06)' } }}
sx={{ '&:hover': { bgcolor: alpha(primaryMain, 0.06) } }}
>
<Box className='flex items-center gap-2'>
<i className='tabler-brain text-lg text-emerald-600' />
<i className='tabler-brain text-lg' style={{ color: primaryMain }} />
<Typography variant='subtitle2' fontWeight={600} color='text.primary'>
{t('result.whyRecommendation')}
</Typography>
</Box>
<i
className={`tabler-chevron-down text-xl text-emerald-600 transition-transform duration-300 ${
className={`tabler-chevron-down text-xl transition-transform duration-300 ${
reasoningExpanded ? 'rotate-180' : ''
}`}
style={{ color: primaryMain }}
/>
</Box>
<Collapse in={reasoningExpanded}>
@@ -355,21 +382,19 @@ export default function SmartFertilizationRecommendation() {
className='mb-6 animate-fade-in'
sx={{
borderRadius: '28px',
background:
'linear-gradient(160deg, #ffffff 0%, #f0fdf4 100%)',
boxShadow: '0 8px 32px rgba(34, 197, 94, 0.1)',
border: '1px solid rgba(34, 197, 94, 0.12)'
background: `linear-gradient(160deg, ${paperBg} 0%, ${alpha(primaryMain, 0.06)} 100%)`,
boxShadow: `0 8px 32px ${alpha(primaryMain, 0.1)}`,
border: `1px solid ${alpha(primaryMain, 0.12)}`
}}
>
<CardContent className='p-12 flex flex-col items-center gap-4'>
<Box
className='w-14 h-14 rounded-2xl flex items-center justify-center animate-pulse'
sx={{
background:
'linear-gradient(135deg, rgba(34, 197, 94, 0.15) 0%, rgba(124, 58, 237, 0.08) 100%)'
background: `linear-gradient(135deg, ${alpha(primaryMain, 0.15)} 0%, ${alpha(primaryMain, 0.08)} 100%)`
}}
>
<i className='tabler-sparkles text-2xl text-emerald-600' />
<i className='tabler-sparkles text-2xl' style={{ color: primaryMain }} />
</Box>
<Typography variant='body2' color='text.secondary'>
{t('generating')}
@@ -378,41 +403,6 @@ export default function SmartFertilizationRecommendation() {
</Card>
)}
</Box>
{/* 5) Primary CTA Button - Sticky */}
<Box
className='fixed bottom-0 start-0 end-0 p-4 z-10'
sx={{
background:
'linear-gradient(to top, rgba(255,255,255,0.98) 0%, rgba(255,255,255,0.9) 70%, transparent 100%)',
backdropFilter: 'blur(8px)'
}}
>
<Button
fullWidth
variant='contained'
disabled={!selectedCrop || loading}
onClick={handleGenerate}
startIcon={<i className='tabler-sparkles text-xl' />}
className='rounded-2xl py-3.5 text-base font-semibold shadow-lg transition-all duration-300 hover:shadow-xl hover:scale-[1.01] active:scale-[0.99]'
sx={{
background:
'linear-gradient(135deg, #22c55e 0%, #16a34a 50%, #15803d 100%)',
boxShadow: '0 4px 20px rgba(34, 197, 94, 0.4)',
'&:hover': {
background:
'linear-gradient(135deg, #4ade80 0%, #22c55e 50%, #16a34a 100%)',
boxShadow: '0 6px 28px rgba(34, 197, 94, 0.5)'
},
'&:disabled': {
background: 'action.disabledBackground',
color: 'action.disabled'
}
}}
>
{t('generateCta')}
</Button>
</Box>
</Box>
)
}
@@ -428,17 +418,18 @@ function FarmBadge({
label: string
value: string
}) {
const theme = useTheme()
const primaryMain = theme.palette.primary.main
return (
<Box
className='flex items-center gap-2 px-4 py-2.5 rounded-2xl transition-all duration-200 hover:scale-[1.02] hover:shadow-md'
sx={{
background:
'linear-gradient(145deg, rgba(34, 197, 94, 0.1) 0%, rgba(124, 58, 237, 0.04) 100%)',
border: '1px solid rgba(34, 197, 94, 0.15)',
background: `linear-gradient(145deg, ${alpha(primaryMain, 0.1)} 0%, ${alpha(primaryMain, 0.04)} 100%)`,
border: `1px solid ${alpha(primaryMain, 0.15)}`,
boxShadow: 'inset 0 1px 2px rgba(255,255,255,0.5)'
}}
>
<i className={`${icon} text-xl text-emerald-600`} />
<i className={`${icon} text-xl`} style={{ color: primaryMain }} />
<Box>
<Typography variant='caption' color='text.secondary' display='block' lineHeight={1.2}>
{label}
@@ -462,6 +453,10 @@ function CropCard({
selected: boolean
onClick: () => void
}) {
const theme = useTheme()
const primaryMain = theme.palette.primary.main
const primaryDark = theme.palette.primary.dark
const paperBg = theme.palette.background.paper
return (
<Card
component='button'
@@ -470,18 +465,18 @@ function CropCard({
onClick={onClick}
className='flex items-center gap-3 px-4 py-3 rounded-2xl cursor-pointer transition-all duration-300 border-2 text-start'
sx={{
borderColor: selected ? '#22c55e' : 'transparent',
borderColor: selected ? primaryMain : 'transparent',
background: selected
? 'linear-gradient(145deg, rgba(34, 197, 94, 0.15) 0%, rgba(124, 58, 237, 0.06) 100%)'
: 'linear-gradient(145deg, #ffffff 0%, #faf5ff 100%)',
? `linear-gradient(145deg, ${alpha(primaryMain, 0.15)} 0%, ${alpha(primaryMain, 0.06)} 100%)`
: `linear-gradient(145deg, ${paperBg} 0%, ${alpha(primaryMain, 0.04)} 100%)`,
boxShadow: selected
? '0 4px 20px rgba(34, 197, 94, 0.2), inset 0 1px 0 rgba(255,255,255,0.8)'
? `0 4px 20px ${alpha(primaryMain, 0.2)}, inset 0 1px 0 rgba(255,255,255,0.8)`
: '0 2px 8px rgba(0,0,0,0.04), inset 0 1px 0 rgba(255,255,255,0.9)',
'&:hover': {
transform: 'translateY(-2px)',
boxShadow: selected
? '0 6px 24px rgba(34, 197, 94, 0.25)'
: '0 4px 16px rgba(34, 197, 94, 0.12)'
? `0 6px 24px ${alpha(primaryMain, 0.25)}`
: `0 4px 16px ${alpha(primaryMain, 0.12)}`
}
}}
>
@@ -489,23 +484,24 @@ function CropCard({
className='w-11 h-11 rounded-xl flex items-center justify-center shrink-0 transition-all duration-300'
sx={{
background: selected
? 'linear-gradient(135deg, #22c55e 0%, #16a34a 100%)'
: 'linear-gradient(145deg, rgba(34, 197, 94, 0.1) 0%, rgba(124, 58, 237, 0.05) 100%)'
? `linear-gradient(135deg, ${primaryMain} 0%, ${primaryDark} 100%)`
: `linear-gradient(145deg, ${alpha(primaryMain, 0.1)} 0%, ${alpha(primaryMain, 0.05)} 100%)`
}}
>
<i
className={`${crop.icon} text-xl ${selected ? 'text-white' : 'text-emerald-600'}`}
className={`${crop.icon} text-xl ${selected ? 'text-white' : ''}`}
style={!selected ? { color: primaryMain } : undefined}
/>
</Box>
<Typography
variant='body2'
fontWeight={600}
color={selected ? '#16a34a' : 'text.primary'}
color={selected ? 'primary.main' : 'text.primary'}
>
{label}
</Typography>
{selected && (
<i className='tabler-circle-check-filled text-xl text-emerald-600 ms-auto' />
<i className='tabler-circle-check-filled text-xl ms-auto' style={{ color: primaryMain }} />
)}
</Card>
)
@@ -520,15 +516,17 @@ function PrescriptionRow({
label: string
value: string
}) {
const theme = useTheme()
const primaryMain = theme.palette.primary.main
return (
<Box
className='flex items-center gap-4 p-3 rounded-2xl transition-colors duration-200'
sx={{
background: 'rgba(34, 197, 94, 0.06)',
border: '1px solid rgba(34, 197, 94, 0.08)'
background: alpha(primaryMain, 0.06),
border: `1px solid ${alpha(primaryMain, 0.08)}`
}}
>
<i className={`${icon} text-2xl text-emerald-600 shrink-0`} />
<i className={`${icon} text-2xl shrink-0`} style={{ color: primaryMain }} />
<Box className='flex-1 min-w-0'>
<Typography variant='caption' color='text.secondary'>
{label}
@@ -9,6 +9,7 @@ import Typography from '@mui/material/Typography'
import Button from '@mui/material/Button'
import IconButton from '@mui/material/IconButton'
import CircularProgress from '@mui/material/CircularProgress'
import { useTheme, alpha } from '@mui/material/styles'
// Types
interface FarmInfo {
@@ -60,10 +61,16 @@ function generateIrrigationPlan(_cropId: string, _farmInfo: FarmInfo): Irrigatio
export default function SmartIrrigationRecommendation() {
const t = useTranslations('irrigation')
const theme = useTheme()
const [farmInfo] = useState<FarmInfo>(DEFAULT_FARM_INFO)
const [selectedCrop, setSelectedCrop] = useState<string | null>(null)
const [plan, setPlan] = useState<IrrigationPlan | null>(null)
const [loading, setLoading] = useState(false)
const primaryMain = theme.palette.primary.main
const primaryLight = theme.palette.primary.light
const primaryDark = theme.palette.primary.dark
const bgDefault = theme.palette.background.default
const paperBg = theme.palette.background.paper
const handleGenerate = () => {
if (!selectedCrop) return
@@ -78,9 +85,10 @@ export default function SmartIrrigationRecommendation() {
return (
<Box
className='min-bs-screen pb-24'
className='min-bs-screen'
sx={{
background: 'linear-gradient(165deg, #e0f2fe 0%, #f0f9ff 35%, #f8fcff 70%, var(--mui-palette-background-default) 100%)',
background: (theme) =>
`linear-gradient(165deg, ${alpha(theme.palette.primary.main, 0.08)} 0%, ${alpha(theme.palette.primary.main, 0.04)} 35%, ${alpha(theme.palette.primary.main, 0.02)} 70%, ${theme.palette.background.default} 100%)`,
minHeight: '100vh'
}}
>
@@ -91,7 +99,7 @@ export default function SmartIrrigationRecommendation() {
variant='h4'
className='font-bold tracking-tight'
sx={{
background: 'linear-gradient(135deg, #0ea5e9 0%, #0284c7 50%, #0369a1 100%)',
background: `linear-gradient(135deg, ${primaryLight} 0%, ${primaryMain} 50%, ${primaryDark} 100%)`,
backgroundClip: 'text',
WebkitBackgroundClip: 'text',
color: 'transparent',
@@ -111,9 +119,9 @@ export default function SmartIrrigationRecommendation() {
className='mb-6 overflow-hidden transition-all duration-300 hover:shadow-lg'
sx={{
borderRadius: '24px',
background: 'linear-gradient(145deg, #ffffff 0%, #f8fcff 100%)',
boxShadow: '0 4px 24px rgba(14, 165, 233, 0.08), 0 1px 3px rgba(0,0,0,0.04)',
border: '1px solid rgba(14, 165, 233, 0.12)'
background: `linear-gradient(145deg, ${paperBg} 0%, ${alpha(primaryMain, 0.04)} 100%)`,
boxShadow: `0 4px 24px ${alpha(primaryMain, 0.08)}, 0 1px 3px rgba(0,0,0,0.04)`,
border: `1px solid ${alpha(primaryMain, 0.12)}`
}}
>
<CardContent className='p-5'>
@@ -125,7 +133,7 @@ export default function SmartIrrigationRecommendation() {
<Box
className='px-2.5 py-1 rounded-full text-xs font-medium'
sx={{
background: 'linear-gradient(135deg, #22c55e 0%, #16a34a 100%)',
background: (t) => `linear-gradient(135deg, ${t.palette.success.main} 0%, ${t.palette.success.dark} 100%)`,
color: 'white',
display: 'flex',
alignItems: 'center',
@@ -152,7 +160,7 @@ export default function SmartIrrigationRecommendation() {
<Typography variant='subtitle2' fontWeight={600} color='text.secondary' className='mbe-3'>
{t('plantSelection.title')}
</Typography>
<Box className='flex flex-wrap gap-3 mb-8'>
<Box className='flex flex-wrap gap-3 mb-6'>
{CROP_OPTIONS.map(crop => (
<CropCard
key={crop.id}
@@ -164,6 +172,33 @@ export default function SmartIrrigationRecommendation() {
))}
</Box>
{/* 4) Primary CTA Button - End of form */}
<Box className='mb-8'>
<Button
fullWidth
variant='contained'
disabled={!selectedCrop || loading}
onClick={handleGenerate}
startIcon={<i className='tabler-sparkles text-xl' />}
className='rounded-2xl py-3.5 text-base font-semibold shadow-lg transition-all duration-300 hover:shadow-xl hover:scale-[1.01] active:scale-[0.99]'
sx={{
background: `linear-gradient(135deg, ${primaryLight} 0%, ${primaryMain} 50%, ${primaryDark} 100%)`,
boxShadow: `0 4px 20px ${alpha(primaryMain, 0.4)}`,
'&:hover': {
background: `linear-gradient(135deg, ${primaryLight} 0%, ${primaryMain} 50%, ${primaryDark} 100%)`,
boxShadow: `0 6px 28px ${alpha(primaryMain, 0.5)}`,
filter: 'brightness(1.05)'
},
'&:disabled': {
background: 'action.disabledBackground',
color: 'action.disabled'
}
}}
>
{t('generateCta')}
</Button>
</Box>
{/* 5) Result Card (after click) */}
{plan && (
<Box className='mb-6 animate-fade-in'>
@@ -171,9 +206,9 @@ export default function SmartIrrigationRecommendation() {
elevation={0}
sx={{
borderRadius: '24px',
background: 'linear-gradient(160deg, #ffffff 0%, #f0f9ff 100%)',
boxShadow: '0 8px 32px rgba(14, 165, 233, 0.15), 0 2px 8px rgba(0,0,0,0.06)',
border: '1px solid rgba(14, 165, 233, 0.18)',
background: `linear-gradient(160deg, ${paperBg} 0%, ${alpha(primaryMain, 0.06)} 100%)`,
boxShadow: `0 8px 32px ${alpha(primaryMain, 0.15)}, 0 2px 8px rgba(0,0,0,0.06)`,
border: `1px solid ${alpha(primaryMain, 0.18)}`,
overflow: 'visible'
}}
>
@@ -187,7 +222,7 @@ export default function SmartIrrigationRecommendation() {
cy={60}
r={52}
fill='none'
stroke='rgba(14, 165, 233, 0.12)'
stroke={alpha(primaryMain, 0.12)}
strokeWidth={10}
/>
<circle
@@ -203,8 +238,8 @@ export default function SmartIrrigationRecommendation() {
/>
<defs>
<linearGradient id='moistureGradient' x1='0%' y1='0%' x2='100%' y2='100%'>
<stop offset='0%' stopColor='#0ea5e9' />
<stop offset='100%' stopColor='#0284c7' />
<stop offset='0%' stopColor={primaryLight} />
<stop offset='100%' stopColor={primaryMain} />
</linearGradient>
</defs>
</svg>
@@ -212,7 +247,7 @@ export default function SmartIrrigationRecommendation() {
className='absolute inset-0 flex flex-col items-center justify-center'
sx={{ top: 0, left: 0, right: 0, bottom: 0 }}
>
<i className='tabler-droplet text-3xl text-[#0ea5e9] mbe-0.5' />
<i className='tabler-droplet text-3xl mbe-0.5' style={{ color: primaryMain }} />
<Typography variant='h4' fontWeight={700} color='primary.main'>
{plan.moistureLevel}%
</Typography>
@@ -274,13 +309,13 @@ export default function SmartIrrigationRecommendation() {
className='mb-6'
sx={{
borderRadius: '24px',
background: 'linear-gradient(160deg, #ffffff 0%, #f0f9ff 100%)',
boxShadow: '0 8px 32px rgba(14, 165, 233, 0.1)',
border: '1px solid rgba(14, 165, 233, 0.12)'
background: `linear-gradient(160deg, ${paperBg} 0%, ${alpha(primaryMain, 0.06)} 100%)`,
boxShadow: `0 8px 32px ${alpha(primaryMain, 0.1)}`,
border: `1px solid ${alpha(primaryMain, 0.12)}`
}}
>
<CardContent className='p-12 flex flex-col items-center gap-4'>
<CircularProgress size={48} sx={{ color: '#0ea5e9' }} />
<CircularProgress size={48} sx={{ color: 'primary.main' }} />
<Typography variant='body2' color='text.secondary'>
{t('generating')}
</Typography>
@@ -288,38 +323,6 @@ export default function SmartIrrigationRecommendation() {
</Card>
)}
</Box>
{/* 4) Primary CTA Button - Sticky */}
<Box
className='fixed bottom-0 start-0 end-0 p-4 z-10'
sx={{
background: 'linear-gradient(to top, rgba(255,255,255,0.98) 0%, rgba(255,255,255,0.9) 70%, transparent 100%)',
backdropFilter: 'blur(8px)'
}}
>
<Button
fullWidth
variant='contained'
disabled={!selectedCrop || loading}
onClick={handleGenerate}
startIcon={<i className='tabler-sparkles text-xl' />}
className='rounded-2xl py-3.5 text-base font-semibold shadow-lg transition-all duration-300 hover:shadow-xl hover:scale-[1.01] active:scale-[0.99]'
sx={{
background: 'linear-gradient(135deg, #0ea5e9 0%, #0284c7 50%, #0369a1 100%)',
boxShadow: '0 4px 20px rgba(14, 165, 233, 0.4)',
'&:hover': {
background: 'linear-gradient(135deg, #38bdf8 0%, #0ea5e9 50%, #0284c7 100%)',
boxShadow: '0 6px 28px rgba(14, 165, 233, 0.5)'
},
'&:disabled': {
background: 'action.disabledBackground',
color: 'action.disabled'
}
}}
>
{t('generateCta')}
</Button>
</Box>
</Box>
)
}
@@ -335,16 +338,18 @@ function FarmBadge({
label: string
value: string
}) {
const theme = useTheme()
const primaryMain = theme.palette.primary.main
return (
<Box
className='flex items-center gap-2 px-4 py-2.5 rounded-2xl transition-transform duration-200 hover:scale-[1.02]'
sx={{
background: 'linear-gradient(145deg, rgba(14, 165, 233, 0.08) 0%, rgba(14, 165, 233, 0.04) 100%)',
border: '1px solid rgba(14, 165, 233, 0.15)',
background: `linear-gradient(145deg, ${alpha(primaryMain, 0.08)} 0%, ${alpha(primaryMain, 0.04)} 100%)`,
border: `1px solid ${alpha(primaryMain, 0.15)}`,
boxShadow: 'inset 0 1px 2px rgba(255,255,255,0.5)'
}}
>
<i className={`${icon} text-xl text-sky-600`} />
<i className={`${icon} text-xl`} style={{ color: primaryMain }} />
<Box>
<Typography variant='caption' color='text.secondary' display='block' lineHeight={1.2}>
{label}
@@ -368,6 +373,10 @@ function CropCard({
selected: boolean
onClick: () => void
}) {
const theme = useTheme()
const primaryMain = theme.palette.primary.main
const primaryDark = theme.palette.primary.dark
const paperBg = theme.palette.background.paper
return (
<Card
component='button'
@@ -376,18 +385,18 @@ function CropCard({
onClick={onClick}
className='flex items-center gap-3 px-4 py-3 rounded-2xl cursor-pointer transition-all duration-300 border-2 text-start'
sx={{
borderColor: selected ? '#0ea5e9' : 'transparent',
borderColor: selected ? primaryMain : 'transparent',
background: selected
? 'linear-gradient(145deg, rgba(14, 165, 233, 0.12) 0%, rgba(14, 165, 233, 0.06) 100%)'
: 'linear-gradient(145deg, #ffffff 0%, #f8fcff 100%)',
? `linear-gradient(145deg, ${alpha(primaryMain, 0.12)} 0%, ${alpha(primaryMain, 0.06)} 100%)`
: `linear-gradient(145deg, ${paperBg} 0%, ${alpha(primaryMain, 0.04)} 100%)`,
boxShadow: selected
? '0 4px 20px rgba(14, 165, 233, 0.2), inset 0 1px 0 rgba(255,255,255,0.8)'
? `0 4px 20px ${alpha(primaryMain, 0.2)}, inset 0 1px 0 rgba(255,255,255,0.8)`
: '0 2px 8px rgba(0,0,0,0.04), inset 0 1px 0 rgba(255,255,255,0.9)',
'&:hover': {
transform: 'translateY(-2px)',
boxShadow: selected
? '0 6px 24px rgba(14, 165, 233, 0.25)'
: '0 4px 16px rgba(14, 165, 233, 0.12)'
? `0 6px 24px ${alpha(primaryMain, 0.25)}`
: `0 4px 16px ${alpha(primaryMain, 0.12)}`
}
}}
>
@@ -395,17 +404,17 @@ function CropCard({
className='w-11 h-11 rounded-xl flex items-center justify-center shrink-0'
sx={{
background: selected
? 'linear-gradient(135deg, #0ea5e9 0%, #0284c7 100%)'
: 'linear-gradient(145deg, rgba(14, 165, 233, 0.1) 0%, rgba(14, 165, 233, 0.05) 100%)'
? `linear-gradient(135deg, ${primaryMain} 0%, ${primaryDark} 100%)`
: `linear-gradient(145deg, ${alpha(primaryMain, 0.1)} 0%, ${alpha(primaryMain, 0.05)} 100%)`
}}
>
<i className={`${crop.icon} text-xl ${selected ? 'text-white' : 'text-sky-600'}`} />
<i className={`${crop.icon} text-xl ${selected ? 'text-white' : ''}`} style={!selected ? { color: primaryMain } : undefined} />
</Box>
<Typography variant='body2' fontWeight={600} color={selected ? 'primary.main' : 'text.primary'}>
{label}
</Typography>
{selected && (
<i className='tabler-circle-check-filled text-xl text-sky-600 ms-auto' />
<i className='tabler-circle-check-filled text-xl ms-auto' style={{ color: primaryMain }} />
)}
</Card>
)
@@ -420,9 +429,11 @@ function ResultRow({
label: string
value: string
}) {
const theme = useTheme()
const primaryMain = theme.palette.primary.main
return (
<Box className='flex items-center gap-4 p-3 rounded-2xl' sx={{ bgcolor: 'rgba(14, 165, 233, 0.06)' }}>
<i className={`${icon} text-2xl text-sky-600 shrink-0`} />
<Box className='flex items-center gap-4 p-3 rounded-2xl' sx={{ bgcolor: alpha(primaryMain, 0.06) }}>
<i className={`${icon} text-2xl shrink-0`} style={{ color: primaryMain }} />
<Box className='flex-1 min-w-0'>
<Typography variant='caption' color='text.secondary'>
{label}