nuxt-prawo-jazdy/pages/exam.vue

173 lines
4.1 KiB
Vue

<script lang="ts" setup>
import { intervalToDuration, addMinutes, addSeconds, isEqual } from 'date-fns';
import { useExamStore } from '~/store/examStore';
definePageMeta({ middleware: ['exam'] });
useHead({
title: 'Pytanie 1/20',
});
const nowTime = ref(new Date());
const timeEnd = addMinutes(new Date(), 25);
const timeRemainingTotal = computed(() =>
intervalToDuration({
start: nowTime.value,
end: timeEnd,
}),
);
// const timeRemainingQuestion - to implement
onMounted(() => {
const endInterval = setInterval(() => {
nowTime.value = addSeconds(nowTime.value, 1);
if (isEqual(nowTime.value, timeEnd)) {
clearInterval(endInterval);
endExam();
}
}, 1000);
});
const examStore = useExamStore();
const {
data: dataBasic,
error: errorBasic,
status: statusBasic,
} = await useLazyFetch<BasicQuestion[]>(`/api/basic`, {
query: {
category: examStore.category,
},
});
const {
data: dataAdvanced,
error: errorAdvanced,
status: statusAdvanced,
} = await useLazyFetch<AdvancedQuestion[]>(`/api/advanced`, {
query: {
category: examStore.category,
},
});
const countBasic = ref(0);
const countAdvanced = ref(-1);
const now = ref('basic');
const answer = ref<string>('');
const ending = ref(false);
const questionBasic = computed<BasicQuestion | undefined>(() =>
dataBasic.value?.at(countBasic.value),
);
const questionAdvanced = computed<AdvancedQuestion | undefined>(() =>
dataAdvanced.value?.at(countAdvanced.value),
);
const question = computed(() => {
if (now.value === 'basic') return questionBasic.value;
if (now.value === 'advanced') return questionAdvanced.value;
return null;
});
const result: Ref<ResultEndType> = ref({
basic: [],
advanced: [],
});
async function next() {
function pushVal() {
if (now.value === 'basic' || now.value === 'advanced') {
result.value[now.value].push({
question: question.value,
chosen_answer: answer.value,
chosen_is_correct: answer.value === question.value?.correct_answer,
});
}
answer.value = '';
}
if (now.value === 'basic') {
pushVal();
countBasic.value++;
useHead({
title: `Pytanie ${countBasic.value + 1}/20`,
});
if (countBasic.value >= 20) {
now.value = 'advanced';
countBasic.value--;
countAdvanced.value++;
}
} else if (now.value === 'advanced') {
pushVal();
countAdvanced.value++;
useHead({
title: `Pytanie ${countAdvanced.value + 1}/12`,
});
if (countAdvanced.value >= 11) {
ending.value = true;
}
}
}
function endExam() {
loading.value = true;
while (!ending.value) {
next();
}
next();
examStore.setResult(result.value);
examStore.setEnd(true);
while (true) {
if (examStore.result == result.value && examStore.end) {
return navigateTo('/result', { replace: true });
}
}
}
const loading = ref(false);
</script>
<template>
<div>
<!-- as in to transition to the next page -->
<Loading v-if="loading" />
<div v-if="statusBasic === 'success' && statusAdvanced === 'success'">
<div class="grid grid-cols-4 min-h-dvh">
<div class="col-span-3 flex flex-col gap-4">
<BarTop
:points="question?.weight"
:category="examStore.category"
:time-remaining="timeRemainingTotal"
/>
<Media :media="question?.media_url" />
<QuestionBasic
v-if="now === 'basic'"
v-model="answer"
:question="questionBasic"
/>
<QuestionAdvanced
v-else-if="now === 'advanced'"
v-model="answer"
:question="questionAdvanced"
/>
</div>
<BarRightExam
:count-basic="countBasic"
:count-advanced="countAdvanced"
:now="now"
:ending="ending"
@next-question="next()"
@end-exam="endExam()"
/>
</div>
</div>
<div v-else-if="statusBasic === 'error' || statusAdvanced === 'error'">
An API error occurred: {{ errorBasic }} {{ errorAdvanced }}
</div>
<Loading v-else />
</div>
</template>