import { Link, useLoaderData, useRevalidator } from "react-router"; import { requireUser } from "@/session.server"; import prisma from "@/lib/prisma"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { formatCurrency, formatDate } from "@/lib/tax"; import { FileText, Users, BarChart3, Plus, Edit, Building2, Mail, Phone, CreditCard, Receipt, Archive, ArchiveRestore, AlertTriangle } from "lucide-react"; import { InvoiceStatus } from "@prisma/client"; import { useState } from "react"; export const handle = { breadcrumbs: (data: { company: { id: string; name: string } }) => [ { label: "Mandanten", href: "/companies" }, { label: data.company.name }, ], }; const statusLabels: Record = { DRAFT: "Entwurf", SENT: "Versendet", PAID: "Bezahlt", CANCELLED: "Storniert", DELETED: "Gelöscht", }; const statusVariants: Record = { DRAFT: "secondary", SENT: "warning", PAID: "success", CANCELLED: "destructive", DELETED: "outline", }; export async function loader({ request, params }: { request: Request; params: { id: string } }) { const user = await requireUser(request); const { id } = params; const company = await prisma.company.findFirst({ where: { id, userId: user.id }, include: { invoices: { include: { customer: { select: { name: true } } }, orderBy: { issueDate: "desc" }, take: 5, }, _count: { select: { invoices: true, customers: true } }, }, }); if (!company) throw new Response("Not Found", { status: 404 }); const revenue = await prisma.invoice.aggregate({ where: { companyId: id, status: InvoiceStatus.PAID }, _sum: { grossTotal: true }, }); return { isAdmin: user.role === "ADMIN", company: { ...company, archivedAt: company.archivedAt?.toISOString() ?? null, invoices: company.invoices.map((inv) => ({ ...inv, grossTotal: Number(inv.grossTotal), issueDate: inv.issueDate.toISOString(), dueDate: inv.dueDate.toISOString(), })), }, revenue: Number(revenue._sum.grossTotal ?? 0), }; } export default function CompanyPage() { const { company, revenue, isAdmin } = useLoaderData(); const { revalidate } = useRevalidator(); const [archiving, setArchiving] = useState(false); const id = company.id; async function toggleArchive() { const action = company.archived ? "Archivierung aufheben?" : "Mandanten archivieren?"; if (!confirm(action)) return; setArchiving(true); await fetch(`/api/companies/${id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ archived: !company.archived }), }); setArchiving(false); revalidate(); } return (
{/* Archiv-Banner */} {company.archived && (
Dieser Mandant ist archiviert {company.archivedAt && ` seit ${new Date(company.archivedAt).toLocaleDateString("de-DE")}`}. {isAdmin && ( )}
)}

{company.name}

{company.legalForm && `${company.legalForm} · `} {company.zip} {company.city}

{isAdmin && !company.archived && ( )} {isAdmin && company.archived && ( )}
Rechnung erstellen
Rechnungen
Kunden
Berichte

Letzte Rechnungen

Alle anzeigen →
{company.invoices.length === 0 ? (

Noch keine Rechnungen

) : (
{company.invoices.map((invoice) => (

{invoice.number}

{invoice.customer.name} · {formatDate(invoice.issueDate)}

{statusLabels[invoice.status]} {formatCurrency(invoice.grossTotal)}
))}
)}
Steuer & Umsatz

Bezahlt (gesamt)

{formatCurrency(revenue)}

Rechnungen

{company._count.invoices}

{company.taxId && (

Steuernummer

{company.taxId}

)} {company.vatId && (

USt-IdNr.

{company.vatId}

)}
{(company.email || company.phone) && ( Kontakt {company.email && (
{company.email}
)} {company.phone && (
{company.phone}
)}
)} {company.bankIban && ( Bankverbindung
{company.bankIban}
{company.bankName &&

{company.bankName}

}
)}
); }