import { useState, useEffect, useMemo } from 'react';
import {
Grid, Card, Box, Stack, Typography, Button, Divider, LinearProgress, CircularProgress, Alert,
Table, TableBody, TableCell, TableHead, TableRow, TableContainer, useMediaQuery
} from '@mui/material';
import { useTheme } from '@mui/material/styles';
import RefreshIcon from '@mui/icons-material/Refresh';
import ApartmentOutlinedIcon from '@mui/icons-material/ApartmentOutlined';
import FiberNewOutlinedIcon from '@mui/icons-material/FiberNewOutlined';
import Inventory2OutlinedIcon from '@mui/icons-material/Inventory2Outlined';
import HandshakeOutlinedIcon from '@mui/icons-material/HandshakeOutlined';
import HistoryOutlinedIcon from '@mui/icons-material/HistoryOutlined';
import DonutLargeOutlinedIcon from '@mui/icons-material/DonutLargeOutlined';
import CategoryOutlinedIcon from '@mui/icons-material/CategoryOutlined';
import GroupsOutlinedIcon from '@mui/icons-material/GroupsOutlined';
import PageHeader from '@/components/PageHeader';
import StatCard from '@/components/StatCard';
import StatusChip from '@/components/StatusChip';
import DonutChart from '@/components/charts/DonutChart';
import UserAvatar from '@/components/UserAvatar';
import EmptyState from '@/components/EmptyState';
import { fetchClients, fetchUsers } from '@/utils/apiClient';
import { toClient, toUser } from '@/utils/mappers';
import { titleCase } from '@/utils/format';
const STATUS_COLOR = { newclient: '#00A2AE', contacted: '#FFBF00', onboarded: '#00A854', lost: '#F04134' };
const statusColor = (s) => STATUS_COLOR[String(s || '').toLowerCase()] || '#8C8C8C';
const BAR_COLORS = ['#C01227', '#00A2AE', '#00A854', '#FFBF00', '#9E0E20', '#8C8C8C', '#D6515C'];
function Panel({ icon: Icon, title, action, color = 'primary', noPadding = false, children }) {
return (
`linear-gradient(90deg, ${theme.palette[color].lighter}66 0%, transparent 100%)`
}}
>
{title}
{action}
{children}
);
}
export default function Dashboard() {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
const [clients, setClients] = useState([]);
const [team, setTeam] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const load = () => {
setLoading(true);
setError(null);
Promise.all([fetchClients(), fetchUsers()])
.then(([cs, us]) => {
setClients((cs || []).map(toClient));
setTeam((us || []).map(toUser));
})
.catch((e) => setError(e.message || 'Failed to load dashboard data'))
.finally(() => setLoading(false));
};
useEffect(() => { load(); }, []);
const stats = useMemo(() => ({
total: clients.length,
newCount: clients.filter((c) => c.status === 'newClient').length,
parcels: clients.reduce((s, c) => s + c.parcelVolume, 0),
contracts: clients.reduce((s, c) => s + c.activeContracts, 0)
}), [clients]);
const statusData = useMemo(() => {
const m = {};
clients.forEach((c) => { m[c.status] = (m[c.status] || 0) + 1; });
return Object.entries(m).sort((a, b) => b[1] - a[1]).map(([status, value]) => ({ label: titleCase(status), value, color: statusColor(status) }));
}, [clients]);
const byType = useMemo(() => {
const m = {};
clients.forEach((c) => { const t = c.businessType || 'other'; m[t] = (m[t] || 0) + 1; });
return Object.entries(m).sort((a, b) => b[1] - a[1]);
}, [clients]);
const maxType = byType[0]?.[1] || 1;
const recent = useMemo(
() => [...clients].sort((a, b) => String(b.lastUpdated).localeCompare(String(a.lastUpdated))).slice(0, 6),
[clients]
);
const today = new Date().toLocaleDateString('en-IN', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' });
if (loading) {
return (
<>
>
);
}
return (
<>
} onClick={load}>Refresh}
/>
{error && Retry}>{error}}
{recent.length === 0 ? (
) : isMobile ? (
}>
{recent.map((c) => (
{c.name}
{[titleCase(c.businessType), c.city].filter(Boolean).join(' · ') || '—'} · {c.parcelVolume.toLocaleString('en-IN')} parcels
))}
) : (
Client
Type
Location
Parcels
Status
{recent.map((c) => (
{c.name}
{titleCase(c.businessType) || '—'}
{c.city || '—'}{c.businessState ? `, ${c.businessState}` : ''}
{c.parcelVolume.toLocaleString('en-IN')}
))}
)}
{statusData.length === 0
?
: }
{byType.length === 0 ? (
) : (
{byType.map(([type, count], i) => (
{titleCase(type)}
{count} · {Math.round((count / clients.length) * 100)}%
))}
)}
{team.length === 0 ? (
) : (
} spacing={0}>
{team.slice(0, 6).map((u) => (
{u.name}
{u.email}
))}
)}
>
);
}