create all proj components also build main screen ui also create sambil dashbord

This commit is contained in:
m7amedez5511
2026-06-04 21:24:01 +03:00
parent 54e57ff32a
commit 5554f5238c
27 changed files with 1274 additions and 73 deletions

90
app/lib/api.ts Normal file
View File

@@ -0,0 +1,90 @@
const DEFAULT_BASE_URL = "/api/proxy";
export const API_BASE_URL =
process.env.NEXT_PUBLIC_API_BASE_URL || DEFAULT_BASE_URL;
function normalizePath(path: string) {
return path.startsWith("/") ? path : `/${path}`;
}
async function requestJson<T>(path: string, init: RequestInit = {}): Promise<T> {
const token = typeof window !== "undefined" ? localStorage.getItem("auth_token") : null;
const headers = new Headers(init.headers || {});
if (!headers.has("Content-Type") && !(init.body instanceof FormData)) {
headers.set("Content-Type", "application/json");
}
if (token) {
headers.set("Authorization", `Bearer ${token}`);
}
const endpoint = `${API_BASE_URL}${normalizePath(path)}`;
let attempt = 0;
const maxAttempts = 3;
while (attempt < maxAttempts) {
try {
const response = await fetch(endpoint, {
...init,
headers,
cache: "no-store",
method: init.method || "GET",
});
if (!response.ok) {
const text = await response.text();
throw new Error(text || `Request failed with status ${response.status}`);
}
return (await response.json()) as T;
} catch (error) {
attempt += 1;
if (attempt >= maxAttempts) {
throw error;
}
await new Promise((resolve) => setTimeout(resolve, 2 ** attempt * 300));
}
}
throw new Error("Request failed after retries.");
}
export type DashboardSummaryResponse = {
success: boolean;
message: string;
data: {
stats: {
clients: number;
orders: number;
trips: number;
cars: number;
drivers: number;
};
alerts: {
expiringCars: Array<Record<string, unknown>>;
expiringDrivers: Array<Record<string, unknown>>;
upcomingMaint: Array<Record<string, unknown>>;
};
activeTrips: Array<{
id: string;
tripNumber: string;
title: string;
progress: number;
}>;
accountSecurity: {
lastLogin: string | null;
requestMeta: Record<string, unknown> | null;
};
};
};
export async function getDashboardSummary() {
return requestJson<DashboardSummaryResponse>("/v1/dashboard/summary");
}
export async function getHealth() {
return requestJson<{ status: string; message: string }>("/health");
}

92
app/lib/auth.ts Normal file
View File

@@ -0,0 +1,92 @@
import { API_BASE_URL } from "./api";
const AUTH_TOKEN_KEY = "auth_token";
const AUTH_USER_KEY = "auth_user";
export interface AuthUser {
id?: string;
name?: string;
email?: string;
role?: string;
permissions?: string[];
roleId?: string;
userName?: string;
phone?: string;
[key: string]: unknown;
}
export interface LoginResponse {
token: string;
user: AuthUser;
}
export function getStoredToken() {
if (typeof window === "undefined") return null;
return localStorage.getItem(AUTH_TOKEN_KEY);
}
export function getStoredUser(): AuthUser | null {
if (typeof window === "undefined") return null;
const raw = localStorage.getItem(AUTH_USER_KEY);
if (!raw) return null;
try {
return JSON.parse(raw) as AuthUser;
} catch {
return null;
}
}
export function saveAuth(token: string, user: AuthUser) {
if (typeof window === "undefined") return;
localStorage.setItem(AUTH_TOKEN_KEY, token);
localStorage.setItem(AUTH_USER_KEY, JSON.stringify(user));
}
export function clearAuth() {
if (typeof window === "undefined") return;
localStorage.removeItem(AUTH_TOKEN_KEY);
localStorage.removeItem(AUTH_USER_KEY);
}
export async function loginUser(identity: string, password: string) {
const response = await fetch(`${API_BASE_URL}/v1/auth/login`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ identity, password }),
});
const payload = (await response.json().catch(() => ({}))) as {
success?: boolean;
message?: string;
data?: {
token?: string;
user?: AuthUser;
};
token?: string;
user?: AuthUser;
};
if (!response.ok) {
throw new Error(payload.message || "Login failed. Please check your credentials.");
}
const token = payload.data?.token ?? payload.token;
const user = payload.data?.user ?? payload.user;
if (!token || !user) {
throw new Error("The server did not return a valid session payload.");
}
const rolePermissions = (user as { role?: { permissions?: Array<{ permission?: { slug?: string } }> } }).role?.permissions ?? [];
const permissions = Array.isArray(rolePermissions)
? rolePermissions
.map((entry) => entry?.permission?.slug)
.filter((slug): slug is string => Boolean(slug))
: [];
saveAuth(token, { ...user, permissions });
return { token, user: { ...user, permissions } } as LoginResponse;
}