diff --git a/et --hard 8e19500 b/et --hard 8e19500 new file mode 100644 index 00000000..d4c85da7 --- /dev/null +++ b/et --hard 8e19500 @@ -0,0 +1,24 @@ +212d1ee (HEAD -> main, origin/main) HEAD@{0}: Branch: renamed refs/heads/clean-main to refs/heads/main +212d1ee (HEAD -> main, origin/main) HEAD@{2}: commit (initial): c initial commit +fd2b653 HEAD@{3}: reset: moving to HEAD~2 +8e19500 HEAD@{4}: commit: feat(TopUpAgent): add , edit, delete , toggle ,... +ecf6574 HEAD@{5}: reset: moving to HEAD~1 +2cebace HEAD@{6}: commit: first commit +ecf6574 HEAD@{7}: commit: feat(Issuer): add admin selection page for issuer +fd2b653 HEAD@{8}: commit: fix(Issuer): correct AllowedCurrencies and Capabilities structure +9d2e2c2 HEAD@{9}: commit: feat(Issuers): add , edit, delete , toggle ,capability and currencies functionality +7cc442b HEAD@{10}: commit: feat(country-province-city): add, edit functionality +77cc753 HEAD@{11}: commit: fix(users): update user role and edit API logic +fc229ca HEAD@{12}: commit: feat(users): add roles page and add, edit, delete , toggle ,reset password functionality +06d430d HEAD@{13}: commit: fix(roles): handle errors properly in edit role API +453cc81 HEAD@{14}: commit: feat(roles): add roles management page with add, edit and delete functionality +5079a5b HEAD@{15}: commit: feat : add signin ,signout, forgot password features +46a1fae HEAD@{16}: rebase (finish): returning to refs/heads/main +46a1fae HEAD@{17}: pull --rebase origin main (pick): move final +43244d4 HEAD@{18}: pull --rebase origin main (start): checkout 43244d4582b5efcbe03c112ce142d32af5d1a87f +247345e HEAD@{19}: commit: test: trigger git hooks refresh +b239399 HEAD@{20}: commit: move final +7633516 HEAD@{21}: pull: Fast-forward +0355898 HEAD@{22}: commit: edit 2 readme +51e9d7e HEAD@{23}: commit: edit readme +d63a5b8 HEAD@{24}: commit (initial): first commit diff --git a/src/pages/Location.jsx b/src/pages/Location.jsx index 658f71b6..35888fda 100644 --- a/src/pages/Location.jsx +++ b/src/pages/Location.jsx @@ -1,6 +1,6 @@ import React, { useEffect, useMemo, useState, useCallback } from 'react'; import DataTable from '../components/DataTable'; -import { countryAPI, provinceAPI, cityAPI, generalAPI } from '../services/api'; +import { countryAPI, provinceAPI, cityAPI } from '../services/api'; import { Plus, Search, Pencil, Trash2, MapPin, Globe, Building2 } from 'lucide-react'; import { ToastContainer, toast } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; @@ -16,8 +16,6 @@ const Location = () => { const [isCountryModalOpen, setIsCountryModalOpen] = useState(false); const [editingCountry, setEditingCountry] = useState(null); const [countryForm, setCountryForm] = useState({ name: '', phoneCode: '', currencyCode: '', timeZoneName: '' }); - const [currencies, setCurrencies] = useState([]); - const [timeZones, setTimeZones] = useState([]); // Province states const [provinces, setProvinces] = useState([]); @@ -41,32 +39,6 @@ const Location = () => { const [selectedProvinceForCity, setSelectedProvinceForCity] = useState(null); const [provincesForCity, setProvincesForCity] = useState([]); - // دریافت ارزها و timezone ها برای dropdown - useEffect(() => { - const fetchCurrencies = async () => { - try { - const list = await generalAPI.getCurrencies(); - setCurrencies(Array.isArray(list) ? list : []); - } catch (err) { - console.error('Failed to load currencies:', err); - toast.error('Failed to load currencies'); - } - }; - - const fetchTimeZones = async () => { - try { - const list = await generalAPI.getTimeZones(); - setTimeZones(Array.isArray(list) ? list : []); - } catch (err) { - console.error('Failed to load timezones:', err); - toast.error('Failed to load timezones'); - } - }; - - fetchCurrencies(); - fetchTimeZones(); - }, []); - // دریافت کشورها const fetchCountries = useCallback(async () => { try { @@ -337,23 +309,6 @@ const Location = () => { // ========== Table Columns ========== const countryColumns = useMemo(() => [ { key: 'name', header: 'Name' }, - { key: 'phoneCode', header: 'Phone Code' }, - { key: 'currencyCode', header: 'Currency' }, - { key: 'timeZone', header: 'Time Zone', render: (val, row) => val || row.timeZoneName || '—' }, - { - key: 'actions', - header: 'Actions', - render: (_val, row) => ( -
- -
- ), - }, ], []); const provinceColumns = useMemo(() => [ @@ -399,9 +354,7 @@ const Location = () => { if (!countryFilter) return countries; const filter = countryFilter.toLowerCase(); return countries.filter(c => - c.name?.toLowerCase().includes(filter) || - c.phoneCode?.toLowerCase().includes(filter) || - c.currencyCode?.toLowerCase().includes(filter) + c.name?.toLowerCase().includes(filter) ); }, [countries, countryFilter]); @@ -484,12 +437,6 @@ const Location = () => { className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500" /> - { )} - {/* Country Modal */} - {isCountryModalOpen && ( - <> -
setIsCountryModalOpen(false)} /> -
-
-

- {editingCountry ? 'Edit Country' : 'Add Country'} -

-
-
- - setCountryForm({ ...countryForm, name: e.target.value })} - className="w-full p-2 border rounded-lg" - required - /> -
-
- - setCountryForm({ ...countryForm, phoneCode: e.target.value })} - className="w-full p-2 border rounded-lg" - required - /> -
-
- - -
-
- - -
-
- - -
-
-
-
- - )} {/* Province Modal */} {isProvinceModalOpen && ( diff --git a/src/services/apiClient.js b/src/services/apiClient.js index 5df862d9..95005a61 100644 --- a/src/services/apiClient.js +++ b/src/services/apiClient.js @@ -103,35 +103,15 @@ api.interceptors.response.use( // اگر errorData خودش یک AxiosError باشد، پیام خطا را از آن استخراج کنیم if (errorData && typeof errorData === 'object' && errorData.name === 'AxiosError') { errorData = { - message: errorData.message || error.message || 'خطا در ارتباط با سرور', + message: errorData.message || error.message, ...(errorData.response?.data || {}) }; } - // اگر errorData وجود نداشت یا خالی است، از status code برای ایجاد پیام مناسب استفاده کنیم + // فقط پیامی که از سرویس می‌آید را استفاده می‌کنیم + // اگر errorData وجود نداشت، از error.response.data اصلی استفاده می‌کنیم if (!errorData || (typeof errorData === 'object' && Object.keys(errorData).length === 0)) { - const status = error.response?.status; - let message = error.message || 'خطا در ارتباط با سرور'; - - // پیام‌های مناسب بر اساس status code - if (status === 500) { - message = 'خطای سرور. لطفاً با پشتیبانی تماس بگیرید یا دوباره تلاش کنید.'; - } else if (status === 400) { - message = 'درخواست نامعتبر. لطفاً اطلاعات را بررسی کنید.'; - } else if (status === 401) { - message = 'نام کاربری یا رمز عبور اشتباه است.'; - } else if (status === 403) { - message = 'شما دسترسی به این بخش را ندارید.'; - } else if (status === 404) { - message = 'منبع مورد نظر یافت نشد.'; - } else if (status === 502 || status === 503) { - message = 'سرور در دسترس نیست. لطفاً بعداً تلاش کنید.'; - } - - errorData = { - message: message, - statusCode: status - }; + errorData = error.response?.data || {}; } if (error.response) { diff --git a/src/services/countryAPI.js b/src/services/countryAPI.js index 6024e818..2686c9c7 100644 --- a/src/services/countryAPI.js +++ b/src/services/countryAPI.js @@ -4,16 +4,6 @@ import api from './apiClient'; // Country API // ----------------------------- export const countryAPI = { - // GET /api/v1/Country (with pagination) - async list(params = {}) { - const { currentPage = 1, pageSize = 10, ...otherParams } = params; - const res = await api.get('/api/v1/Country', { - params: { currentPage, pageSize, ...otherParams }, - skipAuthRedirect: true - }); - return res?.data?.data?.data || []; - }, - // GET /api/v1/Country/All (all countries without pagination) async listAll() { try { @@ -26,61 +16,8 @@ export const countryAPI = { } }, - // POST /api/v1/Country - async create(country) { - const payload = { - Name: String(country?.name || ''), - PhoneCode: String(country?.phoneCode || ''), - CurrencyCode: String(country?.currencyCode || ''), - TimeZone: String(country?.timeZoneName || country?.timeZone || ''), - }; - const res = await api.post('/api/v1/Country', payload, { skipAuthRedirect: true }); - return res?.data; - }, - // PUT /api/v1/Country/{countryId} - async update(countryId, country) { - if (!countryId) { - throw new Error('Country ID is required'); - } - // ساخت payload - سرور در PUT انتظار TimeZoneName دارد (نه TimeZone) - const payload = { - Name: country?.name ? String(country.name).trim() : '', - PhoneCode: country?.phoneCode ? String(country.phoneCode).trim() : '', - CurrencyCode: country?.currencyCode ? String(country.currencyCode).trim() : '', - TimeZoneName: country?.timeZoneName || country?.timeZone ? String((country.timeZoneName || country.timeZone).trim()) : '', - }; - - const url = `/api/v1/Country/${encodeURIComponent(countryId)}`; - - try { - const res = await api.put(url, payload, { skipAuthRedirect: true }); - return res?.data; - } catch (error) { - console.error('🔴 Country API - update error:', { - url, - countryId, - payload, - error: error?.response?.data || error?.message || error - }); - throw error; - } - }, - // POST /api/v1/Country/{countryId}/Province - async createProvince(countryId, province) { - const payload = { - CountryId: countryId, - ProvinceName: String(province?.provinceName || ''), - }; - const res = await api.post(`/api/v1/Country/${encodeURIComponent(countryId)}/Province`, payload, { skipAuthRedirect: true }); - return res?.data; - }, - // GET /api/v1/Country/{countryId}/Province - async getProvinces(countryId) { - const res = await api.get(`/api/v1/Country/${encodeURIComponent(countryId)}/Province`, { skipAuthRedirect: true }); - return res?.data?.data || []; - }, }; diff --git a/src/services/generalAPI.js b/src/services/generalAPI.js index 5bdf8939..3911f5f9 100644 --- a/src/services/generalAPI.js +++ b/src/services/generalAPI.js @@ -4,41 +4,12 @@ import api from './apiClient'; // General API // ----------------------------- export const generalAPI = { - // GET /api/v1/General/Currencies - async getCurrencies() { - try { - const res = await api.get('/api/v1/General/Currencies', { skipAuthRedirect: true }); - // پاسخ به صورت array مستقیم است - return Array.isArray(res?.data) ? res?.data : []; - } catch (error) { - console.error('🔴 General API - getCurrencies error:', error); - throw error; - } - }, - // GET /api/v1/General/TimeZones - async getTimeZones() { - try { - const res = await api.get('/api/v1/General/TimeZones', { skipAuthRedirect: true }); - // پاسخ به صورت { data: [...], statusCode: 200, ... } است - return res?.data?.data || []; - } catch (error) { - console.error('🔴 General API - getTimeZones error:', error); - throw error; - } - }, + - // GET /api/v1/General/IssuerCapabilities - async getIssuerCapabilities() { - try { - const res = await api.get('/api/v1/General/IssuerCapabilities', { skipAuthRedirect: true }); - // پاسخ به صورت { data: [...], statusCode: 200, ... } است - return res?.data?.data || []; - } catch (error) { - console.error('🔴 General API - getIssuerCapabilities error:', error); - throw error; - } - }, + + + // GET /api/v1/General/SearchUsersByEmail async searchUsersByEmail(email) {