fix: ticket
This commit is contained in:
@@ -1,86 +0,0 @@
|
||||
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: '۱۶:۱۲',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
@@ -1,9 +1,10 @@
|
||||
// Shape mirrors backend Postman doc for /admin/tickets:
|
||||
// ticket: { id, student_id, assigned_to_user_id, target_role, status, subject,
|
||||
// created_at, student, assignee, messages: [{ id, ticket_id,
|
||||
// sender_id, message, created_at, sender }] }
|
||||
// Field names use camelCase here (snake_case bridge happens at the HTTP layer
|
||||
// when we swap the mock for the real backend).
|
||||
// ticket: { id, student_id, assigned_to_user_id, type, category, status,
|
||||
// subject, created_at, media: [],
|
||||
// student, assignee,
|
||||
// messages: [{ id, ticket_id, sender_id, message, created_at, sender }] }
|
||||
// Fixture uses camelCase — the mock adapter returns it as-is, mimicking what
|
||||
// the FE sees post-camelize when wired to the real backend.
|
||||
|
||||
const makeUser = (overrides) => ({
|
||||
id: overrides.id,
|
||||
@@ -46,6 +47,26 @@ const studentAli = makeUser({
|
||||
createdAt: '2026-02-10T10:00:00.000Z',
|
||||
})
|
||||
|
||||
const studentReza = makeUser({
|
||||
id: 104,
|
||||
name: 'رضا حسینی',
|
||||
email: 'reza@example.com',
|
||||
phone: '+989124444444',
|
||||
roles: ['student'],
|
||||
avatarUrl: '',
|
||||
createdAt: '2026-02-12T10:00:00.000Z',
|
||||
})
|
||||
|
||||
const studentZahra = makeUser({
|
||||
id: 105,
|
||||
name: 'زهرا کریمی',
|
||||
email: 'zahra@example.com',
|
||||
phone: '+989125555555',
|
||||
roles: ['student'],
|
||||
avatarUrl: '',
|
||||
createdAt: '2026-02-15T10:00:00.000Z',
|
||||
})
|
||||
|
||||
const adminUser = makeUser({
|
||||
id: 1,
|
||||
name: 'مدیر سامانه',
|
||||
@@ -54,15 +75,25 @@ const adminUser = makeUser({
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
})
|
||||
|
||||
const counselorUser = makeUser({
|
||||
id: 7,
|
||||
name: 'مشاور سامانه',
|
||||
email: 'counselor@example.com',
|
||||
roles: ['counselor'],
|
||||
createdAt: '2026-01-15T00:00:00.000Z',
|
||||
})
|
||||
|
||||
export const adminTickets = [
|
||||
{
|
||||
id: 401,
|
||||
studentId: studentJane.id,
|
||||
assignedToUserId: adminUser.id,
|
||||
targetRole: 'admin',
|
||||
type: 'ticket',
|
||||
category: 'enrollment',
|
||||
status: 'answered',
|
||||
subject: 'پیگیری وضعیت ثبتنام',
|
||||
createdAt: '2026-05-09T10:30:00.000Z',
|
||||
media: [],
|
||||
student: studentJane,
|
||||
assignee: adminUser,
|
||||
messages: [
|
||||
@@ -96,10 +127,12 @@ export const adminTickets = [
|
||||
id: 402,
|
||||
studentId: studentMaryam.id,
|
||||
assignedToUserId: null,
|
||||
targetRole: 'admin',
|
||||
type: 'ticket',
|
||||
category: 'schedule',
|
||||
status: 'open',
|
||||
subject: 'سوال درباره جلسه آموزشی',
|
||||
createdAt: '2026-05-08T09:15:00.000Z',
|
||||
media: [],
|
||||
student: studentMaryam,
|
||||
assignee: null,
|
||||
messages: [
|
||||
@@ -117,10 +150,12 @@ export const adminTickets = [
|
||||
id: 403,
|
||||
studentId: studentAli.id,
|
||||
assignedToUserId: adminUser.id,
|
||||
targetRole: 'admin',
|
||||
type: 'ticket',
|
||||
category: 'billing',
|
||||
status: 'closed',
|
||||
subject: 'درخواست بستن تیکت',
|
||||
createdAt: '2026-05-07T14:10:00.000Z',
|
||||
media: [],
|
||||
student: studentAli,
|
||||
assignee: adminUser,
|
||||
messages: [
|
||||
@@ -142,7 +177,138 @@ export const adminTickets = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 501,
|
||||
studentId: studentReza.id,
|
||||
assignedToUserId: adminUser.id,
|
||||
type: 'service',
|
||||
category: 'loan',
|
||||
status: 'open',
|
||||
subject: 'درخواست وام تحصیلی',
|
||||
createdAt: '2026-05-12T13:54:00.000Z',
|
||||
media: [],
|
||||
student: studentReza,
|
||||
assignee: adminUser,
|
||||
messages: [
|
||||
{
|
||||
id: 1,
|
||||
ticketId: 501,
|
||||
senderId: studentReza.id,
|
||||
message: 'برای ادامه تحصیل به وام نیاز دارم.',
|
||||
createdAt: '2026-05-12T13:54:00.000Z',
|
||||
sender: studentReza,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 502,
|
||||
studentId: studentJane.id,
|
||||
assignedToUserId: null,
|
||||
type: 'service',
|
||||
category: 'insurance',
|
||||
status: 'answered',
|
||||
subject: 'درخواست بیمه دانشجویی',
|
||||
createdAt: '2026-05-10T08:20:00.000Z',
|
||||
media: [],
|
||||
student: studentJane,
|
||||
assignee: null,
|
||||
messages: [
|
||||
{
|
||||
id: 1,
|
||||
ticketId: 502,
|
||||
senderId: studentJane.id,
|
||||
message: 'لطفا اطلاعات بیمه را ارسال کنید.',
|
||||
createdAt: '2026-05-10T08:20:00.000Z',
|
||||
sender: studentJane,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 601,
|
||||
studentId: studentZahra.id,
|
||||
assignedToUserId: counselorUser.id,
|
||||
type: 'advise',
|
||||
category: 'education',
|
||||
status: 'answered',
|
||||
subject: 'مشاوره انتخاب رشته',
|
||||
createdAt: '2026-05-12T13:54:00.000Z',
|
||||
media: [],
|
||||
student: studentZahra,
|
||||
assignee: counselorUser,
|
||||
messages: [
|
||||
{
|
||||
id: 1,
|
||||
ticketId: 601,
|
||||
senderId: studentZahra.id,
|
||||
message: 'سلام، در خصوص انتخاب رشته مشاوره میخواستم.',
|
||||
createdAt: '2026-05-12T13:54:00.000Z',
|
||||
sender: studentZahra,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
ticketId: 601,
|
||||
senderId: counselorUser.id,
|
||||
message: 'سلام و وقت بخیر، لطفا رشته فعلی و علاقهمندیهای خود را بفرمایید.',
|
||||
createdAt: '2026-05-12T14:02:00.000Z',
|
||||
sender: counselorUser,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 602,
|
||||
studentId: studentMaryam.id,
|
||||
assignedToUserId: null,
|
||||
type: 'advise',
|
||||
category: 'career',
|
||||
status: 'open',
|
||||
subject: 'مشاوره مسیر شغلی',
|
||||
createdAt: '2026-05-11T09:30:00.000Z',
|
||||
media: [],
|
||||
student: studentMaryam,
|
||||
assignee: null,
|
||||
messages: [
|
||||
{
|
||||
id: 1,
|
||||
ticketId: 602,
|
||||
senderId: studentMaryam.id,
|
||||
message: 'برای ادامه تحصیل در سطح ۳ راهنمایی نیاز دارم.',
|
||||
createdAt: '2026-05-11T09:30:00.000Z',
|
||||
sender: studentMaryam,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 603,
|
||||
studentId: studentAli.id,
|
||||
assignedToUserId: counselorUser.id,
|
||||
type: 'advise',
|
||||
category: 'personal',
|
||||
status: 'closed',
|
||||
subject: 'مشاوره فردی',
|
||||
createdAt: '2026-05-09T16:10:00.000Z',
|
||||
media: [],
|
||||
student: studentAli,
|
||||
assignee: counselorUser,
|
||||
messages: [
|
||||
{
|
||||
id: 1,
|
||||
ticketId: 603,
|
||||
senderId: studentAli.id,
|
||||
message: 'مشاوره دریافت شد، با تشکر.',
|
||||
createdAt: '2026-05-09T16:10:00.000Z',
|
||||
sender: studentAli,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
ticketId: 603,
|
||||
senderId: counselorUser.id,
|
||||
message: 'موفق باشید.',
|
||||
createdAt: '2026-05-09T16:12:00.000Z',
|
||||
sender: counselorUser,
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
// The signed-in admin used as `sender` when a message is posted from the FE.
|
||||
export const currentAdminUser = adminUser
|
||||
export const currentCounselorUser = counselorUser
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
export const studentConsultantTitles = [
|
||||
{ value: 'course-talk', label: 'گفتگو درباره دوره' },
|
||||
{ value: 'academic', label: 'مشاوره تحصیلی' },
|
||||
{ value: 'career', label: 'مشاوره شغلی' },
|
||||
{ value: 'psychology', label: 'مشاوره روانشناسی' },
|
||||
{ value: 'other', label: 'سایر' },
|
||||
]
|
||||
|
||||
const STATUS_LABELS = {
|
||||
pending: 'در حال بررسی',
|
||||
approved: 'پاسخ داده شده',
|
||||
rejected: 'رد شده',
|
||||
closed: 'بسته شده',
|
||||
}
|
||||
|
||||
export const studentConsultants = [
|
||||
{
|
||||
id: 'c-1',
|
||||
requestNumber: 215,
|
||||
title: 'درخواست مشاوره',
|
||||
topicLabel: 'گفتگو درباره دوره',
|
||||
status: 'pending',
|
||||
statusLabel: STATUS_LABELS.pending,
|
||||
description: 'سوال در مورد محتوای دوره',
|
||||
timeLabel: '12:53',
|
||||
dateLabel: '1404/12/21',
|
||||
},
|
||||
{
|
||||
id: 'c-2',
|
||||
requestNumber: 198,
|
||||
title: 'درخواست مشاوره',
|
||||
topicLabel: 'مشاوره شغلی',
|
||||
status: 'approved',
|
||||
statusLabel: STATUS_LABELS.approved,
|
||||
description: 'راهنمایی برای انتخاب مسیر شغلی',
|
||||
timeLabel: '09:12',
|
||||
dateLabel: '1404/11/05',
|
||||
},
|
||||
{
|
||||
id: 'c-3',
|
||||
requestNumber: 174,
|
||||
title: 'درخواست مشاوره',
|
||||
topicLabel: 'مشاوره تحصیلی',
|
||||
status: 'rejected',
|
||||
statusLabel: STATUS_LABELS.rejected,
|
||||
description: 'برنامهریزی درسی',
|
||||
timeLabel: '16:40',
|
||||
dateLabel: '1404/10/02',
|
||||
},
|
||||
]
|
||||
@@ -1,61 +0,0 @@
|
||||
export const studentServiceTypes = [
|
||||
{ value: 'loan', label: 'وام' },
|
||||
{ value: 'consultation', label: 'مشاوره' },
|
||||
{ value: 'insurance', label: 'بیمه' },
|
||||
{ value: 'other', label: 'سایر' },
|
||||
]
|
||||
|
||||
export const studentServiceTitlesByType = {
|
||||
loan: [
|
||||
{ value: 'tuition-loan', label: 'وام شهریه' },
|
||||
{ value: 'living-loan', label: 'وام معیشت' },
|
||||
],
|
||||
consultation: [
|
||||
{ value: 'course-talk', label: 'گفتگو درباره دوره' },
|
||||
{ value: 'career-talk', label: 'مشاوره شغلی' },
|
||||
],
|
||||
insurance: [{ value: 'student-insurance', label: 'بیمه دانشجویی' }],
|
||||
other: [{ value: 'other-issue', label: 'موضوع دیگر' }],
|
||||
}
|
||||
|
||||
const STATUS_LABELS = {
|
||||
approved: 'تاییــد شـــــده',
|
||||
pending: 'در انتظار بررسی',
|
||||
rejected: 'رد شده',
|
||||
}
|
||||
|
||||
export const studentServices = [
|
||||
{
|
||||
id: 's-1',
|
||||
requestNumber: 387,
|
||||
title: 'درخواست وام',
|
||||
typeKey: 'loan',
|
||||
typeLabel: 'وام',
|
||||
status: 'approved',
|
||||
statusLabel: STATUS_LABELS.approved,
|
||||
description: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ',
|
||||
createdAt: '1404/05/12',
|
||||
},
|
||||
{
|
||||
id: 's-2',
|
||||
requestNumber: 44,
|
||||
title: 'درخواست وام',
|
||||
typeKey: 'loan',
|
||||
typeLabel: 'وام',
|
||||
status: 'pending',
|
||||
statusLabel: STATUS_LABELS.pending,
|
||||
description: 'درخواست شهریه ترم جدید',
|
||||
createdAt: '1404/06/02',
|
||||
},
|
||||
{
|
||||
id: 's-3',
|
||||
requestNumber: 18,
|
||||
title: 'گفتگو درباره دوره',
|
||||
typeKey: 'consultation',
|
||||
typeLabel: 'مشاوره',
|
||||
status: 'rejected',
|
||||
statusLabel: STATUS_LABELS.rejected,
|
||||
description: 'سوال در مورد محتوای دوره',
|
||||
createdAt: '1404/04/22',
|
||||
},
|
||||
]
|
||||
@@ -1,56 +0,0 @@
|
||||
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,
|
||||
}),
|
||||
}))
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
|
||||
register('GET', endpoints.getTicketsList, ({ query }) => {
|
||||
let list = filterItems(adminTickets, query, {
|
||||
type: 'eq',
|
||||
status: 'eq',
|
||||
subject: (item, v) =>
|
||||
String(item.subject || '')
|
||||
@@ -51,7 +52,7 @@ register('POST', endpoints.sendTicketMessage, ({ params, data }) => {
|
||||
}
|
||||
ticket.messages = [...(ticket.messages || []), message]
|
||||
ticket.status = 'answered'
|
||||
ticket.assigneeId = currentAdminUser.id
|
||||
ticket.assignedToUserId = currentAdminUser.id
|
||||
ticket.assignee = currentAdminUser
|
||||
return {
|
||||
success: true,
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import { register } from '@/services/mock/registry'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
import { adminTickets, currentCounselorUser } from '@/services/mock/fixtures/admin-tickets'
|
||||
import {
|
||||
filterDateRange,
|
||||
filterItems,
|
||||
findOrThrow,
|
||||
isoNow,
|
||||
makeId,
|
||||
paginate,
|
||||
updateById,
|
||||
} from '@/services/mock/helpers'
|
||||
|
||||
// Counselor scope: backend hides every ticket whose type !== 'advise'.
|
||||
const counselorPool = () => adminTickets.filter((t) => t.type === 'advise')
|
||||
|
||||
register('GET', endpoints.getCounselorTickets, ({ query }) => {
|
||||
let list = filterItems(counselorPool(), query, {
|
||||
type: 'eq',
|
||||
status: 'eq',
|
||||
userName: (item, v) =>
|
||||
String(item.student?.name || '')
|
||||
.toLowerCase()
|
||||
.includes(String(v).toLowerCase()),
|
||||
})
|
||||
list = filterDateRange(list, query)
|
||||
const { data: items, meta } = paginate(list, query)
|
||||
return { success: true, message: 'OK', data: items, meta }
|
||||
})
|
||||
|
||||
register('GET', endpoints.showCounselorTicket, ({ params }) => ({
|
||||
success: true,
|
||||
message: 'OK',
|
||||
data: findOrThrow(counselorPool(), params.id),
|
||||
}))
|
||||
|
||||
register('POST', endpoints.sendCounselorTicketMessage, ({ params, data }) => {
|
||||
const ticket = findOrThrow(counselorPool(), params.id)
|
||||
const message = {
|
||||
id: makeId(),
|
||||
ticketId: ticket.id,
|
||||
senderId: currentCounselorUser.id,
|
||||
message: data.message || '',
|
||||
createdAt: isoNow(),
|
||||
sender: currentCounselorUser,
|
||||
}
|
||||
ticket.messages = [...(ticket.messages || []), message]
|
||||
ticket.status = 'answered'
|
||||
ticket.assignedToUserId = currentCounselorUser.id
|
||||
ticket.assignee = currentCounselorUser
|
||||
return { success: true, message: 'Message posted.', data: message }
|
||||
})
|
||||
|
||||
register('PATCH', endpoints.changeCounselorTicketStatus, ({ params, data }) => ({
|
||||
success: true,
|
||||
message: 'Ticket status updated.',
|
||||
data: updateById(adminTickets, params.id, { status: data.status }),
|
||||
}))
|
||||
@@ -1,29 +0,0 @@
|
||||
import { paginate } from '@/services/mock/helpers'
|
||||
import { register } from '@/services/mock/registry'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
import {
|
||||
studentConsultantTitles,
|
||||
studentConsultants,
|
||||
} from '@/services/mock/fixtures/student-consultants'
|
||||
|
||||
register('GET', endpoints.getStudentConsultants, ({ query }) => paginate(studentConsultants, query))
|
||||
|
||||
register('POST', endpoints.createStudentConsultant, ({ data }) => {
|
||||
const id = `c-${studentConsultants.length + 1}`
|
||||
const next = {
|
||||
id,
|
||||
requestNumber: 500 + studentConsultants.length + 1,
|
||||
title: 'درخواست مشاوره',
|
||||
topicLabel:
|
||||
studentConsultantTitles.find((t) => t.value === data?.title)?.label || data?.title || '—',
|
||||
status: 'pending',
|
||||
statusLabel: 'در حال بررسی',
|
||||
description: data?.description || '',
|
||||
timeLabel: '12:00',
|
||||
dateLabel: '1404/06/12',
|
||||
}
|
||||
studentConsultants.unshift(next)
|
||||
return { data: next }
|
||||
})
|
||||
|
||||
register('GET', endpoints.getStudentConsultantTitles, () => ({ data: studentConsultantTitles }))
|
||||
@@ -1,33 +0,0 @@
|
||||
import { paginate } from '@/services/mock/helpers'
|
||||
import { register } from '@/services/mock/registry'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
import {
|
||||
studentServiceTitlesByType,
|
||||
studentServiceTypes,
|
||||
studentServices,
|
||||
} from '@/services/mock/fixtures/student-services'
|
||||
|
||||
register('GET', endpoints.getStudentServices, ({ query }) => paginate(studentServices, query))
|
||||
|
||||
register('POST', endpoints.createStudentService, ({ data }) => {
|
||||
const id = `s-${studentServices.length + 1}`
|
||||
const next = {
|
||||
id,
|
||||
requestNumber: 500 + studentServices.length + 1,
|
||||
title: data?.title || '—',
|
||||
typeKey: data?.typeKey || 'other',
|
||||
typeLabel: studentServiceTypes.find((t) => t.value === data?.typeKey)?.label || 'سایر',
|
||||
status: 'pending',
|
||||
statusLabel: 'در انتظار بررسی',
|
||||
description: data?.description || '',
|
||||
createdAt: '1404/06/12',
|
||||
}
|
||||
studentServices.unshift(next)
|
||||
return { data: next }
|
||||
})
|
||||
|
||||
register('GET', endpoints.getStudentServiceTypes, () => ({ data: studentServiceTypes }))
|
||||
|
||||
register('GET', endpoints.getStudentServiceTitles, ({ query }) => ({
|
||||
data: studentServiceTitlesByType[query.type] || [],
|
||||
}))
|
||||
@@ -0,0 +1,84 @@
|
||||
import { register } from '@/services/mock/registry'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
import { adminTickets } from '@/services/mock/fixtures/admin-tickets'
|
||||
import { filterItems, findOrThrow, isoNow, makeId, paginate } from '@/services/mock/helpers'
|
||||
|
||||
// Student scope: backend scopes results to the signed-in student. The mock
|
||||
// pretends every ticket whose student is studentJane (id=100) belongs to "me".
|
||||
const SELF_STUDENT_ID = 100
|
||||
|
||||
const myPool = () => adminTickets.filter((t) => t.studentId === SELF_STUDENT_ID)
|
||||
|
||||
register('GET', endpoints.getStudentTickets, ({ query }) => {
|
||||
const list = filterItems(myPool(), query, {
|
||||
type: 'eq',
|
||||
status: 'eq',
|
||||
})
|
||||
const { data: items, meta } = paginate(list, query)
|
||||
return { success: true, message: 'OK', data: items, meta }
|
||||
})
|
||||
|
||||
register('GET', endpoints.showStudentTicket, ({ params }) => ({
|
||||
success: true,
|
||||
message: 'OK',
|
||||
data: findOrThrow(myPool(), params.id),
|
||||
}))
|
||||
|
||||
register('POST', endpoints.createStudentTicket, ({ data }) => {
|
||||
const me = myPool()[0]?.student || adminTickets[0].student
|
||||
const ticket = {
|
||||
id: makeId(),
|
||||
studentId: me.id,
|
||||
assignedToUserId: null,
|
||||
type: data.type || 'ticket',
|
||||
category: data.category || null,
|
||||
status: 'open',
|
||||
subject: data.subject || '',
|
||||
createdAt: isoNow(),
|
||||
media: [],
|
||||
student: me,
|
||||
assignee: null,
|
||||
messages: [
|
||||
{
|
||||
id: makeId(),
|
||||
ticketId: 0,
|
||||
senderId: me.id,
|
||||
message: data.message || '',
|
||||
createdAt: isoNow(),
|
||||
sender: me,
|
||||
},
|
||||
],
|
||||
}
|
||||
ticket.messages[0].ticketId = ticket.id
|
||||
adminTickets.unshift(ticket)
|
||||
return {
|
||||
success: true,
|
||||
message: 'Ticket created.',
|
||||
data: {
|
||||
id: ticket.id,
|
||||
studentId: ticket.studentId,
|
||||
assignedToUserId: ticket.assignedToUserId,
|
||||
type: ticket.type,
|
||||
category: ticket.category,
|
||||
status: ticket.status,
|
||||
subject: ticket.subject,
|
||||
createdAt: ticket.createdAt,
|
||||
media: ticket.media,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
register('POST', endpoints.sendStudentTicketMessage, ({ params, data }) => {
|
||||
const ticket = findOrThrow(myPool(), params.id)
|
||||
const me = ticket.student
|
||||
const message = {
|
||||
id: makeId(),
|
||||
ticketId: ticket.id,
|
||||
senderId: me.id,
|
||||
message: data.message || '',
|
||||
createdAt: isoNow(),
|
||||
sender: me,
|
||||
}
|
||||
ticket.messages = [...(ticket.messages || []), message]
|
||||
return { success: true, message: 'Message posted.', data: message }
|
||||
})
|
||||
Reference in New Issue
Block a user