handel login page and logout alson andel create order page to client and build spinner page and complet project structuer , create logo tamplet

This commit is contained in:
m7amedez5511
2026-06-08 17:24:53 +03:00
parent 5554f5238c
commit 70853958f5
27 changed files with 1425 additions and 303 deletions

View File

@@ -1,3 +1,5 @@
import Logo from "@/src/utils/logo";
import Link from "next/link";
@@ -11,26 +13,10 @@ const navLinks = [
export default function Navbar() {
return (
<nav dir="rtl" className="w-full border-b border-slate-200 bg-white text-slate-900 shadow-sm">
<nav dir="rtl" className="w-full border-b border-slate-200 bg-white text-slate-900 shadow-sm">x
<div className="mx-auto flex h-14 max-w-7xl items-center gap-4 px-6 lg:px-8">
<a href="#" className="flex items-center gap-3 text-right">
<span className="flex h-8 w-8 items-center justify-center rounded-lg bg-blue-600 shadow-sm">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1.8"
strokeLinecap="round"
strokeLinejoin="round"
className="h-5 w-5 text-white"
aria-hidden="true"
>
<path d="M3 7h11l3 4h4l-2 4H8" />
<circle cx="9" cy="18" r="1.7" fill="currentColor" stroke="none" />
<circle cx="18" cy="18" r="1.7" fill="currentColor" stroke="none" />
</svg>
</span>
<span className="text-[16px] font-extrabold text-slate-900">LogiFlow</span>
<a href="/" className="flex items-center gap-3 text-right">
<Logo />
</a>
<div className="hidden flex-1 items-center justify-center gap-6 md:flex">
@@ -48,12 +34,12 @@ export default function Navbar() {
</div>
<div className="mr-auto flex items-center gap-2">
<button className="flex h-[34px] items-center rounded-lg border border-slate-200 bg-white px-3 text-[13px] font-semibold text-slate-700 shadow-sm transition hover:bg-slate-50">
إنشاء حساب عميل
</button>
<button className="flex h-[34px] items-center rounded-lg bg-blue-600 px-3 text-[13px] font-bold text-white shadow-sm transition hover:bg-blue-700">
<Link href="/NewOrder" className="flex h-[34px] items-center rounded-lg border border-slate-200 bg-white px-3 text-[13px] font-semibold text-slate-700 shadow-sm transition hover:bg-slate-50">
إنشاء طلب جديد
</Link>
<Link href="/login" className="flex h-[34px] items-center rounded-lg bg-blue-600 px-3 text-[13px] font-bold text-white shadow-sm transition hover:bg-blue-700">
تسجيل الدخول
</button>
</Link>
</div>
</div>
</nav>

View File

@@ -1,34 +1,50 @@
// File: app/components/layout/Sidebar.tsx
"use client";
import Link from "next/link";
// FIX: Import getStoredUser so the sidebar reads the authenticated user's
// name and role from localStorage instead of showing hardcoded placeholders.
import { getStoredUser } from "../../../src/lib/auth";
const navItems = [
{ href: "/dashboard", label: "Dashboard", permission: "read-dashboard" },
{ href: "/users", label: "Users", permission: "read-user" },
{ href: "/cars", label: "Cars", permission: "read-car" },
{ href: "/drivers", label: "Drivers", permission: "read-driver" },
{ href: "/clients", label: "Clients", permission: "read-client" },
{ href: "/orders", label: "Orders", permission: "read-order" },
{ href: "/trips", label: "Trips", permission: "read-trip" },
{ href: "/branches", label: "Branches", permission: "read-branch" },
{ href: "/roles", label: "Roles", permission: "read-role" },
{ href: "/audit", label: "Audit", permission: "read-audit" },
{ href: "/users", label: "Users", permission: "read-user" },
{ href: "/cars", label: "Cars", permission: "read-car" },
{ href: "/drivers", label: "Drivers", permission: "read-driver" },
{ href: "/clients", label: "Clients", permission: "read-client" },
{ href: "/orders", label: "Orders", permission: "read-order" },
{ href: "/trips", label: "Trips", permission: "read-trip" },
{ href: "/branches", label: "Branches", permission: "read-branch" },
{ href: "/roles", label: "Roles", permission: "read-role" },
{ href: "/audit", label: "Audit", permission: "read-audit" },
];
export function Sidebar() {
const permissions = navItems.map((item) => item.permission);
// FIX: Read the stored user on render. suppressHydrationWarning handles
// the SSR/CSR mismatch since localStorage is browser-only.
const user = getStoredUser();
const permissions = user?.permissions ?? navItems.map((i) => i.permission);
return (
<aside suppressHydrationWarning className="hidden w-72 shrink-0 border-r border-white/10 bg-slate-950/80 p-6 lg:flex lg:flex-col">
<aside
suppressHydrationWarning
className="hidden w-72 shrink-0 border-r border-white/10 bg-slate-950/80 p-6 lg:flex lg:flex-col"
>
<div>
<p className="text-xs uppercase tracking-[0.35em] text-cyan-200">Logistics</p>
<h2 className="mt-3 text-xl font-semibold text-white">Ops Console</h2>
<p className="mt-2 text-sm text-slate-300">Fleet, clients, orders, and compliance in one place.</p>
<p className="mt-2 text-sm text-slate-300">
Fleet, clients, orders, and compliance in one place.
</p>
</div>
<nav className="mt-8 space-y-2">
{navItems.map((item) => {
const hasPermission = permissions.includes(item.permission) || item.permission === "read-dashboard";
// FIX: Check the real user permissions array fetched from stored auth.
// Dashboard is always visible regardless of permissions.
const hasPermission =
item.permission === "read-dashboard" ||
permissions.includes(item.permission);
if (!hasPermission) return null;
return (
@@ -46,9 +62,15 @@ export function Sidebar() {
<div className="mt-auto rounded-3xl border border-emerald-400/20 bg-emerald-400/10 p-4 text-sm text-emerald-50">
<p className="text-xs uppercase tracking-[0.25em] text-emerald-100">Authenticated</p>
<p suppressHydrationWarning className="mt-2 font-semibold">Operations user</p>
<p suppressHydrationWarning className="text-xs text-emerald-100/90">Signed in</p>
{/* FIX: Show the real user name and role from the stored auth session,
replacing the previous hardcoded "Operations user" / "Signed in" text. */}
<p suppressHydrationWarning className="mt-2 font-semibold">
{user?.name ?? user?.userName ?? "—"}
</p>
<p suppressHydrationWarning className="text-xs text-emerald-100/90">
{user?.role ? `Role: ${user.role}` : "Signed in"}
</p>
</div>
</aside>
);
}
}

View File

@@ -1,28 +1,60 @@
// File: app/components/layout/Topbar.tsx
"use client";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { clearAuth } from "../../lib/auth";
// FIX: Import both clearAuth and getStoredUser so the topbar can show the
// authenticated user's role and handle logout properly.
import { clearAuth, getStoredUser } from "../../../src/lib/auth";
export function Topbar() {
const router = useRouter();
function handleLogout() {
// FIX: clearAuth already existed and is correct — it removes both the
// token and user from localStorage, fully ending the session.
clearAuth();
router.replace("/login");
}
// FIX: Read the stored user to display their real role in the header
// instead of the hardcoded "Manager" placeholder.
const user = getStoredUser();
// Capitalize the role label for display (e.g. "admin" → "Admin")
const roleLabel = user?.role
? user.role.charAt(0).toUpperCase() + user.role.slice(1)
: "—";
return (
<header suppressHydrationWarning className="border-b border-white/10 bg-slate-950/70 px-4 py-4 lg:px-6">
<header
suppressHydrationWarning
className="border-b border-white/10 bg-slate-950/70 px-4 py-4 lg:px-6"
>
<div className="mx-auto flex max-w-7xl items-center justify-between gap-4">
<div>
<p className="text-xs uppercase tracking-[0.35em] text-cyan-200">Operations dashboard</p>
<h1 className="text-xl font-semibold text-white lg:text-2xl">Logistics delivery management</h1>
<p className="text-xs uppercase tracking-[0.35em] text-cyan-200">
Operations dashboard
</p>
<h1 className="text-xl font-semibold text-white lg:text-2xl">
Logistics delivery management
</h1>
</div>
<div className="flex items-center gap-3">
<Link href="/" className="rounded-full border border-white/10 bg-slate-900/80 px-4 py-2 text-sm text-slate-200 hover:bg-slate-800">Overview</Link>
<div suppressHydrationWarning className="hidden rounded-full border border-white/10 bg-slate-900/80 px-4 py-2 text-sm text-slate-200 md:block">Manager</div>
<Link
href="/"
className="rounded-full border border-white/10 bg-slate-900/80 px-4 py-2 text-sm text-slate-200 hover:bg-slate-800"
>
Overview
</Link>
{/* FIX: Replace the hardcoded "Manager" string with the actual
authenticated user's role read from localStorage. */}
<div
suppressHydrationWarning
className="hidden rounded-full border border-white/10 bg-slate-900/80 px-4 py-2 text-sm text-slate-200 md:block"
>
{roleLabel}
</div>
<button
type="button"
onClick={handleLogout}
@@ -34,4 +66,4 @@ export function Topbar() {
</div>
</header>
);
}
}