This commit is contained in:
@@ -0,0 +1,95 @@
|
|||||||
|
<template>
|
||||||
|
<div class="missionary-lesson-details">
|
||||||
|
<BoxedIconTitleBlock
|
||||||
|
class="missionary-lesson-details__heading"
|
||||||
|
title="جزئیات درس"
|
||||||
|
:desc="course?.title || 'جلسات این درس را مشاهده کنید.'"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<SvgIcon name="book" :size="24" color="var(--color-primary)" />
|
||||||
|
</template>
|
||||||
|
</BoxedIconTitleBlock>
|
||||||
|
|
||||||
|
<SimpleTitleIconBlock title="همه جلسه ها" class="missionary-lesson-details__list-title">
|
||||||
|
<template #header-icon>
|
||||||
|
<SvgIcon name="list-bullets" :size="16" color="#bcbcbc" />
|
||||||
|
</template>
|
||||||
|
</SimpleTitleIconBlock>
|
||||||
|
|
||||||
|
<SkeletonLoaderBlock
|
||||||
|
v-if="sessionsLoading && sessions.length === 0"
|
||||||
|
:rows="3"
|
||||||
|
:cols-per-row="1"
|
||||||
|
/>
|
||||||
|
<div v-else-if="sessions.length > 0">
|
||||||
|
<StudentSessionItem
|
||||||
|
v-for="session in sessions"
|
||||||
|
:key="session.id"
|
||||||
|
:session="session"
|
||||||
|
@start="onStartSession"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<NoItems v-else title="جلسهای نیست" desc="جلسهای برای این درس ثبت نشده است." />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import SvgIcon from '@/components/icons/SvgIcon.vue'
|
||||||
|
import NoItems from '@/components/blocks/NoItems.vue'
|
||||||
|
import { StudentSessionItem } from '@/features/student/sessions'
|
||||||
|
import BoxedIconTitleBlock from '@/components/blocks/BoxedIconTitleBlock.vue'
|
||||||
|
import SkeletonLoaderBlock from '@/components/blocks/SkeletonLoaderBlock.vue'
|
||||||
|
import SimpleTitleIconBlock from '@/components/blocks/SimpleTitleIconBlock.vue'
|
||||||
|
import {
|
||||||
|
useMissionaryPassedCoursesQuery,
|
||||||
|
useMissionaryPassedSessionsQuery,
|
||||||
|
} from '@/services/query/missionary-education'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const courseId = computed(() => route.params.id)
|
||||||
|
const termId = computed(() => route.query.termId || null)
|
||||||
|
|
||||||
|
// Course header comes from the passed-courses list cache (same key as the term
|
||||||
|
// page), so it needs no detail endpoint.
|
||||||
|
const coursesFilters = computed(() => ({ termId: termId.value }))
|
||||||
|
const coursesPagination = ref({ page: 1, perPage: 20 })
|
||||||
|
const { data: coursesData } = useMissionaryPassedCoursesQuery(coursesFilters, coursesPagination, {
|
||||||
|
enabled: () => !!termId.value,
|
||||||
|
})
|
||||||
|
const course = computed(() =>
|
||||||
|
(coursesData.value?.data ?? []).find((c) => String(c.id) === String(courseId.value))
|
||||||
|
)
|
||||||
|
|
||||||
|
const sessionsFilters = computed(() => ({ courseId: courseId.value }))
|
||||||
|
const sessionsPagination = ref({ page: 1, perPage: 20 })
|
||||||
|
const { data: sessionsData, isLoading: sessionsLoading } = useMissionaryPassedSessionsQuery(
|
||||||
|
sessionsFilters,
|
||||||
|
sessionsPagination,
|
||||||
|
{ enabled: () => !!courseId.value, keepPreviousData: true }
|
||||||
|
)
|
||||||
|
const sessions = computed(() => sessionsData.value?.data ?? [])
|
||||||
|
|
||||||
|
const onStartSession = (session) => {
|
||||||
|
router.push({ name: 'missionary-education-session', params: { id: session.id } }).catch(() => {})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.missionary-lesson-details {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
&__heading {
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__list-title {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
<template>
|
||||||
|
<div class="missionary-term-details">
|
||||||
|
<BoxedIconTitleBlock
|
||||||
|
class="missionary-term-details__heading"
|
||||||
|
title="جزئیات ترم"
|
||||||
|
desc="اطلاعات کامل این ترم گذراندهشده را مشاهده کنید."
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<SvgIcon name="book" :size="24" color="var(--color-primary)" />
|
||||||
|
</template>
|
||||||
|
</BoxedIconTitleBlock>
|
||||||
|
|
||||||
|
<SkeletonLoaderBlock v-if="termLoading && !enrollment" :rows="2" :cols-per-row="1" />
|
||||||
|
<StudentTermSummary v-else-if="enrollment" :enrollment="enrollment" />
|
||||||
|
|
||||||
|
<SimpleTitleIconBlock title="همه درس ها" class="missionary-term-details__list-title">
|
||||||
|
<template #header-icon>
|
||||||
|
<SvgIcon name="list-bullets" :size="16" color="#bcbcbc" />
|
||||||
|
</template>
|
||||||
|
</SimpleTitleIconBlock>
|
||||||
|
|
||||||
|
<SkeletonLoaderBlock
|
||||||
|
v-if="coursesLoading && courses.length === 0"
|
||||||
|
:rows="3"
|
||||||
|
:cols-per-row="1"
|
||||||
|
/>
|
||||||
|
<div v-else-if="courses.length > 0">
|
||||||
|
<StudentLessonItem
|
||||||
|
v-for="lesson in courses"
|
||||||
|
:key="lesson.id"
|
||||||
|
:lesson="lesson"
|
||||||
|
@show-details="onShowLesson"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<NoItems v-else title="درسی نیست" desc="درسی برای این ترم ثبت نشده است." />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import SvgIcon from '@/components/icons/SvgIcon.vue'
|
||||||
|
import NoItems from '@/components/blocks/NoItems.vue'
|
||||||
|
import { StudentLessonItem } from '@/features/student/lessons'
|
||||||
|
import BoxedIconTitleBlock from '@/components/blocks/BoxedIconTitleBlock.vue'
|
||||||
|
import SkeletonLoaderBlock from '@/components/blocks/SkeletonLoaderBlock.vue'
|
||||||
|
import SimpleTitleIconBlock from '@/components/blocks/SimpleTitleIconBlock.vue'
|
||||||
|
import StudentTermSummary from '@/features/student/terms/components/StudentTermSummary.vue'
|
||||||
|
import {
|
||||||
|
useMissionaryPassedTermsQuery,
|
||||||
|
useMissionaryPassedCoursesQuery,
|
||||||
|
} from '@/services/query/missionary-education'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const termId = computed(() => route.params.id)
|
||||||
|
|
||||||
|
// Term summary is served from the passed-terms list cache (same query key as
|
||||||
|
// the list page); it only refetches on a cold deep-link. No detail endpoint.
|
||||||
|
const termsPagination = ref({ page: 1, perPage: 20 })
|
||||||
|
const { data: termsData, isLoading: termLoading } = useMissionaryPassedTermsQuery(termsPagination)
|
||||||
|
const enrollment = computed(() =>
|
||||||
|
(termsData.value?.data ?? []).find((e) => String(e?.term?.id) === String(termId.value))
|
||||||
|
)
|
||||||
|
|
||||||
|
const coursesFilters = computed(() => ({ termId: termId.value }))
|
||||||
|
const coursesPagination = ref({ page: 1, perPage: 20 })
|
||||||
|
const { data: coursesData, isLoading: coursesLoading } = useMissionaryPassedCoursesQuery(
|
||||||
|
coursesFilters,
|
||||||
|
coursesPagination,
|
||||||
|
{ enabled: () => !!termId.value, keepPreviousData: true }
|
||||||
|
)
|
||||||
|
const courses = computed(() => coursesData.value?.data ?? [])
|
||||||
|
|
||||||
|
const onShowLesson = (lesson) => {
|
||||||
|
router
|
||||||
|
.push({
|
||||||
|
name: 'missionary-education-lesson',
|
||||||
|
params: { id: lesson.id },
|
||||||
|
query: { termId: termId.value },
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.missionary-term-details {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
&__heading {
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__list-title {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
<template>
|
||||||
|
<div class="missionary-education">
|
||||||
|
<BoxedIconTitleBlock
|
||||||
|
class="missionary-education__heading"
|
||||||
|
title="آموزش من"
|
||||||
|
desc="ترمهایی که با موفقیت گذراندهاید را مشاهده کنید."
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<SvgIcon name="graduation-cap" :size="24" color="var(--color-primary)" />
|
||||||
|
</template>
|
||||||
|
</BoxedIconTitleBlock>
|
||||||
|
|
||||||
|
<SkeletonLoaderBlock v-if="isLoading" :rows="4" :cols-per-row="1" />
|
||||||
|
<div v-else-if="terms.length > 0">
|
||||||
|
<StudentTermItem
|
||||||
|
v-for="enrollment in terms"
|
||||||
|
:key="enrollment.id"
|
||||||
|
:enrollment="enrollment"
|
||||||
|
@show-details="onShowDetails"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<NoItems v-else title="ترمی نیست" desc="هنوز ترمی را نگذراندهاید." />
|
||||||
|
|
||||||
|
<PaginationBlock :pagination="meta" @update:page="setPage" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import SvgIcon from '@/components/icons/SvgIcon.vue'
|
||||||
|
import NoItems from '@/components/blocks/NoItems.vue'
|
||||||
|
import { usePagination } from '@/composables/usePagination'
|
||||||
|
import PaginationBlock from '@/components/blocks/PaginationBlock.vue'
|
||||||
|
import BoxedIconTitleBlock from '@/components/blocks/BoxedIconTitleBlock.vue'
|
||||||
|
import SkeletonLoaderBlock from '@/components/blocks/SkeletonLoaderBlock.vue'
|
||||||
|
import { useMissionaryPassedTermsQuery } from '@/services/query/missionary-education'
|
||||||
|
import StudentTermItem from '@/features/student/terms/components/StudentTermItem.vue'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const { pagination, setPage } = usePagination({ page: 1, perPage: 20 })
|
||||||
|
|
||||||
|
const { data, isLoading } = useMissionaryPassedTermsQuery(pagination, { keepPreviousData: true })
|
||||||
|
|
||||||
|
const terms = computed(() => data.value?.data ?? [])
|
||||||
|
const meta = computed(() => ({
|
||||||
|
page: pagination.value.page,
|
||||||
|
perPage: pagination.value.perPage,
|
||||||
|
...data.value?.meta,
|
||||||
|
}))
|
||||||
|
|
||||||
|
const onShowDetails = (enrollment) => {
|
||||||
|
router
|
||||||
|
.push({ name: 'missionary-education-term', params: { id: enrollment?.term?.id } })
|
||||||
|
.catch(() => {})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.missionary-education {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
&__heading {
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -32,4 +32,49 @@ export default [
|
|||||||
subtitle: 'اینجا پل ارتباطی شما با پشتیبانی است.',
|
subtitle: 'اینجا پل ارتباطی شما با پشتیبانی است.',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/missionary-panel/education',
|
||||||
|
name: 'missionary-education',
|
||||||
|
component: () => import('@/features/missionary/education/pages/MissionaryTermsPage.vue'),
|
||||||
|
meta: {
|
||||||
|
layout: 'missionary',
|
||||||
|
role: 'missionary',
|
||||||
|
title: 'آموزش من',
|
||||||
|
subtitle: 'ترمها و دورههای گذراندهشده خود را مرور کنید.',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/missionary-panel/education/terms/:id',
|
||||||
|
name: 'missionary-education-term',
|
||||||
|
component: () => import('@/features/missionary/education/pages/MissionaryTermDetailsPage.vue'),
|
||||||
|
meta: {
|
||||||
|
layout: 'missionary',
|
||||||
|
role: 'missionary',
|
||||||
|
title: 'آموزش من',
|
||||||
|
subtitle: 'ترمها و دورههای گذراندهشده خود را مرور کنید.',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/missionary-panel/education/lessons/:id',
|
||||||
|
name: 'missionary-education-lesson',
|
||||||
|
component: () =>
|
||||||
|
import('@/features/missionary/education/pages/MissionaryLessonDetailsPage.vue'),
|
||||||
|
meta: {
|
||||||
|
layout: 'missionary',
|
||||||
|
role: 'missionary',
|
||||||
|
title: 'آموزش من',
|
||||||
|
subtitle: 'ترمها و دورههای گذراندهشده خود را مرور کنید.',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/missionary-panel/education/sessions/:id',
|
||||||
|
name: 'missionary-education-session',
|
||||||
|
component: () => import('@/features/student/sessions/pages/StudentSessionDetailsPage.vue'),
|
||||||
|
meta: {
|
||||||
|
layout: 'missionary',
|
||||||
|
role: 'missionary',
|
||||||
|
title: 'آموزش من',
|
||||||
|
subtitle: 'ترمها و دورههای گذراندهشده خود را مرور کنید.',
|
||||||
|
},
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -70,6 +70,12 @@ const menuItems = computed(() => [
|
|||||||
to: { name: 'missionary-requests' },
|
to: { name: 'missionary-requests' },
|
||||||
active: route.name === 'missionary-requests',
|
active: route.name === 'missionary-requests',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'آموزش من',
|
||||||
|
icon: 'graduation-cap',
|
||||||
|
to: { name: 'missionary-education' },
|
||||||
|
active: route.name?.startsWith('missionary-education'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'تیکت',
|
title: 'تیکت',
|
||||||
icon: 'envelope-open',
|
icon: 'envelope-open',
|
||||||
|
|||||||
@@ -30,6 +30,14 @@ export const endpoints = {
|
|||||||
// dedicated student route (returns the membership row with the nested term).
|
// dedicated student route (returns the membership row with the nested term).
|
||||||
getStudentDashboard: '/student/dashboard',
|
getStudentDashboard: '/student/dashboard',
|
||||||
getStudentTerms: '/student/my-terms',
|
getStudentTerms: '/student/my-terms',
|
||||||
|
|
||||||
|
// Missionary — passed (completed) education. List-only; same shapes as
|
||||||
|
// /student/my-terms, /courses, /sessions. Detail views reuse the shared
|
||||||
|
// /sessions/:id and the already-fetched list data (via query cache).
|
||||||
|
getMissionaryPassedTerms: '/missionary/passed-terms',
|
||||||
|
getMissionaryPassedCourses: '/missionary/passed-courses',
|
||||||
|
getMissionaryPassedSessions: '/missionary/passed-sessions',
|
||||||
|
|
||||||
showStudentTerm: '/student/my-terms/:id',
|
showStudentTerm: '/student/my-terms/:id',
|
||||||
getStudentExamResults: '/student/exam-results',
|
getStudentExamResults: '/student/exam-results',
|
||||||
getStudentHomeworks: '/student/homeworks',
|
getStudentHomeworks: '/student/homeworks',
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { http } from '@/services/api/http'
|
||||||
|
import { endpoints } from '@/services/api/endpoints'
|
||||||
|
|
||||||
|
export const apiGetMissionaryPassedTerms = (params) =>
|
||||||
|
http.get(endpoints.getMissionaryPassedTerms, { params })
|
||||||
|
|
||||||
|
export const apiGetMissionaryPassedCourses = (params) =>
|
||||||
|
http.get(endpoints.getMissionaryPassedCourses, { params })
|
||||||
|
|
||||||
|
export const apiGetMissionaryPassedSessions = (params) =>
|
||||||
|
http.get(endpoints.getMissionaryPassedSessions, { params })
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
// Missionary passed (completed) education. Shapes mirror /student/my-terms,
|
||||||
|
// /courses and /sessions. Session ids reuse existing adminSessions ids so the
|
||||||
|
// shared GET /sessions/:id mock resolves the detail drill-down.
|
||||||
|
|
||||||
|
const makeTerm = (id, title, over) => ({
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
description: 'ترم تکمیلشده',
|
||||||
|
isActive: false,
|
||||||
|
startsAt: '2025-09-22T00:00:00+00:00',
|
||||||
|
endsAt: '2026-01-20T00:00:00+00:00',
|
||||||
|
score: 20,
|
||||||
|
minimumScore: 12,
|
||||||
|
coverUrl: null,
|
||||||
|
coursesCount: 3,
|
||||||
|
sessionsCount: 18,
|
||||||
|
examsCount: 12,
|
||||||
|
homeworksCount: 15,
|
||||||
|
studentsCount: 40,
|
||||||
|
createdAt: '2025-08-01T10:00:00+00:00',
|
||||||
|
...over,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const passedTerms = [
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
userId: 14,
|
||||||
|
termId: 3,
|
||||||
|
status: 'completed',
|
||||||
|
completedAt: '2026-02-01T10:00:00+00:00',
|
||||||
|
term: makeTerm(3, 'پاییز ۱۴۰۴'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 10,
|
||||||
|
userId: 14,
|
||||||
|
termId: 4,
|
||||||
|
status: 'completed',
|
||||||
|
completedAt: '2025-07-05T10:00:00+00:00',
|
||||||
|
term: makeTerm(4, 'تابستان ۱۴۰۴', { coursesCount: 1, sessionsCount: 6 }),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const teacher = { id: 2, name: 'علیرضا حسینی' }
|
||||||
|
|
||||||
|
export const passedCourses = [
|
||||||
|
{
|
||||||
|
id: 21,
|
||||||
|
termId: 3,
|
||||||
|
teacherId: 2,
|
||||||
|
teacher,
|
||||||
|
title: 'مبانی اعتقادات',
|
||||||
|
description: 'درس پایه',
|
||||||
|
capacity: 50,
|
||||||
|
isActive: false,
|
||||||
|
coverUrl: null,
|
||||||
|
sessionsCount: 2,
|
||||||
|
examsCount: 6,
|
||||||
|
homeworksCount: 7,
|
||||||
|
prerequisiteCourseIds: [],
|
||||||
|
prerequisiteCourses: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 22,
|
||||||
|
termId: 3,
|
||||||
|
teacherId: 2,
|
||||||
|
teacher,
|
||||||
|
title: 'اخلاق کاربردی',
|
||||||
|
description: 'درس تکمیلی',
|
||||||
|
capacity: 40,
|
||||||
|
isActive: false,
|
||||||
|
coverUrl: null,
|
||||||
|
sessionsCount: 1,
|
||||||
|
examsCount: 2,
|
||||||
|
homeworksCount: 3,
|
||||||
|
prerequisiteCourseIds: [],
|
||||||
|
prerequisiteCourses: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 30,
|
||||||
|
termId: 4,
|
||||||
|
teacherId: 2,
|
||||||
|
teacher,
|
||||||
|
title: 'تاریخ اسلام',
|
||||||
|
description: 'درس پایه',
|
||||||
|
capacity: 45,
|
||||||
|
isActive: false,
|
||||||
|
coverUrl: null,
|
||||||
|
sessionsCount: 0,
|
||||||
|
examsCount: 1,
|
||||||
|
homeworksCount: 2,
|
||||||
|
prerequisiteCourseIds: [],
|
||||||
|
prerequisiteCourses: [],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const makeSession = (id, courseId, title, over) => ({
|
||||||
|
id,
|
||||||
|
courseId,
|
||||||
|
title,
|
||||||
|
description: 'جلسه گذراندهشده',
|
||||||
|
type: 'online',
|
||||||
|
startsAt: '2025-09-25T18:00:00+03:30',
|
||||||
|
durationMinutes: 90,
|
||||||
|
location: null,
|
||||||
|
link: 'https://meet.example.com/abc',
|
||||||
|
prerequisiteSessionIds: [],
|
||||||
|
examsCount: 1,
|
||||||
|
homeworksCount: 2,
|
||||||
|
prerequisiteSessions: [],
|
||||||
|
isComplete: true,
|
||||||
|
isSeen: true,
|
||||||
|
course: { id: courseId, termId: 3, teacherId: 2, title: 'مبانی اعتقادات' },
|
||||||
|
...over,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const passedSessions = [
|
||||||
|
makeSession(101, 21, 'جلسه اول — مقدمه'),
|
||||||
|
makeSession(102, 21, 'جلسه دوم — مفاهیم پایه'),
|
||||||
|
makeSession(103, 22, 'جلسه اول — کلیات', {
|
||||||
|
course: { id: 22, termId: 3, teacherId: 2, title: 'اخلاق کاربردی' },
|
||||||
|
}),
|
||||||
|
]
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { paginate } from '@/services/mock/helpers'
|
||||||
|
import { register } from '@/services/mock/registry'
|
||||||
|
import { endpoints } from '@/services/api/endpoints'
|
||||||
|
import {
|
||||||
|
passedTerms,
|
||||||
|
passedCourses,
|
||||||
|
passedSessions,
|
||||||
|
} from '@/services/mock/fixtures/missionary-education'
|
||||||
|
|
||||||
|
register('GET', endpoints.getMissionaryPassedTerms, ({ query }) => {
|
||||||
|
const { data: items, meta } = paginate(passedTerms, query)
|
||||||
|
return { success: true, message: 'OK', data: { items, meta } }
|
||||||
|
})
|
||||||
|
|
||||||
|
register('GET', endpoints.getMissionaryPassedCourses, ({ query }) => {
|
||||||
|
let list = passedCourses
|
||||||
|
if (query.termId) list = list.filter((c) => String(c.termId) === String(query.termId))
|
||||||
|
const { data: items, meta } = paginate(list, query)
|
||||||
|
return { success: true, message: 'OK', data: { items, meta } }
|
||||||
|
})
|
||||||
|
|
||||||
|
register('GET', endpoints.getMissionaryPassedSessions, ({ query }) => {
|
||||||
|
let list = passedSessions
|
||||||
|
if (query.courseId) list = list.filter((s) => String(s.courseId) === String(query.courseId))
|
||||||
|
const { data: items, meta } = paginate(list, query)
|
||||||
|
return { success: true, message: 'OK', data: { items, meta } }
|
||||||
|
})
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { useQuery } from '@tanstack/vue-query'
|
||||||
|
import { cleanFilters } from '@/utils/clean-filters'
|
||||||
|
import {
|
||||||
|
apiGetMissionaryPassedTerms,
|
||||||
|
apiGetMissionaryPassedCourses,
|
||||||
|
apiGetMissionaryPassedSessions,
|
||||||
|
} from '@/services/api/missionary-education'
|
||||||
|
|
||||||
|
// All three passed-* endpoints return the paginated `{ items, meta }` envelope,
|
||||||
|
// mirroring /student/my-terms, /courses and /sessions.
|
||||||
|
const selectList = (response) => {
|
||||||
|
const payload = response?.data ?? response ?? {}
|
||||||
|
return {
|
||||||
|
data: Array.isArray(payload.items) ? payload.items : payload ?? [],
|
||||||
|
meta: payload.meta,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useMissionaryPassedTermsQuery = (paginationRef, options = {}) =>
|
||||||
|
useQuery({
|
||||||
|
queryKey: ['missionary', 'passed-terms', paginationRef],
|
||||||
|
queryFn: () => apiGetMissionaryPassedTerms({ ...paginationRef.value }),
|
||||||
|
select: selectList,
|
||||||
|
...options,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const useMissionaryPassedCoursesQuery = (filtersRef, paginationRef, options = {}) =>
|
||||||
|
useQuery({
|
||||||
|
queryKey: ['missionary', 'passed-courses', filtersRef, paginationRef],
|
||||||
|
queryFn: () =>
|
||||||
|
apiGetMissionaryPassedCourses({
|
||||||
|
...cleanFilters(filtersRef.value),
|
||||||
|
...paginationRef.value,
|
||||||
|
}),
|
||||||
|
select: selectList,
|
||||||
|
...options,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const useMissionaryPassedSessionsQuery = (filtersRef, paginationRef, options = {}) =>
|
||||||
|
useQuery({
|
||||||
|
queryKey: ['missionary', 'passed-sessions', filtersRef, paginationRef],
|
||||||
|
queryFn: () =>
|
||||||
|
apiGetMissionaryPassedSessions({
|
||||||
|
...cleanFilters(filtersRef.value),
|
||||||
|
...paginationRef.value,
|
||||||
|
}),
|
||||||
|
select: selectList,
|
||||||
|
...options,
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user