fix
This commit is contained in:
parent
bfa3d44146
commit
1ed7334995
6 changed files with 1324 additions and 18 deletions
1281
mnemo_cards_admin/web/package-lock.json
generated
1281
mnemo_cards_admin/web/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -7,7 +7,8 @@
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc -b && vite build",
|
"build": "tsc -b && vite build",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview",
|
||||||
|
"test": "vitest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^5.2.2",
|
"@hookform/resolvers": "^5.2.2",
|
||||||
|
|
@ -39,6 +40,8 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.39.1",
|
"@eslint/js": "^9.39.1",
|
||||||
|
"@testing-library/jest-dom": "^6.9.1",
|
||||||
|
"@testing-library/react": "^16.3.0",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^24.10.1",
|
||||||
"@types/react": "^19.2.5",
|
"@types/react": "^19.2.5",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
|
|
@ -47,8 +50,10 @@
|
||||||
"eslint-plugin-react-hooks": "^7.0.1",
|
"eslint-plugin-react-hooks": "^7.0.1",
|
||||||
"eslint-plugin-react-refresh": "^0.4.24",
|
"eslint-plugin-react-refresh": "^0.4.24",
|
||||||
"globals": "^16.5.0",
|
"globals": "^16.5.0",
|
||||||
|
"jsdom": "^27.0.1",
|
||||||
"typescript": "~5.9.3",
|
"typescript": "~5.9.3",
|
||||||
"typescript-eslint": "^8.46.4",
|
"typescript-eslint": "^8.46.4",
|
||||||
"vite": "^7.2.4"
|
"vite": "^7.2.4",
|
||||||
|
"vitest": "^3.2.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
import { apiClient } from './client'
|
import { adminApiClient } from './client'
|
||||||
import type { AuthResponse } from '@/types/models'
|
import type { AuthResponse } from '@/types/models'
|
||||||
|
|
||||||
export const authApi = {
|
export const authApi = {
|
||||||
// Request authentication code to be sent to all admin Telegram accounts
|
// Request authentication code to be sent to all admin Telegram accounts
|
||||||
requestCode: async (): Promise<{ success: boolean; message: string }> => {
|
requestCode: async (): Promise<{ success: boolean; message: string }> => {
|
||||||
const response = await apiClient.post('/api/v2/admin/auth/request-code')
|
const response = await adminApiClient.post('/api/v2/admin/auth/request-code')
|
||||||
return response.data
|
return response.data
|
||||||
},
|
},
|
||||||
|
|
||||||
// Verify authentication code
|
// Verify authentication code
|
||||||
verifyCode: async (code: string): Promise<AuthResponse> => {
|
verifyCode: async (code: string): Promise<AuthResponse> => {
|
||||||
const response = await apiClient.post('/api/v2/admin/auth/verify-code', {
|
const response = await adminApiClient.post('/api/v2/admin/auth/verify-code', {
|
||||||
code,
|
code,
|
||||||
})
|
})
|
||||||
return response.data
|
return response.data
|
||||||
|
|
@ -18,7 +18,7 @@ export const authApi = {
|
||||||
|
|
||||||
// Get current admin info (for token validation)
|
// Get current admin info (for token validation)
|
||||||
getCurrentUser: async (): Promise<any> => {
|
getCurrentUser: async (): Promise<any> => {
|
||||||
const response = await apiClient.get('/api/v2/admin/auth/me')
|
const response = await adminApiClient.get('/api/v2/admin/auth/me')
|
||||||
return response.data
|
return response.data
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,10 @@ import axios from 'axios'
|
||||||
|
|
||||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'https://api.mnemo-cards.online'
|
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'https://api.mnemo-cards.online'
|
||||||
|
|
||||||
|
// Admin API always uses production backend (admin auth requires production server)
|
||||||
|
const ADMIN_API_BASE_URL = 'https://api.mnemo-cards.online'
|
||||||
|
|
||||||
|
// Regular API client for non-admin endpoints
|
||||||
export const apiClient = axios.create({
|
export const apiClient = axios.create({
|
||||||
baseURL: API_BASE_URL,
|
baseURL: API_BASE_URL,
|
||||||
headers: {
|
headers: {
|
||||||
|
|
@ -9,23 +13,35 @@ export const apiClient = axios.create({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Admin API client - always uses production backend
|
||||||
|
export const adminApiClient = axios.create({
|
||||||
|
baseURL: ADMIN_API_BASE_URL,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
// Request interceptor to add auth token
|
// Request interceptor to add auth token
|
||||||
apiClient.interceptors.request.use((config) => {
|
const addAuthToken = (config: any) => {
|
||||||
const token = localStorage.getItem('admin_token')
|
const token = localStorage.getItem('admin_token')
|
||||||
if (token) {
|
if (token) {
|
||||||
config.headers.Authorization = `Bearer ${token}`
|
config.headers.Authorization = `Bearer ${token}`
|
||||||
}
|
}
|
||||||
return config
|
return config
|
||||||
})
|
}
|
||||||
|
|
||||||
// Response interceptor for error handling
|
// Response interceptor for error handling
|
||||||
apiClient.interceptors.response.use(
|
const handleAuthError = (error: any) => {
|
||||||
(response) => response,
|
if (error.response?.status === 401) {
|
||||||
(error) => {
|
localStorage.removeItem('admin_token')
|
||||||
if (error.response?.status === 401) {
|
window.location.href = '/login'
|
||||||
localStorage.removeItem('admin_token')
|
|
||||||
window.location.href = '/login'
|
|
||||||
}
|
|
||||||
return Promise.reject(error)
|
|
||||||
}
|
}
|
||||||
)
|
return Promise.reject(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply interceptors to both clients
|
||||||
|
apiClient.interceptors.request.use(addAuthToken)
|
||||||
|
apiClient.interceptors.response.use((response) => response, handleAuthError)
|
||||||
|
|
||||||
|
adminApiClient.interceptors.request.use(addAuthToken)
|
||||||
|
adminApiClient.interceptors.response.use((response) => response, handleAuthError)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
/// <reference types="vitest" />
|
||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import react from '@vitejs/plugin-react'
|
import react from '@vitejs/plugin-react'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
|
@ -10,4 +11,9 @@ export default defineConfig({
|
||||||
"@": path.resolve(__dirname, "./src"),
|
"@": path.resolve(__dirname, "./src"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
test: {
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
setupFiles: './src/test/setup.ts',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Binary file not shown.
Loading…
Reference in a new issue