Order Page

This commit is contained in:
Thanakarn Klangkasame
2025-10-08 11:27:28 +07:00
parent 7fb60ba0f5
commit a1f60fd12e
4 changed files with 1634 additions and 26 deletions

View File

@@ -39,7 +39,7 @@ export default async function ProtectedLayout({ children }: { children: ReactNod
redirect(`/login?returnUrl=${encodeURIComponent("/dashboard")}`);
}
const nav = buildNavForRoles(merged.roles);
const nav = buildNavForRoles(merged.roles, [], { showAll: true });
return (
<AppShell user={merged} nav={nav}>

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,15 @@
// File: src/app/component/layout/AppShell.tsx
"use client";
import { ReactNode, useMemo, useState } from "react";
import {ReactNode, useMemo, useState} from "react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import type { UserSession } from "@/types/auth";
import {usePathname} from "next/navigation";
import type {UserSession} from "@/types/auth";
type NavItem = { label: string; href: string; icon?: React.ReactNode; match?: RegExp };
type Props = { user: UserSession; nav: NavItem[]; children: ReactNode };
export default function AppShell({ user, nav, children }: Props) {
export default function AppShell({user, nav, children}: Props) {
const [sidebarOpen, setSidebarOpen] = useState(true);
const pathname = usePathname();
@@ -28,7 +28,7 @@ export default function AppShell({ user, nav, children }: Props) {
{/* Sidebar (desktop) */}
<aside
className={[
"hidden md:flex sticky top-0 h-screen flex-col border-r border-neutral-200/70 bg-white/70 backdrop-blur",
"hidden md:flex sticky top-0 h-screen flex-col min-h-0 border-r border-neutral-200/70 bg-white/70 backdrop-blur",
"transition-[width] duration-300 ease-out",
sidebarOpen ? "w-72" : "w-20",
"shadow-[inset_-1px_0_0_rgba(0,0,0,0.03)]",
@@ -37,7 +37,8 @@ export default function AppShell({ user, nav, children }: Props) {
{/* Brand */}
<div className="h-16 flex items-center px-4">
<div className="flex items-center gap-2">
<div className="h-9 w-9 rounded-2xl bg-neutral-900 text-white grid place-items-center font-semibold shadow-sm">
<div
className="h-9 w-9 rounded-2xl bg-neutral-900 text-white grid place-items-center font-semibold shadow-sm">
E
</div>
{sidebarOpen && (
@@ -50,7 +51,7 @@ export default function AppShell({ user, nav, children }: Props) {
</div>
{/* Divider */}
<div className="mx-4 mb-2 h-px bg-gradient-to-r from-transparent via-neutral-200/70 to-transparent" />
<div className="mx-4 mb-2 h-px bg-gradient-to-r from-transparent via-neutral-200/70 to-transparent"/>
{/* Tenant pill */}
<div className="px-4">
@@ -61,7 +62,8 @@ export default function AppShell({ user, nav, children }: Props) {
].join(" ")}
title="Current tenant"
>
<span className="inline-block h-2.5 w-2.5 rounded-full bg-emerald-500/90 shadow-[0_0_0_3px_rgba(16,185,129,0.12)]" />
<span
className="inline-block h-2.5 w-2.5 rounded-full bg-emerald-500/90 shadow-[0_0_0_3px_rgba(16,185,129,0.12)]"/>
{sidebarOpen ? (
<span className="truncate text-xs text-neutral-700">{user?.tenantKey ?? "—"}</span>
) : (
@@ -71,7 +73,7 @@ export default function AppShell({ user, nav, children }: Props) {
</div>
{/* Nav */}
<nav className="mt-4 flex-1 space-y-1 px-2">
<nav className="mt-4 flex-1 overflow-y-auto space-y-1 px-2 pr-3">
{nav.map((item) => {
const active = isActive(item);
return (
@@ -90,7 +92,7 @@ export default function AppShell({ user, nav, children }: Props) {
"h-8 w-8",
].join(" ")}
>
{item.icon ?? <span className="h-1.5 w-1.5 rounded-full bg-current" />}
{item.icon ?? <span className="h-1.5 w-1.5 rounded-full bg-current"/>}
</span>
{sidebarOpen && <span className="truncate">{item.label}</span>}
@@ -127,8 +129,10 @@ export default function AppShell({ user, nav, children }: Props) {
</div>
<div className="flex items-center gap-3">
<div className="flex items-center gap-2 rounded-2xl border border-neutral-200/70 bg-white/70 px-2.5 py-1.5 shadow-sm">
<div className="grid h-7 w-7 place-items-center rounded-xl bg-neutral-900 text-[11px] font-semibold text-white shadow-sm">
<div
className="flex items-center gap-2 rounded-2xl border border-neutral-200/70 bg-white/70 px-2.5 py-1.5 shadow-sm">
<div
className="grid h-7 w-7 place-items-center rounded-xl bg-neutral-900 text-[11px] font-semibold text-white shadow-sm">
{initials}
</div>
<div className="hidden leading-tight sm:block">
@@ -142,14 +146,16 @@ export default function AppShell({ user, nav, children }: Props) {
{/* Content */}
<main id="main" className="mx-auto w-full max-w-screen-2xl flex-1 p-4 sm:p-6">
<div className="rounded-3xl border border-neutral-200/70 bg-white/80 p-4 shadow-[0_10px_30px_-12px_rgba(0,0,0,0.08)] sm:p-6">
<div
className="rounded-3xl border border-neutral-200/70 bg-white/80 p-4 shadow-[0_10px_30px_-12px_rgba(0,0,0,0.08)] sm:p-6">
{children}
</div>
</main>
{/* Footer */}
<footer className="mt-auto border-t border-neutral-200/70 bg-white/60 backdrop-blur">
<div className="mx-auto flex h-12 max-w-screen-2xl items-center justify-between px-4 text-xs text-neutral-500">
<div
className="mx-auto flex h-12 max-w-screen-2xl items-center justify-between px-4 text-xs text-neutral-500">
<span>© {year} EOP</span>
<span className="hidden sm:inline">Built for enterprise operations</span>
</div>