Initial commit: admin dashboard for GameNo.
Vue 3 + Vite dashboard with PrimeVue, i18n, and API integration for institution management.
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
// /src/api/activityLogApi.js
|
||||
import axiosInstance from './axiosInstance';
|
||||
|
||||
export const activityLogApi = {
|
||||
getAll: (params) => axiosInstance.get('/activity-logs/admin/get-all', { params }),
|
||||
getActions: () => axiosInstance.get('/activity-logs/admin/actions')
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
// /src/api/attendanceApi.js
|
||||
import axiosInstance from './axiosInstance';
|
||||
|
||||
export const attendanceApi = {
|
||||
recordSessionAttendance: (sessionId, attendanceList) =>
|
||||
axiosInstance.put(`/sessions/admin/${sessionId}/attendance`, { attendanceList }),
|
||||
getSessionAttendance: (sessionId) => axiosInstance.get(`/sessions/admin/get-one/${sessionId}`)
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
// /src/api/authApi.js
|
||||
import axiosInstance from './axiosInstance';
|
||||
|
||||
export const authApi = {
|
||||
login: (data) => axiosInstance.post('/auth/login', data),
|
||||
refresh: (refreshToken) => axiosInstance.post('/auth/refresh', { refreshToken }),
|
||||
logout: (refreshToken) => axiosInstance.post('/auth/logout', { refreshToken }),
|
||||
getSelf: () => axiosInstance.get('/users/user/get-self')
|
||||
};
|
||||
@@ -0,0 +1,121 @@
|
||||
// /src/api/axiosInstance.js
|
||||
import axios from 'axios';
|
||||
import Cookies from 'js-cookie';
|
||||
|
||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:5000/api';
|
||||
|
||||
const axiosInstance = axios.create({
|
||||
baseURL: API_BASE_URL,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
timeout: 15000
|
||||
});
|
||||
|
||||
// Request interceptor: attach token
|
||||
axiosInstance.interceptors.request.use(
|
||||
(config) => {
|
||||
const token = localStorage.getItem('accessToken') || Cookies.get('accessToken');
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
// Ask backend for Persian (or stored) localized error messages
|
||||
const lang = localStorage.getItem('lang') || 'fa';
|
||||
config.headers['Accept-Language'] = lang;
|
||||
if (!config.params) config.params = {};
|
||||
if (config.params.lang == null) {
|
||||
config.params.lang = lang;
|
||||
}
|
||||
|
||||
return config;
|
||||
},
|
||||
(error) => Promise.reject(error)
|
||||
);
|
||||
|
||||
// Response interceptor: auto-refresh token on 401
|
||||
let isRefreshing = false;
|
||||
let failedQueue = [];
|
||||
|
||||
const processQueue = (error, token = null) => {
|
||||
failedQueue.forEach(prom => {
|
||||
if (error) {
|
||||
prom.reject(error);
|
||||
} else {
|
||||
prom.resolve(token);
|
||||
}
|
||||
});
|
||||
failedQueue = [];
|
||||
};
|
||||
|
||||
axiosInstance.interceptors.response.use(
|
||||
(response) => response.data,
|
||||
async (error) => {
|
||||
const originalRequest = error.config;
|
||||
|
||||
if (error.response?.status === 401 && !originalRequest._retry) {
|
||||
if (originalRequest.url.includes('/auth/login') || originalRequest.url.includes('/auth/refresh')) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
if (isRefreshing) {
|
||||
return new Promise((resolve, reject) => {
|
||||
failedQueue.push({ resolve, reject });
|
||||
})
|
||||
.then((token) => {
|
||||
originalRequest.headers.Authorization = `Bearer ${token}`;
|
||||
return axiosInstance(originalRequest);
|
||||
})
|
||||
.catch((err) => Promise.reject(err));
|
||||
}
|
||||
|
||||
originalRequest._retry = true;
|
||||
isRefreshing = true;
|
||||
|
||||
const refreshToken = localStorage.getItem('refreshToken') || Cookies.get('refreshToken');
|
||||
|
||||
if (!refreshToken) {
|
||||
isRefreshing = false;
|
||||
localStorage.removeItem('accessToken');
|
||||
localStorage.removeItem('refreshToken');
|
||||
window.location.href = '/login';
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
try {
|
||||
const refreshResponse = await axios.post(`${API_BASE_URL}/auth/refresh`, { refreshToken });
|
||||
const data = refreshResponse.data?.data || refreshResponse.data;
|
||||
const newAccessToken = data.accessToken;
|
||||
const newRefreshToken = data.refreshToken;
|
||||
|
||||
localStorage.setItem('accessToken', newAccessToken);
|
||||
Cookies.set('accessToken', newAccessToken);
|
||||
if (newRefreshToken) {
|
||||
localStorage.setItem('refreshToken', newRefreshToken);
|
||||
Cookies.set('refreshToken', newRefreshToken);
|
||||
}
|
||||
|
||||
axiosInstance.defaults.headers.common.Authorization = `Bearer ${newAccessToken}`;
|
||||
originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
|
||||
|
||||
processQueue(null, newAccessToken);
|
||||
return axiosInstance(originalRequest);
|
||||
} catch (refreshErr) {
|
||||
processQueue(refreshErr, null);
|
||||
localStorage.removeItem('accessToken');
|
||||
localStorage.removeItem('refreshToken');
|
||||
Cookies.remove('accessToken');
|
||||
Cookies.remove('refreshToken');
|
||||
window.location.href = '/login';
|
||||
return Promise.reject(refreshErr);
|
||||
} finally {
|
||||
isRefreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default axiosInstance;
|
||||
@@ -0,0 +1,16 @@
|
||||
// /src/api/certificateApi.js
|
||||
import axiosInstance from './axiosInstance';
|
||||
|
||||
export const certificateApi = {
|
||||
getAll: (params) => axiosInstance.get('/certificates/admin/get-all', { params }),
|
||||
search: (params) => axiosInstance.get('/certificates/admin/search', { params }),
|
||||
getOne: (id) => axiosInstance.get(`/certificates/admin/get-one/${id}`),
|
||||
create: (data) => axiosInstance.post('/certificates/admin/create', data),
|
||||
update: (id, data) => axiosInstance.put(`/certificates/admin/update/${id}`, data),
|
||||
delete: (id) => axiosInstance.delete(`/certificates/admin/delete/${id}`),
|
||||
uploadTemp: (formData) => axiosInstance.post('/files/admin/upload-temp', formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' }
|
||||
}),
|
||||
userUpload: (data) => axiosInstance.post('/certificates/user/upload', data),
|
||||
getUserCertificates: () => axiosInstance.get('/certificates/user/my-certificates')
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
// /src/api/classApi.js
|
||||
import axiosInstance from './axiosInstance';
|
||||
|
||||
export const classApi = {
|
||||
getAll: (params) => axiosInstance.get('/classes/admin/get-all', { params }),
|
||||
search: (params) => axiosInstance.get('/classes/admin/search', { params }),
|
||||
getOne: (id) => axiosInstance.get(`/classes/admin/get-one/${id}`),
|
||||
create: (data) => axiosInstance.post('/classes/admin/create', data),
|
||||
update: (id, data) => axiosInstance.put(`/classes/admin/update/${id}`, data),
|
||||
delete: (id) => axiosInstance.delete(`/classes/admin/delete/${id}`),
|
||||
registerUsers: (classId, userIds) => axiosInstance.post(`/classes/admin/${classId}/register-users`, { userIds })
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
import axiosInstance from './axiosInstance';
|
||||
|
||||
export const contactInquiryApi = {
|
||||
getAll: (params) => axiosInstance.get('/contact-inquiries/admin/get-all', { params }),
|
||||
getOne: (id) => axiosInstance.get(`/contact-inquiries/admin/get-one/${id}`),
|
||||
update: (id, data) => axiosInstance.put(`/contact-inquiries/admin/update/${id}`, data)
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
// /src/api/courseApi.js
|
||||
import axiosInstance from './axiosInstance';
|
||||
|
||||
export const courseApi = {
|
||||
getAll: (params) => axiosInstance.get('/courses/admin/get-all', { params }),
|
||||
search: (params) => axiosInstance.get('/courses/admin/search', { params }),
|
||||
getOne: (id) => axiosInstance.get(`/courses/admin/get-one/${id}`),
|
||||
create: (data) => axiosInstance.post('/courses/admin/create', data),
|
||||
update: (id, data) => axiosInstance.put(`/courses/admin/update/${id}`, data),
|
||||
delete: (id) => axiosInstance.delete(`/courses/admin/delete/${id}`)
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
// /src/api/dashboardApi.js
|
||||
import axiosInstance from './axiosInstance';
|
||||
|
||||
export const dashboardApi = {
|
||||
getStats: () => axiosInstance.get('/dashboard/admin/stats')
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
// /src/api/notificationApi.js
|
||||
import axiosInstance from './axiosInstance';
|
||||
|
||||
export const notificationApi = {
|
||||
getAll: (params) => axiosInstance.get('/notifications/admin/get-all', { params }),
|
||||
search: (params) => axiosInstance.get('/notifications/admin/search', { params }),
|
||||
getOne: (id) => axiosInstance.get(`/notifications/admin/get-one/${id}`),
|
||||
create: (data) => axiosInstance.post('/notifications/admin/create', data),
|
||||
update: (id, data) => axiosInstance.put(`/notifications/admin/update/${id}`, data),
|
||||
delete: (id) => axiosInstance.delete(`/notifications/admin/delete/${id}`),
|
||||
retry: (id) => axiosInstance.post(`/notifications/admin/${id}/retry`)
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
// /src/api/paymentApi.js
|
||||
import axiosInstance from './axiosInstance';
|
||||
|
||||
export const paymentApi = {
|
||||
getAll: (params) => axiosInstance.get('/payments/admin/get-all', { params }),
|
||||
search: (params) => axiosInstance.get('/payments/admin/search', { params }),
|
||||
getOne: (id) => axiosInstance.get(`/payments/admin/get-one/${id}`),
|
||||
create: (data) => axiosInstance.post('/payments/admin/create', data),
|
||||
update: (id, data) => axiosInstance.put(`/payments/admin/update/${id}`, data),
|
||||
delete: (id) => axiosInstance.delete(`/payments/admin/delete/${id}`),
|
||||
recordTransaction: (paymentId, data) => axiosInstance.post(`/payments/user/pay/${paymentId}`, data)
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
// /src/api/professorApi.js
|
||||
import axiosInstance from './axiosInstance';
|
||||
|
||||
export const professorApi = {
|
||||
getAll: (params) => axiosInstance.get('/professors/admin/get-all', { params }),
|
||||
search: (params) => axiosInstance.get('/professors/admin/search', { params }),
|
||||
getOne: (id) => axiosInstance.get(`/professors/admin/get-one/${id}`),
|
||||
create: (data) => axiosInstance.post('/professors/admin/create', data),
|
||||
update: (id, data) => axiosInstance.put(`/professors/admin/update/${id}`, data),
|
||||
delete: (id) => axiosInstance.delete(`/professors/admin/delete/${id}`)
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
// /src/api/roleApi.js
|
||||
import axiosInstance from './axiosInstance';
|
||||
|
||||
export const roleApi = {
|
||||
getAll: (params) => axiosInstance.get('/roles/admin/get-all', { params }),
|
||||
search: (params) => axiosInstance.get('/roles/admin/search', { params }),
|
||||
getOne: (id) => axiosInstance.get(`/roles/admin/get-one/${id}`),
|
||||
create: (data) => axiosInstance.post('/roles/admin/create', data),
|
||||
update: (id, data) => axiosInstance.put(`/roles/admin/update/${id}`, data),
|
||||
delete: (id) => axiosInstance.delete(`/roles/admin/delete/${id}`)
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
// /src/api/sessionApi.js
|
||||
import axiosInstance from './axiosInstance';
|
||||
|
||||
export const sessionApi = {
|
||||
getAll: (params) => axiosInstance.get('/sessions/admin/get-all', { params }),
|
||||
search: (params) => axiosInstance.get('/sessions/admin/search', { params }),
|
||||
getOne: (id) => axiosInstance.get(`/sessions/admin/get-one/${id}`),
|
||||
create: (data) => axiosInstance.post('/sessions/admin/create', data),
|
||||
update: (id, data) => axiosInstance.put(`/sessions/admin/update/${id}`, data),
|
||||
delete: (id) => axiosInstance.delete(`/sessions/admin/delete/${id}`),
|
||||
bulkDelete: (ids) => axiosInstance.post('/sessions/admin/bulk-delete', { ids }),
|
||||
bulkUpdateStatus: (ids, status) => axiosInstance.post('/sessions/admin/bulk-status', { ids, status }),
|
||||
recordAttendance: (sessionId, data) => axiosInstance.put(`/sessions/admin/${sessionId}/attendance`, data)
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
// /src/api/userApi.js
|
||||
import axiosInstance from './axiosInstance';
|
||||
|
||||
export const userApi = {
|
||||
getAll: (params) => axiosInstance.get('/users/admin/get-all', { params }),
|
||||
search: (params) => axiosInstance.get('/users/admin/search', { params }),
|
||||
getOne: (id) => axiosInstance.get(`/users/admin/get-one/${id}`),
|
||||
create: (data) => axiosInstance.post('/users/admin/create', data),
|
||||
update: (id, data) => axiosInstance.put(`/users/admin/update/${id}`, data),
|
||||
delete: (id) => axiosInstance.delete(`/users/admin/delete/${id}`),
|
||||
enroll: (userId, data) => axiosInstance.post(`/users/admin/${userId}/enroll`, data)
|
||||
};
|
||||
Reference in New Issue
Block a user