setIsModalOpen(false)}
- />
-
- >
- )}
+ {renderModal(isModalOpen, 'Add User', onAddUser, addForm, setAddForm, () => setIsModalOpen(false))}
+ {renderModal(isEditModalOpen, 'Edit User', onUpdateUser, editForm, setEditForm, () => setIsEditModalOpen(false))}
+ {renderRolesModal()}
- {/* Edit Modal */}
- {isEditModalOpen && (
- <>
-
setIsEditModalOpen(false)}
- />
-
- >
- )}
-
- {/* Filter */}
-
-
- {error && (
-
{error}
+ {loading ? (
+
+ ) : (
+
)}
+
+ {error &&
{error}
}
);
};
diff --git a/src/services/api.js b/src/services/api.js
index fcdb5ae..a5fb1f3 100644
--- a/src/services/api.js
+++ b/src/services/api.js
@@ -1,145 +1,131 @@
import axios from 'axios';
-
import { useAuthStore } from "../store/authStore";
-const BASE_URL = import.meta.env.DEV ? "/" : "https://khalijpay-core.qaserver.ir";
+// -----------------------------
+// تنظیم BASE_URL
+// -----------------------------
+const API_BASE_URL = import.meta.env.VITE_API_BASE_URL ||
+ (import.meta.env.DEV ? "/" : "https://khalijpay-core.qaserver.ir");
-// ساخت instance از axios
+// -----------------------------
+// ایجاد instance از axios
+// -----------------------------
const api = axios.create({
- baseURL: BASE_URL,
- withCredentials: true, // ارسال و دریافت cookie/session
- headers: {
- "Content-Type": "application/json",
- },
+ baseURL: API_BASE_URL,
+ withCredentials: true,
+ headers: { "Content-Type": "application/json" },
});
// -----------------------------
-// Interceptor پاسخها
+// Global error handler برای suppress کردن 401/404
+// -----------------------------
+if (typeof window !== 'undefined') {
+ const originalConsoleError = console.error;
+ const originalConsoleWarn = console.warn;
+
+ console.error = function(...args) {
+ const errorStr = JSON.stringify(args);
+ const isSilentError = errorStr.includes('401') || errorStr.includes('404') ||
+ args.some(arg => typeof arg === 'object' && arg?.response?.status && [401,404].includes(arg.response.status));
+
+ if (isSilentError) return;
+ originalConsoleError.apply(console, args);
+ };
+
+ console.warn = function(...args) {
+ const warnStr = JSON.stringify(args);
+ if (warnStr.includes('401') || warnStr.includes('404')) return;
+ originalConsoleWarn.apply(console, args);
+ };
+}
+
+// -----------------------------
+// Request interceptor
+// -----------------------------
+api.interceptors.request.use(config => {
+ const skipAuthRedirect = config?.skipAuthRedirect === true;
+ if (skipAuthRedirect) {
+ const authState = useAuthStore.getState();
+ if (!authState?.isLoggedIn) {
+ const CancelToken = axios.CancelToken;
+ const source = CancelToken.source();
+ source.cancel('User not logged in');
+ config.cancelToken = source.token;
+ config._skipRequest = true;
+ }
+ }
+ return config;
+}, error => Promise.reject(error));
+
+// -----------------------------
+// Response interceptor
// -----------------------------
api.interceptors.response.use(
- (response) => response,
- (error) => {
+ response => response,
+ error => {
+ if (error?.isSilent) return Promise.reject(error);
+ if (axios.isCancel(error)) return Promise.reject({ isSilent: true, isCancel: true, response: { status: 401, data: { message: 'Unauthorized' } }, config: error.config || {} });
+
const skipRedirect = error?.config?.skipAuthRedirect === true;
- if (error.response?.status === 401 && !skipRedirect) {
- // session منقضی شده → هدایت به login
- const setLoggedIn = useAuthStore.getState().setLoggedIn;
- setLoggedIn(false);
- window.location.href = "/";
+ const status = error?.response?.status;
+
+ if (status === 401) {
+ if (!skipRedirect) {
+ useAuthStore.getState().setLoggedIn(false);
+ window.location.href = "/";
+ return Promise.reject(error);
+ } else {
+ return Promise.reject({ isSilent: true, response: { status: 401, data: { message: 'Unauthorized' } }, config: error.config });
+ }
}
+
+ if (status === 404 && skipRedirect) {
+ return Promise.reject({ isSilent: true, response: { status: 404, data: { message: 'Not Found' } }, config: error.config });
+ }
+
return Promise.reject(error.response?.data || error);
}
);
// -----------------------------
-// توابع API
+// Auth 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;
- }
+ const res = await api.post("/api/v1/Auth/SignIn", { userName: username, username, email: username, password });
+ return res.data;
}
-// خروج از سیستم
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;
+ await api.post("/api/v1/Auth/SignOut", null, { skipAuthRedirect: true });
} catch (error) {
- throw error;
+ console.warn("SignOut API error:", error);
}
+ useAuthStore.getState().setLoggedIn(false);
+ window.location.href = "/";
}
-// فراموشی رمز عبور
export async function forgotPassword(email) {
- try {
- const res = await api.post("/api/v1/Auth/ForgotPassword", { email });
- return res.data;
- } catch (error) {
- throw error;
- }
+ const res = await api.post("/api/v1/Auth/ForgotPassword", { email });
+ return res.data;
}
-// گرفتن دادههای محافظتشده
export async function fetchProtectedData(endpoint) {
- try {
- const res = await api.get(endpoint);
- return res.data;
- } catch (error) {
- throw error;
- }
+ const res = await api.get(endpoint);
+ return res.data;
}
-
-
-
-
-
-
-
-
-// Mock data for development
+// -----------------------------
+// Payments API (mock data)
+// -----------------------------
const mockData = {
- stats: {
- total: 1247,
- success: 1189,
- failed: 58
- },
+ 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'
- }
+ { 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 },
@@ -152,382 +138,117 @@ const mockData = {
]
};
-// Expose mock payment API for dashboard until real endpoints are integrated
export const paymentsAPI = {
- async getStats() {
- return mockData.stats;
- },
- async getChartData() {
- return mockData.chartData;
- },
+ async getStats() { return mockData.stats; },
+ async getChartData() { return mockData.chartData; },
};
// -----------------------------
-// Roles API (localStorage mock)
+// Roles API
// -----------------------------
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);
- }
-}
+function readRolesFromStorage() { try { const raw = localStorage.getItem(ROLES_STORAGE_KEY); return raw ? JSON.parse(raw) : []; } catch { return []; } }
+function writeRolesToStorage(roles) { localStorage.setItem(ROLES_STORAGE_KEY, JSON.stringify(roles)); }
+function ensureSeedRoles() { if (readRolesFromStorage().length === 0) writeRolesToStorage([
+ { 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' },
+]); }
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,
- };
-
+ async list(queryOrOptions='') {
+ const opts = typeof queryOrOptions === 'string' ? { nameQuery: queryOrOptions, currentPage:1, pageSize:100 } : { nameQuery: queryOrOptions?.nameQuery||'', currentPage: queryOrOptions?.currentPage||1, pageSize: queryOrOptions?.pageSize||100 };
+ if (!useAuthStore.getState()?.isLoggedIn) { ensureSeedRoles(); return readRolesFromStorage().filter(r=>r.name.toLowerCase().includes((opts.nameQuery||'').toLowerCase())); }
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 })));
+ const res = await api.get('/api/v1/Role', { params: opts, skipAuthRedirect: true });
+ const items = Array.isArray(res?.data?.data?.data) ? res.data.data.data : [];
+ 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));
- }
+ } catch { ensureSeedRoles(); return readRolesFromStorage(); }
},
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;
+ const payload = { name: String(role?.name||''), permissions: Array.isArray(role?.permissions)?role.permissions:[] };
+ let created = payload;
+ if (useAuthStore.getState()?.isLoggedIn) {
+ try { const res = await api.post('/api/v1/Role', payload, { skipAuthRedirect:true }); created = res?.data||payload; } catch {}
}
-
- // 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;
+ 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 };
+ if (useAuthStore.getState()?.isLoggedIn) { try { await api.delete(`/api/v1/Role/${encodeURIComponent(id)}`, { skipAuthRedirect:true }); } catch {} }
+ const roles = readRolesFromStorage(); writeRolesToStorage(roles.filter(r=>r.id!==id)); 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;
+ const payload = { name: String(role?.name||''), permissions: Array.isArray(role?.permissions)?role.permissions:[], userType: role?.userType||undefined };
+ if (useAuthStore.getState()?.isLoggedIn) { try { await api.put(`/api/v1/Role/${encodeURIComponent(id)}`, payload, { skipAuthRedirect:true }); } catch {} }
+ const roles = readRolesFromStorage(); const idx = roles.findIndex(r=>r.id===id); if(idx!==-1){ roles[idx]={...roles[idx], ...payload}; writeRolesToStorage(roles); return roles[idx]; }
+ const updated={id,...payload}; roles.push(updated); writeRolesToStorage(roles); return updated;
},
};
-
-
-
-
-
// -----------------------------
-// ✅ Users API (React version)
+// Users API با رولها
// -----------------------------
-
const USERS_STORAGE_KEY = 'app_users_v1';
-
-// 🧩 localStorage helpers
-function readUsersFromStorage() {
- try {
- const raw = localStorage.getItem(USERS_STORAGE_KEY);
- if (!raw) return [];
- const parsed = JSON.parse(raw);
- return Array.isArray(parsed) ? parsed : [];
- } catch {
- return [];
- }
-}
-
-function writeUsersToStorage(users) {
- localStorage.setItem(USERS_STORAGE_KEY, JSON.stringify(users));
-}
+function readUsersFromStorage(){ try{ const raw = localStorage.getItem(USERS_STORAGE_KEY); return raw?JSON.parse(raw):[]; } catch{return [];} }
+function writeUsersToStorage(users){ localStorage.setItem(USERS_STORAGE_KEY, JSON.stringify(users)); }
export const usersAPI = {
- // 📄 لیست کاربران
- async list({ searchQuery = '', currentPage = 1, pageSize = 100 } = {}) {
+ async list({searchQuery='',currentPage=1,pageSize=100}={}) {
+ const res = await api.get('/api/v1/User',{ params:{searchQuery,currentPage,pageSize}, skipAuthRedirect:true });
+ return res?.data?.data?.data||[];
+ },
+ async create(user){
+ const payload = { firstName:String(user?.firstName||''), lastName:String(user?.lastName||''), email:String(user?.email||''), mobile:String(user?.mobile||''), isActive:!!user?.isActive };
+ const res = await api.post('/api/v1/User',payload,{skipAuthRedirect:true});
+ return res?.data;
+ },
+ async update(id,user){
+ const payload = { firstName:String(user?.firstName||''), lastName:String(user?.lastName||''), email:String(user?.email||''), mobile:String(user?.mobile||''), isActive:!!user?.isActive };
+ const res = await api.put(`/api/v1/User/${encodeURIComponent(id)}`,payload,{skipAuthRedirect:true});
+ return res?.data;
+ },
+ async remove(id){
+ const res = await api.delete(`/api/v1/User/Delete/${encodeURIComponent(id)}/Role`,{skipAuthRedirect:true});
+ return res?.data;
+ },
+ async toggleActivation(id){ const res = await api.patch(`/api/v1/User/${encodeURIComponent(id)}/ToggleActivation`,null,{skipAuthRedirect:true}); return res?.data; },
+ async resetPassword(id){ const res = await api.patch(`/api/v1/User/${encodeURIComponent(id)}/ResetPassword`,null,{skipAuthRedirect:true}); return res?.data; },
+ async getRoles(userId){ try{ const res = await api.get(`/api/v1/User/${encodeURIComponent(userId)}/Role`,{skipAuthRedirect:true}); return res?.data?.data?.data||[]; }catch(err){ console.error(err); return []; } },
+
+ // مدیریت رولها
+ async getRoles(userId){
try {
- const res = await api.get('/api/v1/User', {
- params: { searchQuery, currentPage, pageSize },
- skipAuthRedirect: true,
- });
- const apiItems = Array.isArray(res?.data?.data?.data)
- ? res.data.data.data
- : [];
- writeUsersToStorage(apiItems);
- return apiItems;
- } catch (err) {
- console.warn('List users fallback to localStorage');
- const users = readUsersFromStorage();
- const trimmed = searchQuery.toLowerCase();
- return trimmed
- ? users.filter(
- (u) =>
- u.firstName?.toLowerCase().includes(trimmed) ||
- u.lastName?.toLowerCase().includes(trimmed) ||
- u.email?.toLowerCase().includes(trimmed)
- )
- : users;
- }
- },
-
- // ➕ افزودن کاربر جدید
- async create(user) {
- const payload = {
- firstName: String(user?.firstName || '').trim(),
- lastName: String(user?.lastName || '').trim(),
- email: String(user?.email || '').trim(),
- mobile: String(user?.mobile || '').trim(),
- isActive: !!user?.isActive,
- };
-
- try {
- const res = await api.post('/api/v1/User', payload, { skipAuthRedirect: true });
- const created = res?.data?.data || payload;
-
- const users = readUsersFromStorage();
- const newUser = { id: created.id || crypto.randomUUID(), ...created };
- users.push(newUser);
- writeUsersToStorage(users);
- return newUser;
- } catch (err) {
- console.error('Create user failed', err);
- const fallbackUser = { id: crypto.randomUUID(), ...payload };
- const users = readUsersFromStorage();
- users.push(fallbackUser);
- writeUsersToStorage(users);
- return fallbackUser;
- }
- },
-
- // ✏️ ویرایش کاربر
- async update(id, user) {
- const payload = {
- firstName: String(user?.firstName || '').trim(),
- lastName: String(user?.lastName || '').trim(),
- email: String(user?.email || '').trim(),
- mobile: String(user?.mobile || '').trim(),
- isActive: !!user?.isActive,
- };
-
- try {
- await api.put(`/api/v1/User/${encodeURIComponent(id)}`, payload, { skipAuthRedirect: true });
- } catch (err) {
- console.error('Update user failed', err);
- }
-
- const users = readUsersFromStorage();
- const idx = users.findIndex((u) => u.id === id);
- if (idx !== -1) users[idx] = { ...users[idx], ...payload };
- else users.push({ id, ...payload });
- writeUsersToStorage(users);
- return users[idx] || payload;
- },
-
- // ❌ حذف کاربر
- async remove(id) {
- try {
- await api.delete(`/api/v1/User/Delete/${encodeURIComponent(id)}/Role`, {
- skipAuthRedirect: true,
- });
- } catch (err) {
- console.error('Delete user failed', err);
- }
- const users = readUsersFromStorage().filter((u) => u.id !== id);
- writeUsersToStorage(users);
- return { success: true };
- },
-
- // 🔄 تغییر وضعیت فعال بودن (PATCH)
- async toggleActivation(id) {
- try {
- const res = await api.patch(`/api/v1/User/${encodeURIComponent(id)}/ToggleActivation`, null, {
- skipAuthRedirect: true,
- });
- const updated = res?.data?.data;
-
- if (updated) {
- const users = readUsersFromStorage();
- const idx = users.findIndex((u) => u.id === id);
- if (idx !== -1) {
- users[idx] = { ...users[idx], isActive: updated.isActive };
- writeUsersToStorage(users);
- }
- }
- return updated;
- } catch (err) {
- console.error('Toggle activation failed', err);
- throw err;
- }
- },
-
- // 🔐 ریست پسورد (PATCH)
- async resetPassword(id) {
- try {
- const res = await api.patch(`/api/v1/User/${encodeURIComponent(id)}/ResetPassword`, null, {
- skipAuthRedirect: true,
- });
- return res?.data;
- } catch (err) {
- console.error('Reset password failed', err);
- throw err;
+ const res = await api.get(`/api/v1/User/${encodeURIComponent(userId)}/Role`, { skipAuthRedirect: true });
+ return res?.data?.data || []; // ← اصلاح شد
+ } catch(err) {
+ console.error(err);
+ return [];
}
},
+ async removeRole(userId,roleId){ try{ const res = await api.delete(`/api/v1/User/${encodeURIComponent(userId)}/Role/${encodeURIComponent(roleId)}`,{skipAuthRedirect:true}); return res?.data; } catch(err){ console.error(err); return null; } },
+ async updateRoles(userId,roleIds=[]){ try{ const res = await api.post(`/api/v1/User/${encodeURIComponent(userId)}/Role`,{roleIds},{skipAuthRedirect:true}); return res?.data; } catch(err){ console.error(err); return null; } },
};
-
-
-
-
-
-
-
-
-
-
-
-
// -----------------------------
// 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' },
- ];
- }
+export async function listPermissions(){
+ if(!useAuthStore.getState()?.isLoggedIn) return [
+ {name:'Administrator',description:'Full access'}, {name:'UserManagement',description:'Manage users'}, {name:'AddUser',description:'Create user'}, {name:'EditUser',description:'Edit user'},
+ {name:'UserPasswordManagement',description:'Reset/change password'}, {name:'UserRoleManagement',description:'Assign/modify roles'},
+ {name:'RoleManagement',description:'Manage roles'}, {name:'AddRole',description:'Add role'}, {name:'EditRole',description:'Edit role'}, {name:'DeleteRole',description:'Delete role'}
+ ];
+ try{
+ const res = await api.get('/api/v1/General/Permissions',{skipAuthRedirect:true});
+ const items = Array.isArray(res?.data?.data)?res.data.data:[];
+ return items.map(p=>({name:p.name||p.displayName,description:p.description||p.displayName||p.name})).filter(Boolean);
+ }catch{return [
+ {name:'Administrator',description:'Full access'}, {name:'UserManagement',description:'Manage users'}, {name:'AddUser',description:'Create user'}, {name:'EditUser',description:'Edit user'},
+ {name:'UserPasswordManagement',description:'Reset/change password'}, {name:'UserRoleManagement',description:'Assign/modify roles'},
+ {name:'RoleManagement',description:'Manage roles'}, {name:'AddRole',description:'Add role'}, {name:'EditRole',description:'Edit role'}, {name:'DeleteRole',description:'Delete role'}
+ ];}
}
diff --git a/vite.config.js b/vite.config.js
index 69b68f0..23d7469 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -1,23 +1,36 @@
-import { defineConfig } from 'vite'
-import react from '@vitejs/plugin-react'
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react";
-// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
server: {
proxy: {
- '/api': {
- target: 'https://khalijpay-core.qaserver.ir',
+ "/api": {
+ target: "https://khalijpay-core.qaserver.ir",
changeOrigin: true,
secure: false,
+ // اجازه ارسال کوکیها
configure: (proxy) => {
- proxy.on('proxyReq', (proxyReq, req) => {
- // Ensure cookies are forwarded for withCredentials
+ proxy.on("proxyReq", (proxyReq, req) => {
const origin = req.headers.origin;
- if (origin) proxyReq.setHeader('origin', origin);
+ if (origin) {
+ proxyReq.setHeader("origin", origin);
+ }
+ // اضافه کردن این خط برای اطمینان از ارسال کوکیها
+ proxyReq.setHeader("Access-Control-Allow-Credentials", "true");
+ });
+
+ proxy.on("proxyRes", (proxyRes) => {
+ // اطمینان از دریافت کوکی از سرور
+ proxyRes.headers["Access-Control-Allow-Origin"] = "http://localhost:5173";
+ proxyRes.headers["Access-Control-Allow-Credentials"] = "true";
+ });
+
+ proxy.on("error", (err) => {
+ console.log("Proxy Error:", err);
});
},
},
},
},
-})
+});