first commit
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
import { http } from '@/services/api/http'
|
||||
import { buildUrl, endpoints } from '@/services/api/endpoints'
|
||||
|
||||
export const apiGetAdminAssignments = (params) => http.get(endpoints.getAssignmentsList, { params })
|
||||
|
||||
export const apiShowAdminAssignment = (id) => http.get(buildUrl(endpoints.showAssignment, { id }))
|
||||
|
||||
export const apiAddAdminAssignment = (payload) => http.post(endpoints.addNewAssignment, payload)
|
||||
|
||||
export const apiUpdateAdminAssignment = (id, payload) =>
|
||||
http.put(buildUrl(endpoints.updateAssignment, { id }), payload)
|
||||
|
||||
export const apiDeleteAdminAssignment = (id) =>
|
||||
http.delete(buildUrl(endpoints.deleteAssignment, { id }))
|
||||
|
||||
export const apiGetAdminAssignmentSubmissions = (assignmentId, params) =>
|
||||
http.get(buildUrl(endpoints.getAssignmentSubmissions, { assignmentId }), { params })
|
||||
|
||||
export const apiShowAdminAssignmentSubmission = (assignmentId, submissionId) =>
|
||||
http.get(buildUrl(endpoints.showAssignmentSubmission, { assignmentId, submissionId }))
|
||||
|
||||
export const apiReviewAdminAssignmentSubmission = (assignmentId, submissionId, payload) =>
|
||||
http.post(buildUrl(endpoints.reviewAssignmentSubmission, { assignmentId, submissionId }), payload)
|
||||
@@ -0,0 +1,14 @@
|
||||
import { http } from '@/services/api/http'
|
||||
import { buildUrl, endpoints } from '@/services/api/endpoints'
|
||||
|
||||
export const apiGetAdminConsultations = (params) =>
|
||||
http.get(endpoints.getConsultationsList, { params })
|
||||
|
||||
export const apiShowAdminConsultation = (id) =>
|
||||
http.get(buildUrl(endpoints.showConsultation, { id }))
|
||||
|
||||
export const apiSendAdminConsultationMessage = (id, payload) =>
|
||||
http.post(buildUrl(endpoints.sendConsultationMessage, { id }), payload)
|
||||
|
||||
export const apiChangeAdminConsultationStatus = (id, payload) =>
|
||||
http.post(buildUrl(endpoints.changeConsultationStatus, { id }), payload)
|
||||
@@ -0,0 +1,38 @@
|
||||
import { http } from '@/services/api/http'
|
||||
import { buildUrl, endpoints } from '@/services/api/endpoints'
|
||||
|
||||
export const apiGetAdminCourseTemplates = (params) =>
|
||||
http.get(endpoints.getCourseTemplatesList, { params })
|
||||
|
||||
export const apiShowAdminCourseTemplate = (id) =>
|
||||
http.get(buildUrl(endpoints.showCourseTemplate, { id }))
|
||||
|
||||
export const apiAddAdminCourseTemplate = (payload) =>
|
||||
http.post(endpoints.addNewCourseTemplate, payload)
|
||||
|
||||
export const apiUpdateAdminCourseTemplate = (id, payload) =>
|
||||
http.put(buildUrl(endpoints.updateCourseTemplate, { id }), payload)
|
||||
|
||||
export const apiDeleteAdminCourseTemplate = (id) =>
|
||||
http.delete(buildUrl(endpoints.deleteCourseTemplate, { id }))
|
||||
|
||||
export const apiChangeAdminCourseTemplateStatus = (id, payload) =>
|
||||
http.post(buildUrl(endpoints.changeStatusCourseTemplate, { id }), payload)
|
||||
|
||||
export const apiGetAdminTemplateStudents = (templateId, params) =>
|
||||
http.get(buildUrl(endpoints.listTemplateStudents, { templateId }), { params })
|
||||
|
||||
export const apiAddAdminTemplateStudent = (templateId, payload) =>
|
||||
http.post(buildUrl(endpoints.addTemplateStudent, { templateId }), payload)
|
||||
|
||||
export const apiRemoveAdminTemplateStudent = (templateId, userId) =>
|
||||
http.delete(buildUrl(endpoints.removeTemplateStudent, { templateId, userId }))
|
||||
|
||||
export const apiGetAdminTemplateSessions = (templateId, params) =>
|
||||
http.get(buildUrl(endpoints.listTemplateSessions, { templateId }), { params })
|
||||
|
||||
export const apiAttachAdminTemplateSession = (templateId, payload) =>
|
||||
http.post(buildUrl(endpoints.attachTemplateSession, { templateId }), payload)
|
||||
|
||||
export const apiDetachAdminTemplateSession = (templateId, sessionId) =>
|
||||
http.delete(buildUrl(endpoints.detachTemplateSession, { templateId, sessionId }))
|
||||
@@ -0,0 +1,16 @@
|
||||
import { http } from '@/services/api/http'
|
||||
import { buildUrl, endpoints } from '@/services/api/endpoints'
|
||||
|
||||
export const apiGetAdminCourses = (params) => http.get(endpoints.getCoursesList, { params })
|
||||
|
||||
export const apiShowAdminCourse = (id) => http.get(buildUrl(endpoints.showCourse, { id }))
|
||||
|
||||
export const apiAddAdminCourse = (payload) => http.post(endpoints.addNewCourse, payload)
|
||||
|
||||
export const apiUpdateAdminCourse = (id, payload) =>
|
||||
http.put(buildUrl(endpoints.updateCourse, { id }), payload)
|
||||
|
||||
export const apiDeleteAdminCourse = (id) => http.delete(buildUrl(endpoints.deleteCourse, { id }))
|
||||
|
||||
export const apiChangeAdminCourseStatus = (id, payload) =>
|
||||
http.post(buildUrl(endpoints.changeStatusCourse, { id }), payload)
|
||||
@@ -0,0 +1,19 @@
|
||||
import { http } from '@/services/api/http'
|
||||
import { buildUrl, endpoints } from '@/services/api/endpoints'
|
||||
|
||||
export const apiGetAdminExams = (params) => http.get(endpoints.getExamsList, { params })
|
||||
|
||||
export const apiShowAdminExam = (id) => http.get(buildUrl(endpoints.showExam, { id }))
|
||||
|
||||
export const apiAddAdminExam = (payload) => http.post(endpoints.addNewExam, payload)
|
||||
|
||||
export const apiUpdateAdminExam = (id, payload) =>
|
||||
http.put(buildUrl(endpoints.updateExam, { id }), payload)
|
||||
|
||||
export const apiDeleteAdminExam = (id) => http.delete(buildUrl(endpoints.deleteExam, { id }))
|
||||
|
||||
export const apiGetAdminExamParticipants = (examId, params) =>
|
||||
http.get(buildUrl(endpoints.getExamParticipants, { examId }), { params })
|
||||
|
||||
export const apiShowAdminExamParticipant = (examId, participantId) =>
|
||||
http.get(buildUrl(endpoints.showExamParticipant, { examId, participantId }))
|
||||
@@ -0,0 +1,13 @@
|
||||
import { http } from '@/services/api/http'
|
||||
import { buildUrl, endpoints } from '@/services/api/endpoints'
|
||||
|
||||
export const apiGetPendingStudents = (params) => http.get(endpoints.getPendingStudents, { params })
|
||||
|
||||
export const apiShowPendingStudent = (id) =>
|
||||
http.get(buildUrl(endpoints.showPendingStudent, { id }))
|
||||
|
||||
export const apiChangePendingStudentStatus = (id, payload) =>
|
||||
http.post(buildUrl(endpoints.changeStatusPendingStudent, { id }), payload)
|
||||
|
||||
export const apiDownloadPendingStudentPdf = (id) =>
|
||||
http.get(buildUrl(endpoints.downloadPdfPendingStudentInfo, { id }))
|
||||
@@ -0,0 +1,19 @@
|
||||
import { http } from '@/services/api/http'
|
||||
import { buildUrl, endpoints } from '@/services/api/endpoints'
|
||||
|
||||
export const apiGetAdminSessions = (params) => http.get(endpoints.getSessionsList, { params })
|
||||
|
||||
export const apiShowAdminSession = (id) => http.get(buildUrl(endpoints.showSession, { id }))
|
||||
|
||||
export const apiAddAdminSession = (payload) => http.post(endpoints.addNewSession, payload)
|
||||
|
||||
export const apiUpdateAdminSession = (id, payload) =>
|
||||
http.put(buildUrl(endpoints.updateSession, { id }), payload)
|
||||
|
||||
export const apiDeleteAdminSession = (id) => http.delete(buildUrl(endpoints.deleteSession, { id }))
|
||||
|
||||
export const apiChangeAdminSessionStatus = (id, payload) =>
|
||||
http.post(buildUrl(endpoints.changeStatusSession, { id }), payload)
|
||||
|
||||
export const apiGetSessionAttendance = (sessionId, params) =>
|
||||
http.get(buildUrl(endpoints.getSessionsAttendance, { sessionId }), { params })
|
||||
@@ -0,0 +1,39 @@
|
||||
import { http } from '@/services/api/http'
|
||||
import { buildUrl, endpoints } from '@/services/api/endpoints'
|
||||
|
||||
export const apiGetAdminTerms = (params) => http.get(endpoints.getTermsList, { params })
|
||||
|
||||
export const apiShowAdminTerm = (id) => http.get(buildUrl(endpoints.showTerm, { id }))
|
||||
|
||||
export const apiAddAdminTerm = (payload) => http.post(endpoints.addNewTerm, payload)
|
||||
|
||||
export const apiUpdateAdminTerm = (id, payload) =>
|
||||
http.put(buildUrl(endpoints.updateTerm, { id }), payload)
|
||||
|
||||
export const apiDeleteAdminTerm = (id) => http.delete(buildUrl(endpoints.deleteTerm, { id }))
|
||||
|
||||
export const apiCloneAdminTerm = (id) => http.post(buildUrl(endpoints.cloneTerm, { id }))
|
||||
|
||||
export const apiChangeAdminTermStatus = (id, payload) =>
|
||||
http.post(buildUrl(endpoints.changeStatusTerm, { id }), payload)
|
||||
|
||||
export const apiGetAdminTermStudents = (termId, params) =>
|
||||
http.get(buildUrl(endpoints.listUserTerm, { termId }), { params })
|
||||
|
||||
export const apiAddAdminTermStudents = (termId, payload) =>
|
||||
http.post(buildUrl(endpoints.addUserTerm, { termId }), payload)
|
||||
|
||||
export const apiRemoveAdminTermStudent = (termId, userId) =>
|
||||
http.delete(buildUrl(endpoints.removeUserTerm, { termId, userId }))
|
||||
|
||||
export const apiToggleAdminTermStudentLeave = (termId, userId, payload) =>
|
||||
http.post(buildUrl(endpoints.changeLeaveStatus, { termId, userId }), payload)
|
||||
|
||||
export const apiGetAdminTermCourses = (termId, params) =>
|
||||
http.get(buildUrl(endpoints.listCourseTerm, { termId }), { params })
|
||||
|
||||
export const apiAddAdminTermCourses = (termId, payload) =>
|
||||
http.post(buildUrl(endpoints.addCourseTerm, { termId }), payload)
|
||||
|
||||
export const apiRemoveAdminTermCourse = (termId, courseId) =>
|
||||
http.delete(buildUrl(endpoints.removeCourseTerm, { termId, courseId }))
|
||||
@@ -0,0 +1,12 @@
|
||||
import { http } from '@/services/api/http'
|
||||
import { buildUrl, endpoints } from '@/services/api/endpoints'
|
||||
|
||||
export const apiGetAdminTickets = (params) => http.get(endpoints.getTicketsList, { params })
|
||||
|
||||
export const apiShowAdminTicket = (id) => http.get(buildUrl(endpoints.showTicket, { id }))
|
||||
|
||||
export const apiSendAdminTicketMessage = (id, payload) =>
|
||||
http.post(buildUrl(endpoints.sendTicketMessage, { id }), payload)
|
||||
|
||||
export const apiChangeAdminTicketStatus = (id, payload) =>
|
||||
http.post(buildUrl(endpoints.changeTicketStatus, { id }), payload)
|
||||
@@ -0,0 +1,21 @@
|
||||
import { http } from '@/services/api/http'
|
||||
import { buildUrl, endpoints } from '@/services/api/endpoints'
|
||||
|
||||
export const apiGetAdminUsers = (params) => http.get(endpoints.getApprovedUsers, { params })
|
||||
|
||||
export const apiShowAdminUser = (id) => http.get(buildUrl(endpoints.showUserDetails, { id }))
|
||||
|
||||
export const apiAddAdminUser = (payload) => http.post(endpoints.addNewUser, payload)
|
||||
|
||||
export const apiUpdateAdminUser = (id, payload) =>
|
||||
http.put(buildUrl(endpoints.updateUser, { id }), payload)
|
||||
|
||||
export const apiUpdateAdminUserRole = (id, payload) =>
|
||||
http.post(buildUrl(endpoints.updateUserRole, { id }), payload)
|
||||
|
||||
export const apiChangeAdminUserStatus = (id, payload) =>
|
||||
http.post(buildUrl(endpoints.changeUserStatus, { id }), payload)
|
||||
|
||||
export const apiDeleteAdminUser = (id) => http.delete(buildUrl(endpoints.deleteUser, { id }))
|
||||
|
||||
export const apiGetAdminRoles = () => http.get(endpoints.getRolesList)
|
||||
@@ -0,0 +1,33 @@
|
||||
import { http } from '@/services/api/http'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
|
||||
export const apiLogin = (payload) => http.post(endpoints.login, payload)
|
||||
|
||||
export const apiLoginWithCode = (payload) => http.post(endpoints.loginWithCode2Step, payload)
|
||||
|
||||
export const apiRegister = (payload) => http.post(endpoints.register, payload)
|
||||
|
||||
export const apiVerifyCode = (payload) => http.post(endpoints.verifyCode, payload)
|
||||
|
||||
export const apiResendVerificationCode = (payload) =>
|
||||
http.post(endpoints.resendVerificationCodeForRegister, payload)
|
||||
|
||||
export const apiForgotPassword = (payload) => http.post(endpoints.forgotPassword, payload)
|
||||
|
||||
export const apiVerifyForgotPasswordCode = (payload) =>
|
||||
http.post(endpoints.verifyForgotPasswordCode, payload)
|
||||
|
||||
export const apiResetPassword = (payload) => http.post(endpoints.resetPassword, payload)
|
||||
|
||||
export const apiLogout = () => http.post(endpoints.logout)
|
||||
|
||||
export const apiGetProfile = () => http.get(endpoints.getProfile)
|
||||
|
||||
export const apiCompleteProfile = (payload) => http.post(endpoints.completeProfile, payload)
|
||||
|
||||
export const apiUpdateProfile = (payload) => http.put(endpoints.updateProfile, payload)
|
||||
|
||||
export const apiGetRegistrationQuestionVideo = () =>
|
||||
http.get(endpoints.getRegistrationQuestionVideo)
|
||||
|
||||
export const apiUploadTemporary = (formData) => http.post(endpoints.uploadMediaTemporary, formData)
|
||||
@@ -0,0 +1,7 @@
|
||||
import { http } from '@/services/api/http'
|
||||
import { buildUrl, endpoints } from '@/services/api/endpoints'
|
||||
|
||||
export const apiGetProvinces = () => http.get(endpoints.provinceList)
|
||||
|
||||
export const apiGetCitiesOfProvince = (provinceId) =>
|
||||
http.get(buildUrl(endpoints.citiesList, { provinceId }))
|
||||
@@ -0,0 +1,117 @@
|
||||
export const endpoints = {
|
||||
register: '/register',
|
||||
resendVerificationCodeForRegister: '/resend-verification-code',
|
||||
verifyCode: '/verify-code',
|
||||
completeProfile: '/complete-profile',
|
||||
getRegistrationQuestionVideo: '/verification-registration-media',
|
||||
login: '/login',
|
||||
loginWithCode2Step: '/login-with-code',
|
||||
forgotPassword: '/forgot-password',
|
||||
verifyForgotPasswordCode: '/verify-forgot-password-code',
|
||||
resetPassword: '/reset-password',
|
||||
logout: '/logout',
|
||||
uploadMediaTemporary: '/upload-temp',
|
||||
|
||||
provinceList: '/provinces',
|
||||
citiesList: '/provinces/:provinceId/cities',
|
||||
|
||||
getProfile: '/profile',
|
||||
updateProfile: '/profile',
|
||||
getStudentCourses: '/student/courses',
|
||||
showStudentCourse: '/student/courses/:id',
|
||||
|
||||
getPendingStudents: '/admin/pending-students',
|
||||
showPendingStudent: '/admin/pending-students/:id',
|
||||
changeStatusPendingStudent: '/admin/pending-students/:id/status',
|
||||
downloadPdfPendingStudentInfo: '/admin/pending-students/:id/pdf',
|
||||
getApprovedUsers: '/admin/users',
|
||||
|
||||
showUserDetails: '/admin/users/:id',
|
||||
addNewUser: '/admin/users',
|
||||
updateUser: '/admin/users/:id',
|
||||
updateUserRole: '/admin/users/:id/role',
|
||||
getRolesList: '/admin/roles',
|
||||
changeUserStatus: '/admin/users/:id/status',
|
||||
deleteUser: '/admin/users/:id',
|
||||
|
||||
getTermsList: '/admin/terms',
|
||||
addNewTerm: '/admin/terms',
|
||||
showTerm: '/admin/terms/:id',
|
||||
updateTerm: '/admin/terms/:id',
|
||||
deleteTerm: '/admin/terms/:id',
|
||||
cloneTerm: '/admin/terms/:id/clone',
|
||||
changeStatusTerm: '/admin/terms/:id/status',
|
||||
|
||||
listUserTerm: '/admin/terms/:termId/students',
|
||||
addUserTerm: '/admin/terms/:termId/students',
|
||||
removeUserTerm: '/admin/terms/:termId/students/:userId',
|
||||
changeLeaveStatus: '/admin/terms/:termId/students/:userId/toggle-leave',
|
||||
|
||||
listCourseTerm: '/admin/terms/:termId/courses',
|
||||
addCourseTerm: '/admin/terms/:termId/courses',
|
||||
removeCourseTerm: '/admin/terms/:termId/courses/:courseId',
|
||||
|
||||
getCoursesList: '/admin/courses',
|
||||
addNewCourse: '/admin/courses',
|
||||
showCourse: '/admin/courses/:id',
|
||||
updateCourse: '/admin/courses/:id',
|
||||
deleteCourse: '/admin/courses/:id',
|
||||
changeStatusCourse: '/admin/courses/:id/toggle-status',
|
||||
|
||||
getCourseTemplatesList: '/admin/course-templates',
|
||||
addNewCourseTemplate: '/admin/course-templates',
|
||||
showCourseTemplate: '/admin/course-templates/:id',
|
||||
updateCourseTemplate: '/admin/course-templates/:id',
|
||||
deleteCourseTemplate: '/admin/course-templates/:id',
|
||||
changeStatusCourseTemplate: '/admin/course-templates/:id/status',
|
||||
|
||||
listTemplateStudents: '/admin/course-templates/:templateId/students',
|
||||
addTemplateStudent: '/admin/course-templates/:templateId/students',
|
||||
removeTemplateStudent: '/admin/course-templates/:templateId/students/:userId',
|
||||
|
||||
listTemplateSessions: '/admin/course-templates/:templateId/sessions',
|
||||
attachTemplateSession: '/admin/course-templates/:templateId/sessions',
|
||||
detachTemplateSession: '/admin/course-templates/:templateId/sessions/:sessionId',
|
||||
|
||||
getSessionsList: '/admin/sessions',
|
||||
addNewSession: '/admin/sessions',
|
||||
showSession: '/admin/sessions/:id',
|
||||
updateSession: '/admin/sessions/:id',
|
||||
deleteSession: '/admin/sessions/:id',
|
||||
changeStatusSession: '/admin/sessions/:id/toggle-status',
|
||||
|
||||
getSessionsAttendance: '/admin/sessions/:sessionId/attendances',
|
||||
|
||||
getAssignmentsList: '/admin/assignments',
|
||||
addNewAssignment: '/admin/assignments',
|
||||
showAssignment: '/admin/assignments/:id',
|
||||
updateAssignment: '/admin/assignments/:id',
|
||||
deleteAssignment: '/admin/assignments/:id',
|
||||
getAssignmentSubmissions: '/admin/assignments/:assignmentId/submissions',
|
||||
showAssignmentSubmission: '/admin/assignments/:assignmentId/submissions/:submissionId',
|
||||
reviewAssignmentSubmission: '/admin/assignments/:assignmentId/submissions/:submissionId/review',
|
||||
|
||||
getTicketsList: '/admin/tickets',
|
||||
showTicket: '/admin/tickets/:id',
|
||||
sendTicketMessage: '/admin/tickets/:id/messages',
|
||||
changeTicketStatus: '/admin/tickets/:id/status',
|
||||
|
||||
getConsultationsList: '/admin/consultations',
|
||||
showConsultation: '/admin/consultations/:id',
|
||||
sendConsultationMessage: '/admin/consultations/:id/messages',
|
||||
changeConsultationStatus: '/admin/consultations/:id/status',
|
||||
|
||||
getExamsList: '/admin/exams',
|
||||
addNewExam: '/admin/exams',
|
||||
showExam: '/admin/exams/:id',
|
||||
updateExam: '/admin/exams/:id',
|
||||
deleteExam: '/admin/exams/:id',
|
||||
getExamParticipants: '/admin/exams/:examId/participants',
|
||||
showExamParticipant: '/admin/exams/:examId/participants/:participantId',
|
||||
}
|
||||
|
||||
export const buildUrl = (template, params = {}) =>
|
||||
Object.entries(params).reduce(
|
||||
(url, [key, value]) => url.replace(`:${key}`, encodeURIComponent(value)),
|
||||
template
|
||||
)
|
||||
@@ -0,0 +1,99 @@
|
||||
import axios from 'axios'
|
||||
import { toast } from 'vue3-toastify'
|
||||
|
||||
import { camelize, snakize } from '@/utils/convert-to-camel-snake'
|
||||
import { tokenService } from '@/services/api/token-service'
|
||||
|
||||
const defaultHeaders = {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
}
|
||||
|
||||
const addAuthTokenInterceptor = (instance) => {
|
||||
instance.interceptors.request.use(
|
||||
(config) => {
|
||||
const token = tokenService.getToken()
|
||||
const headers = {
|
||||
...config.headers,
|
||||
Authorization: token ? `Bearer ${token}` : '',
|
||||
}
|
||||
if (config.data instanceof FormData) {
|
||||
delete headers['Content-Type']
|
||||
}
|
||||
return { ...config, headers }
|
||||
},
|
||||
null,
|
||||
{ synchronous: true }
|
||||
)
|
||||
}
|
||||
|
||||
const addSnakizeInterceptor = (instance) => {
|
||||
instance.interceptors.request.use(
|
||||
(config) => {
|
||||
if (config.data instanceof FormData || config.noSnakize) {
|
||||
return config
|
||||
}
|
||||
return {
|
||||
...config,
|
||||
params: config.params ? snakize(config.params) : {},
|
||||
data: config.data ? snakize(config.data) : undefined,
|
||||
}
|
||||
},
|
||||
(e) => Promise.reject(e)
|
||||
)
|
||||
}
|
||||
|
||||
const addResponseUnwrapInterceptor = (instance) => {
|
||||
instance.interceptors.response.use(
|
||||
(res) => {
|
||||
if (typeof res?.data === 'number' || typeof res?.data === 'boolean') {
|
||||
return { data: res.data }
|
||||
}
|
||||
return res?.data || res
|
||||
},
|
||||
(e) => Promise.reject(e)
|
||||
)
|
||||
}
|
||||
|
||||
const addCamelizeInterceptor = (instance) => {
|
||||
instance.interceptors.response.use(
|
||||
(res) => camelize(res),
|
||||
(e) => Promise.reject(e)
|
||||
)
|
||||
}
|
||||
|
||||
const addUnauthorizeInterceptor = (instance) => {
|
||||
instance.interceptors.response.use(
|
||||
(res) => res,
|
||||
async (e) => {
|
||||
if (e?.response?.status === 401) {
|
||||
tokenService.clearAll()
|
||||
toast('نشست شما تایید نشد، لطفا مجدد وارد شوید')
|
||||
try {
|
||||
const { default: router } = await import('@/router')
|
||||
router.push('/login').catch(() => {})
|
||||
} catch {}
|
||||
}
|
||||
throw e
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const createInstance = (baseUrl, { headers = {}, ...configs } = {}) => {
|
||||
const instance = axios.create({
|
||||
timeout: 15_000,
|
||||
baseURL: baseUrl,
|
||||
headers: { ...defaultHeaders, ...headers },
|
||||
...configs,
|
||||
})
|
||||
addAuthTokenInterceptor(instance)
|
||||
addResponseUnwrapInterceptor(instance)
|
||||
addCamelizeInterceptor(instance)
|
||||
addSnakizeInterceptor(instance)
|
||||
addUnauthorizeInterceptor(instance)
|
||||
return instance
|
||||
}
|
||||
|
||||
export const http = createInstance(import.meta.env.VITE_API_BASE_URL || '')
|
||||
|
||||
export { createInstance }
|
||||
@@ -0,0 +1,3 @@
|
||||
export { http, createInstance } from '@/services/api/http'
|
||||
export { endpoints, buildUrl } from '@/services/api/endpoints'
|
||||
export { tokenService } from '@/services/api/token-service'
|
||||
@@ -0,0 +1,6 @@
|
||||
import { http } from '@/services/api/http'
|
||||
import { buildUrl, endpoints } from '@/services/api/endpoints'
|
||||
|
||||
export const apiGetStudentCourses = (params) => http.get(endpoints.getStudentCourses, { params })
|
||||
|
||||
export const apiShowStudentCourse = (id) => http.get(buildUrl(endpoints.showStudentCourse, { id }))
|
||||
@@ -0,0 +1,48 @@
|
||||
const TOKEN = 'user_token'
|
||||
const REFRESH_TOKEN = 'refresh_user_token'
|
||||
const USER_INFO = 'user_info'
|
||||
const STUDENT_REGISTRATION_INFO = 'StudentRegistration'
|
||||
|
||||
export const tokenService = {
|
||||
getToken() {
|
||||
return localStorage.getItem(TOKEN)
|
||||
},
|
||||
saveToken(token) {
|
||||
if (token) localStorage.setItem(TOKEN, token)
|
||||
},
|
||||
removeToken() {
|
||||
localStorage.removeItem(TOKEN)
|
||||
},
|
||||
|
||||
getRefreshToken() {
|
||||
return localStorage.getItem(REFRESH_TOKEN)
|
||||
},
|
||||
saveRefreshToken(newToken) {
|
||||
if (newToken) localStorage.setItem(REFRESH_TOKEN, newToken)
|
||||
},
|
||||
removeRefreshToken() {
|
||||
localStorage.removeItem(REFRESH_TOKEN)
|
||||
},
|
||||
|
||||
getUserInfo() {
|
||||
const info = localStorage.getItem(USER_INFO)
|
||||
return info ? JSON.parse(info) : null
|
||||
},
|
||||
saveUserInfo(info) {
|
||||
if (info) localStorage.setItem(USER_INFO, JSON.stringify(info))
|
||||
},
|
||||
removeUserInfo() {
|
||||
localStorage.removeItem(USER_INFO)
|
||||
localStorage.removeItem(STUDENT_REGISTRATION_INFO)
|
||||
},
|
||||
|
||||
hasToken() {
|
||||
return !!this.getToken()
|
||||
},
|
||||
|
||||
clearAll() {
|
||||
this.removeToken()
|
||||
this.removeRefreshToken()
|
||||
this.removeUserInfo()
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
export const adminAssignments = [
|
||||
{
|
||||
id: 301,
|
||||
title: 'یادداشتبرداری از جلسه اول',
|
||||
description: 'خلاصهای از مباحث جلسه اول را در دو صفحه بنویسید.',
|
||||
courseTemplate: { id: 1, title: 'اصول اخلاق اسلامی' },
|
||||
courseTemplateTitle: 'اصول اخلاق اسلامی',
|
||||
session: { id: 101, title: 'مقدمهای بر اخلاق اسلامی' },
|
||||
sessionTitle: 'مقدمهای بر اخلاق اسلامی',
|
||||
startDate: '2025-09-26T00:00:00.000Z',
|
||||
endDate: '2025-10-05T23:59:00.000Z',
|
||||
durationDays: 9,
|
||||
priority: 'mandatory',
|
||||
submissionsCount: 2,
|
||||
attachments: [],
|
||||
createdAt: '2025-09-24T08:00:00.000Z',
|
||||
},
|
||||
{
|
||||
id: 302,
|
||||
title: 'تحلیل تفسیری سوره حمد',
|
||||
description: 'تحلیل سه آیه از سوره حمد را ارسال نمایید.',
|
||||
courseTemplate: { id: 2, title: 'مفاهیم قرآنی' },
|
||||
courseTemplateTitle: 'مفاهیم قرآنی',
|
||||
session: { id: 102, title: 'تفسیر سوره حمد' },
|
||||
sessionTitle: 'تفسیر سوره حمد',
|
||||
startDate: '2025-10-05T00:00:00.000Z',
|
||||
endDate: '2025-10-20T23:59:00.000Z',
|
||||
durationDays: 15,
|
||||
priority: 'optional',
|
||||
submissionsCount: 1,
|
||||
attachments: [],
|
||||
createdAt: '2025-10-02T08:00:00.000Z',
|
||||
},
|
||||
]
|
||||
|
||||
export const assignmentSubmissions = new Map([
|
||||
[
|
||||
301,
|
||||
[
|
||||
{
|
||||
id: 1,
|
||||
assignmentId: 301,
|
||||
userId: 100,
|
||||
user: {
|
||||
id: 100,
|
||||
firstName: 'فاطمه',
|
||||
lastName: 'رضایی',
|
||||
fullName: 'فاطمه رضایی',
|
||||
avatarUrl: '',
|
||||
address: { province: { name: 'تهران' }, city: { name: 'تهران' } },
|
||||
profile: {
|
||||
educationStatus: 'seminary_student',
|
||||
seminaryLevel: 'level_3',
|
||||
universityLevel: 'not_applicable',
|
||||
},
|
||||
},
|
||||
termTitle: 'ترم پاییز ۱۴۰۴',
|
||||
courseTemplateTitle: 'اصول اخلاق اسلامی',
|
||||
sessionTitle: 'مقدمهای بر اخلاق اسلامی',
|
||||
userDescription: 'یادداشتهای جلسه اول به همراه برداشت شخصی ضمیمه است.',
|
||||
attachments: [{ id: 1, title: 'یادداشت-جلسه-اول.pdf', fileUrl: '#', type: 'document' }],
|
||||
submittedAt: '2025-10-02T18:30:00.000Z',
|
||||
status: 'pending',
|
||||
score: null,
|
||||
reviewerNote: '',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
assignmentId: 301,
|
||||
userId: 102,
|
||||
user: {
|
||||
id: 102,
|
||||
firstName: 'مریم',
|
||||
lastName: 'احمدی',
|
||||
fullName: 'مریم احمدی',
|
||||
avatarUrl: '',
|
||||
address: { province: { name: 'اصفهان' }, city: { name: 'اصفهان' } },
|
||||
profile: {
|
||||
educationStatus: 'seminary_and_university_student',
|
||||
seminaryLevel: 'level_2',
|
||||
universityLevel: 'bachelor',
|
||||
},
|
||||
},
|
||||
termTitle: 'ترم پاییز ۱۴۰۴',
|
||||
courseTemplateTitle: 'اصول اخلاق اسلامی',
|
||||
sessionTitle: 'مقدمهای بر اخلاق اسلامی',
|
||||
userDescription: 'خلاصهای از جلسه به همراه پرسش پایان.',
|
||||
attachments: [],
|
||||
submittedAt: '2025-10-04T20:00:00.000Z',
|
||||
status: 'approved',
|
||||
score: 18,
|
||||
reviewerNote: 'تحلیل خوبی ارائه شده است.',
|
||||
},
|
||||
],
|
||||
],
|
||||
])
|
||||
@@ -0,0 +1,86 @@
|
||||
export const adminConsultations = [
|
||||
{
|
||||
id: 387,
|
||||
requestId: '387',
|
||||
user: {
|
||||
id: 201,
|
||||
firstName: 'علیرضا',
|
||||
lastName: 'محمدی',
|
||||
fullName: 'علیرضا محمدی',
|
||||
avatarUrl: '',
|
||||
},
|
||||
status: 'answered',
|
||||
statusLabel: 'پاسخ داده شده',
|
||||
createdAt: '2026-05-12T13:54:00.000Z',
|
||||
faCreatedAt: '۱۴۰۵/۰۲/۲۲',
|
||||
faCreatedTime: '۱۳:۵۴',
|
||||
messages: [
|
||||
{
|
||||
id: 1,
|
||||
sender: 'user',
|
||||
text: 'سلام، در خصوص انتخاب رشته مشاوره میخواستم.',
|
||||
time: '۱۳:۵۴',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
sender: 'admin',
|
||||
text: 'سلام و وقت بخیر، لطفا رشته فعلی و علاقهمندیهای خود را بفرمایید.',
|
||||
time: '۱۴:۰۲',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 388,
|
||||
requestId: '388',
|
||||
user: {
|
||||
id: 202,
|
||||
firstName: 'زهرا',
|
||||
lastName: 'کریمی',
|
||||
fullName: 'زهرا کریمی',
|
||||
avatarUrl: '',
|
||||
},
|
||||
status: 'in_progress',
|
||||
statusLabel: 'در حال گفتگو',
|
||||
createdAt: '2026-05-11T09:30:00.000Z',
|
||||
faCreatedAt: '۱۴۰۵/۰۲/۲۱',
|
||||
faCreatedTime: '۰۹:۳۰',
|
||||
messages: [
|
||||
{
|
||||
id: 1,
|
||||
sender: 'user',
|
||||
text: 'برای ادامه تحصیل در سطح ۳ راهنمایی نیاز دارم.',
|
||||
time: '۰۹:۳۰',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 389,
|
||||
requestId: '389',
|
||||
user: {
|
||||
id: 203,
|
||||
firstName: 'محمد',
|
||||
lastName: 'حسینی',
|
||||
fullName: 'محمد حسینی',
|
||||
avatarUrl: '',
|
||||
},
|
||||
status: 'closed',
|
||||
statusLabel: 'بسته شده',
|
||||
createdAt: '2026-05-09T16:10:00.000Z',
|
||||
faCreatedAt: '۱۴۰۵/۰۲/۱۹',
|
||||
faCreatedTime: '۱۶:۱۰',
|
||||
messages: [
|
||||
{
|
||||
id: 1,
|
||||
sender: 'user',
|
||||
text: 'مشاوره دریافت شد، با تشکر.',
|
||||
time: '۱۶:۱۰',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
sender: 'admin',
|
||||
text: 'موفق باشید.',
|
||||
time: '۱۶:۱۲',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
@@ -0,0 +1,89 @@
|
||||
export const adminCourseTemplates = [
|
||||
{
|
||||
id: 1,
|
||||
title: 'اصول اخلاق اسلامی',
|
||||
description: 'دوره مقدماتی برای آشنایی با اخلاق اسلامی.',
|
||||
image: 'https://picsum.photos/seed/course1/200/200',
|
||||
defaultTeacher: { id: 5, firstName: 'علی', lastName: 'حسنی', fullName: 'علی حسنی' },
|
||||
defaultCapacity: 30,
|
||||
isActiveByDefault: true,
|
||||
prerequisitesCount: 0,
|
||||
prerequisites: [],
|
||||
createdAt: '2025-08-10T08:00:00.000Z',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'مفاهیم قرآنی',
|
||||
description: 'بررسی مفاهیم قرآنی به همراه تفسیر مختصر.',
|
||||
image: 'https://picsum.photos/seed/course2/200/200',
|
||||
defaultTeacher: { id: 6, firstName: 'حسین', lastName: 'مرادی', fullName: 'حسین مرادی' },
|
||||
defaultCapacity: 25,
|
||||
isActiveByDefault: true,
|
||||
prerequisitesCount: 1,
|
||||
prerequisites: [{ courseId: 1, course: { id: 1, title: 'اصول اخلاق اسلامی' } }],
|
||||
createdAt: '2025-09-12T08:00:00.000Z',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: 'فقه عبادات',
|
||||
description: 'مرور احکام عملی نماز و روزه.',
|
||||
image: '',
|
||||
defaultTeacher: { id: 7, firstName: 'مهدی', lastName: 'سهرابی', fullName: 'مهدی سهرابی' },
|
||||
defaultCapacity: 20,
|
||||
isActiveByDefault: false,
|
||||
prerequisitesCount: 0,
|
||||
prerequisites: [],
|
||||
createdAt: '2026-01-05T08:00:00.000Z',
|
||||
},
|
||||
]
|
||||
|
||||
export const adminOfferedCourses = [
|
||||
{
|
||||
id: 11,
|
||||
title: 'اصول اخلاق اسلامی - پاییز',
|
||||
image: 'https://picsum.photos/seed/offered1/200/200',
|
||||
template: { id: 1, title: 'اصول اخلاق اسلامی' },
|
||||
templateId: 1,
|
||||
term: { id: 1, title: 'ترم پاییز ۱۴۰۴' },
|
||||
termId: 1,
|
||||
teacher: { id: 5, firstName: 'علی', lastName: 'حسنی', fullName: 'علی حسنی' },
|
||||
capacity: 30,
|
||||
isActive: true,
|
||||
prerequisitesCount: 0,
|
||||
startDate: '2025-09-23T00:00:00.000Z',
|
||||
endDate: '2025-11-20T00:00:00.000Z',
|
||||
createdAt: '2025-09-01T08:00:00.000Z',
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
title: 'مفاهیم قرآنی - پاییز',
|
||||
image: 'https://picsum.photos/seed/offered2/200/200',
|
||||
template: { id: 2, title: 'مفاهیم قرآنی' },
|
||||
templateId: 2,
|
||||
term: { id: 1, title: 'ترم پاییز ۱۴۰۴' },
|
||||
termId: 1,
|
||||
teacher: { id: 6, firstName: 'حسین', lastName: 'مرادی', fullName: 'حسین مرادی' },
|
||||
capacity: 25,
|
||||
isActive: true,
|
||||
prerequisitesCount: 1,
|
||||
startDate: '2025-10-01T00:00:00.000Z',
|
||||
endDate: '2025-12-15T00:00:00.000Z',
|
||||
createdAt: '2025-09-10T08:00:00.000Z',
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
title: 'فقه عبادات - زمستان',
|
||||
image: '',
|
||||
template: { id: 3, title: 'فقه عبادات' },
|
||||
templateId: 3,
|
||||
term: { id: 2, title: 'ترم زمستان ۱۴۰۴' },
|
||||
termId: 2,
|
||||
teacher: { id: 7, firstName: 'مهدی', lastName: 'سهرابی', fullName: 'مهدی سهرابی' },
|
||||
capacity: 20,
|
||||
isActive: false,
|
||||
prerequisitesCount: 0,
|
||||
startDate: '2026-01-22T00:00:00.000Z',
|
||||
endDate: '2026-03-15T00:00:00.000Z',
|
||||
createdAt: '2025-12-10T08:00:00.000Z',
|
||||
},
|
||||
]
|
||||
@@ -0,0 +1,123 @@
|
||||
const sampleQuestions = (seed) => [
|
||||
{
|
||||
id: `${seed}-q1`,
|
||||
title: 'کدام گزینه به مفهوم تقوا نزدیکتر است؟',
|
||||
score: 5,
|
||||
correctAnswerId: `${seed}-q1-a2`,
|
||||
answers: [
|
||||
{ id: `${seed}-q1-a1`, title: 'پرهیز از خطا و دوری از گناه' },
|
||||
{ id: `${seed}-q1-a2`, title: 'خودنگهداری در محضر خداوند' },
|
||||
{ id: `${seed}-q1-a3`, title: 'پرهیز از خوراکیهای مضر' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: `${seed}-q2`,
|
||||
title: 'منبع اصلی احکام شیعه چیست؟',
|
||||
score: 5,
|
||||
correctAnswerId: `${seed}-q2-a1`,
|
||||
answers: [
|
||||
{ id: `${seed}-q2-a1`, title: 'قرآن و سنت اهل بیت(ع)' },
|
||||
{ id: `${seed}-q2-a2`, title: 'فقط قرآن کریم' },
|
||||
{ id: `${seed}-q2-a3`, title: 'اجماع علما' },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
export const adminExams = [
|
||||
{
|
||||
id: 201,
|
||||
title: 'آزمون پایان فصل اول اخلاق',
|
||||
description: 'آزمون چهار گزینهای از مفاهیم درسهای ۱ تا ۳.',
|
||||
courseTemplate: { id: 1, title: 'اصول اخلاق اسلامی' },
|
||||
courseTemplateTitle: 'اصول اخلاق اسلامی',
|
||||
session: { id: 101, title: 'مقدمهای بر اخلاق اسلامی' },
|
||||
sessionTitle: 'مقدمهای بر اخلاق اسلامی',
|
||||
durationMinutes: 25,
|
||||
passingScore: 12,
|
||||
questionsCount: 2,
|
||||
randomize: true,
|
||||
endDate: '2026-05-15T00:00:00.000Z',
|
||||
startDate: '2026-05-01T00:00:00.000Z',
|
||||
createdAt: '2026-04-20T08:00:00.000Z',
|
||||
questions: sampleQuestions(201),
|
||||
usedInTerms: [{ termId: 1 }],
|
||||
},
|
||||
{
|
||||
id: 202,
|
||||
title: 'آزمون مفاهیم قرآنی - میانترم',
|
||||
description: 'آزمون میانترم برای مرور آیات کلیدی.',
|
||||
courseTemplate: { id: 2, title: 'مفاهیم قرآنی' },
|
||||
courseTemplateTitle: 'مفاهیم قرآنی',
|
||||
session: { id: 102, title: 'تفسیر سوره حمد' },
|
||||
sessionTitle: 'تفسیر سوره حمد',
|
||||
durationMinutes: 30,
|
||||
passingScore: 14,
|
||||
questionsCount: 2,
|
||||
randomize: false,
|
||||
endDate: '2026-06-10T00:00:00.000Z',
|
||||
startDate: '2026-05-25T00:00:00.000Z',
|
||||
createdAt: '2026-05-10T08:00:00.000Z',
|
||||
questions: sampleQuestions(202),
|
||||
usedInTerms: [{ termId: 1 }],
|
||||
},
|
||||
]
|
||||
|
||||
export const examParticipants = new Map([
|
||||
[
|
||||
201,
|
||||
[
|
||||
{
|
||||
id: 1,
|
||||
userId: 100,
|
||||
firstName: 'فاطمه',
|
||||
lastName: 'رضایی',
|
||||
fullName: 'فاطمه رضایی',
|
||||
avatarUrl: '',
|
||||
address: { province: { name: 'تهران' }, city: { name: 'تهران' } },
|
||||
location: 'تهران، تهران',
|
||||
submittedAt: '2026-05-05T10:30:00.000Z',
|
||||
attempts: [
|
||||
{
|
||||
id: 1,
|
||||
title: 'تلاش اول',
|
||||
courseTitle: 'اصول اخلاق اسلامی',
|
||||
sessionTitle: 'مقدمهای بر اخلاق اسلامی',
|
||||
date: '2026-05-05T10:30:00.000Z',
|
||||
score: 17,
|
||||
scoreTone: 'good',
|
||||
questions: sampleQuestions(201).map((q) => ({
|
||||
...q,
|
||||
userAnswerId: q.correctAnswerId,
|
||||
})),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
userId: 102,
|
||||
firstName: 'مریم',
|
||||
lastName: 'احمدی',
|
||||
fullName: 'مریم احمدی',
|
||||
avatarUrl: '',
|
||||
address: { province: { name: 'اصفهان' }, city: { name: 'اصفهان' } },
|
||||
location: 'اصفهان، اصفهان',
|
||||
submittedAt: '2026-05-06T11:00:00.000Z',
|
||||
attempts: [
|
||||
{
|
||||
id: 2,
|
||||
title: 'تلاش اول',
|
||||
courseTitle: 'اصول اخلاق اسلامی',
|
||||
sessionTitle: 'مقدمهای بر اخلاق اسلامی',
|
||||
date: '2026-05-06T11:00:00.000Z',
|
||||
score: 9,
|
||||
scoreTone: 'bad',
|
||||
questions: sampleQuestions(201).map((q, i) => ({
|
||||
...q,
|
||||
userAnswerId: i === 0 ? q.answers[0].id : q.correctAnswerId,
|
||||
})),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
])
|
||||
@@ -0,0 +1,65 @@
|
||||
const firstNames = ['سکینه', 'رقیه', 'فاطمه', 'مریم', 'لیلا', 'زهرا', 'فریده', 'نسرین']
|
||||
const lastNames = ['طاهری', 'سلیمی', 'افشار', 'بختیاری', 'خراسانی', 'سهرابی', 'محمدی', 'بهرامی']
|
||||
|
||||
const pick = (arr, i) => arr[i % arr.length]
|
||||
|
||||
const makeStudent = (i) => {
|
||||
const firstName = pick(firstNames, i)
|
||||
const lastName = pick(lastNames, i + 2)
|
||||
const status = i % 3 === 0 ? 'rejected' : 'pending'
|
||||
const submittedAt = new Date(Date.now() - i * 86_400_000).toISOString()
|
||||
return {
|
||||
id: 500 + i,
|
||||
firstName,
|
||||
lastName,
|
||||
fullName: `${firstName} ${lastName}`,
|
||||
phoneNumber: `0935${String(2_000_000 + i).padStart(7, '0')}`,
|
||||
nationalCode: String(2_000_000_000 + i * 11).padStart(10, '0'),
|
||||
avatarUrl: '',
|
||||
status,
|
||||
submittedAt,
|
||||
address: {
|
||||
address: 'آدرس نمونه',
|
||||
province: { id: 1, name: 'تهران' },
|
||||
city: { id: 11, name: 'تهران' },
|
||||
},
|
||||
profile: {
|
||||
birthDate: new Date(1992, i % 12, ((i * 5) % 27) + 1).toISOString(),
|
||||
maritalStatus: i % 2 ? 'single' : 'married',
|
||||
gender: 'female',
|
||||
educationStatus: 'seminary_student',
|
||||
seminaryLevel: 'level_3',
|
||||
universityLevel: 'not_applicable',
|
||||
universityName: 'حوزه علمیه قم',
|
||||
fieldOfStudy: 'فقه و اصول',
|
||||
workExperienceSummary: 'پنج سال تدریس در مدرسه دینی.',
|
||||
activitySummary: 'برگزاری جلسات قرآن و حدیث به صورت هفتگی.',
|
||||
propagationExperienceYears: 6,
|
||||
propagationMethodDescription: 'محوریت بیان داستانهای قرآنی و قرابتهای اخلاقی.',
|
||||
specializedTopics: 'تربیت دینی نوجوانان',
|
||||
propagationPlatforms: [
|
||||
{ platform: 'home_gathering_regular' },
|
||||
{ platform: 'online', platformDetails: 'کانال اینستاگرام @example' },
|
||||
],
|
||||
responseToLowSatisfaction: 'change_the_method',
|
||||
responseToSessionCancellation: 'teach_how_to_reduce_costs',
|
||||
responseToAudienceConflict: 'divide_the_crowd',
|
||||
responseToCompetingPropagator: 'strengthen_yourself',
|
||||
responseToUnqualifiedAdvisors: 'تلاش بر شفافسازی و معرفی مراجع تخصصی.',
|
||||
relevantCertificates: 'سطح ۳ حوزوی، تدریس قرآن',
|
||||
hijabApproach: 'گفتگوی همدلانه و آموزشمحور.',
|
||||
},
|
||||
verification: {
|
||||
status,
|
||||
submittedAt,
|
||||
rejectionReason: status === 'rejected' ? 'عدم تکمیل مدارک' : '',
|
||||
adminNote: status === 'rejected' ? 'لطفا مدارک تحصیلی بهروز ارسال شود.' : '',
|
||||
verifiedBy: { firstName: 'سجاد', lastName: 'محمدی' },
|
||||
media: [],
|
||||
},
|
||||
roles: ['student'],
|
||||
createdAt: submittedAt,
|
||||
}
|
||||
}
|
||||
|
||||
export const pendingStudents = Array.from({ length: 14 }, (_, i) => makeStudent(i))
|
||||
@@ -0,0 +1,107 @@
|
||||
export const adminSessions = [
|
||||
{
|
||||
id: 101,
|
||||
title: 'مقدمهای بر اخلاق اسلامی',
|
||||
description: 'جلسه نخست؛ تعاریف و چارچوب دوره.',
|
||||
image: 'https://picsum.photos/seed/session1/200/200',
|
||||
courseTemplate: { id: 1, title: 'اصول اخلاق اسلامی' },
|
||||
sessionType: 'in_person',
|
||||
sessionTypeFa: 'حضوری',
|
||||
durationMinutes: 90,
|
||||
order: 1,
|
||||
sessionConfig: {
|
||||
startTime: '2025-09-25T16:00:00.000Z',
|
||||
location: 'سالن آمفیتئاتر ۲ - مدرسه قم',
|
||||
},
|
||||
materials: [],
|
||||
usedInTerms: [{ termId: 1 }],
|
||||
createdAt: '2025-09-10T08:00:00.000Z',
|
||||
},
|
||||
{
|
||||
id: 102,
|
||||
title: 'تفسیر سوره حمد',
|
||||
description: 'تحلیل آیات سوره حمد.',
|
||||
image: '',
|
||||
courseTemplate: { id: 2, title: 'مفاهیم قرآنی' },
|
||||
sessionType: 'online',
|
||||
sessionTypeFa: 'آنلاین',
|
||||
durationMinutes: 75,
|
||||
order: 1,
|
||||
sessionConfig: {
|
||||
meetingLink: 'https://meet.example.com/quran-1',
|
||||
platform: 'google_meet',
|
||||
startTime: '2025-10-04T19:00:00.000Z',
|
||||
},
|
||||
materials: [],
|
||||
usedInTerms: [{ termId: 1 }],
|
||||
createdAt: '2025-09-25T08:00:00.000Z',
|
||||
},
|
||||
{
|
||||
id: 103,
|
||||
title: 'احکام نماز جماعت',
|
||||
description: 'مرور احکام و شرایط نماز جماعت.',
|
||||
image: '',
|
||||
courseTemplate: { id: 3, title: 'فقه عبادات' },
|
||||
sessionType: 'video',
|
||||
sessionTypeFa: 'ویدئو',
|
||||
durationMinutes: 50,
|
||||
order: 2,
|
||||
sessionConfig: {
|
||||
minWatchedPercent: 80,
|
||||
mustCompleteBeforeNext: true,
|
||||
},
|
||||
materials: [],
|
||||
usedInTerms: [],
|
||||
createdAt: '2026-01-12T08:00:00.000Z',
|
||||
},
|
||||
]
|
||||
|
||||
export const sessionAttendance = new Map([
|
||||
[
|
||||
101,
|
||||
[
|
||||
{
|
||||
id: 1,
|
||||
userId: 100,
|
||||
sessionId: 101,
|
||||
status: 'present',
|
||||
user: {
|
||||
id: 100,
|
||||
firstName: 'فاطمه',
|
||||
lastName: 'رضایی',
|
||||
fullName: 'فاطمه رضایی',
|
||||
avatarUrl: '',
|
||||
address: { province: { name: 'تهران' }, city: { name: 'تهران' } },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
userId: 102,
|
||||
sessionId: 101,
|
||||
status: 'absent',
|
||||
user: {
|
||||
id: 102,
|
||||
firstName: 'مریم',
|
||||
lastName: 'احمدی',
|
||||
fullName: 'مریم احمدی',
|
||||
avatarUrl: '',
|
||||
address: { province: { name: 'اصفهان' }, city: { name: 'اصفهان' } },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
userId: 103,
|
||||
sessionId: 101,
|
||||
status: 'late',
|
||||
user: {
|
||||
id: 103,
|
||||
firstName: 'علی',
|
||||
lastName: 'علوی',
|
||||
fullName: 'علی علوی',
|
||||
avatarUrl: '',
|
||||
address: { province: { name: 'تهران' }, city: { name: 'تهران' } },
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
])
|
||||
@@ -0,0 +1,57 @@
|
||||
export const adminTerms = [
|
||||
{
|
||||
id: 1,
|
||||
title: 'ترم پاییز ۱۴۰۴',
|
||||
description: 'ترم پاییز با محوریت آموزش معارف اسلامی.',
|
||||
image: 'https://picsum.photos/seed/term1/200/200',
|
||||
startDate: '2025-09-23T00:00:00.000Z',
|
||||
endDate: '2026-01-20T00:00:00.000Z',
|
||||
isActive: true,
|
||||
studentsCount: 18,
|
||||
coursesCount: 4,
|
||||
createdAt: '2025-08-01T08:00:00.000Z',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'ترم زمستان ۱۴۰۴',
|
||||
description: 'ترم زمستان با تمرکز بر فقه و اصول.',
|
||||
image: 'https://picsum.photos/seed/term2/200/200',
|
||||
startDate: '2026-01-21T00:00:00.000Z',
|
||||
endDate: '2026-04-20T00:00:00.000Z',
|
||||
isActive: true,
|
||||
studentsCount: 12,
|
||||
coursesCount: 3,
|
||||
createdAt: '2025-11-10T08:00:00.000Z',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: 'ترم بهار ۱۴۰۵',
|
||||
description: 'ترم بهار ویژه دورههای تخصصی.',
|
||||
image: '',
|
||||
startDate: '2026-04-21T00:00:00.000Z',
|
||||
endDate: '2026-08-21T00:00:00.000Z',
|
||||
isActive: false,
|
||||
studentsCount: 0,
|
||||
coursesCount: 2,
|
||||
createdAt: '2026-02-15T08:00:00.000Z',
|
||||
},
|
||||
]
|
||||
|
||||
export const termStudentLinks = new Map([
|
||||
[
|
||||
1,
|
||||
[
|
||||
{ userId: 100, isOnLeave: false },
|
||||
{ userId: 101, isOnLeave: false },
|
||||
{ userId: 102, isOnLeave: true },
|
||||
{ userId: 103, isOnLeave: false },
|
||||
],
|
||||
],
|
||||
[
|
||||
2,
|
||||
[
|
||||
{ userId: 104, isOnLeave: false },
|
||||
{ userId: 105, isOnLeave: false },
|
||||
],
|
||||
],
|
||||
])
|
||||
@@ -0,0 +1,92 @@
|
||||
export const adminTickets = [
|
||||
{
|
||||
id: 401,
|
||||
title: 'پیگیری وضعیت ثبتنام',
|
||||
user: {
|
||||
id: 100,
|
||||
firstName: 'فاطمه',
|
||||
lastName: 'رضایی',
|
||||
fullName: 'فاطمه رضایی',
|
||||
avatarUrl: '',
|
||||
},
|
||||
status: 'answered',
|
||||
statusLabel: 'پاسخ داده شده',
|
||||
createdAt: '2026-05-09T20:28:00.000Z',
|
||||
faCreatedAt: '۱۴۰۵/۰۲/۱۹',
|
||||
faCreatedTime: '۱۰:۳۰',
|
||||
messages: [
|
||||
{
|
||||
id: 1,
|
||||
sender: 'user',
|
||||
text: 'سلام وقت بخیر، در فرایند ثبتنام به مشکل برخوردم.',
|
||||
time: '۱۲:۳۵',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
sender: 'admin',
|
||||
text: 'سلام و عرض ادب. لطفا کد پیگیری ثبتنام را ارسال کنید.',
|
||||
time: '۱۲:۴۰',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
sender: 'user',
|
||||
text: 'کد ثبتنام: ۱۲۳۴۵۶۷۸',
|
||||
time: '۱۲:۴۲',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 402,
|
||||
title: 'سوال درباره جلسه آموزشی',
|
||||
user: {
|
||||
id: 102,
|
||||
firstName: 'مریم',
|
||||
lastName: 'احمدی',
|
||||
fullName: 'مریم احمدی',
|
||||
avatarUrl: '',
|
||||
},
|
||||
status: 'pending',
|
||||
statusLabel: 'در انتظار پاسخ',
|
||||
createdAt: '2026-05-08T09:15:00.000Z',
|
||||
faCreatedAt: '۱۴۰۵/۰۲/۱۸',
|
||||
faCreatedTime: '۱۲:۴۵',
|
||||
messages: [
|
||||
{
|
||||
id: 1,
|
||||
sender: 'user',
|
||||
text: 'سلام، درباره ساعت برگزاری جلسه چهارم سوال داشتم.',
|
||||
time: '۱۲:۴۵',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 403,
|
||||
title: 'درخواست بستن تیکت',
|
||||
user: {
|
||||
id: 103,
|
||||
firstName: 'علی',
|
||||
lastName: 'علوی',
|
||||
fullName: 'علی علوی',
|
||||
avatarUrl: '',
|
||||
},
|
||||
status: 'closed',
|
||||
statusLabel: 'بسته شده',
|
||||
createdAt: '2026-05-07T14:10:00.000Z',
|
||||
faCreatedAt: '۱۴۰۵/۰۲/۱۷',
|
||||
faCreatedTime: '۱۷:۴۰',
|
||||
messages: [
|
||||
{
|
||||
id: 1,
|
||||
sender: 'user',
|
||||
text: 'مشکل برطرف شد. لطفا تیکت بسته شود.',
|
||||
time: '۱۷:۴۰',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
sender: 'admin',
|
||||
text: 'با تشکر از شما. تیکت بسته شد.',
|
||||
time: '۱۷:۴۲',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
@@ -0,0 +1,96 @@
|
||||
export const roles = [
|
||||
{ id: 1, name: 'admin' },
|
||||
{ id: 2, name: 'counselor' },
|
||||
{ id: 3, name: 'missionary' },
|
||||
{ id: 4, name: 'student' },
|
||||
{ id: 5, name: 'teacher' },
|
||||
]
|
||||
|
||||
const provinces = [
|
||||
{ id: 1, name: 'تهران' },
|
||||
{ id: 2, name: 'اصفهان' },
|
||||
{ id: 3, name: 'فارس' },
|
||||
{ id: 4, name: 'خراسان رضوی' },
|
||||
]
|
||||
const cities = {
|
||||
1: [
|
||||
{ id: 11, name: 'تهران' },
|
||||
{ id: 12, name: 'شمیرانات' },
|
||||
],
|
||||
2: [{ id: 21, name: 'اصفهان' }],
|
||||
3: [{ id: 31, name: 'شیراز' }],
|
||||
4: [{ id: 41, name: 'مشهد' }],
|
||||
}
|
||||
const provinceById = (id) => provinces.find((p) => p.id === id) || provinces[0]
|
||||
const cityForProvince = (id) => cities[id]?.[0] || cities[1][0]
|
||||
|
||||
const firstNames = [
|
||||
'فاطمه',
|
||||
'زهرا',
|
||||
'مریم',
|
||||
'علی',
|
||||
'حسین',
|
||||
'محمد',
|
||||
'سمیه',
|
||||
'نرگس',
|
||||
'حسن',
|
||||
'رضا',
|
||||
'مهدی',
|
||||
'الهام',
|
||||
'پروانه',
|
||||
'ساره',
|
||||
'مهسا',
|
||||
]
|
||||
const lastNames = [
|
||||
'رضایی',
|
||||
'محمدی',
|
||||
'حسینی',
|
||||
'احمدی',
|
||||
'جعفری',
|
||||
'علوی',
|
||||
'موسوی',
|
||||
'صالحی',
|
||||
'فاطمی',
|
||||
'کریمی',
|
||||
'تقوی',
|
||||
'مرادی',
|
||||
'هاشمی',
|
||||
'بهرامی',
|
||||
]
|
||||
|
||||
const pick = (arr, i) => arr[i % arr.length]
|
||||
|
||||
const makeUser = (i, overrides = {}) => {
|
||||
const firstName = pick(firstNames, i)
|
||||
const lastName = pick(lastNames, i + 3)
|
||||
const province = provinceById((i % 4) + 1)
|
||||
const city = cityForProvince(province.id)
|
||||
const role = roles[(i % 4) + 1]?.name || 'student'
|
||||
return {
|
||||
id: 100 + i,
|
||||
firstName,
|
||||
lastName,
|
||||
fullName: `${firstName} ${lastName}`,
|
||||
phoneNumber: `0912${String(1_000_000 + i).padStart(7, '0')}`,
|
||||
nationalCode: String(1_000_000_000 + i * 7).padStart(10, '0'),
|
||||
avatarUrl: '',
|
||||
status: i % 5 === 0 ? 'pending' : 'approved',
|
||||
roles: [role],
|
||||
roleId: roles.find((r) => r.name === role)?.id,
|
||||
address: {
|
||||
address: 'آدرس نمونه',
|
||||
province,
|
||||
city,
|
||||
},
|
||||
profile: {
|
||||
bio: '',
|
||||
birthDate: new Date(1990, i % 12, ((i * 3) % 27) + 1).toISOString(),
|
||||
maritalStatus: i % 2 ? 'single' : 'married',
|
||||
gender: i % 2 ? 'female' : 'male',
|
||||
},
|
||||
createdAt: new Date(Date.now() - i * 86_400_000).toISOString(),
|
||||
...overrides,
|
||||
}
|
||||
}
|
||||
|
||||
export const adminUsers = Array.from({ length: 24 }, (_, i) => makeUser(i))
|
||||
@@ -0,0 +1,47 @@
|
||||
export const provinces = [
|
||||
{ id: 1, name: 'تهران' },
|
||||
{ id: 2, name: 'اصفهان' },
|
||||
{ id: 3, name: 'فارس' },
|
||||
{ id: 4, name: 'خراسان رضوی' },
|
||||
{ id: 5, name: 'گیلان' },
|
||||
{ id: 6, name: 'مازندران' },
|
||||
{ id: 7, name: 'البرز' },
|
||||
{ id: 8, name: 'یزد' },
|
||||
]
|
||||
|
||||
export const cities = {
|
||||
1: [
|
||||
{ id: 11, name: 'تهران' },
|
||||
{ id: 12, name: 'شمیرانات' },
|
||||
{ id: 13, name: 'ری' },
|
||||
],
|
||||
2: [
|
||||
{ id: 21, name: 'اصفهان' },
|
||||
{ id: 22, name: 'کاشان' },
|
||||
{ id: 23, name: 'نجفآباد' },
|
||||
],
|
||||
3: [
|
||||
{ id: 31, name: 'شیراز' },
|
||||
{ id: 32, name: 'مرودشت' },
|
||||
],
|
||||
4: [
|
||||
{ id: 41, name: 'مشهد' },
|
||||
{ id: 42, name: 'نیشابور' },
|
||||
],
|
||||
5: [
|
||||
{ id: 51, name: 'رشت' },
|
||||
{ id: 52, name: 'لاهیجان' },
|
||||
],
|
||||
6: [
|
||||
{ id: 61, name: 'ساری' },
|
||||
{ id: 62, name: 'بابل' },
|
||||
],
|
||||
7: [
|
||||
{ id: 71, name: 'کرج' },
|
||||
{ id: 72, name: 'نظرآباد' },
|
||||
],
|
||||
8: [
|
||||
{ id: 81, name: 'یزد' },
|
||||
{ id: 82, name: 'میبد' },
|
||||
],
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
export const currentProfile = {
|
||||
id: 1,
|
||||
firstName: 'سجاد',
|
||||
lastName: 'محمدی',
|
||||
fullName: 'سجاد محمدی',
|
||||
phoneNumber: '09123456789',
|
||||
nationalCode: '0079827498',
|
||||
avatarUrl: '',
|
||||
status: 'approved',
|
||||
roles: ['admin'],
|
||||
address: {
|
||||
address: 'خیابان آزادی، پلاک ۱۲',
|
||||
province: { id: 1, name: 'تهران' },
|
||||
city: { id: 11, name: 'تهران' },
|
||||
},
|
||||
profile: {
|
||||
bio: 'مدیر سامانه و طلبه فعال در حوزه آموزش مجازی.',
|
||||
birthDate: '1989-06-12T00:00:00.000Z',
|
||||
maritalStatus: 'married',
|
||||
gender: 'male',
|
||||
educationStatus: 'graduate',
|
||||
seminaryLevel: 'level_3',
|
||||
universityLevel: 'master',
|
||||
universityName: 'تهران',
|
||||
fieldOfStudy: 'علوم قرآنی',
|
||||
avatarId: null,
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
export const studentCourses = [
|
||||
{
|
||||
id: 11,
|
||||
title: 'اصول اخلاق اسلامی - پاییز',
|
||||
image: 'https://picsum.photos/seed/student1/200/200',
|
||||
teacher: { firstName: 'علی', lastName: 'حسنی', fullName: 'علی حسنی' },
|
||||
term: { id: 1, title: 'ترم پاییز ۱۴۰۴' },
|
||||
startDate: '2025-09-23T00:00:00.000Z',
|
||||
endDate: '2025-11-20T00:00:00.000Z',
|
||||
status: 'watching',
|
||||
averageScore: null,
|
||||
sessions: [
|
||||
{
|
||||
id: 1001,
|
||||
title: 'جلسه اول: مقدمه',
|
||||
sessionTypeFa: 'حضوری',
|
||||
durationMinutes: 90,
|
||||
status: 'completed',
|
||||
statusLabel: 'تکمیل شده',
|
||||
},
|
||||
{
|
||||
id: 1002,
|
||||
title: 'جلسه دوم: مبانی',
|
||||
sessionTypeFa: 'حضوری',
|
||||
durationMinutes: 90,
|
||||
status: 'in_progress',
|
||||
statusLabel: 'در حال بررسی',
|
||||
},
|
||||
{
|
||||
id: 1003,
|
||||
title: 'جلسه سوم: کاربردها',
|
||||
sessionTypeFa: 'حضوری',
|
||||
durationMinutes: 90,
|
||||
status: 'locked',
|
||||
statusLabel: 'قفل',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
title: 'مفاهیم قرآنی - پاییز',
|
||||
image: 'https://picsum.photos/seed/student2/200/200',
|
||||
teacher: { firstName: 'حسین', lastName: 'مرادی', fullName: 'حسین مرادی' },
|
||||
term: { id: 1, title: 'ترم پاییز ۱۴۰۴' },
|
||||
startDate: '2025-10-01T00:00:00.000Z',
|
||||
endDate: '2025-12-15T00:00:00.000Z',
|
||||
status: 'waitForExam',
|
||||
averageScore: 17.5,
|
||||
sessions: [
|
||||
{
|
||||
id: 1004,
|
||||
title: 'تفسیر سوره حمد',
|
||||
sessionTypeFa: 'آنلاین',
|
||||
durationMinutes: 75,
|
||||
status: 'completed',
|
||||
statusLabel: 'تکمیل شده',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 21,
|
||||
title: 'مفاهیم قرآنی - بهار قبل',
|
||||
image: '',
|
||||
teacher: { firstName: 'حسین', lastName: 'مرادی', fullName: 'حسین مرادی' },
|
||||
term: { id: 0, title: 'ترم بهار ۱۴۰۳' },
|
||||
startDate: '2024-03-21T00:00:00.000Z',
|
||||
endDate: '2024-06-21T00:00:00.000Z',
|
||||
status: 'completed',
|
||||
averageScore: 18.25,
|
||||
sessions: [],
|
||||
},
|
||||
]
|
||||
@@ -0,0 +1,71 @@
|
||||
import { camelize } from '@/utils/convert-to-camel-snake'
|
||||
import { findHandler } from '@/services/mock/registry'
|
||||
|
||||
const sleep = (ms) => new Promise((r) => setTimeout(r, ms))
|
||||
|
||||
const stripUrl = (url) => (url ? url.split('?')[0] : '')
|
||||
|
||||
const safeParse = (value) => {
|
||||
try {
|
||||
return camelize(JSON.parse(value))
|
||||
} catch {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
const mockAdapter = async (config) => {
|
||||
const url = stripUrl(config.url || '')
|
||||
const method = (config.method || 'get').toUpperCase()
|
||||
const match = findHandler(method, url)
|
||||
|
||||
if (!match) {
|
||||
const err = new Error(`No mock registered for ${method} ${url}`)
|
||||
err.response = {
|
||||
status: 404,
|
||||
statusText: 'Not Mocked',
|
||||
data: { message: err.message },
|
||||
}
|
||||
err.config = config
|
||||
throw err
|
||||
}
|
||||
|
||||
await sleep(150)
|
||||
|
||||
const query = config.params ? camelize(config.params) : {}
|
||||
let data = config.data
|
||||
if (data instanceof FormData) {
|
||||
/* leave as-is */
|
||||
} else if (typeof data === 'string') {
|
||||
data = safeParse(data)
|
||||
} else if (data) {
|
||||
data = camelize(data)
|
||||
}
|
||||
|
||||
const result = await match.entry.handler({
|
||||
method,
|
||||
url,
|
||||
params: match.params,
|
||||
query,
|
||||
data,
|
||||
headers: config.headers,
|
||||
})
|
||||
|
||||
return {
|
||||
data: result,
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
headers: {},
|
||||
config,
|
||||
}
|
||||
}
|
||||
|
||||
export const isMocksEnabled = () => import.meta.env.VITE_USE_MOCKS === 'true'
|
||||
|
||||
import.meta.glob('@/services/mock/routes/*.js', { eager: true })
|
||||
|
||||
export const setupMocks = (instance) => {
|
||||
if (!isMocksEnabled()) return
|
||||
instance.defaults.adapter = mockAdapter
|
||||
}
|
||||
|
||||
export { register } from '@/services/mock/registry'
|
||||
@@ -0,0 +1,91 @@
|
||||
export const ok = (data, meta) => ({ data, meta })
|
||||
|
||||
export const paginate = (items, query) => {
|
||||
const page = Number(query.page || 1)
|
||||
const perPage = Number(query.perPage || 10)
|
||||
const total = items.length
|
||||
const lastPage = Math.max(1, Math.ceil(total / perPage))
|
||||
const start = (page - 1) * perPage
|
||||
const sliced = items.slice(start, start + perPage)
|
||||
return {
|
||||
data: sliced,
|
||||
meta: { page, perPage, total, lastPage, currentPage: page },
|
||||
}
|
||||
}
|
||||
|
||||
const stringIncludes = (haystack, needle) =>
|
||||
String(haystack ?? '')
|
||||
.toLowerCase()
|
||||
.includes(String(needle ?? '').toLowerCase())
|
||||
|
||||
export const filterItems = (items, query, rules = {}) =>
|
||||
items.filter((item) => {
|
||||
for (const [key, rule] of Object.entries(rules)) {
|
||||
const value = query[key]
|
||||
if (value === '' || value == null) continue
|
||||
if (typeof rule === 'function') {
|
||||
if (!rule(item, value)) return false
|
||||
} else
|
||||
switch (rule) {
|
||||
case 'eq': {
|
||||
if (String(item[key]) !== String(value)) return false
|
||||
|
||||
break
|
||||
}
|
||||
case 'includes': {
|
||||
if (!stringIncludes(item[key], value)) return false
|
||||
|
||||
break
|
||||
}
|
||||
case 'fromDate': {
|
||||
if (!item[rule.field || 'createdAt']) continue
|
||||
if (new Date(item[rule.field || 'createdAt']) < new Date(value)) return false
|
||||
|
||||
break
|
||||
}
|
||||
// No default
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
export const filterDateRange = (items, query, field = 'createdAt') => {
|
||||
if (!query.fromDate && !query.toDate) return items
|
||||
return items.filter((item) => {
|
||||
const v = item[field]
|
||||
if (!v) return !query.fromDate && !query.toDate
|
||||
const d = new Date(v).getTime()
|
||||
if (query.fromDate && d < new Date(query.fromDate).getTime()) return false
|
||||
if (query.toDate && d > new Date(query.toDate).getTime()) return false
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
let nextId = 1000
|
||||
export const makeId = () => ++nextId
|
||||
|
||||
export const findOrThrow = (list, id) => {
|
||||
const found = list.find((item) => String(item.id) === String(id))
|
||||
if (!found) {
|
||||
const err = new Error('Not Found')
|
||||
err.response = { status: 404, statusText: 'Not Found', data: { message: 'Not Found' } }
|
||||
throw err
|
||||
}
|
||||
return found
|
||||
}
|
||||
|
||||
export const removeById = (list, id) => {
|
||||
const idx = list.findIndex((x) => String(x.id) === String(id))
|
||||
if (idx !== -1) list.splice(idx, 1)
|
||||
}
|
||||
|
||||
export const updateById = (list, id, patch) => {
|
||||
const idx = list.findIndex((x) => String(x.id) === String(id))
|
||||
if (idx === -1) return null
|
||||
list[idx] = { ...list[idx], ...patch }
|
||||
return list[idx]
|
||||
}
|
||||
|
||||
export const isoDaysFromNow = (days) => new Date(Date.now() + days * 86_400_000).toISOString()
|
||||
|
||||
export const isoNow = () => new Date().toISOString()
|
||||
@@ -0,0 +1 @@
|
||||
export { register, setupMocks, isMocksEnabled } from '@/services/mock/handlers'
|
||||
@@ -0,0 +1,27 @@
|
||||
const handlers = []
|
||||
|
||||
export const register = (method, urlPattern, handler) => {
|
||||
const paramNames = []
|
||||
const regexSource = urlPattern.replace(/:([A-Za-z][\dA-Za-z]*)/g, (_, name) => {
|
||||
paramNames.push(name)
|
||||
return '([^/]+)'
|
||||
})
|
||||
const regex = new RegExp(`^${regexSource}$`)
|
||||
handlers.push({ method: method.toUpperCase(), regex, paramNames, handler })
|
||||
}
|
||||
|
||||
export const findHandler = (method, url) => {
|
||||
const upper = method.toUpperCase()
|
||||
for (const entry of handlers) {
|
||||
if (entry.method !== upper) continue
|
||||
const match = entry.regex.exec(url)
|
||||
if (match) {
|
||||
const params = {}
|
||||
entry.paramNames.forEach((name, i) => {
|
||||
params[name] = decodeURIComponent(match[i + 1])
|
||||
})
|
||||
return { entry, params }
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import { register } from '@/services/mock/registry'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
import { adminAssignments, assignmentSubmissions } from '@/services/mock/fixtures/admin-assignments'
|
||||
import { adminCourseTemplates } from '@/services/mock/fixtures/admin-courses'
|
||||
import { adminSessions } from '@/services/mock/fixtures/admin-sessions'
|
||||
import {
|
||||
filterDateRange,
|
||||
filterItems,
|
||||
findOrThrow,
|
||||
isoNow,
|
||||
makeId,
|
||||
paginate,
|
||||
removeById,
|
||||
updateById,
|
||||
} from '@/services/mock/helpers'
|
||||
|
||||
const computeDurationDays = (start, end) => {
|
||||
if (!start || !end) return null
|
||||
const diff = Math.ceil((new Date(end).getTime() - new Date(start).getTime()) / 86_400_000)
|
||||
return diff >= 0 ? diff : null
|
||||
}
|
||||
|
||||
register('GET', endpoints.getAssignmentsList, ({ query }) => {
|
||||
let list = filterItems(adminAssignments, query, {
|
||||
title: 'includes',
|
||||
courseTemplateId: (item, v) => String(item.courseTemplate?.id) === String(v),
|
||||
sessionId: (item, v) => String(item.session?.id) === String(v),
|
||||
})
|
||||
list = filterDateRange(list, query)
|
||||
return paginate(list, query)
|
||||
})
|
||||
|
||||
register('GET', endpoints.showAssignment, ({ params }) => ({
|
||||
data: findOrThrow(adminAssignments, params.id),
|
||||
}))
|
||||
|
||||
register('POST', endpoints.addNewAssignment, ({ data }) => {
|
||||
const tpl = adminCourseTemplates.find((c) => c.id === Number(data.courseTemplateId))
|
||||
const sess = adminSessions.find((s) => s.id === Number(data.sessionId))
|
||||
const item = {
|
||||
id: makeId(),
|
||||
title: data.title || '',
|
||||
description: data.description || '',
|
||||
courseTemplate: tpl ? { id: tpl.id, title: tpl.title } : null,
|
||||
courseTemplateTitle: tpl?.title || '',
|
||||
session: sess ? { id: sess.id, title: sess.title } : null,
|
||||
sessionTitle: sess?.title || '',
|
||||
startDate: data.startDate || '',
|
||||
endDate: data.endDate || '',
|
||||
durationDays: computeDurationDays(data.startDate, data.endDate),
|
||||
priority: data.priority || 'mandatory',
|
||||
submissionsCount: 0,
|
||||
attachments: data.attachments || [],
|
||||
createdAt: isoNow(),
|
||||
}
|
||||
adminAssignments.unshift(item)
|
||||
return { data: item }
|
||||
})
|
||||
|
||||
register('PUT', endpoints.updateAssignment, ({ params, data }) => {
|
||||
const tpl = adminCourseTemplates.find((c) => c.id === Number(data.courseTemplateId))
|
||||
const sess = adminSessions.find((s) => s.id === Number(data.sessionId))
|
||||
return {
|
||||
data: updateById(adminAssignments, params.id, {
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
courseTemplate: tpl ? { id: tpl.id, title: tpl.title } : undefined,
|
||||
courseTemplateTitle: tpl?.title,
|
||||
session: sess ? { id: sess.id, title: sess.title } : undefined,
|
||||
sessionTitle: sess?.title,
|
||||
startDate: data.startDate,
|
||||
endDate: data.endDate,
|
||||
durationDays: computeDurationDays(data.startDate, data.endDate),
|
||||
priority: data.priority,
|
||||
attachments: data.attachments || [],
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
register('DELETE', endpoints.deleteAssignment, ({ params }) => {
|
||||
removeById(adminAssignments, params.id)
|
||||
return { data: { message: 'حذف موفق' } }
|
||||
})
|
||||
|
||||
register('GET', endpoints.getAssignmentSubmissions, ({ params, query }) => {
|
||||
const list = assignmentSubmissions.get(Number(params.assignmentId)) || []
|
||||
return paginate(list, query)
|
||||
})
|
||||
|
||||
register('GET', endpoints.showAssignmentSubmission, ({ params }) => {
|
||||
const list = assignmentSubmissions.get(Number(params.assignmentId)) || []
|
||||
const found = list.find((s) => String(s.id) === String(params.submissionId))
|
||||
return { data: found || null }
|
||||
})
|
||||
|
||||
register('POST', endpoints.reviewAssignmentSubmission, ({ params, data }) => {
|
||||
const list = assignmentSubmissions.get(Number(params.assignmentId)) || []
|
||||
const sub = list.find((s) => String(s.id) === String(params.submissionId))
|
||||
if (sub) {
|
||||
Object.assign(sub, {
|
||||
score: data.score ?? sub.score,
|
||||
status: data.status ?? sub.status,
|
||||
reviewerNote: data.reviewerNote ?? sub.reviewerNote,
|
||||
})
|
||||
}
|
||||
return { data: sub || null }
|
||||
})
|
||||
@@ -0,0 +1,56 @@
|
||||
import { register } from '@/services/mock/registry'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
import { adminConsultations } from '@/services/mock/fixtures/admin-consultations'
|
||||
import {
|
||||
filterDateRange,
|
||||
filterItems,
|
||||
findOrThrow,
|
||||
isoNow,
|
||||
makeId,
|
||||
paginate,
|
||||
updateById,
|
||||
} from '@/services/mock/helpers'
|
||||
|
||||
const STATUS_LABELS = {
|
||||
in_progress: 'در حال گفتگو',
|
||||
answered: 'پاسخ داده شده',
|
||||
closed: 'بسته شده',
|
||||
}
|
||||
|
||||
register('GET', endpoints.getConsultationsList, ({ query }) => {
|
||||
let list = filterItems(adminConsultations, query, {
|
||||
status: 'eq',
|
||||
userName: (item, v) =>
|
||||
`${item.user?.firstName || ''} ${item.user?.lastName || ''}`
|
||||
.toLowerCase()
|
||||
.includes(String(v).toLowerCase()),
|
||||
})
|
||||
list = filterDateRange(list, query)
|
||||
return paginate(list, query)
|
||||
})
|
||||
|
||||
register('GET', endpoints.showConsultation, ({ params }) => ({
|
||||
data: findOrThrow(adminConsultations, params.id),
|
||||
}))
|
||||
|
||||
register('POST', endpoints.sendConsultationMessage, ({ params, data }) => {
|
||||
const consultation = findOrThrow(adminConsultations, params.id)
|
||||
const message = {
|
||||
id: makeId(),
|
||||
sender: 'admin',
|
||||
text: data.text || '',
|
||||
time: 'همین الان',
|
||||
sentAt: isoNow(),
|
||||
}
|
||||
consultation.messages = [...(consultation.messages || []), message]
|
||||
consultation.status = 'answered'
|
||||
consultation.statusLabel = STATUS_LABELS.answered
|
||||
return { data: consultation }
|
||||
})
|
||||
|
||||
register('POST', endpoints.changeConsultationStatus, ({ params, data }) => ({
|
||||
data: updateById(adminConsultations, params.id, {
|
||||
status: data.status,
|
||||
statusLabel: STATUS_LABELS[data.status] || data.status,
|
||||
}),
|
||||
}))
|
||||
@@ -0,0 +1,166 @@
|
||||
import { register } from '@/services/mock/registry'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
import { adminCourseTemplates, adminOfferedCourses } from '@/services/mock/fixtures/admin-courses'
|
||||
import { adminTerms } from '@/services/mock/fixtures/admin-terms'
|
||||
import { adminUsers } from '@/services/mock/fixtures/admin-users'
|
||||
import {
|
||||
filterDateRange,
|
||||
filterItems,
|
||||
findOrThrow,
|
||||
isoNow,
|
||||
makeId,
|
||||
paginate,
|
||||
removeById,
|
||||
updateById,
|
||||
} from '@/services/mock/helpers'
|
||||
|
||||
register('GET', endpoints.getCourseTemplatesList, ({ query }) => {
|
||||
let list = filterItems(adminCourseTemplates, query, {
|
||||
title: 'includes',
|
||||
status: (item, v) => String(item.isActiveByDefault ? 1 : 0) === String(v),
|
||||
})
|
||||
list = filterDateRange(list, query)
|
||||
return paginate(list, query)
|
||||
})
|
||||
|
||||
register('GET', endpoints.showCourseTemplate, ({ params }) => ({
|
||||
data: findOrThrow(adminCourseTemplates, params.id),
|
||||
}))
|
||||
|
||||
register('POST', endpoints.addNewCourseTemplate, ({ data }) => {
|
||||
const teacher = adminUsers.find((u) => u.id === Number(data.defaultTeacherId))
|
||||
const item = {
|
||||
id: makeId(),
|
||||
title: data.title || '',
|
||||
description: data.description || '',
|
||||
image: data.imageId ? `https://picsum.photos/seed/course-${data.imageId}/200/200` : '',
|
||||
defaultTeacher: teacher
|
||||
? {
|
||||
id: teacher.id,
|
||||
firstName: teacher.firstName,
|
||||
lastName: teacher.lastName,
|
||||
fullName: `${teacher.firstName} ${teacher.lastName}`,
|
||||
}
|
||||
: null,
|
||||
defaultCapacity: Number(data.defaultCapacity) || 0,
|
||||
isActiveByDefault: !!data.isActiveByDefault,
|
||||
prerequisitesCount: (data.prerequisites || []).length,
|
||||
prerequisites: (data.prerequisites || []).map((id) => ({
|
||||
courseId: id,
|
||||
course: adminCourseTemplates.find((c) => c.id === Number(id)) || { id },
|
||||
})),
|
||||
createdAt: isoNow(),
|
||||
}
|
||||
adminCourseTemplates.unshift(item)
|
||||
return { data: item }
|
||||
})
|
||||
|
||||
register('PUT', endpoints.updateCourseTemplate, ({ params, data }) => {
|
||||
const teacher = adminUsers.find((u) => u.id === Number(data.defaultTeacherId))
|
||||
return {
|
||||
data: updateById(adminCourseTemplates, params.id, {
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
image: data.imageId ? `https://picsum.photos/seed/course-${data.imageId}/200/200` : undefined,
|
||||
defaultTeacher: teacher
|
||||
? {
|
||||
id: teacher.id,
|
||||
firstName: teacher.firstName,
|
||||
lastName: teacher.lastName,
|
||||
fullName: `${teacher.firstName} ${teacher.lastName}`,
|
||||
}
|
||||
: undefined,
|
||||
defaultCapacity: Number(data.defaultCapacity) || 0,
|
||||
isActiveByDefault: !!data.isActiveByDefault,
|
||||
prerequisites: (data.prerequisites || []).map((id) => ({
|
||||
courseId: id,
|
||||
course: adminCourseTemplates.find((c) => c.id === Number(id)) || { id },
|
||||
})),
|
||||
prerequisitesCount: (data.prerequisites || []).length,
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
register('DELETE', endpoints.deleteCourseTemplate, ({ params }) => {
|
||||
removeById(adminCourseTemplates, params.id)
|
||||
return { data: { message: 'حذف موفق' } }
|
||||
})
|
||||
|
||||
register('POST', endpoints.changeStatusCourseTemplate, ({ params, data }) => ({
|
||||
data: updateById(adminCourseTemplates, params.id, {
|
||||
isActiveByDefault: !!data.isActiveByDefault,
|
||||
}),
|
||||
}))
|
||||
|
||||
register('GET', endpoints.getCoursesList, ({ query }) => {
|
||||
let list = filterItems(adminOfferedCourses, query, {
|
||||
title: 'includes',
|
||||
termId: 'eq',
|
||||
status: (item, v) => String(item.isActive ? 1 : 0) === String(v),
|
||||
})
|
||||
list = filterDateRange(list, query, 'startDate')
|
||||
return paginate(list, query)
|
||||
})
|
||||
|
||||
register('GET', endpoints.showCourse, ({ params }) => ({
|
||||
data: findOrThrow(adminOfferedCourses, params.id),
|
||||
}))
|
||||
|
||||
register('POST', endpoints.addNewCourse, ({ data }) => {
|
||||
const template = adminCourseTemplates.find((t) => t.id === Number(data.templateId))
|
||||
const term = adminTerms.find((t) => t.id === Number(data.termId))
|
||||
const teacher = adminUsers.find((u) => u.id === Number(data.teacherId))
|
||||
const item = {
|
||||
id: makeId(),
|
||||
title: data.title || template?.title || '',
|
||||
image: data.imageId ? `https://picsum.photos/seed/offered-${data.imageId}/200/200` : '',
|
||||
template: template ? { id: template.id, title: template.title } : null,
|
||||
templateId: template?.id,
|
||||
term: term ? { id: term.id, title: term.title } : null,
|
||||
termId: term?.id,
|
||||
teacher: teacher
|
||||
? {
|
||||
id: teacher.id,
|
||||
firstName: teacher.firstName,
|
||||
lastName: teacher.lastName,
|
||||
fullName: `${teacher.firstName} ${teacher.lastName}`,
|
||||
}
|
||||
: null,
|
||||
capacity: Number(data.capacity) || 0,
|
||||
isActive: !!data.isActive,
|
||||
prerequisitesCount: 0,
|
||||
startDate: term?.startDate || '',
|
||||
endDate: term?.endDate || '',
|
||||
createdAt: isoNow(),
|
||||
}
|
||||
adminOfferedCourses.unshift(item)
|
||||
return { data: item }
|
||||
})
|
||||
|
||||
register('PUT', endpoints.updateCourse, ({ params, data }) => {
|
||||
const template = adminCourseTemplates.find((t) => t.id === Number(data.templateId))
|
||||
const term = adminTerms.find((t) => t.id === Number(data.termId))
|
||||
return {
|
||||
data: updateById(adminOfferedCourses, params.id, {
|
||||
title: data.title,
|
||||
image: data.imageId
|
||||
? `https://picsum.photos/seed/offered-${data.imageId}/200/200`
|
||||
: undefined,
|
||||
template: template ? { id: template.id, title: template.title } : undefined,
|
||||
templateId: template?.id,
|
||||
term: term ? { id: term.id, title: term.title } : undefined,
|
||||
termId: term?.id,
|
||||
capacity: Number(data.capacity) || 0,
|
||||
isActive: !!data.isActive,
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
register('DELETE', endpoints.deleteCourse, ({ params }) => {
|
||||
removeById(adminOfferedCourses, params.id)
|
||||
return { data: { message: 'حذف موفق' } }
|
||||
})
|
||||
|
||||
register('POST', endpoints.changeStatusCourse, ({ params, data }) => ({
|
||||
data: updateById(adminOfferedCourses, params.id, { isActive: !!data.isActive }),
|
||||
}))
|
||||
@@ -0,0 +1,94 @@
|
||||
import { register } from '@/services/mock/registry'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
import { adminExams, examParticipants } from '@/services/mock/fixtures/admin-exams'
|
||||
import { adminCourseTemplates } from '@/services/mock/fixtures/admin-courses'
|
||||
import { adminSessions } from '@/services/mock/fixtures/admin-sessions'
|
||||
import {
|
||||
filterDateRange,
|
||||
filterItems,
|
||||
findOrThrow,
|
||||
isoNow,
|
||||
makeId,
|
||||
paginate,
|
||||
removeById,
|
||||
updateById,
|
||||
} from '@/services/mock/helpers'
|
||||
|
||||
register('GET', endpoints.getExamsList, ({ query }) => {
|
||||
let list = filterItems(adminExams, query, {
|
||||
title: 'includes',
|
||||
courseTemplateId: (item, v) => String(item.courseTemplate?.id) === String(v),
|
||||
})
|
||||
list = filterDateRange(list, query)
|
||||
return paginate(list, query)
|
||||
})
|
||||
|
||||
register('GET', endpoints.showExam, ({ params }) => ({
|
||||
data: findOrThrow(adminExams, params.id),
|
||||
}))
|
||||
|
||||
register('POST', endpoints.addNewExam, ({ data }) => {
|
||||
const session = adminSessions.find((s) => s.id === Number(data.sessionId))
|
||||
const template = session?.courseTemplate
|
||||
? adminCourseTemplates.find((c) => c.id === Number(session.courseTemplate.id))
|
||||
: null
|
||||
const item = {
|
||||
id: makeId(),
|
||||
title: data.title || '',
|
||||
description: data.description || '',
|
||||
session: session ? { id: session.id, title: session.title } : null,
|
||||
sessionTitle: session?.title || '',
|
||||
courseTemplate: template ? { id: template.id, title: template.title } : null,
|
||||
courseTemplateTitle: template?.title || '',
|
||||
durationMinutes: Number(data.durationMinutes) || 0,
|
||||
passingScore: Number(data.passingScore) || 0,
|
||||
questionsCount: data.questions?.length || 0,
|
||||
randomize: !!data.randomize,
|
||||
endDate: data.endDate || '',
|
||||
startDate: isoNow(),
|
||||
createdAt: isoNow(),
|
||||
questions: data.questions || [],
|
||||
usedInTerms: [],
|
||||
}
|
||||
adminExams.unshift(item)
|
||||
return { data: item }
|
||||
})
|
||||
|
||||
register('PUT', endpoints.updateExam, ({ params, data }) => {
|
||||
const session = adminSessions.find((s) => s.id === Number(data.sessionId))
|
||||
const template = session?.courseTemplate
|
||||
? adminCourseTemplates.find((c) => c.id === Number(session.courseTemplate.id))
|
||||
: null
|
||||
return {
|
||||
data: updateById(adminExams, params.id, {
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
session: session ? { id: session.id, title: session.title } : undefined,
|
||||
sessionTitle: session?.title,
|
||||
courseTemplate: template ? { id: template.id, title: template.title } : undefined,
|
||||
courseTemplateTitle: template?.title,
|
||||
durationMinutes: Number(data.durationMinutes) || 0,
|
||||
passingScore: Number(data.passingScore) || 0,
|
||||
questionsCount: data.questions?.length || 0,
|
||||
randomize: !!data.randomize,
|
||||
endDate: data.endDate,
|
||||
questions: data.questions || [],
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
register('DELETE', endpoints.deleteExam, ({ params }) => {
|
||||
removeById(adminExams, params.id)
|
||||
return { data: { message: 'حذف موفق' } }
|
||||
})
|
||||
|
||||
register('GET', endpoints.getExamParticipants, ({ params, query }) => {
|
||||
const list = examParticipants.get(Number(params.examId)) || []
|
||||
return paginate(list, query)
|
||||
})
|
||||
|
||||
register('GET', endpoints.showExamParticipant, ({ params }) => {
|
||||
const list = examParticipants.get(Number(params.examId)) || []
|
||||
const found = list.find((p) => String(p.id) === String(params.participantId))
|
||||
return { data: found || null }
|
||||
})
|
||||
@@ -0,0 +1,49 @@
|
||||
import { register } from '@/services/mock/registry'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
import { pendingStudents } from '@/services/mock/fixtures/admin-pending-students'
|
||||
import {
|
||||
filterDateRange,
|
||||
filterItems,
|
||||
findOrThrow,
|
||||
paginate,
|
||||
removeById,
|
||||
updateById,
|
||||
} from '@/services/mock/helpers'
|
||||
|
||||
register('GET', endpoints.getPendingStudents, ({ query }) => {
|
||||
let list = filterItems(pendingStudents, query, {
|
||||
name: (item, v) =>
|
||||
`${item.firstName} ${item.lastName}`.toLowerCase().includes(String(v).toLowerCase()),
|
||||
nationalCode: 'includes',
|
||||
})
|
||||
list = filterDateRange(list, query, 'submittedAt')
|
||||
return paginate(list, query)
|
||||
})
|
||||
|
||||
register('GET', endpoints.showPendingStudent, ({ params }) => ({
|
||||
data: findOrThrow(pendingStudents, params.id),
|
||||
}))
|
||||
|
||||
register('POST', endpoints.changeStatusPendingStudent, ({ params, data }) => {
|
||||
const target = findOrThrow(pendingStudents, params.id)
|
||||
const patch = {
|
||||
status: data.status,
|
||||
verification: {
|
||||
...target.verification,
|
||||
status: data.status,
|
||||
rejectionReason: data.rejectionReason || '',
|
||||
adminNote: data.adminNote || '',
|
||||
},
|
||||
}
|
||||
updateById(pendingStudents, params.id, patch)
|
||||
if (data.status === 'approved') {
|
||||
removeById(pendingStudents, params.id)
|
||||
}
|
||||
return { data: { user: { ...target, ...patch } } }
|
||||
})
|
||||
|
||||
register('GET', endpoints.downloadPdfPendingStudentInfo, ({ params }) => ({
|
||||
data: {
|
||||
downloadUrl: `https://example.com/mock-pdf-${params.id}.pdf`,
|
||||
},
|
||||
}))
|
||||
@@ -0,0 +1,86 @@
|
||||
import { register } from '@/services/mock/registry'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
import { adminSessions, sessionAttendance } from '@/services/mock/fixtures/admin-sessions'
|
||||
import { adminCourseTemplates } from '@/services/mock/fixtures/admin-courses'
|
||||
import { SESSION_TYPE } from '@/enums'
|
||||
import {
|
||||
filterDateRange,
|
||||
filterItems,
|
||||
findOrThrow,
|
||||
isoNow,
|
||||
makeId,
|
||||
paginate,
|
||||
removeById,
|
||||
updateById,
|
||||
} from '@/services/mock/helpers'
|
||||
|
||||
const enrich = (session) => ({
|
||||
...session,
|
||||
sessionTypeFa: SESSION_TYPE[session.sessionType] || session.sessionTypeFa || '',
|
||||
})
|
||||
|
||||
register('GET', endpoints.getSessionsList, ({ query }) => {
|
||||
let list = filterItems(adminSessions, query, {
|
||||
title: 'includes',
|
||||
courseTemplateId: (item, v) => String(item.courseTemplate?.id) === String(v),
|
||||
sessionType: 'eq',
|
||||
})
|
||||
list = filterDateRange(list, query)
|
||||
// eslint-disable-next-line unicorn/no-array-callback-reference
|
||||
return paginate(list.map(enrich), query)
|
||||
})
|
||||
|
||||
register('GET', endpoints.showSession, ({ params }) => ({
|
||||
data: enrich(findOrThrow(adminSessions, params.id)),
|
||||
}))
|
||||
|
||||
register('POST', endpoints.addNewSession, ({ data }) => {
|
||||
const tpl = adminCourseTemplates.find((c) => c.id === Number(data.courseTemplateId))
|
||||
const item = {
|
||||
id: makeId(),
|
||||
title: data.title || '',
|
||||
description: data.description || '',
|
||||
image: data.imageId ? `https://picsum.photos/seed/session-${data.imageId}/200/200` : '',
|
||||
courseTemplate: tpl ? { id: tpl.id, title: tpl.title } : null,
|
||||
sessionType: data.sessionType || 'in_person',
|
||||
durationMinutes: Number(data.durationMinutes) || 0,
|
||||
order: Number(data.order) || 1,
|
||||
sessionConfig: data.sessionConfig || {},
|
||||
materials: data.materials || [],
|
||||
usedInTerms: [],
|
||||
createdAt: isoNow(),
|
||||
}
|
||||
adminSessions.unshift(item)
|
||||
return { data: enrich(item) }
|
||||
})
|
||||
|
||||
register('PUT', endpoints.updateSession, ({ params, data }) => {
|
||||
const tpl = adminCourseTemplates.find((c) => c.id === Number(data.courseTemplateId))
|
||||
const updated = updateById(adminSessions, params.id, {
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
image: data.imageId ? `https://picsum.photos/seed/session-${data.imageId}/200/200` : undefined,
|
||||
courseTemplate: tpl ? { id: tpl.id, title: tpl.title } : undefined,
|
||||
sessionType: data.sessionType,
|
||||
durationMinutes: Number(data.durationMinutes) || 0,
|
||||
order: Number(data.order) || 1,
|
||||
sessionConfig: data.sessionConfig ?? undefined,
|
||||
materials: data.materials ?? undefined,
|
||||
})
|
||||
return { data: enrich(updated) }
|
||||
})
|
||||
|
||||
register('DELETE', endpoints.deleteSession, ({ params }) => {
|
||||
removeById(adminSessions, params.id)
|
||||
return { data: { message: 'حذف موفق' } }
|
||||
})
|
||||
|
||||
register('POST', endpoints.changeStatusSession, ({ params, data }) => {
|
||||
const updated = updateById(adminSessions, params.id, { isActive: !!data.isActive })
|
||||
return { data: enrich(updated) }
|
||||
})
|
||||
|
||||
register('GET', endpoints.getSessionsAttendance, ({ params, query }) => {
|
||||
const list = sessionAttendance.get(Number(params.sessionId)) || []
|
||||
return paginate(list, query)
|
||||
})
|
||||
@@ -0,0 +1,153 @@
|
||||
import { register } from '@/services/mock/registry'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
import { adminTerms, termStudentLinks } from '@/services/mock/fixtures/admin-terms'
|
||||
import { adminUsers } from '@/services/mock/fixtures/admin-users'
|
||||
import { adminOfferedCourses } from '@/services/mock/fixtures/admin-courses'
|
||||
import {
|
||||
filterDateRange,
|
||||
filterItems,
|
||||
findOrThrow,
|
||||
isoNow,
|
||||
makeId,
|
||||
paginate,
|
||||
removeById,
|
||||
updateById,
|
||||
} from '@/services/mock/helpers'
|
||||
|
||||
register('GET', endpoints.getTermsList, ({ query }) => {
|
||||
let list = filterItems(adminTerms, query, {
|
||||
title: 'includes',
|
||||
status: (item, v) => String(item.isActive ? 1 : 0) === String(v),
|
||||
})
|
||||
list = filterDateRange(list, query, 'startDate')
|
||||
return paginate(list, query)
|
||||
})
|
||||
|
||||
register('GET', endpoints.showTerm, ({ params }) => ({
|
||||
data: findOrThrow(adminTerms, params.id),
|
||||
}))
|
||||
|
||||
register('POST', endpoints.addNewTerm, ({ data }) => {
|
||||
const term = {
|
||||
id: makeId(),
|
||||
title: data.title || '',
|
||||
description: data.description || '',
|
||||
image: data.imageId ? `https://picsum.photos/seed/term-${data.imageId}/200/200` : '',
|
||||
startDate: data.startDate || '',
|
||||
endDate: data.endDate || '',
|
||||
isActive: true,
|
||||
studentsCount: 0,
|
||||
coursesCount: 0,
|
||||
createdAt: isoNow(),
|
||||
}
|
||||
adminTerms.unshift(term)
|
||||
return { data: term }
|
||||
})
|
||||
|
||||
register('PUT', endpoints.updateTerm, ({ params, data }) => ({
|
||||
data: updateById(adminTerms, params.id, {
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
startDate: data.startDate,
|
||||
endDate: data.endDate,
|
||||
image: data.imageId ? `https://picsum.photos/seed/term-${data.imageId}/200/200` : undefined,
|
||||
}),
|
||||
}))
|
||||
|
||||
register('DELETE', endpoints.deleteTerm, ({ params }) => {
|
||||
removeById(adminTerms, params.id)
|
||||
return { data: { message: 'حذف موفق' } }
|
||||
})
|
||||
|
||||
register('POST', endpoints.cloneTerm, ({ params }) => {
|
||||
const src = findOrThrow(adminTerms, params.id)
|
||||
const clone = { ...src, id: makeId(), title: `${src.title} (کپی)`, createdAt: isoNow() }
|
||||
adminTerms.unshift(clone)
|
||||
return { data: clone }
|
||||
})
|
||||
|
||||
register('POST', endpoints.changeStatusTerm, ({ params, data }) => ({
|
||||
data: updateById(adminTerms, params.id, { isActive: !!data.isActive }),
|
||||
}))
|
||||
|
||||
const studentSnapshot = (link) => {
|
||||
const user = adminUsers.find((u) => u.id === link.userId)
|
||||
return user ? { ...user, isOnLeave: link.isOnLeave } : null
|
||||
}
|
||||
|
||||
register('GET', endpoints.listUserTerm, ({ params, query }) => {
|
||||
const links = termStudentLinks.get(Number(params.termId)) || []
|
||||
const list = links.map((element) => studentSnapshot(element)).filter(Boolean)
|
||||
return paginate(list, query)
|
||||
})
|
||||
|
||||
register('POST', endpoints.addUserTerm, ({ params, data }) => {
|
||||
const termId = Number(params.termId)
|
||||
const links = termStudentLinks.get(termId) || []
|
||||
const ids = Array.isArray(data.userIds) ? data.userIds : []
|
||||
ids.forEach((userId) => {
|
||||
if (!links.some((l) => l.userId === Number(userId))) {
|
||||
links.push({ userId: Number(userId), isOnLeave: false })
|
||||
}
|
||||
})
|
||||
termStudentLinks.set(termId, links)
|
||||
const added = ids
|
||||
.map((id) => adminUsers.find((u) => u.id === Number(id)))
|
||||
.filter(Boolean)
|
||||
.map((u) => ({ ...u, isOnLeave: false }))
|
||||
const term = adminTerms.find((t) => t.id === termId)
|
||||
if (term) term.studentsCount = links.length
|
||||
return { data: added }
|
||||
})
|
||||
|
||||
register('DELETE', endpoints.removeUserTerm, ({ params }) => {
|
||||
const termId = Number(params.termId)
|
||||
const links = termStudentLinks.get(termId) || []
|
||||
const idx = links.findIndex((l) => String(l.userId) === String(params.userId))
|
||||
if (idx !== -1) links.splice(idx, 1)
|
||||
termStudentLinks.set(termId, links)
|
||||
const term = adminTerms.find((t) => t.id === termId)
|
||||
if (term) term.studentsCount = links.length
|
||||
return { data: { message: 'حذف موفق' } }
|
||||
})
|
||||
|
||||
register('POST', endpoints.changeLeaveStatus, ({ params, data }) => {
|
||||
const termId = Number(params.termId)
|
||||
const links = termStudentLinks.get(termId) || []
|
||||
const link = links.find((l) => String(l.userId) === String(params.userId))
|
||||
if (link) link.isOnLeave = !!data.setLeave
|
||||
return { data: { isOnLeave: !!data.setLeave } }
|
||||
})
|
||||
|
||||
register('GET', endpoints.listCourseTerm, ({ params, query }) => {
|
||||
const termId = Number(params.termId)
|
||||
const list = adminOfferedCourses.filter((c) => Number(c.termId) === termId)
|
||||
return paginate(list, query)
|
||||
})
|
||||
|
||||
register('POST', endpoints.addCourseTerm, ({ params, data }) => {
|
||||
const termId = Number(params.termId)
|
||||
const ids = Array.isArray(data.courseIds) ? data.courseIds : []
|
||||
const linked = []
|
||||
ids.forEach((id) => {
|
||||
const course = adminOfferedCourses.find((c) => Number(c.id) === Number(id))
|
||||
if (course) {
|
||||
course.termId = termId
|
||||
course.term = adminTerms.some((t) => t.id === termId)
|
||||
? { id: termId, title: adminTerms.find((t) => t.id === termId).title }
|
||||
: course.term
|
||||
linked.push(course)
|
||||
}
|
||||
})
|
||||
return { data: linked }
|
||||
})
|
||||
|
||||
register('DELETE', endpoints.removeCourseTerm, ({ params }) => {
|
||||
const courseId = Number(params.courseId)
|
||||
const course = adminOfferedCourses.find((c) => c.id === courseId)
|
||||
if (course) {
|
||||
course.termId = null
|
||||
course.term = null
|
||||
}
|
||||
return { data: { message: 'حذف موفق' } }
|
||||
})
|
||||
@@ -0,0 +1,55 @@
|
||||
import { register } from '@/services/mock/registry'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
import { adminTickets } from '@/services/mock/fixtures/admin-tickets'
|
||||
import {
|
||||
filterDateRange,
|
||||
filterItems,
|
||||
findOrThrow,
|
||||
isoNow,
|
||||
makeId,
|
||||
paginate,
|
||||
updateById,
|
||||
} from '@/services/mock/helpers'
|
||||
|
||||
register('GET', endpoints.getTicketsList, ({ query }) => {
|
||||
let list = filterItems(adminTickets, query, {
|
||||
status: 'eq',
|
||||
userName: (item, v) =>
|
||||
`${item.user?.firstName || ''} ${item.user?.lastName || ''}`
|
||||
.toLowerCase()
|
||||
.includes(String(v).toLowerCase()),
|
||||
})
|
||||
list = filterDateRange(list, query)
|
||||
return paginate(list, query)
|
||||
})
|
||||
|
||||
register('GET', endpoints.showTicket, ({ params }) => ({
|
||||
data: findOrThrow(adminTickets, params.id),
|
||||
}))
|
||||
|
||||
register('POST', endpoints.sendTicketMessage, ({ params, data }) => {
|
||||
const ticket = findOrThrow(adminTickets, params.id)
|
||||
const message = {
|
||||
id: makeId(),
|
||||
sender: 'admin',
|
||||
text: data.text || '',
|
||||
time: 'همین الان',
|
||||
sentAt: isoNow(),
|
||||
}
|
||||
ticket.messages = [...(ticket.messages || []), message]
|
||||
ticket.status = 'answered'
|
||||
ticket.statusLabel = 'پاسخ داده شده'
|
||||
return { data: ticket }
|
||||
})
|
||||
|
||||
register('POST', endpoints.changeTicketStatus, ({ params, data }) => ({
|
||||
data: updateById(adminTickets, params.id, {
|
||||
status: data.status,
|
||||
statusLabel:
|
||||
data.status === 'closed'
|
||||
? 'بسته شده'
|
||||
: data.status === 'answered'
|
||||
? 'پاسخ داده شده'
|
||||
: 'در انتظار پاسخ',
|
||||
}),
|
||||
}))
|
||||
@@ -0,0 +1,103 @@
|
||||
import { register } from '@/services/mock/registry'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
import { adminUsers, roles } from '@/services/mock/fixtures/admin-users'
|
||||
import {
|
||||
filterDateRange,
|
||||
filterItems,
|
||||
findOrThrow,
|
||||
isoNow,
|
||||
makeId,
|
||||
paginate,
|
||||
removeById,
|
||||
updateById,
|
||||
} from '@/services/mock/helpers'
|
||||
|
||||
register('GET', endpoints.getApprovedUsers, ({ query }) => {
|
||||
let list = filterItems(adminUsers, query, {
|
||||
name: (item, v) =>
|
||||
`${item.firstName} ${item.lastName}`.toLowerCase().includes(String(v).toLowerCase()),
|
||||
nationalCode: 'includes',
|
||||
phoneNumber: 'includes',
|
||||
roleId: (item, v) => String(item.roleId) === String(v),
|
||||
})
|
||||
list = filterDateRange(list, query)
|
||||
return paginate(list, query)
|
||||
})
|
||||
|
||||
register('GET', endpoints.showUserDetails, ({ params }) => ({
|
||||
data: findOrThrow(adminUsers, params.id),
|
||||
}))
|
||||
|
||||
register('POST', endpoints.addNewUser, ({ data }) => {
|
||||
const id = makeId()
|
||||
const role = roles.find((r) => r.id === Number(data.roleId)) || null
|
||||
const province = data.provinceId ? { id: data.provinceId, name: '' } : null
|
||||
const city = data.cityId ? { id: data.cityId, name: '' } : null
|
||||
const user = {
|
||||
id,
|
||||
firstName: data.firstName || '',
|
||||
lastName: data.lastName || '',
|
||||
fullName: `${data.firstName || ''} ${data.lastName || ''}`.trim(),
|
||||
phoneNumber: data.phoneNumber || '',
|
||||
nationalCode: data.nationalCode || '',
|
||||
avatarUrl: '',
|
||||
status: 'approved',
|
||||
roles: role ? [role.name] : [],
|
||||
roleId: role?.id,
|
||||
address: { address: data.address || '', province, city },
|
||||
profile: {
|
||||
bio: data.bio || '',
|
||||
birthDate: data.birthDate || '',
|
||||
maritalStatus: data.maritalStatus || '',
|
||||
gender: data.gender || '',
|
||||
avatarId: data.avatarId || null,
|
||||
},
|
||||
createdAt: isoNow(),
|
||||
}
|
||||
adminUsers.unshift(user)
|
||||
return { data: user }
|
||||
})
|
||||
|
||||
register('PUT', endpoints.updateUser, ({ params, data }) => {
|
||||
const role = roles.find((r) => r.id === Number(data.roleId))
|
||||
const patch = {
|
||||
firstName: data.firstName,
|
||||
lastName: data.lastName,
|
||||
fullName: `${data.firstName || ''} ${data.lastName || ''}`.trim(),
|
||||
phoneNumber: data.phoneNumber,
|
||||
nationalCode: data.nationalCode,
|
||||
roleId: role?.id,
|
||||
roles: role ? [role.name] : [],
|
||||
address: {
|
||||
address: data.address || '',
|
||||
province: data.provinceId ? { id: data.provinceId, name: '' } : null,
|
||||
city: data.cityId ? { id: data.cityId, name: '' } : null,
|
||||
},
|
||||
profile: {
|
||||
bio: data.bio || '',
|
||||
birthDate: data.birthDate || '',
|
||||
maritalStatus: data.maritalStatus || '',
|
||||
gender: data.gender || '',
|
||||
avatarId: data.avatarId || null,
|
||||
},
|
||||
}
|
||||
const updated = updateById(adminUsers, params.id, patch)
|
||||
return { data: updated }
|
||||
})
|
||||
|
||||
register('POST', endpoints.updateUserRole, ({ params, data }) => {
|
||||
const role = roles.find((r) => r.id === Number(data.roleId))
|
||||
const patch = role ? { roleId: role.id, roles: [role.name] } : {}
|
||||
return { data: updateById(adminUsers, params.id, patch) }
|
||||
})
|
||||
|
||||
register('POST', endpoints.changeUserStatus, ({ params, data }) => ({
|
||||
data: updateById(adminUsers, params.id, { status: data.status }),
|
||||
}))
|
||||
|
||||
register('DELETE', endpoints.deleteUser, ({ params }) => {
|
||||
removeById(adminUsers, params.id)
|
||||
return { data: { message: 'حذف موفق' } }
|
||||
})
|
||||
|
||||
register('GET', endpoints.getRolesList, () => ({ data: roles }))
|
||||
@@ -0,0 +1,89 @@
|
||||
import { register } from '@/services/mock/registry'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
import { currentProfile } from '@/services/mock/fixtures/profile'
|
||||
import { makeId } from '@/services/mock/helpers'
|
||||
|
||||
const fakeToken = 'mock-token-1234567890'
|
||||
|
||||
register('POST', endpoints.login, () => ({
|
||||
data: { user: currentProfile, token: fakeToken },
|
||||
}))
|
||||
|
||||
register('POST', endpoints.loginWithCode2Step, () => ({
|
||||
data: { user: currentProfile, token: fakeToken },
|
||||
}))
|
||||
|
||||
register('POST', endpoints.verifyCode, () => ({
|
||||
data: { user: currentProfile, token: fakeToken },
|
||||
}))
|
||||
|
||||
register('POST', endpoints.register, ({ data }) => ({
|
||||
data: { user: { ...currentProfile, ...data }, token: fakeToken },
|
||||
}))
|
||||
|
||||
register('POST', endpoints.resendVerificationCodeForRegister, () => ({
|
||||
data: { message: 'کد جدید ارسال شد' },
|
||||
}))
|
||||
|
||||
register('POST', endpoints.forgotPassword, () => ({
|
||||
data: { message: 'کد بازیابی ارسال شد' },
|
||||
}))
|
||||
|
||||
register('POST', endpoints.verifyForgotPasswordCode, () => ({
|
||||
data: { token: fakeToken },
|
||||
}))
|
||||
|
||||
register('POST', endpoints.resetPassword, () => ({
|
||||
data: { message: 'رمز عبور با موفقیت تغییر کرد' },
|
||||
}))
|
||||
|
||||
register('POST', endpoints.logout, () => ({ data: { message: 'خروج موفق' } }))
|
||||
|
||||
register('GET', endpoints.getProfile, () => ({ data: currentProfile }))
|
||||
|
||||
register('PUT', endpoints.updateProfile, ({ data }) => {
|
||||
Object.assign(currentProfile, {
|
||||
firstName: data.firstName ?? currentProfile.firstName,
|
||||
lastName: data.lastName ?? currentProfile.lastName,
|
||||
phoneNumber: data.phoneNumber ?? currentProfile.phoneNumber,
|
||||
nationalCode: data.nationalCode ?? currentProfile.nationalCode,
|
||||
})
|
||||
if (data.provinceId) {
|
||||
currentProfile.address = currentProfile.address || {}
|
||||
currentProfile.address.province = { id: data.provinceId, name: '' }
|
||||
}
|
||||
if (data.cityId) {
|
||||
currentProfile.address = currentProfile.address || {}
|
||||
currentProfile.address.city = { id: data.cityId, name: '' }
|
||||
}
|
||||
if (data.address) {
|
||||
currentProfile.address = { ...currentProfile.address, address: data.address }
|
||||
}
|
||||
currentProfile.profile = {
|
||||
...currentProfile.profile,
|
||||
bio: data.bio ?? currentProfile.profile?.bio,
|
||||
birthDate: data.birthDate ?? currentProfile.profile?.birthDate,
|
||||
maritalStatus: data.maritalStatus ?? currentProfile.profile?.maritalStatus,
|
||||
gender: data.gender ?? currentProfile.profile?.gender,
|
||||
}
|
||||
return { data: currentProfile }
|
||||
})
|
||||
|
||||
register('POST', endpoints.completeProfile, ({ data }) => ({
|
||||
data: { user: { ...currentProfile, ...data } },
|
||||
}))
|
||||
|
||||
register('GET', endpoints.getRegistrationQuestionVideo, () => ({
|
||||
data: { url: '', id: 0 },
|
||||
}))
|
||||
|
||||
register('POST', endpoints.uploadMediaTemporary, () => {
|
||||
const id = makeId()
|
||||
return {
|
||||
data: {
|
||||
id,
|
||||
uploadId: id,
|
||||
url: `https://picsum.photos/seed/${id}/240/240`,
|
||||
},
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
import { register } from '@/services/mock/registry'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
import { cities, provinces } from '@/services/mock/fixtures/common'
|
||||
|
||||
register('GET', endpoints.provinceList, () => ({ data: provinces }))
|
||||
|
||||
register('GET', endpoints.citiesList, ({ params }) => ({
|
||||
data: cities[params.provinceId] || [],
|
||||
}))
|
||||
@@ -0,0 +1,24 @@
|
||||
import { register } from '@/services/mock/registry'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
import { studentCourses } from '@/services/mock/fixtures/student-courses'
|
||||
import { findOrThrow, paginate } from '@/services/mock/helpers'
|
||||
|
||||
const filterByStatus = (status) => {
|
||||
if (!status) return studentCourses
|
||||
if (status === 'current') {
|
||||
return studentCourses.filter((c) => ['watching', 'waitForExam'].includes(c.status))
|
||||
}
|
||||
if (status === 'ended') {
|
||||
return studentCourses.filter((c) => ['completed', 'failed'].includes(c.status))
|
||||
}
|
||||
return studentCourses.filter((c) => c.status === status)
|
||||
}
|
||||
|
||||
register('GET', endpoints.getStudentCourses, ({ query }) => {
|
||||
const list = filterByStatus(query.status)
|
||||
return paginate(list, query)
|
||||
})
|
||||
|
||||
register('GET', endpoints.showStudentCourse, ({ params }) => ({
|
||||
data: findOrThrow(studentCourses, params.id),
|
||||
}))
|
||||
@@ -0,0 +1,95 @@
|
||||
import { useMutation, useQuery } from '@tanstack/vue-query'
|
||||
|
||||
import {
|
||||
apiAddAdminAssignment,
|
||||
apiDeleteAdminAssignment,
|
||||
apiGetAdminAssignmentSubmissions,
|
||||
apiGetAdminAssignments,
|
||||
apiReviewAdminAssignmentSubmission,
|
||||
apiShowAdminAssignment,
|
||||
apiShowAdminAssignmentSubmission,
|
||||
apiUpdateAdminAssignment,
|
||||
} from '@/services/api/admin-assignments'
|
||||
import { cleanFilters } from '@/utils/clean-filters'
|
||||
|
||||
export const adminAssignmentsKeys = {
|
||||
all: ['admin', 'assignments'],
|
||||
list: (filters, pagination) => ['admin', 'assignments', 'list', filters, pagination],
|
||||
detail: (id) => ['admin', 'assignments', 'detail', id],
|
||||
submissions: (assignmentId, filters, pagination) => [
|
||||
'admin',
|
||||
'assignments',
|
||||
'submissions',
|
||||
assignmentId,
|
||||
filters,
|
||||
pagination,
|
||||
],
|
||||
submissionDetail: (assignmentId, submissionId) => [
|
||||
'admin',
|
||||
'assignments',
|
||||
'submissions',
|
||||
assignmentId,
|
||||
'detail',
|
||||
submissionId,
|
||||
],
|
||||
}
|
||||
|
||||
export const useAdminAssignmentsListQuery = (filtersRef, paginationRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'assignments', 'list', filtersRef, paginationRef],
|
||||
queryFn: () =>
|
||||
apiGetAdminAssignments({
|
||||
...cleanFilters(filtersRef.value),
|
||||
...paginationRef.value,
|
||||
}),
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAdminAssignmentQuery = (idRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'assignments', 'detail', idRef],
|
||||
queryFn: () => apiShowAdminAssignment(idRef.value),
|
||||
select: (response) => response?.data ?? response,
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAdminAssignmentSubmissionsQuery = (
|
||||
assignmentIdRef,
|
||||
filtersRef,
|
||||
paginationRef,
|
||||
options = {}
|
||||
) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'assignments', 'submissions', assignmentIdRef, filtersRef, paginationRef],
|
||||
queryFn: () =>
|
||||
apiGetAdminAssignmentSubmissions(assignmentIdRef.value, {
|
||||
...cleanFilters(filtersRef?.value || {}),
|
||||
...paginationRef?.value,
|
||||
}),
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAdminAssignmentSubmissionQuery = (assignmentIdRef, submissionIdRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'assignments', 'submissions', assignmentIdRef, 'detail', submissionIdRef],
|
||||
queryFn: () => apiShowAdminAssignmentSubmission(assignmentIdRef.value, submissionIdRef.value),
|
||||
select: (response) => response?.data ?? response,
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAddAdminAssignmentMutation = () =>
|
||||
useMutation({ mutationFn: (payload) => apiAddAdminAssignment(payload) })
|
||||
|
||||
export const useUpdateAdminAssignmentMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ id, payload }) => apiUpdateAdminAssignment(id, payload),
|
||||
})
|
||||
|
||||
export const useDeleteAdminAssignmentMutation = () =>
|
||||
useMutation({ mutationFn: (id) => apiDeleteAdminAssignment(id) })
|
||||
|
||||
export const useReviewAdminAssignmentSubmissionMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ assignmentId, submissionId, payload }) =>
|
||||
apiReviewAdminAssignmentSubmission(assignmentId, submissionId, payload),
|
||||
})
|
||||
@@ -0,0 +1,41 @@
|
||||
import { useMutation, useQuery } from '@tanstack/vue-query'
|
||||
|
||||
import {
|
||||
apiChangeAdminConsultationStatus,
|
||||
apiGetAdminConsultations,
|
||||
apiSendAdminConsultationMessage,
|
||||
apiShowAdminConsultation,
|
||||
} from '@/services/api/admin-consultations'
|
||||
import { cleanFilters } from '@/utils/clean-filters'
|
||||
|
||||
export const adminConsultationsKeys = {
|
||||
all: ['admin', 'consultations'],
|
||||
list: (filters, pagination) => ['admin', 'consultations', 'list', filters, pagination],
|
||||
detail: (id) => ['admin', 'consultations', 'detail', id],
|
||||
}
|
||||
|
||||
export const useAdminConsultationsListQuery = (filtersRef, paginationRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'consultations', 'list', filtersRef, paginationRef],
|
||||
queryFn: () =>
|
||||
apiGetAdminConsultations({ ...cleanFilters(filtersRef.value), ...paginationRef.value }),
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAdminConsultationQuery = (idRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'consultations', 'detail', idRef],
|
||||
queryFn: () => apiShowAdminConsultation(idRef.value),
|
||||
select: (response) => response?.data ?? response,
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useSendAdminConsultationMessageMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ id, payload }) => apiSendAdminConsultationMessage(id, payload),
|
||||
})
|
||||
|
||||
export const useChangeAdminConsultationStatusMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ id, payload }) => apiChangeAdminConsultationStatus(id, payload),
|
||||
})
|
||||
@@ -0,0 +1,126 @@
|
||||
import { useMutation, useQuery } from '@tanstack/vue-query'
|
||||
|
||||
import {
|
||||
apiAddAdminCourseTemplate,
|
||||
apiAddAdminTemplateStudent,
|
||||
apiAttachAdminTemplateSession,
|
||||
apiChangeAdminCourseTemplateStatus,
|
||||
apiDeleteAdminCourseTemplate,
|
||||
apiDetachAdminTemplateSession,
|
||||
apiGetAdminCourseTemplates,
|
||||
apiGetAdminTemplateSessions,
|
||||
apiGetAdminTemplateStudents,
|
||||
apiRemoveAdminTemplateStudent,
|
||||
apiShowAdminCourseTemplate,
|
||||
apiUpdateAdminCourseTemplate,
|
||||
} from '@/services/api/admin-course-templates'
|
||||
import { cleanFilters } from '@/utils/clean-filters'
|
||||
|
||||
export const adminCourseTemplatesKeys = {
|
||||
all: ['admin', 'course-templates'],
|
||||
list: (filters, pagination) => ['admin', 'course-templates', 'list', filters, pagination],
|
||||
detail: (id) => ['admin', 'course-templates', 'detail', id],
|
||||
students: (templateId, filters, pagination) => [
|
||||
'admin',
|
||||
'course-templates',
|
||||
'students',
|
||||
templateId,
|
||||
filters,
|
||||
pagination,
|
||||
],
|
||||
sessions: (templateId, filters, pagination) => [
|
||||
'admin',
|
||||
'course-templates',
|
||||
'sessions',
|
||||
templateId,
|
||||
filters,
|
||||
pagination,
|
||||
],
|
||||
}
|
||||
|
||||
export const useAdminCourseTemplatesListQuery = (filtersRef, paginationRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'course-templates', 'list', filtersRef, paginationRef],
|
||||
queryFn: () =>
|
||||
apiGetAdminCourseTemplates({
|
||||
...cleanFilters(filtersRef.value),
|
||||
...paginationRef.value,
|
||||
}),
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAdminCourseTemplateQuery = (idRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'course-templates', 'detail', idRef],
|
||||
queryFn: () => apiShowAdminCourseTemplate(idRef.value),
|
||||
select: (response) => response?.data ?? response,
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAddAdminCourseTemplateMutation = () =>
|
||||
useMutation({ mutationFn: (payload) => apiAddAdminCourseTemplate(payload) })
|
||||
|
||||
export const useUpdateAdminCourseTemplateMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ id, payload }) => apiUpdateAdminCourseTemplate(id, payload),
|
||||
})
|
||||
|
||||
export const useDeleteAdminCourseTemplateMutation = () =>
|
||||
useMutation({ mutationFn: (id) => apiDeleteAdminCourseTemplate(id) })
|
||||
|
||||
export const useChangeAdminCourseTemplateStatusMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ id, payload }) => apiChangeAdminCourseTemplateStatus(id, payload),
|
||||
})
|
||||
|
||||
export const useAdminTemplateStudentsQuery = (
|
||||
templateIdRef,
|
||||
filtersRef,
|
||||
paginationRef,
|
||||
options = {}
|
||||
) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'course-templates', 'students', templateIdRef, filtersRef, paginationRef],
|
||||
queryFn: () =>
|
||||
apiGetAdminTemplateStudents(templateIdRef.value, {
|
||||
...cleanFilters(filtersRef?.value || {}),
|
||||
...paginationRef?.value,
|
||||
}),
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAddAdminTemplateStudentMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ templateId, payload }) => apiAddAdminTemplateStudent(templateId, payload),
|
||||
})
|
||||
|
||||
export const useRemoveAdminTemplateStudentMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ templateId, userId }) => apiRemoveAdminTemplateStudent(templateId, userId),
|
||||
})
|
||||
|
||||
export const useAdminTemplateSessionsQuery = (
|
||||
templateIdRef,
|
||||
filtersRef,
|
||||
paginationRef,
|
||||
options = {}
|
||||
) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'course-templates', 'sessions', templateIdRef, filtersRef, paginationRef],
|
||||
queryFn: () =>
|
||||
apiGetAdminTemplateSessions(templateIdRef.value, {
|
||||
...cleanFilters(filtersRef?.value || {}),
|
||||
...paginationRef?.value,
|
||||
}),
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAttachAdminTemplateSessionMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ templateId, payload }) => apiAttachAdminTemplateSession(templateId, payload),
|
||||
})
|
||||
|
||||
export const useDetachAdminTemplateSessionMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ templateId, sessionId }) => apiDetachAdminTemplateSession(templateId, sessionId),
|
||||
})
|
||||
@@ -0,0 +1,49 @@
|
||||
import { useMutation, useQuery } from '@tanstack/vue-query'
|
||||
|
||||
import {
|
||||
apiAddAdminCourse,
|
||||
apiChangeAdminCourseStatus,
|
||||
apiDeleteAdminCourse,
|
||||
apiGetAdminCourses,
|
||||
apiShowAdminCourse,
|
||||
apiUpdateAdminCourse,
|
||||
} from '@/services/api/admin-courses'
|
||||
import { cleanFilters } from '@/utils/clean-filters'
|
||||
|
||||
export const adminCoursesKeys = {
|
||||
all: ['admin', 'courses'],
|
||||
list: (filters, pagination) => ['admin', 'courses', 'list', filters, pagination],
|
||||
detail: (id) => ['admin', 'courses', 'detail', id],
|
||||
}
|
||||
|
||||
export const useAdminCoursesListQuery = (filtersRef, paginationRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'courses', 'list', filtersRef, paginationRef],
|
||||
queryFn: () =>
|
||||
apiGetAdminCourses({ ...cleanFilters(filtersRef.value), ...paginationRef.value }),
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAdminCourseQuery = (idRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'courses', 'detail', idRef],
|
||||
queryFn: () => apiShowAdminCourse(idRef.value),
|
||||
select: (response) => response?.data ?? response,
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAddAdminCourseMutation = () =>
|
||||
useMutation({ mutationFn: (payload) => apiAddAdminCourse(payload) })
|
||||
|
||||
export const useUpdateAdminCourseMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ id, payload }) => apiUpdateAdminCourse(id, payload),
|
||||
})
|
||||
|
||||
export const useDeleteAdminCourseMutation = () =>
|
||||
useMutation({ mutationFn: (id) => apiDeleteAdminCourse(id) })
|
||||
|
||||
export const useChangeAdminCourseStatusMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ id, payload }) => apiChangeAdminCourseStatus(id, payload),
|
||||
})
|
||||
@@ -0,0 +1,77 @@
|
||||
import { useMutation, useQuery } from '@tanstack/vue-query'
|
||||
|
||||
import {
|
||||
apiAddAdminExam,
|
||||
apiDeleteAdminExam,
|
||||
apiGetAdminExams,
|
||||
apiGetAdminExamParticipants,
|
||||
apiShowAdminExam,
|
||||
apiShowAdminExamParticipant,
|
||||
apiUpdateAdminExam,
|
||||
} from '@/services/api/admin-exams'
|
||||
import { cleanFilters } from '@/utils/clean-filters'
|
||||
|
||||
export const adminExamsKeys = {
|
||||
all: ['admin', 'exams'],
|
||||
list: (filters, pagination) => ['admin', 'exams', 'list', filters, pagination],
|
||||
detail: (id) => ['admin', 'exams', 'detail', id],
|
||||
participants: (examId, filters, pagination) => [
|
||||
'admin',
|
||||
'exams',
|
||||
'participants',
|
||||
examId,
|
||||
filters,
|
||||
pagination,
|
||||
],
|
||||
participantDetail: (examId, participantId) => [
|
||||
'admin',
|
||||
'exams',
|
||||
'participants',
|
||||
examId,
|
||||
'detail',
|
||||
participantId,
|
||||
],
|
||||
}
|
||||
|
||||
export const useAdminExamsListQuery = (filtersRef, paginationRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'exams', 'list', filtersRef, paginationRef],
|
||||
queryFn: () => apiGetAdminExams({ ...cleanFilters(filtersRef.value), ...paginationRef.value }),
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAdminExamQuery = (idRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'exams', 'detail', idRef],
|
||||
queryFn: () => apiShowAdminExam(idRef.value),
|
||||
select: (response) => response?.data ?? response,
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAdminExamParticipantsQuery = (examIdRef, filtersRef, paginationRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'exams', 'participants', examIdRef, filtersRef, paginationRef],
|
||||
queryFn: () =>
|
||||
apiGetAdminExamParticipants(examIdRef.value, {
|
||||
...cleanFilters(filtersRef?.value || {}),
|
||||
...paginationRef?.value,
|
||||
}),
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAdminExamParticipantQuery = (examIdRef, participantIdRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'exams', 'participants', examIdRef, 'detail', participantIdRef],
|
||||
queryFn: () => apiShowAdminExamParticipant(examIdRef.value, participantIdRef.value),
|
||||
select: (response) => response?.data ?? response,
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAddAdminExamMutation = () =>
|
||||
useMutation({ mutationFn: (payload) => apiAddAdminExam(payload) })
|
||||
|
||||
export const useUpdateAdminExamMutation = () =>
|
||||
useMutation({ mutationFn: ({ id, payload }) => apiUpdateAdminExam(id, payload) })
|
||||
|
||||
export const useDeleteAdminExamMutation = () =>
|
||||
useMutation({ mutationFn: (id) => apiDeleteAdminExam(id) })
|
||||
@@ -0,0 +1,39 @@
|
||||
import { useMutation, useQuery } from '@tanstack/vue-query'
|
||||
|
||||
import {
|
||||
apiChangePendingStudentStatus,
|
||||
apiDownloadPendingStudentPdf,
|
||||
apiGetPendingStudents,
|
||||
apiShowPendingStudent,
|
||||
} from '@/services/api/admin-pending-students'
|
||||
import { cleanFilters } from '@/utils/clean-filters'
|
||||
|
||||
export const adminPendingStudentsKeys = {
|
||||
all: ['admin', 'pending-students'],
|
||||
list: (filters, pagination) => ['admin', 'pending-students', 'list', filters, pagination],
|
||||
detail: (id) => ['admin', 'pending-students', 'detail', id],
|
||||
}
|
||||
|
||||
export const usePendingStudentsListQuery = (filtersRef, paginationRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'pending-students', 'list', filtersRef, paginationRef],
|
||||
queryFn: () =>
|
||||
apiGetPendingStudents({ ...cleanFilters(filtersRef.value), ...paginationRef.value }),
|
||||
...options,
|
||||
})
|
||||
|
||||
export const usePendingStudentQuery = (idRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'pending-students', 'detail', idRef],
|
||||
queryFn: () => apiShowPendingStudent(idRef.value),
|
||||
select: (response) => response?.data ?? response,
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useChangePendingStudentStatusMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ id, payload }) => apiChangePendingStudentStatus(id, payload),
|
||||
})
|
||||
|
||||
export const useDownloadPendingStudentPdfMutation = () =>
|
||||
useMutation({ mutationFn: (id) => apiDownloadPendingStudentPdf(id) })
|
||||
@@ -0,0 +1,74 @@
|
||||
import { useMutation, useQuery } from '@tanstack/vue-query'
|
||||
|
||||
import {
|
||||
apiAddAdminSession,
|
||||
apiChangeAdminSessionStatus,
|
||||
apiDeleteAdminSession,
|
||||
apiGetAdminSessions,
|
||||
apiGetSessionAttendance,
|
||||
apiShowAdminSession,
|
||||
apiUpdateAdminSession,
|
||||
} from '@/services/api/admin-sessions'
|
||||
import { cleanFilters } from '@/utils/clean-filters'
|
||||
|
||||
export const adminSessionsKeys = {
|
||||
all: ['admin', 'sessions'],
|
||||
list: (filters, pagination) => ['admin', 'sessions', 'list', filters, pagination],
|
||||
detail: (id) => ['admin', 'sessions', 'detail', id],
|
||||
attendance: (sessionId, filters, pagination) => [
|
||||
'admin',
|
||||
'sessions',
|
||||
'attendance',
|
||||
sessionId,
|
||||
filters,
|
||||
pagination,
|
||||
],
|
||||
}
|
||||
|
||||
export const useAdminSessionsListQuery = (filtersRef, paginationRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'sessions', 'list', filtersRef, paginationRef],
|
||||
queryFn: () =>
|
||||
apiGetAdminSessions({ ...cleanFilters(filtersRef.value), ...paginationRef.value }),
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAdminSessionQuery = (idRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'sessions', 'detail', idRef],
|
||||
queryFn: () => apiShowAdminSession(idRef.value),
|
||||
select: (response) => response?.data ?? response,
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAdminSessionAttendanceQuery = (
|
||||
sessionIdRef,
|
||||
filtersRef,
|
||||
paginationRef,
|
||||
options = {}
|
||||
) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'sessions', 'attendance', sessionIdRef, filtersRef, paginationRef],
|
||||
queryFn: () =>
|
||||
apiGetSessionAttendance(sessionIdRef.value, {
|
||||
...cleanFilters(filtersRef?.value || {}),
|
||||
...paginationRef?.value,
|
||||
}),
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAddAdminSessionMutation = () =>
|
||||
useMutation({ mutationFn: (payload) => apiAddAdminSession(payload) })
|
||||
|
||||
export const useUpdateAdminSessionMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ id, payload }) => apiUpdateAdminSession(id, payload),
|
||||
})
|
||||
|
||||
export const useDeleteAdminSessionMutation = () =>
|
||||
useMutation({ mutationFn: (id) => apiDeleteAdminSession(id) })
|
||||
|
||||
export const useChangeAdminSessionStatusMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ id, payload }) => apiChangeAdminSessionStatus(id, payload),
|
||||
})
|
||||
@@ -0,0 +1,119 @@
|
||||
import { useMutation, useQuery } from '@tanstack/vue-query'
|
||||
|
||||
import {
|
||||
apiAddAdminTerm,
|
||||
apiAddAdminTermCourses,
|
||||
apiAddAdminTermStudents,
|
||||
apiChangeAdminTermStatus,
|
||||
apiCloneAdminTerm,
|
||||
apiDeleteAdminTerm,
|
||||
apiGetAdminTerms,
|
||||
apiGetAdminTermCourses,
|
||||
apiGetAdminTermStudents,
|
||||
apiRemoveAdminTermCourse,
|
||||
apiRemoveAdminTermStudent,
|
||||
apiShowAdminTerm,
|
||||
apiToggleAdminTermStudentLeave,
|
||||
apiUpdateAdminTerm,
|
||||
} from '@/services/api/admin-terms'
|
||||
import { cleanFilters } from '@/utils/clean-filters'
|
||||
|
||||
export const adminTermsKeys = {
|
||||
all: ['admin', 'terms'],
|
||||
list: (filters, pagination) => ['admin', 'terms', 'list', filters, pagination],
|
||||
detail: (id) => ['admin', 'terms', 'detail', id],
|
||||
students: (termId, filters, pagination) => [
|
||||
'admin',
|
||||
'terms',
|
||||
'students',
|
||||
termId,
|
||||
filters,
|
||||
pagination,
|
||||
],
|
||||
courses: (termId, filters, pagination) => [
|
||||
'admin',
|
||||
'terms',
|
||||
'courses',
|
||||
termId,
|
||||
filters,
|
||||
pagination,
|
||||
],
|
||||
}
|
||||
|
||||
export const useAdminTermsListQuery = (filtersRef, paginationRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'terms', 'list', filtersRef, paginationRef],
|
||||
queryFn: () => apiGetAdminTerms({ ...cleanFilters(filtersRef.value), ...paginationRef.value }),
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAdminTermQuery = (idRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'terms', 'detail', idRef],
|
||||
queryFn: () => apiShowAdminTerm(idRef.value),
|
||||
select: (response) => response?.data ?? response,
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAddAdminTermMutation = () =>
|
||||
useMutation({ mutationFn: (payload) => apiAddAdminTerm(payload) })
|
||||
|
||||
export const useUpdateAdminTermMutation = () =>
|
||||
useMutation({ mutationFn: ({ id, payload }) => apiUpdateAdminTerm(id, payload) })
|
||||
|
||||
export const useDeleteAdminTermMutation = () =>
|
||||
useMutation({ mutationFn: (id) => apiDeleteAdminTerm(id) })
|
||||
|
||||
export const useCloneAdminTermMutation = () =>
|
||||
useMutation({ mutationFn: (id) => apiCloneAdminTerm(id) })
|
||||
|
||||
export const useChangeAdminTermStatusMutation = () =>
|
||||
useMutation({ mutationFn: ({ id, payload }) => apiChangeAdminTermStatus(id, payload) })
|
||||
|
||||
export const useAdminTermStudentsQuery = (termIdRef, filtersRef, paginationRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'terms', 'students', termIdRef, filtersRef, paginationRef],
|
||||
queryFn: () =>
|
||||
apiGetAdminTermStudents(termIdRef.value, {
|
||||
...cleanFilters(filtersRef.value),
|
||||
...paginationRef.value,
|
||||
}),
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAddAdminTermStudentsMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ termId, payload }) => apiAddAdminTermStudents(termId, payload),
|
||||
})
|
||||
|
||||
export const useRemoveAdminTermStudentMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ termId, userId }) => apiRemoveAdminTermStudent(termId, userId),
|
||||
})
|
||||
|
||||
export const useToggleAdminTermStudentLeaveMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ termId, userId, payload }) =>
|
||||
apiToggleAdminTermStudentLeave(termId, userId, payload),
|
||||
})
|
||||
|
||||
export const useAdminTermCoursesQuery = (termIdRef, filtersRef, paginationRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'terms', 'courses', termIdRef, filtersRef, paginationRef],
|
||||
queryFn: () =>
|
||||
apiGetAdminTermCourses(termIdRef.value, {
|
||||
...cleanFilters(filtersRef?.value || {}),
|
||||
...paginationRef?.value,
|
||||
}),
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAddAdminTermCoursesMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ termId, payload }) => apiAddAdminTermCourses(termId, payload),
|
||||
})
|
||||
|
||||
export const useRemoveAdminTermCourseMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ termId, courseId }) => apiRemoveAdminTermCourse(termId, courseId),
|
||||
})
|
||||
@@ -0,0 +1,41 @@
|
||||
import { useMutation, useQuery } from '@tanstack/vue-query'
|
||||
|
||||
import {
|
||||
apiChangeAdminTicketStatus,
|
||||
apiGetAdminTickets,
|
||||
apiSendAdminTicketMessage,
|
||||
apiShowAdminTicket,
|
||||
} from '@/services/api/admin-tickets'
|
||||
import { cleanFilters } from '@/utils/clean-filters'
|
||||
|
||||
export const adminTicketsKeys = {
|
||||
all: ['admin', 'tickets'],
|
||||
list: (filters, pagination) => ['admin', 'tickets', 'list', filters, pagination],
|
||||
detail: (id) => ['admin', 'tickets', 'detail', id],
|
||||
}
|
||||
|
||||
export const useAdminTicketsListQuery = (filtersRef, paginationRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'tickets', 'list', filtersRef, paginationRef],
|
||||
queryFn: () =>
|
||||
apiGetAdminTickets({ ...cleanFilters(filtersRef.value), ...paginationRef.value }),
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAdminTicketQuery = (idRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'tickets', 'detail', idRef],
|
||||
queryFn: () => apiShowAdminTicket(idRef.value),
|
||||
select: (response) => response?.data ?? response,
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useSendAdminTicketMessageMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ id, payload }) => apiSendAdminTicketMessage(id, payload),
|
||||
})
|
||||
|
||||
export const useChangeAdminTicketStatusMutation = () =>
|
||||
useMutation({
|
||||
mutationFn: ({ id, payload }) => apiChangeAdminTicketStatus(id, payload),
|
||||
})
|
||||
@@ -0,0 +1,58 @@
|
||||
import { useMutation, useQuery } from '@tanstack/vue-query'
|
||||
|
||||
import {
|
||||
apiAddAdminUser,
|
||||
apiChangeAdminUserStatus,
|
||||
apiDeleteAdminUser,
|
||||
apiGetAdminRoles,
|
||||
apiGetAdminUsers,
|
||||
apiShowAdminUser,
|
||||
apiUpdateAdminUser,
|
||||
apiUpdateAdminUserRole,
|
||||
} from '@/services/api/admin-users'
|
||||
import { cleanFilters } from '@/utils/clean-filters'
|
||||
|
||||
export const adminUsersKeys = {
|
||||
all: ['admin', 'users'],
|
||||
list: (filters, pagination) => ['admin', 'users', 'list', filters, pagination],
|
||||
detail: (id) => ['admin', 'users', 'detail', id],
|
||||
roles: () => ['admin', 'users', 'roles'],
|
||||
}
|
||||
|
||||
export const useAdminUsersListQuery = (filtersRef, paginationRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'users', 'list', filtersRef, paginationRef],
|
||||
queryFn: () => apiGetAdminUsers({ ...cleanFilters(filtersRef.value), ...paginationRef.value }),
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAdminUserQuery = (idRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'users', 'detail', idRef],
|
||||
queryFn: () => apiShowAdminUser(idRef.value),
|
||||
select: (response) => response?.data ?? response,
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAdminRolesListQuery = (options = {}) =>
|
||||
useQuery({
|
||||
queryKey: adminUsersKeys.roles(),
|
||||
queryFn: () => apiGetAdminRoles(),
|
||||
select: (response) => response?.data ?? response,
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAddAdminUserMutation = () =>
|
||||
useMutation({ mutationFn: (payload) => apiAddAdminUser(payload) })
|
||||
|
||||
export const useUpdateAdminUserMutation = () =>
|
||||
useMutation({ mutationFn: ({ id, payload }) => apiUpdateAdminUser(id, payload) })
|
||||
|
||||
export const useUpdateAdminUserRoleMutation = () =>
|
||||
useMutation({ mutationFn: ({ id, payload }) => apiUpdateAdminUserRole(id, payload) })
|
||||
|
||||
export const useChangeAdminUserStatusMutation = () =>
|
||||
useMutation({ mutationFn: ({ id, payload }) => apiChangeAdminUserStatus(id, payload) })
|
||||
|
||||
export const useDeleteAdminUserMutation = () =>
|
||||
useMutation({ mutationFn: (id) => apiDeleteAdminUser(id) })
|
||||
@@ -0,0 +1,65 @@
|
||||
import { useMutation, useQuery } from '@tanstack/vue-query'
|
||||
|
||||
import {
|
||||
apiCompleteProfile,
|
||||
apiForgotPassword,
|
||||
apiGetProfile,
|
||||
apiGetRegistrationQuestionVideo,
|
||||
apiLogin,
|
||||
apiLoginWithCode,
|
||||
apiLogout,
|
||||
apiRegister,
|
||||
apiResendVerificationCode,
|
||||
apiResetPassword,
|
||||
apiUpdateProfile,
|
||||
apiUploadTemporary,
|
||||
apiVerifyCode,
|
||||
apiVerifyForgotPasswordCode,
|
||||
} from '@/services/api/auth'
|
||||
|
||||
export const authKeys = {
|
||||
profile: () => ['auth', 'profile'],
|
||||
registrationVideo: () => ['auth', 'registration-video'],
|
||||
}
|
||||
|
||||
export const useLoginMutation = () => useMutation({ mutationFn: apiLogin })
|
||||
|
||||
export const useLoginWithCodeMutation = () => useMutation({ mutationFn: apiLoginWithCode })
|
||||
|
||||
export const useRegisterMutation = () => useMutation({ mutationFn: apiRegister })
|
||||
|
||||
export const useVerifyCodeMutation = () => useMutation({ mutationFn: apiVerifyCode })
|
||||
|
||||
export const useResendVerificationCodeMutation = () =>
|
||||
useMutation({ mutationFn: apiResendVerificationCode })
|
||||
|
||||
export const useForgotPasswordMutation = () => useMutation({ mutationFn: apiForgotPassword })
|
||||
|
||||
export const useVerifyForgotPasswordCodeMutation = () =>
|
||||
useMutation({ mutationFn: apiVerifyForgotPasswordCode })
|
||||
|
||||
export const useResetPasswordMutation = () => useMutation({ mutationFn: apiResetPassword })
|
||||
|
||||
export const useLogoutMutation = () => useMutation({ mutationFn: apiLogout })
|
||||
|
||||
export const useGetProfileQuery = (options = {}) =>
|
||||
useQuery({
|
||||
queryKey: authKeys.profile(),
|
||||
queryFn: () => apiGetProfile(),
|
||||
select: (response) => response?.data?.user ?? response?.data ?? response,
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useCompleteProfileMutation = () => useMutation({ mutationFn: apiCompleteProfile })
|
||||
|
||||
export const useUpdateProfileMutation = () => useMutation({ mutationFn: apiUpdateProfile })
|
||||
|
||||
export const useGetRegistrationVideoQuery = (options = {}) =>
|
||||
useQuery({
|
||||
queryKey: authKeys.registrationVideo(),
|
||||
queryFn: () => apiGetRegistrationQuestionVideo(),
|
||||
select: (response) => response?.data ?? response,
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useUploadTemporaryMutation = () => useMutation({ mutationFn: apiUploadTemporary })
|
||||
@@ -0,0 +1,24 @@
|
||||
import { useQuery } from '@tanstack/vue-query'
|
||||
|
||||
import { apiGetCitiesOfProvince, apiGetProvinces } from '@/services/api/common'
|
||||
|
||||
export const commonKeys = {
|
||||
provinces: () => ['common', 'provinces'],
|
||||
cities: (provinceId) => ['common', 'cities', provinceId],
|
||||
}
|
||||
|
||||
export const useGetProvincesQuery = (options = {}) =>
|
||||
useQuery({
|
||||
queryKey: commonKeys.provinces(),
|
||||
queryFn: () => apiGetProvinces(),
|
||||
select: (response) => response?.data ?? response,
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useGetCitiesOfProvinceQuery = (provinceIdRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['common', 'cities', provinceIdRef],
|
||||
queryFn: () => apiGetCitiesOfProvince(provinceIdRef.value),
|
||||
select: (response) => response?.data ?? response,
|
||||
...options,
|
||||
})
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from '@/services/query/common'
|
||||
export * from '@/services/query/auth'
|
||||
export * from '@/services/query/admin-users'
|
||||
@@ -0,0 +1,29 @@
|
||||
import { useQuery } from '@tanstack/vue-query'
|
||||
|
||||
import { apiGetStudentCourses, apiShowStudentCourse } from '@/services/api/student-courses'
|
||||
import { cleanFilters } from '@/utils/clean-filters'
|
||||
|
||||
export const studentCoursesKeys = {
|
||||
all: ['student', 'courses'],
|
||||
list: (filters, pagination) => ['student', 'courses', 'list', filters, pagination],
|
||||
detail: (id) => ['student', 'courses', 'detail', id],
|
||||
}
|
||||
|
||||
export const useStudentCoursesListQuery = (filtersRef, paginationRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['student', 'courses', 'list', filtersRef, paginationRef],
|
||||
queryFn: () =>
|
||||
apiGetStudentCourses({
|
||||
...cleanFilters(filtersRef.value),
|
||||
...paginationRef.value,
|
||||
}),
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useStudentCourseQuery = (idRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['student', 'courses', 'detail', idRef],
|
||||
queryFn: () => apiShowStudentCourse(idRef.value),
|
||||
select: (response) => response?.data ?? response,
|
||||
...options,
|
||||
})
|
||||
Reference in New Issue
Block a user