finshing architecture for project now we have all layers to build profitionl project app,components ,hooks ,lib,services,styel ,types
This commit is contained in:
@@ -4,10 +4,10 @@
|
||||
// نقطة الدخول — تحقق من الجلسة وتوجيه المستخدم
|
||||
// ─────────────────────────────────────────────
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import { loadSession, type ClientSession } from "@/src/utils/helperFun";
|
||||
import RegisterStep from "../../src/Components/Client/client";
|
||||
import DashboardStep from "../../src/Components/Order/order";
|
||||
import Logo from "@/src/utils/logo";
|
||||
import { loadSession, type ClientSession } from "@/utils/helperFun";
|
||||
import RegisterStep from "../../Components/Client/client";
|
||||
import DashboardStep from "../../Components/Order/order";
|
||||
import Logo from "@/utils/logo";
|
||||
|
||||
type Step = "bootstrap" | "register" | "dashboard";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Logo from "@/src/utils/logo";
|
||||
import Logo from "@/utils/logo";
|
||||
import Link from "next/link";
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
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";
|
||||
import { getStoredUser } from "../../../lib/auth";
|
||||
|
||||
const navItems = [
|
||||
{ href: "/dashboard", label: "Dashboard", permission: "read-dashboard" },
|
||||
|
||||
@@ -5,7 +5,7 @@ import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
// 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";
|
||||
import { clearAuth, getStoredUser } from "../../../lib/auth";
|
||||
|
||||
export function Topbar() {
|
||||
const router = useRouter();
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { getDashboardSummary, type DashboardSummaryResponse } from "../../src/lib/api";
|
||||
import { clearAuth, getStoredToken, getStoredUser } from "../../src/lib/auth";
|
||||
import { getDashboardSummary, type DashboardSummaryResponse } from "../../lib/api";
|
||||
import { clearAuth, getStoredToken, getStoredUser } from "../../lib/auth";
|
||||
|
||||
export default function DashboardPage() {
|
||||
const router = useRouter();
|
||||
|
||||
@@ -1,44 +1,41 @@
|
||||
@import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap");
|
||||
@import "../styles/tokens.css";
|
||||
@import "tailwindcss";
|
||||
|
||||
:root {
|
||||
--blue: #1A73E8;
|
||||
--blue-dark: #1557B0;
|
||||
--blue-light: #EBF3FF;
|
||||
--green: #34A853;
|
||||
--green-light: #D1FAE5;
|
||||
--amber: #F59E0B;
|
||||
--amber-light: #FEF3C7;
|
||||
--red: #E53935;
|
||||
--red-light: #FEE2E2;
|
||||
--text: #111827;
|
||||
--text-muted: #6B7280;
|
||||
--text-hint: #9CA3AF;
|
||||
--border: #E5E7EB;
|
||||
--surface: #F9FAFB;
|
||||
--white: #fff;
|
||||
--sidebar: 230px;
|
||||
--radius: 10px;
|
||||
--radius-sm: 7px;
|
||||
--font: 'Plus Jakarta Sans', sans-serif;
|
||||
--mono: 'IBM Plex Mono', monospace;
|
||||
--background: #ECEEF2;
|
||||
--foreground: #111827;
|
||||
/* ── Base resets ────────────────────────────────────── */
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--font-sans: var(--font-geist-sans);
|
||||
--font-mono: var(--font-geist-mono);
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
font-size: 14px;
|
||||
/* RTL is set per route-group layout, not globally */
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
html { scroll-behavior: smooth; font-size: 14px; }
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
background: #ECEEF2;
|
||||
color: var(--foreground);
|
||||
font-family: var(--font);
|
||||
background-color: var(--color-surface-sunken);
|
||||
color: var(--color-text-primary);
|
||||
font-family: var(--font-sans);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* ── Tailwind theme bridge ──────────────────────────── */
|
||||
/* Expose CSS variables as Tailwind color utilities. */
|
||||
@theme inline {
|
||||
--color-background: var(--color-surface-sunken);
|
||||
--color-foreground: var(--color-text-primary);
|
||||
--color-brand: var(--color-brand-600);
|
||||
--font-sans: var(--font-sans);
|
||||
--font-mono: var(--font-mono);
|
||||
}
|
||||
|
||||
/* ── Focus ring utility ─────────────────────────────── */
|
||||
.focus-ring {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 2px var(--color-brand-600);
|
||||
}
|
||||
@@ -1,33 +1,46 @@
|
||||
// app/layout.tsx
|
||||
// Root layout — single location for font loading and global metadata.
|
||||
// No inline styles, no @import in CSS.
|
||||
|
||||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import { Plus_Jakarta_Sans, IBM_Plex_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
const jakartaSans = Plus_Jakarta_Sans({
|
||||
subsets: ["latin"],
|
||||
weight: ["400", "500", "600", "700"],
|
||||
variable: "--font-sans",
|
||||
display: "swap",
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono",
|
||||
const ibmPlexMono = IBM_Plex_Mono({
|
||||
subsets: ["latin"],
|
||||
weight: ["400", "500"],
|
||||
variable: "--font-mono",
|
||||
display: "swap",
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Logistics Client Portal",
|
||||
description: "Modern frontend for the LogisticsApp backend with dashboard and client views.",
|
||||
title: {
|
||||
default: "Slash.sa — Logistics Management",
|
||||
template: "%s | Slash.sa",
|
||||
},
|
||||
description:
|
||||
"Modern logistics client portal — manage deliveries, drivers, and fleet operations.",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
}) {
|
||||
return (
|
||||
// dir is set per route-group (ar = RTL, en = LTR) not globally
|
||||
<html
|
||||
lang="en"
|
||||
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
|
||||
lang="ar"
|
||||
className={`${jakartaSans.variable} ${ibmPlexMono.variable} h-full antialiased`}
|
||||
>
|
||||
<body className="min-h-full flex flex-col">{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,9 @@
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { loginUser } from "../../src/lib/auth";
|
||||
import Logo from "@/src/utils/logo";
|
||||
import { loginUser } from "../../lib/auth";
|
||||
import Logo from "@/utils/logo";
|
||||
import { Spinner } from "@/Components/UI";
|
||||
|
||||
export default function LoginPage() {
|
||||
const router = useRouter();
|
||||
@@ -161,7 +162,7 @@ export default function LoginPage() {
|
||||
disabled={loading}
|
||||
className="mt-6 inline-flex h-11.5 w-full items-center justify-center rounded-[9px] bg-blue-600 text-[15px] font-semibold text-white transition hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-70"
|
||||
>
|
||||
{loading ? "جاري تسجيل الدخول…" : "تسجيل الدخول"}
|
||||
{loading ? <Spinner /> : "تسجيل الدخول"}
|
||||
</button>
|
||||
|
||||
<p className="mt-4 text-center text-[13px] text-slate-500">
|
||||
|
||||
Reference in New Issue
Block a user