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 (
<>
Tägliche und monatliche Übersicht deiner Filiale
Heute erfasst
{dayTrend.arrow} Gestern: {yesterdayCount}
Diesen Monat
{monthTrend.arrow} Letzter Monat: {lastMonthCount}
Meine Filiale
⌀ Alle Filialen
Keine Mitarbeiter gefunden
) : (