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:
m7amedez5511
2026-06-08 23:05:19 +03:00
parent 70853958f5
commit 53c03e9867
45 changed files with 1408 additions and 78 deletions

69
services/api.ts Normal file
View File

@@ -0,0 +1,69 @@
// Base HTTP helper — no React, no UI imports.
// All network calls in the app ultimately call `request()` from here.
/** Resolved at runtime: server-side reads INTERNAL_API_BASE_URL,
* browser always hits the Next.js proxy to avoid CORS. */
function resolveBase() {
if (typeof window === "undefined") {
return process.env.INTERNAL_API_BASE_URL ?? "";
}
return "/api/proxy";
}
// ── Error type ─────────────────────────────────────────
export class ApiError extends Error {
constructor(
public readonly status: number,
message: string,
) {
super(message);
this.name = "ApiError";
}
}
// ── Core request helper ────────────────────────────────
export async function request<T>(
path: string,
init: RequestInit = {},
token?: string | null,
): Promise<T> {
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 url = `${resolveBase()}/${path.replace(/^\/+/, "")}`;
const res = await fetch(url, {
...init,
headers,
cache: "no-store",
method: init.method ?? "GET",
});
if (!res.ok) {
const json = await res.json().catch(() => null);
const message: string =
json?.message ?? json?.error ?? `HTTP ${res.status}: ${res.statusText}`;
throw new ApiError(res.status, message);
}
return res.json() as Promise<T>;
}
// ── Convenience shorthands ────────────────────────────
export const get = <T>(path: string, token?: string | null) =>
request<T>(path, {}, token);
export const post = <T>(path: string, body: unknown, token?: string | null) =>
request<T>(path, { method: "POST", body: JSON.stringify(body) }, token);
export const put = <T>(path: string, body: unknown, token?: string | null) =>
request<T>(path, { method: "PUT", body: JSON.stringify(body) }, token);
export const del = <T>(path: string, token?: string | null) =>
request<T>(path, { method: "DELETE" }, token);

31
services/auth.service.ts Normal file
View File

@@ -0,0 +1,31 @@
// All authentication API calls in one place.
import { post } from "./api";
import type { LoginResponse } from "../types/auth";
export interface LoginPayload {
identity: string;
password: string;
}
export const authService = {
/**
* Authenticate a user with email / phone / username + password.
* Throws `ApiError` on network or credential failure.
*/
login: (payload: LoginPayload) =>
post<LoginResponse>("auth/login", payload),
/**
* Request a password reset email.
*/
forgotPassword: (email: string) =>
post<{ message: string }>("auth/forgot-password", { email }),
/**
* Confirm a password reset with a token.
*/
resetPassword: (token: string, newPassword: string) =>
post<{ message: string }>("auth/reset-password", { token, newPassword }),
};

View File

@@ -0,0 +1,46 @@
// services/client.service.ts
import { get, post } from "./api";
import type { ClientAddress, Order } from "../types/client";
export interface CreateClientPayload {
name: string;
email: string;
phone: string;
companyName?: string;
}
export interface CreateAddressPayload {
label: string;
branchName?: string | null;
contactPerson: { name: string; phone: string };
details: {
city: string;
district?: string;
street: string;
buildingNo?: string;
unitNo?: string;
zipCode?: string;
};
}
export const clientService = {
/** Register a new client account */
create: (payload: CreateClientPayload) =>
post<{ id: string; name: string; email: string; phone: string }>(
"client",
payload,
),
/** Fetch all saved delivery addresses for a client */
getAddresses: (clientId: string) =>
get<ClientAddress[]>(`client/${clientId}/addresses`),
/** Save a new delivery address */
addAddress: (clientId: string, payload: CreateAddressPayload) =>
post<ClientAddress>(`client/${clientId}/addresses`, payload),
/** Fetch all orders placed by a client */
getOrders: (clientId: string) =>
get<Order[]>(`client/${clientId}/orders`),
};

View File

@@ -0,0 +1,7 @@
import { get } from "./api";
import type { DashboardSummaryResponse } from "../types/dashboard";
export const dashboardService = {
getSummary: (token: string) =>
get<DashboardSummaryResponse>("dashboard/summary", token),
};

4
services/index.ts Normal file
View File

@@ -0,0 +1,4 @@
export { request, get, post, put, del, ApiError } from "./api";
export { authService } from "./auth.service";
export { dashboardService } from "./dashboard.service";
export { clientService } from "./client.service";