mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
Merge pull request #4 from Tria-plc/feat/customer_registration
add customers page
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
"@tria-plc/iamui-common": "1.1.1",
|
||||
"axios": "^1.7.7",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^1.14.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-router-dom": "^6.27.0",
|
||||
|
||||
@@ -17,9 +17,11 @@ import BillingPage from "./pages/billing/BillingPage";
|
||||
import TrainsPage from "./pages/trains/TrainsPage";
|
||||
import DashboardPage from "./pages/dashboard/DashboardPage";
|
||||
import { IamLoginPage } from "@tria-plc/iamui-common";
|
||||
import CustomersPage from "./pages/customers/CustomersPage";
|
||||
|
||||
const sidebarItems: SidebarItem[] = [
|
||||
{ label: "Dashboard", href: "/" },
|
||||
{ label: "Customers", href: "/Customers" },
|
||||
{ label: "Bookings", href: "/bookings" },
|
||||
{ label: "Consignments", href: "/consignments" },
|
||||
{ label: "Tracking", href: "/tracking" },
|
||||
@@ -50,6 +52,7 @@ const App = () => {
|
||||
<Routes>
|
||||
<Route path="/" element={<DashboardPage />} />
|
||||
<Route path="/bookings" element={<BookingsPage />} />
|
||||
<Route path="/customers" element={<CustomersPage />} />
|
||||
<Route path="/bookings/new" element={<CreateBookingPage />} />
|
||||
<Route path="/bookings/:id" element={<BookingDetailPage />} />
|
||||
<Route path="/consignments" element={<ConsignmentsPage />} />
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
export default function CustomerPage() {
|
||||
const customers = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Abel Tesfaye',
|
||||
email: 'abel@example.com',
|
||||
company: 'Addis Logistics',
|
||||
status: 'Active',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Sara Bekele',
|
||||
email: 'sara@example.com',
|
||||
company: 'Blue Nile Trading',
|
||||
status: 'Pending',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Henok Alemu',
|
||||
email: 'henok@example.com',
|
||||
company: 'Ethio Freight',
|
||||
status: 'Inactive',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-slate-50 p-6">
|
||||
<div className="mx-auto max-w-7xl space-y-6">
|
||||
{/* Header */}
|
||||
<div className="flex flex-col gap-4 rounded-3xl bg-white p-6 shadow-sm md:flex-row md:items-center md:justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold tracking-tight text-slate-900">
|
||||
Customers
|
||||
</h1>
|
||||
<p className="mt-1 text-sm text-slate-500">
|
||||
Manage and monitor your customer records.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<button className="inline-flex items-center gap-2 rounded-2xl border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 transition hover:bg-slate-100">
|
||||
<Search className="h-4 w-4" />
|
||||
Search
|
||||
</button>
|
||||
|
||||
<button className="inline-flex items-center gap-2 rounded-2xl bg-slate-900 px-4 py-2 text-sm font-medium text-white transition hover:bg-slate-800">
|
||||
<Plus className="h-4 w-4" />
|
||||
Add Customer
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Stats */}
|
||||
<div className="grid gap-4 md:grid-cols-3">
|
||||
<StatCard
|
||||
title="Total Customers"
|
||||
value="1,284"
|
||||
icon={<Users className="h-5 w-5" />}
|
||||
/>
|
||||
|
||||
<StatCard
|
||||
title="Active Accounts"
|
||||
value="964"
|
||||
icon={<UserCheck className="h-5 w-5" />}
|
||||
/>
|
||||
|
||||
<StatCard
|
||||
title="Pending Requests"
|
||||
value="48"
|
||||
icon={<Clock3 className="h-5 w-5" />}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Customer Table */}
|
||||
<div className="overflow-hidden rounded-3xl bg-white shadow-sm">
|
||||
<div className="flex items-center justify-between border-b border-slate-100 px-6 py-4">
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-slate-900">
|
||||
Customer List
|
||||
</h2>
|
||||
<p className="text-sm text-slate-500">
|
||||
Recent customer activities and records.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button className="inline-flex items-center gap-2 rounded-2xl border border-slate-200 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-100">
|
||||
<Filter className="h-4 w-4" />
|
||||
Filter
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full min-w-[700px] text-left">
|
||||
<thead className="bg-slate-50 text-sm text-slate-500">
|
||||
<tr>
|
||||
<th className="px-6 py-4 font-medium">Customer</th>
|
||||
<th className="px-6 py-4 font-medium">Company</th>
|
||||
<th className="px-6 py-4 font-medium">Email</th>
|
||||
<th className="px-6 py-4 font-medium">Status</th>
|
||||
<th className="px-6 py-4 font-medium text-right">
|
||||
Actions
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{customers.map((customer) => (
|
||||
<tr
|
||||
key={customer.id}
|
||||
className="border-t border-slate-100 transition hover:bg-slate-50"
|
||||
>
|
||||
<td className="px-6 py-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-slate-100">
|
||||
<User className="h-5 w-5 text-slate-600" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="font-medium text-slate-900">
|
||||
{customer.name}
|
||||
</p>
|
||||
<p className="text-sm text-slate-500">
|
||||
ID #{customer.id}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td className="px-6 py-4 text-sm text-slate-700">
|
||||
{customer.company}
|
||||
</td>
|
||||
|
||||
<td className="px-6 py-4 text-sm text-slate-700">
|
||||
{customer.email}
|
||||
</td>
|
||||
|
||||
<td className="px-6 py-4">
|
||||
<StatusBadge status={customer.status} />
|
||||
</td>
|
||||
|
||||
<td className="px-6 py-4">
|
||||
<div className="flex justify-end gap-2">
|
||||
<button className="rounded-xl border border-slate-200 p-2 text-slate-600 hover:bg-slate-100">
|
||||
<Eye className="h-4 w-4" />
|
||||
</button>
|
||||
|
||||
<button className="rounded-xl border border-slate-200 p-2 text-slate-600 hover:bg-slate-100">
|
||||
<Pencil className="h-4 w-4" />
|
||||
</button>
|
||||
|
||||
<button className="rounded-xl border border-red-200 p-2 text-red-600 hover:bg-red-50">
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function StatCard({
|
||||
title,
|
||||
value,
|
||||
icon,
|
||||
}: {
|
||||
title: string;
|
||||
value: string;
|
||||
icon: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<div className="rounded-3xl bg-white p-6 shadow-sm">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-slate-500">{title}</p>
|
||||
<h3 className="mt-2 text-3xl font-bold text-slate-900">
|
||||
{value}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div className="flex h-12 w-12 items-center justify-center rounded-2xl bg-slate-100 text-slate-700">
|
||||
{icon}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function StatusBadge({ status }: { status: string }) {
|
||||
const styles: Record<string, 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>
|
||||
);
|
||||
}
|
||||
|
||||
import {
|
||||
Clock3,
|
||||
Eye,
|
||||
Filter,
|
||||
Pencil,
|
||||
Plus,
|
||||
Search,
|
||||
Trash2,
|
||||
User,
|
||||
UserCheck,
|
||||
Users,
|
||||
} from 'lucide-react';
|
||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -229,6 +229,9 @@ importers:
|
||||
clsx:
|
||||
specifier: ^2.1.1
|
||||
version: 2.1.1
|
||||
lucide-react:
|
||||
specifier: ^1.14.0
|
||||
version: 1.14.0(react@18.3.1)
|
||||
react:
|
||||
specifier: 18.3.1
|
||||
version: 18.3.1
|
||||
|
||||
Reference in New Issue
Block a user