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:
69
services/api.ts
Normal file
69
services/api.ts
Normal 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
31
services/auth.service.ts
Normal 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 }),
|
||||
};
|
||||
46
services/client.service.ts
Normal file
46
services/client.service.ts
Normal 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`),
|
||||
};
|
||||
7
services/dashboard.service.ts
Normal file
7
services/dashboard.service.ts
Normal 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
4
services/index.ts
Normal 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";
|
||||
Reference in New Issue
Block a user