1 line
19 KiB
JSON
1 line
19 KiB
JSON
{"file":"seasons-B_EJxQ8K.js","mappings":"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","names":["_unref","_ssrRenderList","_ssrInterpolate","_ssrRenderClass","_ssrRenderAttr","_ssrIncludeBooleanAttr","_ssrLooseContain"],"sources":["../../../../pages/gamification/seasons.vue"],"sourcesContent":["<template>\n <div>\n <!-- Page Header -->\n <div class=\"mb-8 flex items-center justify-between\">\n <div>\n <h1 class=\"text-2xl font-bold text-white\">{{ t('gamification.seasons.title') }}</h1>\n <p class=\"text-slate-400 mt-1\">{{ t('gamification.seasons.subtitle') }}</p>\n </div>\n <button\n class=\"flex items-center gap-2 px-4 py-2 bg-indigo-600 hover:bg-indigo-500 text-white text-sm font-medium rounded-lg transition\"\n @click=\"openCreateModal\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 4v16m8-8H4\" />\n </svg>\n {{ t('gamification.seasons.create_btn') }}\n </button>\n </div>\n\n <!-- Loading State -->\n <div v-if=\"loading\" class=\"flex items-center justify-center py-20\">\n <div class=\"text-slate-400 flex items-center gap-3\">\n <svg class=\"w-5 h-5 animate-spin\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n <span>{{ t('gamification.seasons.loading') }}</span>\n </div>\n </div>\n\n <!-- Error State -->\n <div v-else-if=\"error\" class=\"bg-rose-500/10 border border-rose-500/30 rounded-xl p-6 mb-8\">\n <p class=\"text-rose-400\">{{ t('gamification.seasons.load_error') }}</p>\n <button class=\"mt-2 text-sm text-rose-300 hover:text-rose-200 underline\" @click=\"fetchSeasons\">{{ t('gamification.seasons.retry') }}</button>\n </div>\n\n <!-- Seasons List -->\n <template v-else>\n <!-- Empty State -->\n <div v-if=\"seasons.length === 0\" class=\"bg-slate-800 rounded-xl border border-slate-700 p-12 text-center\">\n <svg class=\"w-12 h-12 mx-auto text-slate-600 mb-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z\" />\n </svg>\n <p class=\"text-slate-400\">{{ t('gamification.seasons.empty') }}</p>\n <button\n class=\"mt-4 px-4 py-2 bg-indigo-600 hover:bg-indigo-500 text-white text-sm font-medium rounded-lg transition\"\n @click=\"openCreateModal\"\n >\n {{ t('gamification.seasons.create_first') }}\n </button>\n </div>\n\n <!-- Season Cards -->\n <div v-else class=\"space-y-4\">\n <div\n v-for=\"season in seasons\"\n :key=\"season.id\"\n class=\"bg-slate-800 rounded-xl border border-slate-700 p-6 hover:border-slate-600 transition\"\n >\n <div class=\"flex items-start justify-between\">\n <div class=\"flex-1\">\n <div class=\"flex items-center gap-3 mb-2\">\n <h3 class=\"text-lg font-semibold text-white\">{{ season.name }}</h3>\n <span\n class=\"px-2.5 py-0.5 rounded-full text-xs font-medium\"\n :class=\"season.is_active\n ? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/30'\n : 'bg-slate-700 text-slate-400 border border-slate-600'\"\n >\n {{ season.is_active ? t('gamification.seasons.active') : t('gamification.seasons.inactive') }}\n </span>\n </div>\n <div class=\"flex items-center gap-6 text-sm text-slate-400\">\n <div class=\"flex items-center gap-2\">\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z\" />\n </svg>\n <span>{{ formatDate(season.start_date) }} → {{ formatDate(season.end_date) }}</span>\n </div>\n <div class=\"flex items-center gap-2\">\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <span>{{ t('gamification.seasons.created_at') }} {{ formatDateTime(season.created_at) }}</span>\n </div>\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"flex items-center gap-2 ml-4\">\n <button\n v-if=\"!season.is_active\"\n class=\"p-2 rounded-lg text-emerald-400 hover:bg-emerald-500/10 transition\"\n :title=\"t('gamification.seasons.activate')\"\n @click=\"activateSeason(season)\"\n >\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z\" />\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n </button>\n <button\n class=\"p-2 rounded-lg text-indigo-400 hover:bg-indigo-500/10 transition\"\n :title=\"t('gamification.seasons.edit')\"\n @click=\"openEditModal(season)\"\n >\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n </div>\n </template>\n\n <!-- Create/Edit Modal -->\n <div\n v-if=\"showModal\"\n class=\"fixed inset-0 z-50 flex items-center justify-center p-4\"\n >\n <div class=\"fixed inset-0 bg-black/60\" @click=\"closeModal\" />\n <div class=\"relative bg-slate-800 rounded-xl border border-slate-700 w-full max-w-lg p-6 shadow-2xl\">\n <h2 class=\"text-lg font-semibold text-white mb-6\">\n {{ editingSeason ? t('gamification.seasons.edit_title') : t('gamification.seasons.create_title') }}\n </h2>\n\n <form @submit.prevent=\"saveSeason\" class=\"space-y-4\">\n <!-- Name -->\n <div>\n <label class=\"block text-sm font-medium text-slate-300 mb-1\">{{ t('gamification.seasons.name_label') }}</label>\n <input\n v-model=\"form.name\"\n type=\"text\"\n required\n class=\"w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent\"\n :placeholder=\"t('gamification.seasons.name_placeholder')\"\n />\n </div>\n\n <!-- Start Date -->\n <div>\n <label class=\"block text-sm font-medium text-slate-300 mb-1\">{{ t('gamification.seasons.start_date_label') }}</label>\n <input\n v-model=\"form.start_date\"\n type=\"date\"\n required\n class=\"w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent\"\n />\n </div>\n\n <!-- End Date -->\n <div>\n <label class=\"block text-sm font-medium text-slate-300 mb-1\">{{ t('gamification.seasons.end_date_label') }}</label>\n <input\n v-model=\"form.end_date\"\n type=\"date\"\n required\n class=\"w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent\"\n />\n </div>\n\n <!-- Active toggle (only for create) -->\n <div v-if=\"!editingSeason\" class=\"flex items-center gap-3\">\n <input\n v-model=\"form.is_active\"\n type=\"checkbox\"\n id=\"is_active\"\n class=\"w-4 h-4 rounded border-slate-600 bg-slate-700 text-indigo-600 focus:ring-indigo-500\"\n />\n <label for=\"is_active\" class=\"text-sm text-slate-300\">{{ t('gamification.seasons.active_on_create') }}</label>\n </div>\n\n <!-- Error -->\n <div v-if=\"formError\" class=\"bg-rose-500/10 border border-rose-500/30 rounded-lg p-3\">\n <p class=\"text-sm text-rose-400\">{{ formError }}</p>\n </div>\n\n <!-- Buttons -->\n <div class=\"flex items-center justify-end gap-3 pt-2\">\n <button\n type=\"button\"\n class=\"px-4 py-2 text-sm text-slate-400 hover:text-white transition\"\n @click=\"closeModal\"\n >\n {{ t('gamification.seasons.cancel') }}\n </button>\n <button\n type=\"submit\"\n :disabled=\"saving\"\n class=\"px-4 py-2 bg-indigo-600 hover:bg-indigo-500 disabled:bg-indigo-600/50 text-white text-sm font-medium rounded-lg transition flex items-center gap-2\"\n >\n <svg v-if=\"saving\" class=\"w-4 h-4 animate-spin\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n {{ editingSeason ? t('gamification.seasons.save') : t('gamification.seasons.create') }}\n </button>\n </div>\n </form>\n </div>\n </div>\n\n <!-- Activate Confirmation Modal -->\n <div\n v-if=\"showActivateModal\"\n class=\"fixed inset-0 z-50 flex items-center justify-center p-4\"\n >\n <div class=\"fixed inset-0 bg-black/60\" @click=\"showActivateModal = false\" />\n <div class=\"relative bg-slate-800 rounded-xl border border-slate-700 w-full max-w-md p-6 shadow-2xl\">\n <h2 class=\"text-lg font-semibold text-white mb-2\">{{ t('gamification.seasons.activate_title') }}</h2>\n <p class=\"text-slate-400 text-sm mb-6\">\n {{ t('gamification.seasons.activate_confirm', { name: activatingSeason?.name }) }}\n </p>\n <div class=\"flex items-center justify-end gap-3\">\n <button\n class=\"px-4 py-2 text-sm text-slate-400 hover:text-white transition\"\n @click=\"showActivateModal = false\"\n >\n {{ t('gamification.seasons.cancel') }}\n </button>\n <button\n :disabled=\"saving\"\n class=\"px-4 py-2 bg-emerald-600 hover:bg-emerald-500 disabled:bg-emerald-600/50 text-white text-sm font-medium rounded-lg transition\"\n @click=\"confirmActivate\"\n >\n {{ saving ? t('gamification.seasons.activating') : t('gamification.seasons.activate') }}\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\ndefinePageMeta({\n middleware: 'auth',\n})\n\nconst { t } = useI18n()\n\ninterface Season {\n id: number\n name: string\n start_date: string\n end_date: string\n is_active: boolean\n created_at: string | null\n}\n\ninterface SeasonForm {\n name: string\n start_date: string\n end_date: string\n is_active: boolean\n}\n\nconst loading = ref(true)\nconst error = ref(false)\nconst saving = ref(false)\nconst showModal = ref(false)\nconst showActivateModal = ref(false)\nconst seasons = ref<Season[]>([])\nconst editingSeason = ref<Season | null>(null)\nconst activatingSeason = ref<Season | null>(null)\nconst formError = ref('')\n\nconst form = reactive<SeasonForm>({\n name: '',\n start_date: '',\n end_date: '',\n is_active: false,\n})\n\nfunction getAuthHeaders() {\n const tokenCookie = useCookie('access_token')\n const token = tokenCookie.value\n return token ? { Authorization: `Bearer ${token}` } : {}\n}\n\nfunction formatDate(dateStr: string): string {\n if (!dateStr) return ''\n const d = new Date(dateStr)\n return d.toLocaleDateString('hu-HU', { year: 'numeric', month: 'long', day: 'numeric' })\n}\n\nfunction formatDateTime(dateStr: string | null): string {\n if (!dateStr) return ''\n const d = new Date(dateStr)\n return d.toLocaleDateString('hu-HU', { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit' })\n}\n\nfunction resetForm() {\n form.name = ''\n form.start_date = ''\n form.end_date = ''\n form.is_active = false\n formError.value = ''\n}\n\nfunction openCreateModal() {\n editingSeason.value = null\n resetForm()\n showModal.value = true\n}\n\nfunction openEditModal(season: Season) {\n editingSeason.value = season\n form.name = season.name\n form.start_date = season.start_date\n form.end_date = season.end_date\n form.is_active = season.is_active\n formError.value = ''\n showModal.value = true\n}\n\nfunction closeModal() {\n showModal.value = false\n editingSeason.value = null\n resetForm()\n}\n\nfunction activateSeason(season: Season) {\n activatingSeason.value = season\n showActivateModal.value = true\n}\n\nasync function fetchSeasons() {\n loading.value = true\n error.value = false\n try {\n const data = await $fetch('/api/v1/admin/gamification/seasons', {\n headers: getAuthHeaders(),\n })\n seasons.value = data as Season[]\n } catch (e) {\n console.error('Failed to fetch seasons:', e)\n error.value = true\n } finally {\n loading.value = false\n }\n}\n\nasync function saveSeason() {\n saving.value = true\n formError.value = ''\n\n try {\n if (editingSeason.value) {\n // Update existing season\n const payload: Record<string, any> = {}\n if (form.name !== editingSeason.value.name) payload.name = form.name\n if (form.start_date !== editingSeason.value.start_date) payload.start_date = form.start_date\n if (form.end_date !== editingSeason.value.end_date) payload.end_date = form.end_date\n\n if (Object.keys(payload).length > 0) {\n await $fetch(`/api/v1/admin/gamification/seasons/${editingSeason.value.id}`, {\n method: 'PUT',\n headers: { ...getAuthHeaders(), 'Content-Type': 'application/json' },\n body: payload,\n })\n }\n } else {\n // Create new season\n await $fetch('/api/v1/admin/gamification/seasons', {\n method: 'POST',\n headers: { ...getAuthHeaders(), 'Content-Type': 'application/json' },\n body: {\n name: form.name,\n start_date: form.start_date,\n end_date: form.end_date,\n is_active: form.is_active,\n },\n })\n }\n\n closeModal()\n await fetchSeasons()\n } catch (e: any) {\n console.error('Failed to save season:', e)\n formError.value = e?.data?.detail || e?.message || t('gamification.seasons.save_error')\n } finally {\n saving.value = false\n }\n}\n\nasync function confirmActivate() {\n if (!activatingSeason.value) return\n saving.value = true\n\n try {\n await $fetch(`/api/v1/admin/gamification/seasons/${activatingSeason.value.id}/activate`, {\n method: 'POST',\n headers: getAuthHeaders(),\n })\n showActivateModal.value = false\n activatingSeason.value = null\n await fetchSeasons()\n } catch (e: any) {\n console.error('Failed to activate season:', e)\n } finally {\n saving.value = false\n }\n}\n\nonMounted(() => {\n fetchSeasons()\n})\n</script>\n"],"version":3} |