feat: добавил ограничение записи на лекции
Backend CI / build-and-test (push) Failing after 32s
Frontend CI / build-and-check (push) Failing after 5m5s
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Successful in 6s
🚀 Create and publish a Docker image / Build & publish backend image (push) Failing after 1m28s
🚀 Create and publish a Docker image / Build & publish frontend image (push) Failing after 19s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Has been skipped

This commit is contained in:
2026-05-21 19:34:08 +03:00
parent 32b8bdfd24
commit 2e7ce6c2e8
21 changed files with 569 additions and 23 deletions
@@ -1,19 +1,25 @@
<script setup lang="ts">
import { computed, onMounted } from 'vue'
import { computed, inject, onMounted, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useLecturesStore } from '@/stores/lectures'
import { useUserStore } from '@/stores/user'
import GlassCard from '@/components/ui/GlassCard.vue'
import LectureCard from '@/components/ui/LectureCard.vue'
import StatusBadge from '@/components/ui/StatusBadge.vue'
import EmptyState from '@/components/ui/EmptyState.vue'
import EnrollmentLimitModal from '@/components/ui/EnrollmentLimitModal.vue'
const route = useRoute()
const router = useRouter()
const lecturesStore = useLecturesStore()
const userStore = useUserStore()
const addToast = inject('addToast') as ((message: string, type?: 'success' | 'error' | 'info') => void) | undefined
const enrollmentLimitModalOpen = ref(false)
const lectureId = computed(() => String(route.params.id))
const lecture = computed(() => lecturesStore.all.find(l => l.id === lectureId.value))
const isRegistered = computed(() => (lecture.value ? lecturesStore.isRegistered(lecture.value.id) : false))
const slotRegistrationDisabled = computed(() => !userStore.hasEnrollmentSlotAvailable && !isRegistered.value)
const isAttended = computed(() => lecture.value?.status === 'completed')
const reviews = computed(() => lecturesStore.reviewsByLecture[lectureId.value] ?? [])
@@ -24,6 +30,25 @@ onMounted(async () => {
await lecturesStore.fetchLecture(lectureId.value)
await lecturesStore.fetchReviews(lectureId.value)
})
async function registerLecture() {
if (!lecture.value) return
if (slotRegistrationDisabled.value) {
enrollmentLimitModalOpen.value = true
return
}
try {
await lecturesStore.register(lecture.value.id)
addToast?.('Вы записаны на лекцию.', 'success')
} catch (err) {
if (err instanceof Error && err.message.includes('Лимит записей достигнут')) {
enrollmentLimitModalOpen.value = true
return
}
addToast?.(err instanceof Error ? err.message : 'Не удалось записаться на лекцию.', 'error')
}
}
</script>
<template>
@@ -49,7 +74,7 @@ onMounted(async () => {
v-if="!isRegistered"
class="btn-primary"
:disabled="lecture.freeSeats === 0 || lecture.registrationClosed"
@click="lecturesStore.register(lecture.id)"
@click="registerLecture"
>
Записаться
</button>
@@ -107,6 +132,8 @@ onMounted(async () => {
<LectureCard v-for="l in similarLectures" :key="l.id" :lecture="l" />
</div>
</section>
<EnrollmentLimitModal v-model="enrollmentLimitModalOpen" />
</div>
</template>