import { Link, useLoaderData } from "react-router"; import { useState } from "react"; import { requireUser } from "@/session.server"; import prisma from "@/lib/prisma"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { formatCurrency, formatDate } from "@/lib/tax"; import { Building2, Plus, FileText, Users, X, Edit, Receipt, Mail, Phone, CreditCard, ChevronRight, ChevronDown, Archive, } from "lucide-react"; import { InvoiceStatus } from "@prisma/client"; export const handle = { breadcrumbs: () => [{ label: "Mandanten" }], }; const statusLabels: Record = { DRAFT: "Entwurf", SENT: "Versendet", PAID: "Bezahlt", CANCELLED: "Storniert", DELETED: "Gelöscht", }; const statusVariants: Record< InvoiceStatus, "secondary" | "default" | "success" | "destructive" | "warning" | "outline" > = { DRAFT: "secondary", SENT: "warning", PAID: "success", CANCELLED: "destructive", DELETED: "outline", }; export async function loader({ request }: { request: Request }) { const user = await requireUser(request); const companies = await prisma.company.findMany({ where: { userId: user.id }, include: { _count: { select: { invoices: true, customers: true } }, invoices: { include: { customer: { select: { name: true } } }, orderBy: { issueDate: "desc" }, }, }, orderBy: { name: "asc" }, }); return { companies: companies.map((c) => ({ ...c, invoices: c.invoices.map((inv) => ({ ...inv, grossTotal: Number(inv.grossTotal), issueDate: inv.issueDate.toISOString(), dueDate: inv.dueDate.toISOString(), })), })), }; } type Company = ReturnType>["companies"][number]; function CompanyCard({ company, isActive, onSelect, }: { company: Company; isActive: boolean; onSelect: () => void; }) { const archived = company.archived; return ( ); } export default function CompaniesPage() { const { companies } = useLoaderData(); const [selectedId, setSelectedId] = useState(null); const [archivedOpen, setArchivedOpen] = useState(false); const selected = companies.find((c) => c.id === selectedId) ?? null; const active = companies.filter((c) => !c.archived); const archived = companies.filter((c) => c.archived); return (
{/* Kacheln */}

Mandanten

{active.length} aktive Mandanten {archived.length > 0 && · {archived.length} archiviert}

{active.length === 0 && archived.length === 0 ? (

Noch keine Mandanten

Legen Sie Ihren ersten Mandanten an, um loszulegen.

) : (
{/* Aktive Mandanten */} {active.length > 0 && (
{active.map((company) => ( setSelectedId(selectedId === company.id ? null : company.id)} /> ))}
)} {/* Archivierte Mandanten */} {archived.length > 0 && (
{archivedOpen && (
{archived.map((company) => ( setSelectedId(selectedId === company.id ? null : company.id)} /> ))}
)}
)}
)}
{/* Detail-Panel */} {selected && (
{/* Header */}

{selected.name}

{selected.legalForm && (

{selected.legalForm}

)}
{/* Aktionen */}
{/* Firmendaten */}
{selected.city && (

Adresse

{selected.zip} {selected.city}

)} {selected.email && (

E-Mail

{selected.email}

)} {selected.phone && (

Telefon

{selected.phone}

)} {selected.taxId && (

Steuernummer

{selected.taxId}

)} {selected.vatId && (

USt-IdNr.

{selected.vatId}

)} {selected.bankIban && (

IBAN

{selected.bankIban}

)}
{/* Rechnungen */}

Rechnungen

Alle
{selected.invoices.length === 0 ? (

Noch keine Rechnungen

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

{invoice.number}

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

{statusLabels[invoice.status]} {formatCurrency(invoice.grossTotal)}
))}
)}
)}
); }