mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
246 lines
7.5 KiB
TypeScript
246 lines
7.5 KiB
TypeScript
import { Link, useNavigate, useParams } from "react-router-dom";
|
|
import {
|
|
ArrowLeft,
|
|
Building2,
|
|
FileText,
|
|
Globe,
|
|
Mail,
|
|
MapPin,
|
|
Phone,
|
|
StickyNote,
|
|
Trash2,
|
|
User,
|
|
} from "lucide-react";
|
|
|
|
import Breadcrumbs from "@/components/Breadcrumbs";
|
|
import NewCustomerPage from "./NewCustomerPage";
|
|
import DeleteCustomerDialog from "./DeleteCustomerDialog";
|
|
import { getCustomerById, type CustomerStatus } from "./customers.mock";
|
|
|
|
export default function CustomerDetailPage() {
|
|
const { id } = useParams<{ id: string }>();
|
|
const navigate = useNavigate();
|
|
const customer = id ? getCustomerById(id) : undefined;
|
|
|
|
if (!customer) {
|
|
return (
|
|
<div className="min-h-screen bg-slate-50 p-6">
|
|
<div className="mx-auto max-w-5xl space-y-6">
|
|
<Breadcrumbs
|
|
items={[
|
|
{ label: "Customers", href: "/customers" },
|
|
{ label: "Not found" },
|
|
]}
|
|
/>
|
|
|
|
<div className="rounded-3xl bg-white p-8 text-center shadow-sm">
|
|
<h1 className="text-2xl font-bold text-slate-900">
|
|
Customer not found
|
|
</h1>
|
|
<p className="mt-2 text-sm text-slate-500">
|
|
The customer you're looking for doesn't exist or has been removed.
|
|
</p>
|
|
<Link
|
|
to="/customers"
|
|
className="mt-6 inline-flex items-center gap-2 rounded-2xl bg-[#10B981] px-4 py-2 text-sm font-medium text-white transition hover:bg-[#10B981]/90"
|
|
>
|
|
<ArrowLeft className="h-4 w-4" />
|
|
Back to Customers
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen bg-slate-50 p-6">
|
|
<div className="mx-auto max-w-5xl space-y-6">
|
|
<Breadcrumbs
|
|
items={[
|
|
{ label: "Customers", href: "/customers" },
|
|
{ label: customer.name },
|
|
]}
|
|
/>
|
|
|
|
{/* Header */}
|
|
<div className="rounded-3xl bg-white p-6 shadow-sm">
|
|
<div className="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
|
|
<div className="flex items-center gap-4">
|
|
<div className="flex h-16 w-16 items-center justify-center rounded-2xl bg-[#10B981] text-white">
|
|
<User className="h-8 w-8" />
|
|
</div>
|
|
|
|
<div>
|
|
<h1 className="text-3xl font-bold tracking-tight text-slate-900">
|
|
{customer.name}
|
|
</h1>
|
|
<div className="mt-1 flex items-center gap-3 text-sm text-slate-500">
|
|
<span>ID #{customer.id}</span>
|
|
<span className="text-slate-300">•</span>
|
|
<span>{customer.company}</span>
|
|
<span className="text-slate-300">•</span>
|
|
<StatusBadge status={customer.status} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-3">
|
|
<NewCustomerPage
|
|
mode="edit"
|
|
customer={{
|
|
companyName: customer.company,
|
|
customerType: customer.customerType,
|
|
contactPerson: customer.name,
|
|
email: customer.email,
|
|
phone: customer.phone,
|
|
tinNumber: customer.tinNumber,
|
|
city: customer.city,
|
|
country: customer.country,
|
|
address: customer.address,
|
|
notes: customer.notes,
|
|
}}
|
|
>
|
|
<button
|
|
type="button"
|
|
className="inline-flex items-center gap-2 rounded-2xl bg-[#10B981] px-4 py-2 text-sm font-medium text-white transition hover:bg-[#10B981]/90"
|
|
>
|
|
Edit Customer
|
|
</button>
|
|
</NewCustomerPage>
|
|
|
|
<DeleteCustomerDialog
|
|
customerName={customer.name}
|
|
onConfirm={() => navigate("/customers")}
|
|
>
|
|
<button
|
|
type="button"
|
|
className="inline-flex items-center gap-2 rounded-2xl border border-red-200 px-4 py-2 text-sm font-medium text-red-600 transition hover:bg-red-50"
|
|
>
|
|
<Trash2 className="h-4 w-4" />
|
|
Delete
|
|
</button>
|
|
</DeleteCustomerDialog>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Detail grid */}
|
|
<div className="grid gap-6 md:grid-cols-2">
|
|
<DetailCard title="Company Information">
|
|
<DetailRow
|
|
icon={<Building2 className="h-4 w-4" />}
|
|
label="Company Name"
|
|
value={customer.company}
|
|
/>
|
|
<DetailRow
|
|
icon={<FileText className="h-4 w-4" />}
|
|
label="Customer Type"
|
|
value={customer.customerType}
|
|
/>
|
|
<DetailRow
|
|
icon={<FileText className="h-4 w-4" />}
|
|
label="TIN Number"
|
|
value={customer.tinNumber}
|
|
/>
|
|
</DetailCard>
|
|
|
|
<DetailCard title="Contact">
|
|
<DetailRow
|
|
icon={<User className="h-4 w-4" />}
|
|
label="Contact Person"
|
|
value={customer.name}
|
|
/>
|
|
<DetailRow
|
|
icon={<Mail className="h-4 w-4" />}
|
|
label="Email"
|
|
value={customer.email}
|
|
/>
|
|
<DetailRow
|
|
icon={<Phone className="h-4 w-4" />}
|
|
label="Phone"
|
|
value={customer.phone}
|
|
/>
|
|
</DetailCard>
|
|
|
|
<DetailCard title="Location">
|
|
<DetailRow
|
|
icon={<MapPin className="h-4 w-4" />}
|
|
label="City"
|
|
value={customer.city}
|
|
/>
|
|
<DetailRow
|
|
icon={<Globe className="h-4 w-4" />}
|
|
label="Country"
|
|
value={customer.country}
|
|
/>
|
|
<DetailRow
|
|
icon={<MapPin className="h-4 w-4" />}
|
|
label="Address"
|
|
value={customer.address}
|
|
/>
|
|
</DetailCard>
|
|
|
|
<DetailCard title="Notes">
|
|
<div className="flex items-start gap-3 text-sm text-slate-700">
|
|
<StickyNote className="mt-0.5 h-4 w-4 text-[#10B981]" />
|
|
<p className="leading-relaxed">{customer.notes}</p>
|
|
</div>
|
|
</DetailCard>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function DetailCard({
|
|
title,
|
|
children,
|
|
}: {
|
|
title: string;
|
|
children: React.ReactNode;
|
|
}) {
|
|
return (
|
|
<div className="rounded-3xl bg-white p-6 shadow-sm">
|
|
<h2 className="text-lg font-semibold text-slate-900">{title}</h2>
|
|
<div className="mt-4 space-y-3">{children}</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function DetailRow({
|
|
icon,
|
|
label,
|
|
value,
|
|
}: {
|
|
icon: React.ReactNode;
|
|
label: string;
|
|
value: string;
|
|
}) {
|
|
return (
|
|
<div className="flex items-start gap-3">
|
|
<div className="mt-0.5 text-[#10B981]">{icon}</div>
|
|
<div className="flex-1">
|
|
<p className="text-xs font-medium text-slate-500">{label}</p>
|
|
<p className="mt-0.5 text-sm text-slate-900">{value}</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function StatusBadge({ status }: { status: CustomerStatus }) {
|
|
const styles: Record<CustomerStatus, string> = {
|
|
Active: "bg-emerald-100 text-emerald-700",
|
|
Pending: "bg-amber-100 text-amber-700",
|
|
Inactive: "bg-red-100 text-red-700",
|
|
};
|
|
|
|
return (
|
|
<span
|
|
className={`inline-flex rounded-full px-3 py-1 text-xs font-medium ${styles[status]}`}
|
|
>
|
|
{status}
|
|
</span>
|
|
);
|
|
}
|