This commit is contained in:
Hamed
2026-07-30 10:57:49 +04:00
parent e03a4dfcb0
commit 31f261bf5f
102 changed files with 8782 additions and 1432 deletions
+31
View File
@@ -0,0 +1,31 @@
import apiClient from "./axios";
/**
* Auth service placeholder — wires up the shape the login/dashboard
* flow will eventually call. No real backend is connected yet.
*/
export const authService = {
/**
* @param {{ email: string, password: string }} credentials
* @returns {Promise<{ user: Object, token: string }>}
*/
async login(credentials) {
// TODO: Connect Login API
// return apiClient.post("/auth/login", credentials).then((res) => res.data);
return Promise.resolve({
user: { name: "کاربر مهمان", email: credentials?.email ?? "" },
token: "mock-token",
});
},
/**
* @returns {Promise<void>}
*/
async logout() {
// TODO: Connect Logout API
// return apiClient.post("/auth/logout");
return Promise.resolve();
},
};
export default authService;
+45
View File
@@ -0,0 +1,45 @@
import axios from "axios";
/**
* Single Axios instance for the whole app. Every service file
* imports this instead of calling axios directly, so base URL,
* headers, and interceptors only need to be configured once.
*/
const apiClient = axios.create({
baseURL:
process.env.NEXT_PUBLIC_API_BASE_URL ||
"https://api.robotmarket.example.com",
timeout: 15000,
headers: {
"Content-Type": "application/json",
},
});
// Attach the auth token (once real login exists) to every request.
apiClient.interceptors.request.use((config) => {
if (typeof window !== "undefined") {
const token = window.localStorage.getItem("rm_token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
}
return config;
});
// Centralized error normalization so services/components can rely
// on a consistent error shape regardless of what the backend sends.
apiClient.interceptors.response.use(
(response) => response,
(error) => {
const normalized = {
message:
error?.response?.data?.message ||
error?.message ||
"خطای غیرمنتظره‌ای رخ داد.",
status: error?.response?.status || 500,
};
return Promise.reject(normalized);
}
);
export default apiClient;
+23
View File
@@ -0,0 +1,23 @@
import apiClient from "./axios";
/**
* Dashboard service placeholder. The navbar's "داشبورد" link is a
* UI placeholder only — this file exists so the future dashboard
* page has a clean, ready-made data-fetching seam.
*/
export const dashboardService = {
/**
* @returns {Promise<Object>} summary metrics for the dashboard home
*/
async getSummary() {
// TODO: Connect Dashboard API
// return apiClient.get("/dashboard/summary").then((res) => res.data);
return Promise.resolve({
totalMachines: 0,
totalRevenue: 0,
activeLocations: 0,
});
},
};
export default dashboardService;
+30
View File
@@ -0,0 +1,30 @@
import apiClient from "./axios";
import productsData from "@/data/products.json";
/**
* Product service — every method returns a Promise so components
* and Redux thunks can call it the same way once the real backend
* exists. Until then, each method resolves with local mock data.
*/
export const productService = {
/**
* @returns {Promise<Array>} list of vending machine products
*/
async getAll() {
// TODO: Connect Product API
// return apiClient.get("/products").then((res) => res.data);
return Promise.resolve(productsData);
},
/**
* @param {string} id
* @returns {Promise<Object|undefined>}
*/
async getById(id) {
// TODO: Connect Product API
// return apiClient.get(`/products/${id}`).then((res) => res.data);
return Promise.resolve(productsData.find((product) => product.id === id));
},
};
export default productService;