+ >
+ )}
+
+ {/* Currency Management Modal */}
+ {isCurrencyModalOpen && selectedAgentForCurrency && (
+ <>
+
setIsCurrencyModalOpen(false)} />
+
+
+
+
+ Manage Currencies - {selectedAgentForCurrency.name}
+
+
+
+
+
+
+
+
Current Currencies
+
+ {agentCurrencies.length === 0 ? (
+
No currencies added
+ ) : (
+ agentCurrencies.map((curr) => (
+
+
+ {curr.currencyCode}
+
+ Commission: {curr.voucherGenerationCommission}
+
+
+
+
+
+
+
+ ))
+ )}
+
+
+
+
+ >
+ )}
+
+ {/* Wallet Management Modal */}
+ {isWalletModalOpen && selectedAgentForWallet && (
+ <>
+
setIsWalletModalOpen(false)} />
+
+
+
+
+ Wallet Management - {selectedAgentForWallet.name}
+
+
+
+
+ {walletData && (
+ <>
+
+
Wallet Balance
+
+ {walletData.balances?.map((balance, idx) => (
+
+ Amount:
+ {balance.amount} {balance.currencyCode}
+
+ ))}
+
+
+
+
+
+
+
Transactions
+
+ {walletTransactions.length === 0 ? (
+
No transactions
+ ) : (
+ walletTransactions.map((tx, idx) => (
+
+
+ {tx.type || 'Transaction'}
+
+ {tx.amount?.amount} {tx.amount?.currencyCode}
+
+
+ {tx.date &&
{new Date(tx.date).toLocaleString()}
}
+
+ ))
+ )}
+
+
+ >
+ )}
+
+
+ >
+ )}
+
+ );
+};
+
+export default TopUpAgent;
+
diff --git a/src/pages/Transactions.jsx b/src/pages/Transactions.jsx
deleted file mode 100644
index 498d890a..00000000
--- a/src/pages/Transactions.jsx
+++ /dev/null
@@ -1,277 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { RefreshCw, Download, Filter } from 'lucide-react';
-import DataTable from '../components/DataTable';
-import { paymentsAPI } from '../services/api';
-
-const Transactions = () => {
- const [payments, setPayments] = useState([]);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState('');
- const [filter, setFilter] = useState('all');
- const [refreshing, setRefreshing] = useState(false);
-
- useEffect(() => {
- fetchPayments();
- }, []);
-
- const fetchPayments = async () => {
- try {
- setLoading(true);
- setError('');
- const response = await paymentsAPI.getPayments();
- setPayments(response.data || []);
- } catch (err) {
- setError('Failed to fetch transactions');
- console.error('Transactions fetch error:', err);
- } finally {
- setLoading(false);
- }
- };
-
- const handleRefresh = async () => {
- setRefreshing(true);
- await fetchPayments();
- setRefreshing(false);
- };
-
- const handleFilter = (status) => {
- setFilter(status);
- };
-
- const filteredPayments = payments.filter(payment => {
- if (filter === 'all') return true;
- return payment.status === filter;
- });
-
- const getStatusBadge = (status) => {
- const statusClasses = {
- success: 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300',
- failed: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300',
- pending: 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300',
- };
-
- return (
-
- {status}
-
- );
- };
-
- const formatCurrency = (amount, currency = 'USD') => {
- return new Intl.NumberFormat('en-US', {
- style: 'currency',
- currency: currency,
- }).format(amount);
- };
-
- const formatDate = (dateString) => {
- return new Date(dateString).toLocaleDateString('en-US', {
- year: 'numeric',
- month: 'short',
- day: 'numeric',
- hour: '2-digit',
- minute: '2-digit',
- });
- };
-
- const exportToCSV = () => {
- const csvContent = [
- ['ID', 'User', 'Amount', 'Status', 'Date', 'Currency'],
- ...filteredPayments.map(payment => [
- payment.id,
- payment.user,
- payment.amount,
- payment.status,
- formatDate(payment.date),
- payment.currency
- ])
- ].map(row => row.join(',')).join('\n');
-
- const blob = new Blob([csvContent], { type: 'text/csv' });
- const url = window.URL.createObjectURL(blob);
- const a = document.createElement('a');
- a.href = url;
- a.download = `transactions-${new Date().toISOString().split('T')[0]}.csv`;
- a.click();
- window.URL.revokeObjectURL(url);
- };
-
- const columns = [
- {
- key: 'id',
- header: 'Transaction ID',
- render: (value) => (
-
- {value}
-
- )
- },
- {
- key: 'user',
- header: 'User',
- render: (value) => (
-
-
-
- {value.charAt(0).toUpperCase()}
-
-
-
{value}
-
- )
- },
- {
- key: 'amount',
- header: 'Amount',
- render: (value, row) => (
-
- {formatCurrency(value, row.currency)}
-
- )
- },
- {
- key: 'status',
- header: 'Status',
- render: (value) => getStatusBadge(value)
- },
- {
- key: 'date',
- header: 'Date',
- render: (value) => (
-
- {formatDate(value)}
-
- )
- }
- ];
-
- return (
-
-
-
-
-
Transactions
-
View and manage all payment transactions
-
-
-
-
-
-
-
-
- {/* Filters */}
-
-
-
-
- Filter by status:
-
-
- {[
- { key: 'all', label: 'All', count: payments.length },
- { key: 'success', label: 'Success', count: payments.filter(p => p.status === 'success').length },
- { key: 'pending', label: 'Pending', count: payments.filter(p => p.status === 'pending').length },
- { key: 'failed', label: 'Failed', count: payments.filter(p => p.status === 'failed').length },
- ].map(({ key, label, count }) => (
-
- ))}
-
-
-
-
- {/* Error State */}
- {error && (
-
-
{error}
-
-
- )}
-
- {/* Transactions Table */}
-
-
- {/* Summary Stats */}
-
-
-
-
-
Total Transactions
-
- {filteredPayments.length}
-
-
-
-
-
-
-
-
-
-
Total Amount
-
- {formatCurrency(
- filteredPayments.reduce((sum, payment) => sum + payment.amount, 0)
- )}
-
-
-
-
-
-
-
-
-
-
Success Rate
-
- {filteredPayments.length > 0
- ? ((filteredPayments.filter(p => p.status === 'success').length / filteredPayments.length) * 100).toFixed(1)
- : 0}%
-
-
-
-
-
-
-
- );
-};
-
-export default Transactions;
diff --git a/src/pages/Users.jsx b/src/pages/Users.jsx
deleted file mode 100644
index dd102a84..00000000
--- a/src/pages/Users.jsx
+++ /dev/null
@@ -1,332 +0,0 @@
-import React, { useEffect, useMemo, useState, useCallback, useRef } from 'react';
-import DataTable from '../components/DataTable';
-import { usersAPI, rolesAPI } from '../services/api';
-import { Plus, Trash2, Search, Pencil, ShieldOff, RefreshCcw } from 'lucide-react';
-import { ToastContainer, toast } from 'react-toastify';
-import 'react-toastify/dist/ReactToastify.css';
-import { getErrorMessage, getSuccessMessage } from '../utils/errorHandler';
-
-const Users = () => {
- const [users, setUsers] = useState([]);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState('');
- const [filter, setFilter] = useState('');
-
- const [addForm, setAddForm] = useState({ firstName: '', lastName: '', email: '' });
- const [editForm, setEditForm] = useState({ firstName: '', lastName: '', email: '' });
-
- const [isModalOpen, setIsModalOpen] = useState(false);
- const [isEditModalOpen, setIsEditModalOpen] = useState(false);
- const [editingUser, setEditingUser] = useState(null);
-
- const [roles, setRoles] = useState([]);
- const [rolesModalUser, setRolesModalUser] = useState(null);
- const [selectedRoles, setSelectedRoles] = useState([]);
-
- // دریافت کاربران و رولها
- const fetchUsers = useCallback(async (q = '') => {
- try {
- setLoading(true);
- const list = await usersAPI.list({ searchQuery: q });
- const usersWithRoles = await Promise.all(
- (list || []).map(async (user) => {
- const roles = await usersAPI.getRoles(user.id); // باید طبق ریسپانس نمونه برگرداند
- return { ...user, roles };
- })
- );
- setUsers(usersWithRoles);
- setError('');
- } catch (err) {
- console.error(err);
- const errorMsg = getErrorMessage(err);
- setError(errorMsg);
- toast.error(errorMsg);
- } finally {
- setLoading(false);
- }
- }, []);
-
- const fetchRoles = useCallback(async () => {
- const list = await rolesAPI.list(); // گرفتن تمام رولها
- setRoles(list);
- }, []);
-
- // Initial load - fetch all users once
- useEffect(() => {
- fetchUsers('');
- fetchRoles();
- }, [fetchUsers, fetchRoles]);
-
- // --- اضافه کردن کاربر ---
- const onAddUser = async (e) => {
- e.preventDefault();
- const { firstName, lastName, email } = addForm;
- if (!firstName.trim() || !lastName.trim() || !email.trim()) return;
- try {
- const newUser = await usersAPI.create(addForm);
- await fetchUsers(filter);
- setIsModalOpen(false);
- setAddForm({ firstName: '', lastName: '', email: '' });
- toast.success(getSuccessMessage(newUser) || 'User added successfully');
- } catch (err) {
- toast.error(getErrorMessage(err));
- }
- };
-
- // --- ویرایش کاربر ---
- const openEdit = (user) => {
- setEditingUser(user);
- setEditForm({
- firstName: user.firstName || '',
- lastName: user.lastName || '',
- email: user.email || '',
- });
- setIsEditModalOpen(true);
- };
-
- const onUpdateUser = async (e) => {
- e.preventDefault();
- if (!editingUser) return;
- try {
- const updatedUser = await usersAPI.update(editingUser.id, editForm);
- await fetchUsers(filter);
- setIsEditModalOpen(false);
- setEditingUser(null);
- toast.success(getSuccessMessage(updatedUser) || 'User updated successfully');
- } catch (err) {
- toast.error(getErrorMessage(err));
- }
- };
-
- // --- حذف کاربر ---
- const onDelete = async (id) => {
- if (!window.confirm('Are you sure you want to delete this user?')) return;
- try {
- const result = await usersAPI.remove(id);
- await fetchUsers(filter);
- toast.success(getSuccessMessage(result) || 'User deleted successfully');
- } catch (err) {
- toast.error(getErrorMessage(err));
- }
- };
-
- // --- تغییر وضعیت فعال بودن ---
- const onToggleActivation = async (id) => {
- try {
- const updated = await usersAPI.toggleActivation(id);
- await fetchUsers(filter);
- toast.success(getSuccessMessage(updated) || 'User status updated');
- } catch (err) {
- toast.error(getErrorMessage(err));
- }
- };
-
- // --- ریست پسورد ---
- const onResetPassword = async (id) => {
- try {
- const res = await usersAPI.resetPassword(id);
- toast.success(getSuccessMessage(res) || 'Password reset successfully');
- } catch (err) {
- toast.error(getErrorMessage(err));
- }
- };
-
- // --- مدیریت رولها ---
- const openRolesModal = async (user) => {
- setRolesModalUser(user);
- try {
- // دریافت roles کاربر از API
- const userRoles = await usersAPI.getRoles(user.id);
- setSelectedRoles(userRoles?.map(r => r.id) || []);
- } catch (err) {
- console.error('Error fetching user roles:', err);
- // Fallback to roles from user object
- setSelectedRoles(user.roles?.map(r => r.id) || []);
- toast.error('Failed to load user roles');
- }
- };
-
- const onUpdateRoles = async () => {
- if (!rolesModalUser) return;
- try {
- await usersAPI.updateRoles(rolesModalUser.id, selectedRoles);
- toast.success('Roles updated successfully');
- setRolesModalUser(null);
- await fetchUsers(filter);
- } catch (err) {
- toast.error(getErrorMessage(err));
- }
- };
-
- // --- ستونهای جدول ---
- const columns = useMemo(() => [
- { key: 'firstName', header: 'First Name' },
- { key: 'lastName', header: 'Last Name' },
- { key: 'email', header: 'Email' },
- {
- key: 'roles',
- header: 'Roles',
- render: (_val, row) => (
-
- {row.roles?.length
- ? row.roles.map(r => r.name).join(', ')
- : '—'}
-
- ),
- },
- { key: 'isActive', header: 'Active', render: (val) => (val ? '✅' : '❌') },
- {
- key: 'actions',
- header: 'Actions',
- render: (_val, row) => (
-
-
-
-
-
-
-
- ),
- },
- ], []);
-
- // --- مودال اضافه و ویرایش ---
- const renderModal = (isOpen, title, onSubmit, formState, setFormState, onClose) => {
- if (!isOpen) return null;
- return (
- <>
-
-
- >
- );
- };
-
- // --- مودال مدیریت رولها ---
- const renderRolesModal = () => {
- if (!rolesModalUser) return null;
- return (
- <>
-
setRolesModalUser(null)} />
-
-
-
- Manage Roles for {rolesModalUser.firstName}
-
-
- {roles.map(role => (
-
- ))}
-
-
-
-
-
-
-
- >
- );
- };
-
- return (
-
-
-
-
-
-
Users
-
- Manage users: add, edit, activate/deactivate, reset password, and assign roles
-
-
-
-
-
- {renderModal(isModalOpen, 'Add User', onAddUser, addForm, setAddForm, () => setIsModalOpen(false))}
- {renderModal(isEditModalOpen, 'Edit User', onUpdateUser, editForm, setEditForm, () => setIsEditModalOpen(false))}
- {renderRolesModal()}
-
-
-
-
- {
- setFilter(e.target.value);
- }}
- placeholder="Filter by name, email or role"
- className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500"
- />
-
-
-
- {loading ? (
-
- ) : (
-
{
- if (!filter.trim()) return true;
- const searchTerm = filter.toLowerCase();
- const firstName = (user.firstName || '').toLowerCase();
- const lastName = (user.lastName || '').toLowerCase();
- const email = (user.email || '').toLowerCase();
- const rolesText = (user.roles || []).map(r => r.name).join(' ').toLowerCase();
- return firstName.includes(searchTerm) ||
- lastName.includes(searchTerm) ||
- email.includes(searchTerm) ||
- rolesText.includes(searchTerm);
- })}
- columns={columns}
- searchable={false}
- />
- )}
-
- {error && {error}
}
-
- );
-};
-
-export default Users;
diff --git a/src/services/api.js b/src/services/api.js
index 8c257bb4..82a65e84 100644
--- a/src/services/api.js
+++ b/src/services/api.js
@@ -5,13 +5,12 @@
// Individual APIs are now in separate files for better organization
export * from './authAPI';
-export { paymentsAPI } from './paymentsAPI';
-export { rolesAPI } from './rolesAPI';
-export { usersAPI } from './usersAPI';
-export { currencyAPI } from './currencyAPI';
+
export { countryAPI } from './countryAPI';
export { provinceAPI } from './provinceAPI';
export { cityAPI } from './cityAPI';
-export { issuerAPI } from './issuerAPI';
export { listPermissions } from './permissionsAPI';
export { generalAPI } from './generalAPI';
+export { paymentsAPI } from './paymentsAPI';
+export { currencyAPI } from './currencyAPI';
+export { topUpAgentAPI } from './topUpAgentAPI';
diff --git a/src/services/apiClient.js b/src/services/apiClient.js
index ddd94084..5df862d9 100644
--- a/src/services/apiClient.js
+++ b/src/services/apiClient.js
@@ -5,7 +5,7 @@ import { useAuthStore } from "../store/authStore";
// تنظیم BASE_URL
// -----------------------------
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL ||
- (import.meta.env.DEV ? "/" : "https://khalijpay-core.qaserver.ir");
+ (import.meta.env.DEV ? "/" : "https://khalijpay-issuer.qaserver.ir");
// -----------------------------
// ایجاد instance از axios
@@ -43,38 +43,27 @@ if (typeof window !== 'undefined') {
// Request interceptor
// -----------------------------
api.interceptors.request.use(config => {
- console.log("🔵 Request interceptor:", {
- url: config.url,
- fullUrl: config.baseURL + config.url,
- skipAuthRedirect: config?.skipAuthRedirect,
- method: config.method,
- data: config.data,
- headers: config.headers
- });
-
const skipAuthRedirect = config?.skipAuthRedirect === true;
if (skipAuthRedirect) {
// بررسی اینکه آیا درخواست به endpoint احراز هویت است یا نه
const isAuthEndpoint = config.url?.includes('/Auth/SignIn') ||
config.url?.includes('/Auth/SignOut') ||
- config.url?.includes('/Auth/ForgotPassword');
-
- console.log("🔵 Auth endpoint check:", { isAuthEndpoint, url: config.url });
+ config.url?.includes('/Auth/ForgotPassword') ||
+ config.url?.includes('/Auth/User/Issuers') ||
+ config.url?.includes('/Auth/Issuers');
// اگر endpoint احراز هویت است، اجازه ارسال درخواست را بدهیم (حتی اگر کاربر لاگین نباشد)
+ // برای سایر endpointها با skipAuthRedirect، اگر کاربر لاگین نباشد، درخواست را cancel میکنیم
+ // چون این endpointها نیاز به احراز هویت دارند
if (!isAuthEndpoint) {
const authState = useAuthStore.getState();
- console.log("🔵 Auth state:", { isLoggedIn: authState?.isLoggedIn });
if (!authState?.isLoggedIn) {
- console.warn("⚠️ Canceling request - user not logged in");
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
source.cancel('User not logged in');
config.cancelToken = source.token;
config._skipRequest = true;
}
- } else {
- console.log("✅ Allowing auth endpoint request");
}
}
return config;
@@ -84,57 +73,10 @@ api.interceptors.request.use(config => {
// Response interceptor
// -----------------------------
api.interceptors.response.use(
- response => {
- console.log("🟢 Response interceptor - Success:", {
- url: response.config?.url,
- status: response.status,
- data: response.data
- });
- return response;
- },
+ response => response,
error => {
- console.log("🔴 Response interceptor - Error:", {
- url: error.config?.url,
- isSilent: error?.isSilent,
- isCancel: axios.isCancel(error),
- status: error?.response?.status,
- message: error?.message
- });
-
- // لاگ کامل error.response
- console.log("🔴 Full error.response:", error.response);
- console.log("🔴 error.response exists:", !!error.response);
-
- if (error.response) {
- console.log("🔴 error.response.status:", error.response.status);
- console.log("🔴 error.response.statusText:", error.response.statusText);
- console.log("🔴 error.response.headers:", error.response.headers);
- console.log("🔴 error.response.data exists:", !!error.response.data);
- console.log("🔴 error.response.data:", error.response.data);
- console.log("🔴 error.response.data type:", typeof error.response.data);
-
- // بررسی اینکه آیا data یک string است
- if (typeof error.response.data === 'string') {
- console.log("🔴 Response data is string:", error.response.data);
- }
-
- // بررسی اینکه آیا data یک object است
- if (error.response.data && typeof error.response.data === 'object') {
- console.log("🔴 Response data keys:", Object.keys(error.response.data));
- try {
- console.log("🔴 Response data (JSON):", JSON.stringify(error.response.data, null, 2));
- } catch (e) {
- console.log("🔴 Cannot stringify response.data:", e);
- }
- }
- } else {
- console.log("🔴 No error.response object");
- console.log("🔴 Full error object:", error);
- }
-
if (error?.isSilent) return Promise.reject(error);
if (axios.isCancel(error)) {
- console.warn("⚠️ Request was canceled");
return Promise.reject({ isSilent: true, isCancel: true, response: { status: 401, data: { message: 'Unauthorized' } }, config: error.config || {} });
}
diff --git a/src/services/authAPI.js b/src/services/authAPI.js
index b7dbe51a..a5a5db34 100644
--- a/src/services/authAPI.js
+++ b/src/services/authAPI.js
@@ -4,12 +4,60 @@ import { useAuthStore } from "../store/authStore";
// -----------------------------
// Auth API
// -----------------------------
-export async function login(email, password) {
- try {
- const res = await api.post("/api/v1/Auth/SignIn", { email: email, password }, { skipAuthRedirect: true });
- const data = res.data;
- console.log("data login", data);
+// Get user issuers
+export async function getUserIssuers(email, password) {
+ try {
+ console.log("🔵 Requesting issuers from:", "/api/v1/Auth/User/Issuers");
+ const res = await api.post("/api/v1/Auth/User/Issuers", { email, password }, { skipAuthRedirect: true });
+ console.log("🟢 Response received:", res);
+ const data = res.data;
+
+ // بررسی اینکه آیا پاسخ موفقیتآمیز است یا نه (پشتیبانی از isSuccess و IsSuccess)
+ if (data && (data.isSuccess === false || data.IsSuccess === false)) {
+ const errorMessage = data.message || data.Message || 'Failed to get issuers';
+ const error = new Error(errorMessage);
+ error.response = {
+ ...res,
+ data: data,
+ status: data.statusCode || data.StatusCode || 409
+ };
+ throw error;
+ }
+
+ // استخراج لیست issuers از response
+ // ممکن است پاسخ به صورت مستقیم array باشد یا در data باشد
+ const issuers = Array.isArray(data) ? data : (data?.data || data || []);
+ return Array.isArray(issuers) ? issuers : [];
+ } catch (error) {
+ // اگر خطای 404 است، پیام مناسب نمایش دهیم
+ if (error?.response?.status === 404) {
+ const customError = new Error('Endpoint not found. Please check the API configuration.');
+ customError.response = error.response;
+ throw customError;
+ }
+
+ if (error.response) {
+ const errorData = error.response.data || {};
+ const errorMessage = errorData.message || errorData.Message || error.message || 'خطا در ارتباط با سرور';
+ const customError = new Error(errorMessage);
+ customError.response = error.response;
+ throw customError;
+ }
+ throw error;
+ }
+}
+
+// Sign in with issuer
+export async function login(email, password, issuerId) {
+ try {
+ const requestBody = { email, password };
+ if (issuerId) {
+ requestBody.issuerId = issuerId;
+ }
+
+ const res = await api.post("/api/v1/Auth/SignIn", requestBody, { skipAuthRedirect: true });
+ const data = res.data;
// بررسی اینکه آیا پاسخ موفقیتآمیز است یا نه (پشتیبانی از isSuccess و IsSuccess)
if (data && (data.isSuccess === false || data.IsSuccess === false)) {
@@ -26,8 +74,6 @@ export async function login(email, password) {
return data;
} catch (error) {
-
-
// اگر خطا از سمت سرور است (500, 400, etc.)، آن را throw کنیم
if (error.response) {
const errorData = error.response.data || {};
diff --git a/src/services/cityAPI.js b/src/services/cityAPI.js
index bff8eded..cf8b0141 100644
--- a/src/services/cityAPI.js
+++ b/src/services/cityAPI.js
@@ -17,15 +17,11 @@ export const cityAPI = {
requestParams.provinceId = provinceId;
}
- console.log('🔵 City API - list request:', { params: requestParams });
-
const res = await api.get('/api/v1/City', {
params: requestParams,
skipAuthRedirect: true
});
- console.log('🟢 City API - list response:', res?.data);
-
// پاسخ به صورت { data: { data: [...], filterSummary: {...} } } است
return res?.data?.data?.data || [];
},
@@ -49,7 +45,6 @@ export const cityAPI = {
ProvinceId: city?.provinceId || '',
CityName: String(city?.cityName || '').trim(),
};
- console.log('City API Update:', { cityId, payload });
try {
const res = await api.put(`/api/v1/City/${encodeURIComponent(cityId)}`, payload, { skipAuthRedirect: true });
return res?.data;
diff --git a/src/services/countryAPI.js b/src/services/countryAPI.js
index 1902192b..6024e818 100644
--- a/src/services/countryAPI.js
+++ b/src/services/countryAPI.js
@@ -19,7 +19,6 @@ export const countryAPI = {
try {
const res = await api.get('/api/v1/Country/All', { skipAuthRedirect: true });
// پاسخ به صورت { data: [...], statusCode: 200, isSuccess: true, ... } است
- console.log('🔵 Country API - listAll response:', res?.data);
return res?.data?.data || [];
} catch (error) {
console.error('🔴 Country API - listAll error:', error);
@@ -35,7 +34,6 @@ export const countryAPI = {
CurrencyCode: String(country?.currencyCode || ''),
TimeZone: String(country?.timeZoneName || country?.timeZone || ''),
};
- console.log('🔵 Country API - create payload:', payload);
const res = await api.post('/api/v1/Country', payload, { skipAuthRedirect: true });
return res?.data;
},
@@ -54,7 +52,6 @@ export const countryAPI = {
};
const url = `/api/v1/Country/${encodeURIComponent(countryId)}`;
- console.log('🔵 Country API - update payload:', { url, countryId, payload });
try {
const res = await api.put(url, payload, { skipAuthRedirect: true });
diff --git a/src/services/currencyAPI.js b/src/services/currencyAPI.js
index 3bf6c207..54bb5332 100644
--- a/src/services/currencyAPI.js
+++ b/src/services/currencyAPI.js
@@ -4,54 +4,84 @@ import api from './apiClient';
// Currency API
// -----------------------------
export const currencyAPI = {
- // GET /api/v1/Currency
- async list() {
- const res = await api.get('/api/v1/Currency', { skipAuthRedirect: true });
- return res?.data?.data || [];
+ // GET /api/v1/Currency (with pagination)
+ async list(params = {}) {
+ try {
+ const queryParams = {
+ currentPage: params.currentPage || 1,
+ pageSize: params.pageSize || 1000,
+ ...params
+ };
+
+ const res = await api.get('/api/v1/Currency', {
+ params: queryParams,
+ skipAuthRedirect: true
+ });
+
+ // Response might be: { data: [...], statusCode: 200, ... }
+ // Or direct array: [...]
+ const currencies = Array.isArray(res?.data)
+ ? res.data
+ : (res?.data?.data || []);
+
+ return currencies;
+ } catch (error) {
+ console.error('🔴 Currency API - list error:', error);
+ throw error;
+ }
+ },
+
+ // GET /api/v1/Currency/{id}
+ async getById(id) {
+ try {
+ const res = await api.get(`/api/v1/Currency/${encodeURIComponent(id)}`, {
+ skipAuthRedirect: true
+ });
+ return res?.data?.data || res?.data;
+ } catch (error) {
+ console.error('🔴 Currency API - getById error:', error);
+ throw error;
+ }
},
// POST /api/v1/Currency
- async create(currencyCode) {
- const payload = { currencyCode: String(currencyCode || '') };
- const res = await api.post('/api/v1/Currency', payload, { skipAuthRedirect: true });
- return res?.data;
+ async create(data) {
+ try {
+ const res = await api.post('/api/v1/Currency', data, {
+ skipAuthRedirect: true
+ });
+ return res?.data?.data || res?.data;
+ } catch (error) {
+ console.error('🔴 Currency API - create error:', error);
+ throw error;
+ }
},
- // PATCH /api/v1/Currency/{currencyCode}/ToggleActivation
- async toggleActivation(currencyCode) {
- const res = await api.patch(`/api/v1/Currency/${encodeURIComponent(currencyCode)}/ToggleActivation`, null, { skipAuthRedirect: true });
- return res?.data;
+ // PUT /api/v1/Currency/{id}
+ async update(id, data) {
+ try {
+ const res = await api.put(`/api/v1/Currency/${encodeURIComponent(id)}`, data, {
+ skipAuthRedirect: true
+ });
+ return res?.data?.data || res?.data;
+ } catch (error) {
+ console.error('🔴 Currency API - update error:', error);
+ throw error;
+ }
},
- // PATCH /api/v1/Currency/{currencyCode}/Maintenance/Enable
- async enableMaintenance(currencyCode, maintenanceMessage = null) {
- const payload = maintenanceMessage ? { maintenanceMessage } : {};
- const res = await api.patch(`/api/v1/Currency/${encodeURIComponent(currencyCode)}/Maintenance/Enable`, payload, { skipAuthRedirect: true });
- return res?.data;
- },
-
- // PATCH /api/v1/Currency/{currencyCode}/Maintenance/Disable
- async disableMaintenance(currencyCode) {
- const res = await api.patch(`/api/v1/Currency/${encodeURIComponent(currencyCode)}/Maintenance/Disable`, null, { skipAuthRedirect: true });
- return res?.data;
- },
-
- // PUT /api/v1/Currency/{currencyCode}/Permissions
- async updatePermissions(currencyCode, permissions) {
- const res = await api.put(`/api/v1/Currency/${encodeURIComponent(currencyCode)}/Permissions`, permissions, { skipAuthRedirect: true });
- return res?.data;
- },
-
- // PUT /api/v1/Currency/{currencyCode}/Limits
- async updateLimits(currencyCode, limits) {
- const res = await api.put(`/api/v1/Currency/${encodeURIComponent(currencyCode)}/Limits`, limits, { skipAuthRedirect: true });
- return res?.data;
- },
-
- // PUT /api/v1/Currency/{currencyCode}/Fees
- async updateFees(currencyCode, fees) {
- const res = await api.put(`/api/v1/Currency/${encodeURIComponent(currencyCode)}/Fees`, fees, { skipAuthRedirect: true });
- return res?.data;
+ // DELETE /api/v1/Currency/{id}
+ async remove(id) {
+ try {
+ const res = await api.delete(`/api/v1/Currency/${encodeURIComponent(id)}`, {
+ skipAuthRedirect: true
+ });
+ return res?.data?.data || res?.data;
+ } catch (error) {
+ console.error('🔴 Currency API - remove error:', error);
+ throw error;
+ }
},
};
+
diff --git a/src/services/issuerAPI.js b/src/services/issuerAPI.js
deleted file mode 100644
index a96e33fc..00000000
--- a/src/services/issuerAPI.js
+++ /dev/null
@@ -1,582 +0,0 @@
-import api from './apiClient';
-
-// -----------------------------
-// Issuer API
-// -----------------------------
-export const issuerAPI = {
- // GET /api/v1/Issuer (with pagination and filters)
- async list(params = {}) {
- const { currentPage = 1, pageSize = 100, isActive, supportCurrencyCode, supportCapabilities, ...otherParams } = params;
- const requestParams = { currentPage, pageSize, ...otherParams };
-
- // اگر فیلترها وجود دارند، آنها را به params اضافه کن
- if (isActive !== undefined && isActive !== null && isActive !== '') {
- requestParams.isActive = isActive;
- }
- if (supportCurrencyCode) {
- requestParams.supportCurrencyCode = supportCurrencyCode;
- }
- if (supportCapabilities) {
- requestParams.supportCapabilities = supportCapabilities;
- }
-
- console.log('🔵 Issuer API - list request:', { params: requestParams });
-
- const res = await api.get('/api/v1/Issuer', {
- params: requestParams,
- skipAuthRedirect: true
- });
-
- console.log('🟢 Issuer API - list response:', res?.data);
-
- // پاسخ به صورت { data: { data: [...], filterSummary: {...} } } است
- return res?.data?.data?.data || [];
- },
-
- // GET /api/v1/Issuer/{id}
- async getById(id) {
- const res = await api.get(`/api/v1/Issuer/${encodeURIComponent(id)}`, {
- skipAuthRedirect: true
- });
- console.log('Full API response:', res?.data);
- console.log('API response data:', res?.data?.data);
- return res?.data?.data;
- },
-
- // POST /api/v1/Issuer
- async create(issuer) {
- // Build payload according to AddIssuerCommand structure:
- // name (required), supportEmail (required), title (nullable), cityId (Guid nullable), postalCode, addressDetails (nullable)
- const payload = {
- name: String(issuer?.name || '').trim(),
- supportEmail: String(issuer?.supportEmail || '').trim(),
- postalCode: String(issuer?.postalCode || '').trim()
- };
-
- // Add title only if provided (nullable field - don't send if empty)
- if (issuer?.title && String(issuer.title).trim()) {
- payload.title = String(issuer.title).trim();
- }
-
- // Add addressDetails only if provided (nullable field - don't send if empty)
- const addressValue = String(issuer?.addressDetails || issuer?.address || '').trim();
- if (addressValue) {
- payload.addressDetails = addressValue;
- }
-
- // Include cityId only if valid GUID (nullable Guid - don't send if null/empty)
- if (issuer?.cityId && issuer.cityId !== '' && issuer.cityId !== 'null' && issuer.cityId !== null) {
- // Validate GUID format (basic check)
- const guidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
- if (guidPattern.test(issuer.cityId)) {
- payload.cityId = issuer.cityId;
- } else {
- console.warn('⚠️ Invalid cityId GUID format:', issuer.cityId);
- }
- }
-
- console.log('🔵 Issuer Create Payload:', JSON.stringify(payload, null, 2));
- console.log('🔵 Issuer Create Payload (original):', issuer);
-
- try {
- const res = await api.post('/api/v1/Issuer', payload, { skipAuthRedirect: true });
- console.log('🟢 Issuer Create Response:', res?.data);
- return res?.data;
- } catch (err) {
- console.error('🔴 Issuer Create Error:', {
- status: err?.response?.status,
- statusText: err?.response?.statusText,
- data: err?.response?.data,
- errors: err?.response?.data?.errors,
- message: err?.response?.data?.message,
- payload: payload
- });
- console.error('🔴 Full error.response:', err?.response);
- console.error('🔴 Full error.response.data:', err?.response?.data);
- console.error('🔴 Error response data type:', typeof err?.response?.data);
- if (err?.response?.data) {
- try {
- console.error('🔴 Error response data stringified:', JSON.stringify(err?.response?.data, null, 2));
- } catch (e) {
- console.error('🔴 Error response data (could not stringify):', err?.response?.data);
- console.error('🔴 Error response data toString:', String(err?.response?.data));
- }
- }
- throw err;
- }
- },
-
- // PUT /api/v1/Issuer/{id}
- async update(id, issuer) {
- // Build payload according to UpdateIssuerCommand structure (similar to AddIssuerCommand)
- const payload = {
- name: String(issuer?.name || '').trim(),
- supportEmail: String(issuer?.supportEmail || '').trim(),
- postalCode: String(issuer?.postalCode || '').trim()
- };
-
- // Add title if provided (nullable field)
- if (issuer?.title && String(issuer.title).trim()) {
- payload.title = String(issuer.title).trim();
- }
-
- // Add addressDetails if provided (nullable field)
- const addressValue = String(issuer?.addressDetails || issuer?.address || '').trim();
- if (addressValue) {
- payload.addressDetails = addressValue;
- }
-
- // Include cityId - validate GUID format
- if (issuer?.cityId && issuer.cityId !== '' && issuer.cityId !== 'null' && issuer.cityId !== null) {
- // Validate GUID format (basic check)
- const guidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
- if (guidPattern.test(issuer.cityId)) {
- payload.cityId = issuer.cityId;
- } else {
- console.warn('⚠️ Invalid cityId GUID format:', issuer.cityId);
- }
- }
-
- console.log('🔵 Issuer Update Payload:', JSON.stringify(payload, null, 2));
-
- try {
- const res = await api.put(`/api/v1/Issuer/${encodeURIComponent(id)}`, payload, {
- skipAuthRedirect: true
- });
- console.log('🟢 Issuer Update Response:', res?.data);
- return res?.data;
- } catch (err) {
- console.error('🔴 Issuer Update Error:', {
- status: err?.response?.status,
- statusText: err?.response?.statusText,
- data: err?.response?.data,
- errors: err?.response?.data?.errors,
- message: err?.response?.data?.message,
- payload: payload
- });
- throw err;
- }
- },
-
- // DELETE /api/v1/Issuer/{id}
- async remove(id) {
- const res = await api.delete(`/api/v1/Issuer/${encodeURIComponent(id)}`, {
- skipAuthRedirect: true
- });
- return res?.data;
- },
-
- // PATCH /api/v1/Issuer/{id}/ToggleActivation
- async toggleActivation(id) {
- const res = await api.patch(`/api/v1/Issuer/${encodeURIComponent(id)}/ToggleActivation`, null, {
- skipAuthRedirect: true
- });
- return res?.data;
- },
-
- // GET /api/v1/Issuer/{issuerId}/Capabilities
- async getCapabilities(issuerId) {
- try {
- console.log('🔵 Getting capabilities for issuer:', issuerId);
- const res = await api.get(`/api/v1/Issuer/${encodeURIComponent(issuerId)}/Capabilities`, {
- skipAuthRedirect: true
- });
- // Response structure: { data: [...], statusCode, isSuccess, ... }
- // Or direct array: [...]
- const capabilities = Array.isArray(res?.data) ? res.data : (res?.data?.data || []);
- console.log('🟢 Capabilities from API:', capabilities);
- return capabilities;
- } catch (err) {
- console.error('🔴 Error getting capabilities:', {
- status: err?.response?.status,
- data: err?.response?.data
- });
- // Handle 404 gracefully - endpoint might not exist for some issuers
- if (err?.response?.status === 404) {
- console.warn('⚠️ Capabilities endpoint not found (404), returning empty array');
- return [];
- }
- throw err;
- }
- },
-
- // PUT /api/v1/Issuer/{issuerId}/Capabilities
- // Payload: IssuerManageCapabilitiesCommand { capabilities: List
}
- async updateCapabilities(issuerId, capabilities) {
- // Build IssuerCapabilityDto array from input
- // Each IssuerCapabilityDto should have: capability, capabilityName, hasCapability (or similar fields)
- const validCapabilities = Array.isArray(capabilities) ? capabilities
- .filter(cap => {
- // Filter out invalid capabilities
- if (typeof cap === 'string') {
- return cap && String(cap).trim() !== '';
- }
- if (typeof cap === 'object' && cap !== null) {
- const capabilityValue = cap.capability || cap.capabilityName || '';
- return capabilityValue && String(capabilityValue).trim() !== '';
- }
- return false;
- })
- .map(cap => {
- // Convert to IssuerCapabilityDto format
- if (typeof cap === 'string') {
- return {
- capability: String(cap).trim(),
- capabilityName: String(cap).trim(),
- hasCapability: true
- };
- }
-
- // If it's an object, ensure it has the required fields
- const capabilityValue = cap.capability || cap.capabilityName || '';
- const capabilityName = cap.capabilityName || cap.capability || String(capabilityValue).trim();
- const hasCapability = cap.hasCapability !== undefined ? Boolean(cap.hasCapability) : true;
-
- return {
- capability: String(capabilityValue).trim(),
- capabilityName: String(capabilityName).trim() || String(capabilityValue).trim(),
- hasCapability: hasCapability
- };
- })
- .filter(cap => cap.capability && cap.capability.trim() !== '') : [];
-
- // Wrap in IssuerManageCapabilitiesCommand structure
- const payload = {
- capabilities: validCapabilities
- };
-
- console.log('🔵 Update Capabilities Payload:', JSON.stringify(payload, null, 2));
- console.log('🔵 Issuer ID:', issuerId);
- console.log('🔵 Valid capabilities count:', validCapabilities.length);
-
- try {
- const res = await api.put(`/api/v1/Issuer/${encodeURIComponent(issuerId)}/Capabilities`, payload, {
- skipAuthRedirect: true
- });
- console.log('🟢 Capabilities Update Response:', res?.data);
- return res?.data;
- } catch (err) {
- console.error('🔴 Capabilities update error:', {
- status: err?.response?.status,
- statusText: err?.response?.statusText,
- data: err?.response?.data,
- errors: err?.response?.data?.errors,
- message: err?.response?.data?.message,
- payload: payload
- });
- if (err?.response?.data) {
- try {
- console.error('🔴 Error response data stringified:', JSON.stringify(err?.response?.data, null, 2));
- } catch (e) {
- console.error('🔴 Error response data (could not stringify):', err?.response?.data);
- }
- }
- throw err;
- }
- },
-
- // GET /api/v1/Issuer/{issuerId}/AllowedCurrencies
- // Response: { data: [{ currencyCode, currencyEnglishName, allowed }, ...], statusCode, ... }
- async getAllowedCurrencies(issuerId) {
- try {
- console.log('🔵 Getting allowed currencies for issuer:', issuerId);
- const res = await api.get(`/api/v1/Issuer/${encodeURIComponent(issuerId)}/AllowedCurrencies`, {
- skipAuthRedirect: true
- });
- // Response structure: { data: [{ currencyCode, currencyEnglishName, allowed }, ...], statusCode, ... }
- // Or direct array: [{ currencyCode, currencyEnglishName, allowed }, ...]
- const currencies = Array.isArray(res?.data) ? res.data : (res?.data?.data || []);
- console.log('🟢 Allowed Currencies from API:', currencies);
- return currencies;
- } catch (err) {
- console.error('🔴 Error getting allowed currencies:', {
- status: err?.response?.status,
- data: err?.response?.data
- });
- // Handle 404 gracefully - endpoint might not exist for some issuers
- if (err?.response?.status === 404) {
- console.warn('⚠️ AllowedCurrencies endpoint not found (404), returning empty array');
- return [];
- }
- throw err;
- }
- },
-
- // PUT /api/v1/Issuer/{issuerId}/AllowedCurrencies
- // Payload: { allowedCurrencies: List }
- async updateAllowedCurrencies(issuerId, allowedCurrencies) {
- // Build IssuerAllowedCurrencyDto array from input
- // Each should have: currencyCode, currencyEnglishName, allowed
- const currencyMap = new Map(); // Use Map to avoid duplicates
-
- if (Array.isArray(allowedCurrencies)) {
- allowedCurrencies.forEach(curr => {
- const currencyCode = String(curr.currencyCode || curr.code || '').trim();
- if (!currencyCode) return; // Skip invalid currencies
-
- // Use currencyCode as key to avoid duplicates
- if (!currencyMap.has(currencyCode)) {
- const currencyEnglishName = String(curr.currencyEnglishName || curr.name || '').trim();
- const allowed = curr.allowed !== undefined ? Boolean(curr.allowed) : true;
-
- currencyMap.set(currencyCode, {
- currencyCode: currencyCode,
- currencyEnglishName: currencyEnglishName || currencyCode,
- allowed: allowed
- });
- }
- });
- }
-
- // Convert Map to array
- const validCurrencies = Array.from(currencyMap.values());
-
- // Wrap in command structure
- const payload = {
- allowedCurrencies: validCurrencies
- };
-
- console.log('🔵 Update Allowed Currencies Payload:', JSON.stringify(payload, null, 2));
- console.log('🔵 Issuer ID:', issuerId);
- console.log('🔵 Valid currencies count:', validCurrencies.length);
- console.log('🔵 Currencies with allowed=true:', validCurrencies.filter(c => c.allowed).length);
- console.log('🔵 Currencies with allowed=false:', validCurrencies.filter(c => !c.allowed).length);
- console.log('🔵 Duplicate check - unique currency codes:', [...currencyMap.keys()]);
-
- try {
- const res = await api.put(`/api/v1/Issuer/${encodeURIComponent(issuerId)}/AllowedCurrencies`, payload, {
- skipAuthRedirect: true
- });
- console.log('🟢 Allowed Currencies Update Response:', res?.data);
- return res?.data;
- } catch (err) {
- console.error('🔴 Allowed Currencies update error:', {
- status: err?.response?.status,
- statusText: err?.response?.statusText,
- data: err?.response?.data,
- errors: err?.response?.data?.errors,
- message: err?.response?.data?.message,
- code: err?.response?.data?.code,
- payload: payload
- });
- console.error('🔴 Full error.response:', err?.response);
- if (err?.response?.data) {
- try {
- console.error('🔴 Error response data stringified:', JSON.stringify(err?.response?.data, null, 2));
- } catch (e) {
- console.error('🔴 Error response data (could not stringify):', err?.response?.data);
- console.error('🔴 Error response data toString:', String(err?.response?.data));
- }
- }
- throw err;
- }
- },
-
- // ========== TopUpAgentManagement API ==========
-
- // GET /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement
- async getTopUpAgentManagement(issuerId) {
- try {
- const res = await api.get(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement`, {
- skipAuthRedirect: true
- });
- return res?.data?.data || { maxAgents: 0, isActive: false };
- } catch (error) {
- console.error('🔴 TopUpAgentManagement GET error:', error);
- throw error;
- }
- },
-
- // PUT /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement
- async updateTopUpAgentManagement(issuerId, maxAgents) {
- try {
- const payload = { maxAgents: Number(maxAgents) || 0 };
- const res = await api.put(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement`, payload, {
- skipAuthRedirect: true
- });
- return res?.data;
- } catch (error) {
- console.error('🔴 TopUpAgentManagement PUT error:', error);
- throw error;
- }
- },
-
- // GET /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement/Currency
- async getTopUpAgentManagementCurrencies(issuerId) {
- try {
- const res = await api.get(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement/Currency`, {
- skipAuthRedirect: true
- });
- return Array.isArray(res?.data?.data) ? res?.data?.data : [];
- } catch (error) {
- console.error('🔴 TopUpAgentManagement Currencies GET error:', error);
- throw error;
- }
- },
-
- // GET /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement/Currency/{currencyCode}
- async getTopUpAgentManagementCurrency(issuerId, currencyCode) {
- try {
- const res = await api.get(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement/Currency/${encodeURIComponent(currencyCode)}`, {
- skipAuthRedirect: true
- });
- return res?.data?.data || null;
- } catch (error) {
- console.error('🔴 TopUpAgentManagement Currency GET error:', error);
- throw error;
- }
- },
-
- // POST /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement/Currency/{currencyCode}
- async createTopUpAgentManagementCurrency(issuerId, currencyCode, currencyData) {
- try {
- const payload = {
- voucherGeneratingFee: {
- percent: Number(currencyData.voucherGeneratingFee?.percent) || 0,
- fixed: Number(currencyData.voucherGeneratingFee?.fixed) || 0,
- minAmount: Number(currencyData.voucherGeneratingFee?.minAmount) || 0,
- maxAmount: Number(currencyData.voucherGeneratingFee?.maxAmount) || 0
- },
- agentMarketingFee: {
- percent: Number(currencyData.agentMarketingFee?.percent) || 0,
- fixed: Number(currencyData.agentMarketingFee?.fixed) || 0,
- minAmount: Number(currencyData.agentMarketingFee?.minAmount) || 0,
- maxAmount: Number(currencyData.agentMarketingFee?.maxAmount) || 0
- },
- agentWalletMaxBalanceLimit: {
- min: Number(currencyData.agentWalletMaxBalanceLimit?.min) || 0,
- max: Number(currencyData.agentWalletMaxBalanceLimit?.max) || 0
- },
- agentWalletDepositMonthlyLimit: {
- amount: Number(currencyData.agentWalletDepositMonthlyLimit?.amount) || 0
- }
- };
- const res = await api.post(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement/Currency/${encodeURIComponent(currencyCode)}`, payload, {
- skipAuthRedirect: true
- });
- return res?.data;
- } catch (error) {
- console.error('🔴 TopUpAgentManagement Currency POST error:', error);
- throw error;
- }
- },
-
- // PUT /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement/Currency/{currencyCode}
- async updateTopUpAgentManagementCurrency(issuerId, currencyCode, currencyData) {
- try {
- const payload = {
- voucherGeneratingFee: {
- percent: Number(currencyData.voucherGeneratingFee?.percent) || 0,
- fixed: Number(currencyData.voucherGeneratingFee?.fixed) || 0,
- minAmount: Number(currencyData.voucherGeneratingFee?.minAmount) || 0,
- maxAmount: Number(currencyData.voucherGeneratingFee?.maxAmount) || 0
- },
- agentMarketingFee: {
- percent: Number(currencyData.agentMarketingFee?.percent) || 0,
- fixed: Number(currencyData.agentMarketingFee?.fixed) || 0,
- minAmount: Number(currencyData.agentMarketingFee?.minAmount) || 0,
- maxAmount: Number(currencyData.agentMarketingFee?.maxAmount) || 0
- },
- agentWalletMaxBalanceLimit: {
- min: Number(currencyData.agentWalletMaxBalanceLimit?.min) || 0,
- max: Number(currencyData.agentWalletMaxBalanceLimit?.max) || 0
- },
- agentWalletDepositMonthlyLimit: {
- amount: Number(currencyData.agentWalletDepositMonthlyLimit?.amount) || 0
- }
- };
- const res = await api.put(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement/Currency/${encodeURIComponent(currencyCode)}`, payload, {
- skipAuthRedirect: true
- });
- return res?.data;
- } catch (error) {
- console.error('🔴 TopUpAgentManagement Currency PUT error:', error);
- throw error;
- }
- },
-
- // DELETE /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement/Currency/{currencyCode}
- async deleteTopUpAgentManagementCurrency(issuerId, currencyCode) {
- try {
- const res = await api.delete(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement/Currency/${encodeURIComponent(currencyCode)}`, {
- skipAuthRedirect: true
- });
- return res?.data;
- } catch (error) {
- console.error('🔴 TopUpAgentManagement Currency DELETE error:', error);
- throw error;
- }
- },
-
- // ========== TopUpAgentManagement Wallet API ==========
-
- // GET /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement/Currency/{currencyCode}/Wallet/Balance
- async getTopUpAgentManagementWalletBalance(issuerId, currencyCode) {
- try {
- const res = await api.get(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement/Currency/${encodeURIComponent(currencyCode)}/Wallet/Balance`, {
- skipAuthRedirect: true
- });
- return res?.data?.data || null;
- } catch (error) {
- console.error('🔴 TopUpAgentManagement Wallet Balance GET error:', error);
- throw error;
- }
- },
-
- // POST /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement/Currency/{currencyCode}/Wallet/Deposit
- async depositTopUpAgentManagementWallet(issuerId, currencyCode, amount) {
- try {
- const payload = { amount: Number(amount) || 0 };
- const res = await api.post(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement/Currency/${encodeURIComponent(currencyCode)}/Wallet/Deposit`, payload, {
- skipAuthRedirect: true
- });
- return res?.data;
- } catch (error) {
- console.error('🔴 TopUpAgentManagement Wallet Deposit POST error:', error);
- throw error;
- }
- },
-
- // GET /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement/Currency/{currencyCode}/Wallet/Transactions
- async getTopUpAgentManagementWalletTransactions(issuerId, currencyCode) {
- try {
- const res = await api.get(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement/Currency/${encodeURIComponent(currencyCode)}/Wallet/Transactions`, {
- skipAuthRedirect: true
- });
- return Array.isArray(res?.data?.data) ? res?.data?.data : [];
- } catch (error) {
- console.error('🔴 TopUpAgentManagement Wallet Transactions GET error:', error);
- throw error;
- }
- },
-
- // ========== Issuer Admin API ==========
-
- // GET /api/v1/Issuer/{issuerId}/Admin
- async getAdmins(issuerId) {
- try {
- const res = await api.get(`/api/v1/Issuer/${encodeURIComponent(issuerId)}/Admin`, {
- skipAuthRedirect: true
- });
- // Response structure: { data: { data: [...], filterSummary: {...} }, statusCode, ... }
- return res?.data?.data?.data || [];
- } catch (error) {
- console.error('🔴 Issuer Admin GET error:', error);
- throw error;
- }
- },
-
- // POST /api/v1/Issuer/{issuerId}/Admin
- async addAdmin(issuerId, adminData) {
- try {
- const res = await api.post(`/api/v1/Issuer/${encodeURIComponent(issuerId)}/Admin`, adminData, {
- skipAuthRedirect: true
- });
- return res?.data;
- } catch (error) {
- console.error('🔴 Issuer Admin POST error:', error);
- throw error;
- }
- }
-};
-
diff --git a/src/services/paymentsAPI.js b/src/services/paymentsAPI.js
index 93b25a8b..ced62c47 100644
--- a/src/services/paymentsAPI.js
+++ b/src/services/paymentsAPI.js
@@ -1,28 +1,44 @@
-// -----------------------------
-// Payments API (mock data)
-// -----------------------------
-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 }
- ]
-};
+import api from './apiClient';
+// -----------------------------
+// Payments API
+// -----------------------------
export const paymentsAPI = {
- async getStats() { return mockData.stats; },
- async getChartData() { return mockData.chartData; },
+ // GET /api/v1/Payments/Stats
+ async getStats() {
+ try {
+ const res = await api.get('/api/v1/Payments/Stats', { skipAuthRedirect: true });
+ // پاسخ ممکن است به صورت { data: {...}, statusCode: 200 } باشد
+ return res?.data?.data || res?.data || {
+ total: 0,
+ success: 0,
+ failed: 0
+ };
+ } catch (error) {
+ console.error('🔴 Payments API - getStats error:', error);
+ // در صورت خطا، دادههای پیشفرض برگردان
+ return {
+ total: 0,
+ success: 0,
+ failed: 0
+ };
+ }
+ },
+
+ // GET /api/v1/Payments/ChartData
+ async getChartData() {
+ try {
+ const res = await api.get('/api/v1/Payments/ChartData', { skipAuthRedirect: true });
+ // پاسخ ممکن است به صورت { data: [...], statusCode: 200 } باشد
+ const data = res?.data?.data || res?.data || [];
+ // اطمینان از اینکه دادهها به فرمت مورد نیاز هستند
+ return Array.isArray(data) ? data : [];
+ } catch (error) {
+ console.error('🔴 Payments API - getChartData error:', error);
+ // در صورت خطا، آرایه خالی برگردان
+ return [];
+ }
+ },
};
+
diff --git a/src/services/provinceAPI.js b/src/services/provinceAPI.js
index a0b48f7e..e1384df1 100644
--- a/src/services/provinceAPI.js
+++ b/src/services/provinceAPI.js
@@ -14,15 +14,11 @@ export const provinceAPI = {
requestParams.countryId = countryId;
}
- console.log('🔵 Province API - list request:', { params: requestParams });
-
const res = await api.get('/api/v1/Province', {
params: requestParams,
skipAuthRedirect: true
});
- console.log('🟢 Province API - list response:', res?.data);
-
// پاسخ به صورت { data: { data: [...], filterSummary: {...} } } است
return res?.data?.data?.data || [];
},
@@ -46,7 +42,6 @@ export const provinceAPI = {
CountryId: province?.countryId || '',
ProvinceName: String(province?.provinceName || '').trim(),
};
- console.log('Province API Update:', { provinceId, payload });
try {
const res = await api.put(`/api/v1/Province/${encodeURIComponent(provinceId)}`, payload, { skipAuthRedirect: true });
return res?.data;
diff --git a/src/services/rolesAPI.js b/src/services/rolesAPI.js
deleted file mode 100644
index 4bd5c37e..00000000
--- a/src/services/rolesAPI.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import api from './apiClient';
-import { useAuthStore } from "../store/authStore";
-
-// -----------------------------
-// Roles API
-// -----------------------------
-const ROLES_STORAGE_KEY = 'app_roles_v1';
-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='') {
- 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: 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 { ensureSeedRoles(); return readRolesFromStorage(); }
- },
-
- async create(role) {
- 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 {}
- }
- const roles = readRolesFromStorage(); const newRole = { id: crypto.randomUUID(), ...created }; roles.push(newRole); writeRolesToStorage(roles); return newRole;
- },
-
- async remove(id) {
- 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 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;
- },
-};
-
diff --git a/src/services/topUpAgentAPI.js b/src/services/topUpAgentAPI.js
new file mode 100644
index 00000000..d7bb280e
--- /dev/null
+++ b/src/services/topUpAgentAPI.js
@@ -0,0 +1,209 @@
+import api from './apiClient';
+
+// -----------------------------
+// TopUpAgent API
+// -----------------------------
+export const topUpAgentAPI = {
+ // GET /api/v1/TopUpAgent (with pagination)
+ async list(params = {}) {
+ const { currentPage = 1, pageSize = 10, ...otherParams } = params;
+ const res = await api.get('/api/v1/TopUpAgent', {
+ params: { currentPage, pageSize, ...otherParams },
+ skipAuthRedirect: true
+ });
+
+ // بررسی ساختار response
+ // ممکن است به صورت { data: { data: { data: [...] } } } باشد
+ // یا { data: { data: [...] } } باشد
+ // یا { data: [...] } باشد
+ if (res?.data?.data?.data) {
+ return Array.isArray(res.data.data.data) ? res.data.data.data : [];
+ }
+ if (res?.data?.data) {
+ return Array.isArray(res.data.data) ? res.data.data : [];
+ }
+ if (res?.data) {
+ return Array.isArray(res.data) ? res.data : [];
+ }
+ return [];
+ },
+
+ // GET /api/v1/TopUpAgent/{topUpAgentId}
+ async getById(topUpAgentId) {
+ try {
+ const res = await api.get(`/api/v1/TopUpAgent/${encodeURIComponent(topUpAgentId)}`, {
+ skipAuthRedirect: true
+ });
+ return res?.data?.data || res?.data;
+ } catch (error) {
+ console.error('🔴 TopUpAgent API - getById error:', error);
+ throw error;
+ }
+ },
+
+ // POST /api/v1/TopUpAgent
+ async create(topUpAgent) {
+ const payload = {
+ name: String(topUpAgent?.name || ''),
+ supportEmail: String(topUpAgent?.supportEmail || ''),
+ cityId: topUpAgent?.cityId || '',
+ postalCode: String(topUpAgent?.postalCode || ''),
+ addressDetails: String(topUpAgent?.addressDetails || ''),
+ };
+ const res = await api.post('/api/v1/TopUpAgent', payload, { skipAuthRedirect: true });
+ return res?.data;
+ },
+
+ // PUT /api/v1/TopUpAgent/{topUpAgentId}
+ async update(topUpAgentId, topUpAgent) {
+ if (!topUpAgentId) {
+ throw new Error('TopUpAgent ID is required');
+ }
+ const payload = {
+ name: String(topUpAgent?.name || '').trim(),
+ supportEmail: String(topUpAgent?.supportEmail || '').trim(),
+ cityId: topUpAgent?.cityId || '',
+ postalCode: String(topUpAgent?.postalCode || '').trim(),
+ addressDetails: String(topUpAgent?.addressDetails || '').trim(),
+ };
+ const url = `/api/v1/TopUpAgent/${encodeURIComponent(topUpAgentId)}`;
+ try {
+ const res = await api.put(url, payload, { skipAuthRedirect: true });
+ return res?.data;
+ } catch (error) {
+ console.error('🔴 TopUpAgent API - update error:', {
+ url,
+ topUpAgentId,
+ payload,
+ error: error?.response?.data || error?.message || error
+ });
+ throw error;
+ }
+ },
+
+ // DELETE /api/v1/TopUpAgent/{topUpAgentId}
+ async remove(topUpAgentId) {
+ try {
+ const res = await api.delete(`/api/v1/TopUpAgent/${encodeURIComponent(topUpAgentId)}`, {
+ skipAuthRedirect: true
+ });
+ return res?.data;
+ } catch (error) {
+ console.error('🔴 TopUpAgent API - remove error:', error);
+ throw error;
+ }
+ },
+
+ // PATCH /api/v1/TopUpAgent/{topUpAgentId}/ToggleActivation
+ async toggleActivation(topUpAgentId) {
+ try {
+ const res = await api.patch(`/api/v1/TopUpAgent/${encodeURIComponent(topUpAgentId)}/ToggleActivation`, null, {
+ skipAuthRedirect: true
+ });
+ return res?.data;
+ } catch (error) {
+ console.error('🔴 TopUpAgent API - toggleActivation error:', error);
+ throw error;
+ }
+ },
+
+ // POST /api/v1/TopUpAgent/{topUpAgentId}/Currency
+ async addCurrency(topUpAgentId, currency) {
+ const payload = {
+ currencyCode: String(currency?.currencyCode || ''),
+ voucherGenerationCommission: Number(currency?.voucherGenerationCommission || 0),
+ };
+ const res = await api.post(`/api/v1/TopUpAgent/${encodeURIComponent(topUpAgentId)}/Currency`, payload, {
+ skipAuthRedirect: true
+ });
+ return res?.data;
+ },
+
+ // GET /api/v1/TopUpAgent/{topUpAgentId}/Currency
+ async getCurrencies(topUpAgentId) {
+ try {
+ const res = await api.get(`/api/v1/TopUpAgent/${encodeURIComponent(topUpAgentId)}/Currency`, {
+ skipAuthRedirect: true
+ });
+ return res?.data?.data || [];
+ } catch (error) {
+ console.error('🔴 TopUpAgent API - getCurrencies error:', error);
+ throw error;
+ }
+ },
+
+ // GET /api/v1/TopUpAgent/{topUpAgentId}/Currency/{currencyCode}
+ async getCurrency(topUpAgentId, currencyCode) {
+ try {
+ const res = await api.get(`/api/v1/TopUpAgent/${encodeURIComponent(topUpAgentId)}/Currency/${encodeURIComponent(currencyCode)}`, {
+ skipAuthRedirect: true
+ });
+ return res?.data?.data || res?.data;
+ } catch (error) {
+ console.error('🔴 TopUpAgent API - getCurrency error:', error);
+ throw error;
+ }
+ },
+
+ // PUT /api/v1/TopUpAgent/{topUpAgentId}/Currency/{currencyCode}
+ async updateCurrency(topUpAgentId, currencyCode, currency) {
+ const payload = {
+ voucherGenerationCommission: Number(currency?.voucherGenerationCommission || 0),
+ };
+ const res = await api.put(`/api/v1/TopUpAgent/${encodeURIComponent(topUpAgentId)}/Currency/${encodeURIComponent(currencyCode)}`, payload, {
+ skipAuthRedirect: true
+ });
+ return res?.data;
+ },
+
+ // DELETE /api/v1/TopUpAgent/{topUpAgentId}/Currency/{currencyCode}
+ async removeCurrency(topUpAgentId, currencyCode) {
+ try {
+ const res = await api.delete(`/api/v1/TopUpAgent/${encodeURIComponent(topUpAgentId)}/Currency/${encodeURIComponent(currencyCode)}`, {
+ skipAuthRedirect: true
+ });
+ return res?.data;
+ } catch (error) {
+ console.error('🔴 TopUpAgent API - removeCurrency error:', error);
+ throw error;
+ }
+ },
+
+ // GET /api/v1/TopUpAgent/{topUpAgentId}/Wallet
+ async getWallet(topUpAgentId) {
+ try {
+ const res = await api.get(`/api/v1/TopUpAgent/${encodeURIComponent(topUpAgentId)}/Wallet`, {
+ skipAuthRedirect: true
+ });
+ return res?.data?.data || res?.data;
+ } catch (error) {
+ console.error('🔴 TopUpAgent API - getWallet error:', error);
+ throw error;
+ }
+ },
+
+ // POST /api/v1/TopUpAgent/{topUpAgentId}/Wallet/{walletId}/Deposit
+ async depositWallet(topUpAgentId, walletId, amount) {
+ const payload = {
+ amount: {
+ amount: Number(amount?.amount || 0),
+ currencyCode: String(amount?.currencyCode || ''),
+ },
+ };
+ const res = await api.post(`/api/v1/TopUpAgent/${encodeURIComponent(topUpAgentId)}/Wallet/${encodeURIComponent(walletId)}/Deposit`, payload, {
+ skipAuthRedirect: true
+ });
+ return res?.data;
+ },
+
+ // GET /api/v1/TopUpAgent/{topUpAgentId}/Wallet/{walletId}/Transaction
+ async getWalletTransactions(topUpAgentId, walletId, params = {}) {
+ const { currentPage = 1, pageSize = 10, ...otherParams } = params;
+ const res = await api.get(`/api/v1/TopUpAgent/${encodeURIComponent(topUpAgentId)}/Wallet/${encodeURIComponent(walletId)}/Transaction`, {
+ params: { currentPage, pageSize, ...otherParams },
+ skipAuthRedirect: true
+ });
+ return res?.data?.data?.data || [];
+ },
+};
+
diff --git a/src/services/usersAPI.js b/src/services/usersAPI.js
deleted file mode 100644
index 6e4abb0e..00000000
--- a/src/services/usersAPI.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import api from './apiClient';
-
-// -----------------------------
-// Users API با رولها
-// -----------------------------
-const USERS_STORAGE_KEY = 'app_users_v1';
-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}={}) {
- try {
- // اطمینان از اینکه params همیشه object است
- const params = {
- searchQuery: searchQuery || '',
- currentPage: currentPage || 1,
- pageSize: pageSize || 100
- };
-
- console.log('🔵 Users API - list request:', {
- url: '/api/v1/User',
- method: 'GET',
- params
- });
-
- const res = await api.get('/api/v1/User',{
- params,
- skipAuthRedirect:true
- });
-
- console.log('🟢 Users API - list response:', res?.data);
-
- return res?.data?.data?.data||[];
- } catch (error) {
- console.error('🔴 Users API - list error:', error);
- console.error('🔴 Error details:', {
- url: error.config?.url,
- method: error.config?.method,
- params: error.config?.params,
- data: error.config?.data,
- response: error.response?.data
- });
- throw error;
- }
- },
- async get(id){
- if (!id) throw new Error('User ID is required');
- const res = await api.get(`/api/v1/User/${encodeURIComponent(id)}`, { skipAuthRedirect: true });
- return res?.data?.data || res?.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 || [];
- } 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.put(`/api/v1/User/${encodeURIComponent(userId)}/Role`,{roleIds},{skipAuthRedirect:true});
- return res?.data;
- } catch(err){
- console.error(err);
- return null;
- }
- },
-};
-
diff --git a/vite.config.js b/vite.config.js
index 76949681..71871893 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -6,9 +6,9 @@ export default defineConfig({
server: {
proxy: {
"/api": {
- target: "https://khalijpay-core.qaserver.ir",
+ target: "https://khalijpay-issuer.qaserver.ir",
changeOrigin: true,
- secure: false,
+ secure: true,
// اجازه ارسال کوکیها
configure: (proxy) => {
proxy.on("proxyReq", (proxyReq, req) => {