import { Link, useLoaderData } from "react-router"; import { requireUser } from "@/session.server"; import prisma from "@/lib/prisma"; import { formatCurrency } from "@/lib/tax"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Building2, FileText, Euro, TrendingUp } from "lucide-react"; import { InvoiceStatus } from "@prisma/client"; export const handle = { breadcrumbs: () => [{ label: "Dashboard" }], }; export async function loader({ request }: { request: Request }) { const user = await requireUser(request); const userId = user.id; const [companies, invoiceStats, paidTotal, openInvoices] = await Promise.all([ prisma.company.findMany({ where: { userId, archived: false }, include: { _count: { select: { invoices: true, customers: true } } }, orderBy: { name: "asc" }, }), prisma.invoice.aggregate({ where: { company: { userId, archived: false } }, _count: true, _sum: { grossTotal: true }, }), prisma.invoice.aggregate({ where: { company: { userId, archived: false }, status: InvoiceStatus.PAID }, _sum: { grossTotal: true }, }), prisma.invoice.count({ where: { company: { userId, archived: false }, status: { in: [InvoiceStatus.SENT, InvoiceStatus.DRAFT] } }, }), ]); return { companies, totalInvoices: invoiceStats._count, paidTotal: Number(paidTotal._sum.grossTotal ?? 0), openInvoices, }; } const statCards = [ { key: "companies", label: "Mandanten", icon: Building2, gradient: "from-indigo-500 to-violet-600", bg: "bg-indigo-50", iconColor: "text-indigo-600", shadowColor: "shadow-indigo-500/15", }, { key: "totalInvoices", label: "Rechnungen gesamt", icon: FileText, gradient: "from-blue-500 to-cyan-500", bg: "bg-blue-50", iconColor: "text-blue-600", shadowColor: "shadow-blue-500/15", }, { key: "openInvoices", label: "Offen / Entwurf", icon: TrendingUp, gradient: "from-amber-500 to-orange-500", bg: "bg-amber-50", iconColor: "text-amber-600", shadowColor: "shadow-amber-500/15", }, { key: "paidTotal", label: "Bezahlt (brutto)", icon: Euro, gradient: "from-emerald-500 to-teal-500", bg: "bg-emerald-50", iconColor: "text-emerald-600", shadowColor: "shadow-emerald-500/15", }, ]; export default function DashboardPage() { const { companies, totalInvoices, paidTotal, openInvoices } = useLoaderData(); const statValues: Record = { companies: companies.length, totalInvoices, openInvoices, paidTotal: formatCurrency(paidTotal), }; return (

Dashboard

Übersicht aller Mandanten und Rechnungen

{/* Stats */}
{statCards.map((card) => { const Icon = card.icon; return (
Gesamt

{statValues[card.key]}

{card.label}

); })}
{/* Companies */}

Mandanten

{companies.length} Mandanten verwaltet

Alle anzeigen
{companies.length === 0 ? (

Noch keine Mandanten angelegt

Legen Sie Ihren ersten Mandanten an, um loszulegen.

Mandant anlegen
) : (
{companies.map((company) => (

{company.name}

{company.legalForm && (

{company.legalForm}

)}
{company._count.invoices} Rechnungen {company._count.customers} Kunden
{company.city && (

{company.zip} {company.city}

)}
))}
)}
); }