import { useState, useEffect, useCallback, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from 'recharts'; import { databases, DATABASE_ID } from '@/lib/appwrite'; import { Query } from 'appwrite'; import Header from './Header'; import { useToast } from '@/hooks/useToast'; import { useAuth } from '@/context/AuthContext'; import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'; import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from '@/components/ui/table'; import { Progress } from '@/components/ui/progress'; import { Badge } from '@/components/ui/badge'; import { ChartContainer, ChartTooltip, ChartTooltipContent, ChartLegend, ChartLegendContent, } from '@/components/ui/chart'; function getToday() { const d = new Date(); return new Date(d.getFullYear(), d.getMonth(), d.getDate()); } function getMonthStart() { const d = new Date(); return new Date(d.getFullYear(), d.getMonth(), 1); } function getLastMonthStart() { const d = new Date(); return new Date(d.getFullYear(), d.getMonth() - 1, 1); } function getLastMonthEnd() { const d = new Date(); return new Date(d.getFullYear(), d.getMonth(), 0, 23, 59, 59); } function getYesterday() { const d = getToday(); d.setDate(d.getDate() - 1); return d; } function countInRange(assets, start, end) { return assets.filter((a) => { const d = new Date(a.$createdAt); return d >= start && d <= end; }).length; } function countErledigtInRange(assets, start, end) { return assets.filter((a) => { if (a.status !== 'entsorgt') return false; const d = new Date(a.$updatedAt || a.$createdAt); return d >= start && d <= end; }).length; } function countUeberfaelligAt(assets, endOfPeriod) { const cutoff = new Date(endOfPeriod); cutoff.setDate(cutoff.getDate() - 7); return assets.filter((a) => { const created = new Date(a.$createdAt); if (created > cutoff) return false; if (a.status === 'entsorgt') { const disposed = new Date(a.$updatedAt || a.$createdAt); return disposed > endOfPeriod; } return true; }).length; } export default function FilialleiterDashboard() { const navigate = useNavigate(); const { userMeta } = useAuth(); const { showToast } = useToast(); const locationId = userMeta?.locationId || ''; const [ownAssets, setOwnAssets] = useState([]); const [allAssetsTotal, setAllAssetsTotal] = useState(0); const [allLocationsCount, setAllLocationsCount] = useState(1); const [colleagues, setColleagues] = useState([]); const loadData = useCallback(async () => { if (!locationId) return; try { const [assetsRes, lagerRes, metaRes, locsRes] = await Promise.all([ databases.listDocuments(DATABASE_ID, 'assets', [Query.limit(500)]), databases.listDocuments(DATABASE_ID, 'lagerstandorte', [ Query.equal('locationId', [locationId]), Query.limit(200), ]), databases.listDocuments(DATABASE_ID, 'users_meta', [ Query.equal('locationId', [locationId]), Query.limit(100), ]), databases.listDocuments(DATABASE_ID, 'locations', [Query.limit(100)]), ]); const lagerIds = new Set(lagerRes.documents.map((l) => l.$id)); const assetsForLocation = assetsRes.documents.filter((a) => a.lagerstandortId && lagerIds.has(a.lagerstandortId)); setOwnAssets(assetsForLocation); setAllAssetsTotal(assetsRes.total); setAllLocationsCount(Math.max(locsRes.total, 1)); setColleagues(metaRes.documents.filter((d) => d.userName)); } catch (err) { console.error('Filialleiter-Daten laden fehlgeschlagen:', err); } }, [locationId]); useEffect(() => { loadData(); }, [loadData]); const now = new Date(); const today = getToday(); const yesterday = getYesterday(); const monthStart = getMonthStart(); const lastMonthStart = getLastMonthStart(); const lastMonthEnd = getLastMonthEnd(); const todayCount = countInRange(ownAssets, today, now); const yesterdayCount = countInRange(ownAssets, yesterday, today); const thisMonthCount = countInRange(ownAssets, monthStart, now); const lastMonthCount = countInRange(ownAssets, lastMonthStart, lastMonthEnd); const chartData = useMemo(() => { const days = []; const dayNames = ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa']; for (let i = 6; i >= 0; i--) { const d = new Date(); d.setDate(d.getDate() - i); const dayStart = new Date(d.getFullYear(), d.getMonth(), d.getDate()); const dayEnd = new Date(d.getFullYear(), d.getMonth(), d.getDate(), 23, 59, 59); days.push({ day: `${dayNames[d.getDay()]} ${d.getDate()}.`, erfasst: countInRange(ownAssets, dayStart, dayEnd), erledigt: countErledigtInRange(ownAssets, dayStart, dayEnd), ueberfaellig: countUeberfaelligAt(ownAssets, dayEnd), }); } return days; }, [ownAssets]); const monthChartData = useMemo(() => { const months = []; const monthNames = ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']; for (let i = 5; i >= 0; i--) { const d = new Date(); d.setMonth(d.getMonth() - i); const monthStart = new Date(d.getFullYear(), d.getMonth(), 1); const monthEnd = new Date(d.getFullYear(), d.getMonth() + 1, 0, 23, 59, 59); months.push({ month: `${monthNames[d.getMonth()]} ${d.getFullYear().toString().slice(2)}`, erfasst: countInRange(ownAssets, monthStart, monthEnd), erledigt: countErledigtInRange(ownAssets, monthStart, monthEnd), ueberfaellig: countUeberfaelligAt(ownAssets, monthEnd), }); } return months; }, [ownAssets]); const chartConfig = { erfasst: { label: 'Erfasst', color: '#60a5fa', }, erledigt: { label: 'Erledigt', color: '#22c55e', }, ueberfaellig: { label: 'Überfällig', color: '#ef4444', }, }; const avgAllFilialen = allLocationsCount > 0 ? Math.round(allAssetsTotal / allLocationsCount) : 0; const ownTotal = ownAssets.length; const employeeStats = useMemo(() => { return colleagues.map((c) => { const assigned = ownAssets.filter((a) => a.zustaendig === c.userName); const resolved = assigned.filter((a) => a.status === 'entsorgt').length; const open = assigned.filter((a) => a.status === 'offen').length; const inProgress = assigned.filter((a) => a.status === 'in_bearbeitung').length; return { userId: c.userId, name: c.userName, total: assigned.length, resolved, open, inProgress, rate: assigned.length > 0 ? Math.round((resolved / assigned.length) * 100) : 0, }; }).sort((a, b) => b.rate - a.rate); }, [colleagues, ownAssets]); function trendArrow(current, previous) { if (current > previous) return { arrow: '▲', cls: 'text-green-600' }; if (current < previous) return { arrow: '▼', cls: 'text-red-600' }; return { arrow: '–', cls: 'text-muted-foreground' }; } const dayTrend = trendArrow(todayCount, yesterdayCount); const monthTrend = trendArrow(thisMonthCount, lastMonthCount); const comparisonMax = Math.max(ownTotal, avgAllFilialen, 1); return ( <>

Filialleiter Dashboard

Tägliche und monatliche Übersicht deiner Filiale

{todayCount}

Heute erfasst

{dayTrend.arrow} Gestern: {yesterdayCount}

Math.floor(v)} /> } cursor={false} /> } />
{thisMonthCount}

Diesen Monat

{monthTrend.arrow} Letzter Monat: {lastMonthCount}

Math.floor(v)} /> } cursor={false} /> } />
{ownTotal}

Meine Filiale

{avgAllFilialen}

⌀ Alle Filialen

Filialvergleich
Meine Filiale {ownTotal}
⌀ Durchschnitt {avgAllFilialen}
Mitarbeiter-Performance {employeeStats.length === 0 ? (

Keine Mitarbeiter gefunden

) : ( Mitarbeiter Zugewiesen Offen In Bearbeitung Erledigt Erledigungsrate {employeeStats.map((e) => ( e.userId && navigate(`/filialleiter/mitarbeiter/${e.userId}`)} > {e.name} {e.total} {e.open} {e.inProgress} {e.resolved}
{e.rate}%
))}
)}
); }