import { useState } from "react"; import { Link, useLoaderData, useParams, useRevalidator } from "react-router"; import { requireUser } from "@/session.server"; import prisma from "@/lib/prisma"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; import { Users, Plus, Edit, Trash2, ChevronLeft, Mail, Phone } from "lucide-react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; const schema = z.object({ name: z.string().min(1, "Pflichtfeld"), vatId: z.string().optional(), address: z.string().min(1, "Pflichtfeld"), zip: z.string().min(1, "Pflichtfeld"), city: z.string().min(1, "Pflichtfeld"), country: z.string().optional(), email: z.string().email("Ungültige E-Mail").optional().or(z.literal("")), phone: z.string().optional(), }); type FormData = z.infer; interface Customer { id: string; name: string; vatId?: string | null; address: string; zip: string; city: string; email?: string | null; phone?: string | null; } export async function loader({ request, params }: { request: Request; params: { id: string } }) { const user = await requireUser(request); const company = await prisma.company.findFirst({ where: { id: params.id, userId: user.id }, }); if (!company) throw new Response("Not Found", { status: 404 }); const customers = await prisma.customer.findMany({ where: { companyId: params.id }, orderBy: { name: "asc" }, }); return { customers, companyId: params.id }; } function CustomerForm({ defaultValues, onSubmit, submitLabel, }: { defaultValues?: Partial; onSubmit: (d: FormData) => Promise; submitLabel: string; }) { const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm({ resolver: zodResolver(schema), defaultValues: { country: "DE", ...defaultValues }, }); return (
{errors.name &&

{errors.name.message}

}
{errors.address &&

{errors.address.message}

}
); } export default function CustomersPage() { const { customers, companyId } = useLoaderData(); const { revalidate } = useRevalidator(); const [open, setOpen] = useState(false); const [editCustomer, setEditCustomer] = useState(null); async function handleCreate(data: FormData) { await fetch("/api/customers", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ ...data, companyId }), }); setOpen(false); revalidate(); } async function handleEdit(data: FormData) { if (!editCustomer) return; await fetch(`/api/customers/${editCustomer.id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), }); setEditCustomer(null); revalidate(); } async function handleDelete(customerId: string) { if (!confirm("Kunden wirklich löschen?")) return; await fetch(`/api/customers/${customerId}`, { method: "DELETE" }); revalidate(); } return (
Zurück zum Mandanten

Kunden

{customers.length} Kunden

Neuer Kunde
!o && setEditCustomer(null)}> Kunde bearbeiten {editCustomer && ( )} {customers.length === 0 ? (

Noch keine Kunden angelegt

) : (
{customers.map((customer) => (

{customer.name}

{customer.address}, {customer.zip} {customer.city}

{customer.vatId &&

USt-IdNr.: {customer.vatId}

}
{customer.email && ( {customer.email} )} {customer.phone && ( {customer.phone} )}
))}
)}
); }