176 lines
6.1 KiB
TypeScript
176 lines
6.1 KiB
TypeScript
"use client";
|
|
|
|
import React, {useEffect, useState} from "react";
|
|
import {useParams, useRouter} from "next/navigation";
|
|
import {ChevronLeft} from "lucide-react";
|
|
import {Button} from "@/components/ui/button";
|
|
import {Dialog} from "@/components/ui/dialog";
|
|
import {Skeleton} from "@/components/ui/skeleton";
|
|
import CustomerDetailContent from "@/components/customers/details/CustomerDetailContent";
|
|
import CustomerInformationContent from "@/components/customers/details/sub/ContactInformationContent";
|
|
import CustomerPhoneNumberContent from "@/components/customers/details/sub/CustomerPhoneNumberContent";
|
|
import CustomerNotesContent from "@/components/customers/details/sub/CustomerNotesContent";
|
|
import CustomerProjectsContent from "@/components/customers/details/sub/CustomerProjectsContent";
|
|
import {Customer} from "@/services/customers/entities/customer";
|
|
|
|
export default function CustomerDetailPage() {
|
|
const router = useRouter();
|
|
const {id} = useParams<{ id: string }>();
|
|
const [customer, setCustomer] = useState<Customer | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [openDialog, setOpenDialog] = useState(false);
|
|
const [dialogContent, setDialogContent] = useState<React.ReactNode | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (!id) {
|
|
setError("Keine Kunden-ID angegeben");
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
|
|
let isMounted = true;
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
fetch(`/api/customers/${id}`)
|
|
.then(async (response) => {
|
|
if (!isMounted) return;
|
|
|
|
if (response.status === 404) {
|
|
setError("Kunde nicht gefunden");
|
|
setCustomer(null);
|
|
return;
|
|
}
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch customer: ${response.statusText}`);
|
|
}
|
|
|
|
const result = await response.json();
|
|
setCustomer(result);
|
|
})
|
|
.catch((error) => {
|
|
if (!isMounted) return;
|
|
console.error("Error fetching customer:", error);
|
|
setCustomer(null);
|
|
setError("Fehler beim Laden der Kundendaten");
|
|
})
|
|
.finally(() => {
|
|
if (isMounted) {
|
|
setLoading(false);
|
|
}
|
|
});
|
|
|
|
return () => {
|
|
isMounted = false;
|
|
};
|
|
}, [id]);
|
|
|
|
const handleOpenDialog = (content: React.ReactNode) => {
|
|
setDialogContent(content);
|
|
setOpenDialog(true);
|
|
};
|
|
|
|
const formatDate = (date: string) => {
|
|
try {
|
|
const formattedDate = new Date(date).toLocaleDateString("de-DE", {
|
|
day: "2-digit",
|
|
month: "2-digit",
|
|
year: "numeric",
|
|
hour: "2-digit",
|
|
minute: "2-digit",
|
|
});
|
|
return formattedDate === "Invalid Date" ? "-" : formattedDate;
|
|
} catch (error) {
|
|
console.error("Error formatting date:", error);
|
|
return "-";
|
|
}
|
|
};
|
|
|
|
const customerMetadata = {
|
|
createdInfo: customer
|
|
? `Erstellt von ${customer.createdBy || "-"} am ${formatDate(customer.createdAt)}`
|
|
: "Erstellt von - am -",
|
|
lastActivityInfo: customer
|
|
? `Letzte Aktivität: ${customer.updatedBy || "-"} am ${formatDate(customer.updatedAt)}`
|
|
: "Letzte Aktivität: - am -",
|
|
};
|
|
|
|
const renderMetadata = () => {
|
|
if (loading) {
|
|
return (
|
|
<div className="flex flex-col items-end gap-1">
|
|
<div className="space-y-1">
|
|
<Skeleton className="h-4 w-[250px]"/>
|
|
<Skeleton className="h-4 w-[280px]"/>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="flex flex-col items-end gap-1 text-xs text-muted-foreground">
|
|
<div>{customerMetadata.createdInfo}</div>
|
|
<div>{customerMetadata.lastActivityInfo}</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<div className="h-full w-full p-6 space-y-4 text-sm">
|
|
<div className="flex justify-between items-start">
|
|
<Button
|
|
variant="ghost"
|
|
onClick={() => router.push("/customers")}
|
|
disabled={loading}
|
|
aria-label="Zurück zur Kundenliste"
|
|
>
|
|
<ChevronLeft className="w-4 h-4 mr-1"/>
|
|
Zurück
|
|
</Button>
|
|
|
|
{renderMetadata()}
|
|
</div>
|
|
|
|
{error ? (
|
|
<div className="text-center text-red-500 p-4" role="alert">
|
|
{error}
|
|
</div>
|
|
) : (
|
|
<CustomerDetailContent
|
|
loading={loading}
|
|
customer={customer}
|
|
informationSection={
|
|
<CustomerInformationContent
|
|
customer={customer!}
|
|
handleOpenDialog={handleOpenDialog}
|
|
/>
|
|
}
|
|
phoneNumberSection={
|
|
<CustomerPhoneNumberContent
|
|
customer={customer!}
|
|
handleOpenDialog={handleOpenDialog}
|
|
/>
|
|
}
|
|
notesSection={
|
|
<CustomerNotesContent
|
|
customer={customer!}
|
|
handleOpenDialog={handleOpenDialog}
|
|
/>
|
|
}
|
|
projectsSection={
|
|
<CustomerProjectsContent
|
|
customer={customer!}
|
|
handleOpenDialog={handleOpenDialog}
|
|
/>
|
|
}
|
|
/>
|
|
)}
|
|
|
|
<Dialog open={openDialog} onOpenChange={setOpenDialog}>
|
|
{dialogContent}
|
|
</Dialog>
|
|
</div>
|
|
);
|
|
} |