import axios from 'axios'; import { useAuthStore } from "../store/authStore"; const BASE_URL = import.meta.env.DEV ? "/" : "https://khalijpay-core.qaserver.ir"; // ساخت instance از axios const api = axios.create({ baseURL: BASE_URL, withCredentials: true, // ارسال و دریافت cookie/session headers: { "Content-Type": "application/json", }, }); // ----------------------------- // Interceptor پاسخ‌ها // ----------------------------- api.interceptors.response.use( (response) => response, (error) => { const skipRedirect = error?.config?.skipAuthRedirect === true; if (error.response?.status === 401 && !skipRedirect) { // session منقضی شده → هدایت به login const setLoggedIn = useAuthStore.getState().setLoggedIn; setLoggedIn(false); window.location.href = "/"; } return Promise.reject(error.response?.data || error); } ); // ----------------------------- // توابع API // ----------------------------- // Login export async function login(username, password) { try { const res = await api.post("/api/v1/Auth/SignIn", { // include common variants to satisfy different backends userName: username, username: username, email: username, password: password, }); return res.data; } catch (error) { throw error; } } // خروج از سیستم export async function signOut() { try { const res = await api.post("/api/v1/Auth/SignOut"); // پاک کردن وضعیت login در Zustand const setLoggedIn = useAuthStore.getState().setLoggedIn; setLoggedIn(false); window.location.href = "/"; return res.data; } catch (error) { throw error; } } // فراموشی رمز عبور export async function forgotPassword(email) { try { const res = await api.post("/api/v1/Auth/ForgotPassword", { email }); return res.data; } catch (error) { throw error; } } // گرفتن داده‌های محافظت‌شده export async function fetchProtectedData(endpoint) { try { const res = await api.get(endpoint); return res.data; } catch (error) { throw error; } } // Mock data for development const mockData = { stats: { total: 1247, success: 1189, failed: 58 }, payments: [ { id: 'TXN-001', user: 'John Doe', amount: 299.99, status: 'success', date: '2024-01-15T10:30:00Z', currency: 'USD' }, { id: 'TXN-002', user: 'Jane Smith', amount: 150.00, status: 'pending', date: '2024-01-15T11:45:00Z', currency: 'USD' }, { id: 'TXN-003', user: 'Bob Johnson', amount: 75.50, status: 'failed', date: '2024-01-15T12:15:00Z', currency: 'USD' }, { id: 'TXN-004', user: 'Alice Brown', amount: 450.00, status: 'success', date: '2024-01-15T13:20:00Z', currency: 'USD' }, { id: 'TXN-005', user: 'Charlie Wilson', amount: 89.99, status: 'success', date: '2024-01-15T14:30:00Z', currency: 'USD' } ], chartData: [ { date: '2024-01-09', amount: 1200 }, { date: '2024-01-10', amount: 1900 }, { date: '2024-01-11', amount: 3000 }, { date: '2024-01-12', amount: 2800 }, { date: '2024-01-13', amount: 1890 }, { date: '2024-01-14', amount: 2390 }, { date: '2024-01-15', amount: 3490 } ] }; // Expose mock payment API for dashboard until real endpoints are integrated export const paymentsAPI = { async getStats() { return mockData.stats; }, async getChartData() { return mockData.chartData; }, }; // ----------------------------- // Roles API (localStorage mock) // ----------------------------- const ROLES_STORAGE_KEY = 'app_roles_v1'; function readRolesFromStorage() { try { const raw = localStorage.getItem(ROLES_STORAGE_KEY); if (!raw) return []; const parsed = JSON.parse(raw); if (!Array.isArray(parsed)) return []; return parsed; } catch (_) { return []; } } function writeRolesToStorage(roles) { localStorage.setItem(ROLES_STORAGE_KEY, JSON.stringify(roles)); } function ensureSeedRoles() { const existing = readRolesFromStorage(); if (existing.length === 0) { const seed = [ { id: crypto.randomUUID(), name: 'Admin', permissions: ['read', 'write', 'delete'], userType: 'internal' }, { id: crypto.randomUUID(), name: 'Editor', permissions: ['read', 'write'], userType: 'internal' }, { id: crypto.randomUUID(), name: 'Viewer', permissions: ['read'], userType: 'external' }, ]; writeRolesToStorage(seed); } } export const rolesAPI = { async list(queryOrOptions = '') { // Support both: list('admin') and list({ nameQuery, currentPage, pageSize }) const opts = typeof queryOrOptions === 'string' ? { nameQuery: queryOrOptions, currentPage: 1, pageSize: 100 } : { nameQuery: queryOrOptions?.nameQuery || '', currentPage: queryOrOptions?.currentPage ?? 1, pageSize: queryOrOptions?.pageSize ?? 100, }; try { const res = await api.get('/api/v1/Role', { params: { nameQuery: opts.nameQuery, currentPage: opts.currentPage, pageSize: opts.pageSize, }, // prevent global 401 redirect for optional fetch skipAuthRedirect: true, }); const raw = res?.data; // Backend shape example: // { data: { filterSummary: {...}, data: Role[] }, isSuccess: true, ... } const apiItems = Array.isArray(raw?.data?.data) ? raw.data.data : undefined; // Fallbacks for other shapes we may encounter const items = apiItems || (Array.isArray(raw) ? raw : undefined) || (Array.isArray(raw?.items) ? raw.items : []) || []; // Sync a snapshot to local storage for offline UX writeRolesToStorage(items.map(r => ({ id: r.id || crypto.randomUUID(), ...r }))); return items; } catch (_) { // Fallback to local filtering ensureSeedRoles(); const roles = readRolesFromStorage(); const trimmed = String(opts.nameQuery || '').toLowerCase(); if (!trimmed) return roles; return roles.filter(r => r.name?.toLowerCase().includes(trimmed)); } }, async create(role) { const payload = { name: String(role?.name || '').trim(), permissions: Array.isArray(role?.permissions) ? role.permissions : [], // userType: String(role?.userType || '').trim(), }; let created = null; try { // Try real backend const res = await api.post('/api/v1/Role', payload, { skipAuthRedirect: true }); created = res?.data || payload; } catch (_) { // Fallback to local-only if backend unavailable created = payload; } // Sync into local storage list so UI updates immediately const roles = readRolesFromStorage(); const newRole = { id: crypto.randomUUID(), ...created }; roles.push(newRole); writeRolesToStorage(roles); return newRole; }, async remove(id) { try { await api.delete(`/api/v1/Role/${encodeURIComponent(id)}`, { skipAuthRedirect: true }); } catch (_) { // ignore backend failure, proceed with local removal for UX } const roles = readRolesFromStorage(); const next = roles.filter(r => r.id !== id); writeRolesToStorage(next); return { success: true }; }, async update(id, role) { const existingLocal = readRolesFromStorage().find(r => r.id === id) || {}; const payload = { name: String(role?.name || '').trim(), permissions: Array.isArray(role?.permissions) ? role.permissions : [], ...(role?.userType !== undefined ? { userType: String(role?.userType || '').trim() } : (existingLocal.userType ? { userType: existingLocal.userType } : {})), }; try { await api.put(`/api/v1/Role/${encodeURIComponent(id)}`, payload, { skipAuthRedirect: true }); } catch (err) { const status = err?.statusCode || err?.status || err?.response?.status; if (status === 404 || status === 405 || status === 400) { try { await api.put('/api/v1/Role', { id, ...payload }, { skipAuthRedirect: true }); } catch (e2) { const s2 = e2?.statusCode || e2?.status || e2?.response?.status; if (s2 === 401 || s2 === 403) { throw { message: 'Unauthorized to edit roles (401/403). Check permissions/login.', status: s2 }; } } } else if (status === 401 || status === 403) { throw { message: 'Unauthorized to edit roles (401/403). Check permissions/login.', status }; } } const roles = readRolesFromStorage(); const idx = roles.findIndex(r => r.id === id); if (idx !== -1) { roles[idx] = { ...roles[idx], ...payload }; writeRolesToStorage(roles); return roles[idx]; } // If not found locally, append const updated = { id, ...payload }; roles.push(updated); writeRolesToStorage(roles); return updated; }, }; // ----------------------------- // Permissions API // ----------------------------- export async function listPermissions() { try { const res = await api.get('/api/v1/General/Permission', { skipAuthRedirect: true }); const raw = res?.data; // Expected shape: { data: Permission[] } const items = Array.isArray(raw?.data) ? raw.data : []; // Prefer returning structured objects with name and description const objs = items .map((p) => { const name = typeof p?.name === 'string' ? p.name : (typeof p?.displayName === 'string' ? p.displayName : null); if (!name) return null; const description = typeof p?.description === 'string' && p.description ? p.description : (typeof p?.displayName === 'string' ? p.displayName : name); return { name, description }; }) .filter(Boolean); if (objs.length > 0) return objs; // Fallback to simple names if server returned unexpected shape const names = items .map((p) => (typeof p?.name === 'string' ? p.name : (typeof p?.displayName === 'string' ? p.displayName : null))) .filter(Boolean); return names.map((n) => ({ name: n, description: n })); } catch (_) { // Fallback to a minimal static list to keep UI usable return [ { name: 'Administrator', description: 'Full access to administrative features' }, { name: 'UserManagement', description: 'Manage users and their profiles' }, { name: 'AddUser', description: 'Create new user accounts' }, { name: 'EditUser', description: 'Edit existing user accounts' }, { name: 'UserPasswordManagement', description: 'Reset or change user passwords' }, { name: 'UserRoleManagement', description: 'Assign or modify user roles' }, { name: 'RoleManagement', description: 'Manage roles and permissions' }, { name: 'AddRole', description: 'Create new roles' }, { name: 'EditRole', description: 'Edit existing roles' }, { name: 'DeleteRole', description: 'Remove roles from the system' }, ]; } }