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: 'اینجا پل ارتباطی شما با پشتیبانی است.',
|
||||
},
|
||||
},
|
||||
{
|
||||
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: 'ترمها و دورههای گذراندهشده خود را مرور کنید.',
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user