201 előtti mentés

This commit is contained in:
Roo
2026-03-26 07:09:44 +00:00
parent 89668a9beb
commit 03258db091
124 changed files with 13619 additions and 13347 deletions

View File

@@ -0,0 +1,261 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useQuizStore = defineStore('quiz', () => {
// State
const userPoints = ref(0)
const currentStreak = ref(0)
const lastPlayedDate = ref(null)
const questions = ref([])
const isLoading = ref(false)
const error = ref(null)
// Getters
const canPlayToday = computed(() => {
if (!lastPlayedDate.value) return true
const last = new Date(lastPlayedDate.value)
const now = new Date()
// Reset at midnight (different calendar day)
const lastDay = last.toDateString()
const today = now.toDateString()
return lastDay !== today
})
const totalQuestions = computed(() => questions.value.length)
// Helper function to get auth token
function getAuthToken() {
if (typeof window !== 'undefined') {
// Try both token keys for compatibility
return localStorage.getItem('token') || localStorage.getItem('auth_token')
}
return null
}
// Helper function for API calls
async function apiFetch(url, options = {}) {
const token = getAuthToken()
const headers = {
'Content-Type': 'application/json',
...options.headers
}
if (token) {
headers['Authorization'] = `Bearer ${token}`
}
const response = await fetch(`${import.meta.env.VITE_API_BASE_URL || 'https://dev.servicefinder.hu'}${url}`, {
...options,
headers
})
if (!response.ok) {
const errorText = await response.text()
throw new Error(`API error ${response.status}: ${errorText}`)
}
return response.json()
}
// Actions
async function fetchQuizStats() {
isLoading.value = true
error.value = null
try {
const data = await apiFetch('/api/v1/gamification/quiz/stats')
userPoints.value = data.total_quiz_points || 0
currentStreak.value = data.current_streak || 0
lastPlayedDate.value = data.last_played || null
return data
} catch (err) {
console.error('Failed to fetch quiz stats:', err)
error.value = err.message
// Fallback to localStorage if API fails
userPoints.value = getStoredPoints()
currentStreak.value = getStoredStreak()
lastPlayedDate.value = getStoredLastPlayedDate()
return {
total_quiz_points: userPoints.value,
current_streak: currentStreak.value,
last_played: lastPlayedDate.value,
can_play_today: canPlayToday.value
}
} finally {
isLoading.value = false
}
}
async function fetchDailyQuiz() {
isLoading.value = true
error.value = null
try {
const data = await apiFetch('/api/v1/gamification/quiz/daily')
questions.value = data.questions || []
return data
} catch (err) {
console.error('Failed to fetch daily quiz:', err)
error.value = err.message
// Fallback to mock questions if API fails
questions.value = getMockQuestions()
return {
questions: questions.value,
total_questions: questions.value.length,
date: new Date().toISOString().split('T')[0]
}
} finally {
isLoading.value = false
}
}
async function answerQuestion(questionId, selectedOptionIndex) {
try {
const response = await apiFetch('/api/v1/gamification/quiz/answer', {
method: 'POST',
body: JSON.stringify({
question_id: questionId,
selected_option: selectedOptionIndex
})
})
if (response.is_correct) {
userPoints.value += response.points_awarded
currentStreak.value += 1
persistState() // Update localStorage as fallback
} else {
currentStreak.value = 0
}
return response
} catch (err) {
console.error('Failed to submit quiz answer:', err)
error.value = err.message
// Fallback to local logic
return answerQuestionLocal(questionId, selectedOptionIndex)
}
}
async function completeDailyQuiz() {
try {
await apiFetch('/api/v1/gamification/quiz/complete', {
method: 'POST'
})
lastPlayedDate.value = new Date().toISOString()
persistState()
} catch (err) {
console.error('Failed to complete daily quiz:', err)
error.value = err.message
// Fallback to local storage
lastPlayedDate.value = new Date().toISOString()
persistState()
}
}
// Local fallback functions
function answerQuestionLocal(questionId, selectedOptionIndex) {
const question = questions.value.find(q => q.id === questionId)
if (!question) return { is_correct: false, correct_answer: -1, explanation: 'Question not found' }
const isCorrect = selectedOptionIndex === question.correctAnswer
if (isCorrect) {
userPoints.value += 10
currentStreak.value += 1
} else {
currentStreak.value = 0
}
persistState()
return {
is_correct: isCorrect,
correct_answer: question.correctAnswer,
points_awarded: isCorrect ? 10 : 0,
explanation: question.explanation
}
}
function resetStreak() {
currentStreak.value = 0
persistState()
}
function addPoints(points) {
userPoints.value += points
persistState()
}
// SSR-safe localStorage persistence (fallback only)
function persistState() {
if (typeof window !== 'undefined') {
localStorage.setItem('quiz_points', userPoints.value.toString())
localStorage.setItem('quiz_streak', currentStreak.value.toString())
localStorage.setItem('quiz_last_played', lastPlayedDate.value)
}
}
function getStoredPoints() {
if (typeof window !== 'undefined') {
return parseInt(localStorage.getItem('quiz_points') || '0')
}
return 0
}
function getStoredStreak() {
if (typeof window !== 'undefined') {
return parseInt(localStorage.getItem('quiz_streak') || '0')
}
return 0
}
function getStoredLastPlayedDate() {
if (typeof window !== 'undefined') {
return localStorage.getItem('quiz_last_played') || null
}
return null
}
function getMockQuestions() {
return [
{
id: 1,
question: 'Melyik alkatrész felelős a motor levegőüzemanyag keverékének szabályozásáért?',
options: ['Generátor', 'Lambdaszonda', 'Féktárcsa', 'Olajszűrő'],
correctAnswer: 1,
explanation: 'A lambdaszonda méri a kipufogógáz oxigéntartalmát, és ezen alapul a befecskendezés.'
},
{
id: 2,
question: 'Mennyi ideig érvényes egy gépjármű műszaki vizsgája Magyarországon?',
options: ['1 év', '2 év', '4 év', '6 év'],
correctAnswer: 1,
explanation: 'A személygépkocsik műszaki vizsgája 2 évre érvényes, kivéve az újonnan forgalomba helyezett autókat.'
},
{
id: 3,
question: 'Melyik anyag NEM része a hibrid autók akkumulátorának?',
options: ['Lítium', 'Nikkel', 'Ólom', 'Kobalt'],
correctAnswer: 2,
explanation: 'A hibrid és elektromos autók akkumulátoraiban általában lítium, nikkel és kobalt található, ólom az ólomsavas akkukban van.'
}
]
}
// Initialize store with stats - DISABLED for debugging
// fetchQuizStats()
console.log('🚨 Quiz store: Auto-fetch DISABLED for debugging')
return {
userPoints,
currentStreak,
lastPlayedDate,
questions,
canPlayToday,
totalQuestions,
isLoading,
error,
fetchQuizStats,
fetchDailyQuiz,
answerQuestion,
completeDailyQuiz,
resetStreak,
addPoints
}
})