exam: warning on refresh and end-exam
warning on end-exam if it isn't the last question - otherwise exam ends without warning
This commit is contained in:
parent
97b8d5dab9
commit
59497e8b01
4 changed files with 92 additions and 20 deletions
45
README.md
45
README.md
|
|
@ -1,18 +1,12 @@
|
||||||
# nuxt-prawo-jazdy
|
# nuxt-prawo-jazdy
|
||||||
|
|
||||||
## Setup
|
|
||||||
|
|
||||||
This project utilizes `pnpm`, thus it is recommended
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm install
|
|
||||||
```
|
|
||||||
|
|
||||||
## Required
|
## Required
|
||||||
|
|
||||||
The [db-prawo-jazdy](https://git.mandarynki.eu/netman/db-prawo-jazdy) project is designed for this one in mind, so use it in conjunction with this - visit it for more details
|
The [db-prawo-jazdy](https://git.mandarynki.eu/netman/db-prawo-jazdy) project is designed for this one in mind, so use it in conjunction with this - visit it for more details
|
||||||
|
|
||||||
You also need the exam media files from the (Ministry of Infrasture)[https://www.gov.pl/web/infrastruktura/prawo-jazdy] - the latest files should be there. The newest at the moment of me writing this (13th of Decemver 2025) are the (visualisations for questions from November(?) of 2025)[https://www.gov.pl/pliki/mi/pytania_egzaminacyjne_na_prawo_jazdy_11_2025.zip]
|
You also need the exam media files from the (Ministry of Infrasture)[https://www.gov.pl/web/infrastruktura/prawo-jazdy] - the latest files should be there
|
||||||
|
|
||||||
|
The newest at the moment of me writing this (December 13th 2025) are the (visualisations for questions from November 2025)[https://www.gov.pl/pliki/mi/pytania_egzaminacyjne_na_prawo_jazdy_11_2025.zip]
|
||||||
|
|
||||||
# To-do:
|
# To-do:
|
||||||
|
|
||||||
|
|
@ -21,20 +15,41 @@ You also need the exam media files from the (Ministry of Infrasture)[https://www
|
||||||
- [x] come up with how to show results appropriately
|
- [x] come up with how to show results appropriately
|
||||||
- [x] better answer click recognition
|
- [x] better answer click recognition
|
||||||
- [x] beautify website (good for now)
|
- [x] beautify website (good for now)
|
||||||
- [x] <b>Fixed?</b> Needs testing, but should be fine question-mark? - <b>fix pinia middleware between pages, MAJOR ISSUE - finishing exam sometimes redirects to homepage instead of results, help appreciated</b>
|
- [x] <b>Fixed?</b> Needs testing, but should be fine question-mark? - fix pinia middleware between pages, MAJOR ISSUE - finishing exam sometimes redirects to homepage instead of results
|
||||||
- [x] (scrapped - lazy loading)
|
|
||||||
- [x] question timers
|
- [x] question timers
|
||||||
- [ ] exam (& results?) warning leave message on exit and timer end (and definitely on refresh)
|
- [x] exam (& results?) warning leave message on exit and timer end (and definitely on refresh)
|
||||||
|
- [ ] add keybinds:
|
||||||
|
- S - start
|
||||||
|
- D - nast.pyt
|
||||||
|
- X - koniec egzaminu (na pewno chcesz zakonczyc egzamin?)
|
||||||
|
- T - Tak
|
||||||
|
- N - Nie
|
||||||
|
- A - A
|
||||||
|
- B - B
|
||||||
|
- C - C
|
||||||
- [ ] i18n - pl, en, de, ua (not all questions are available in ua, api handle)
|
- [ ] i18n - pl, en, de, ua (not all questions are available in ua, api handle)
|
||||||
- UI i18n
|
- UI i18n
|
||||||
- db: examstore add language field, api handle languages
|
- db: examstore add language field, api handle languages
|
||||||
- [ ] db: (revise) script for processing, (revise and) share appropriate files
|
- [ ] db: (revise) script for processing, (revise and) share appropriate files
|
||||||
|
- [ ] clean up js code in exam.vue and result.vue (currently a little bit of a mess)
|
||||||
|
|
||||||
## Some info
|
## Some information about the project
|
||||||
|
|
||||||
My intention is, to share access to test exams free of charge - all data is free of charge and is already available as public information, either on the gov website, or by writing to the MI
|
My intention is, to share access to test exams free of charge, you don't have to pay me - although you can, I greatly appreciate if you donate!
|
||||||
|
|
||||||
This project is a website mimicking an official driver's license exam (for different categories) with a seperate CDN for media, connected using an ORM to a postgres DB
|
In the future I will host this project publicly `aaS`, and will probably put non-invasive, privacy friendly ads if it gains enough traction
|
||||||
|
|
||||||
|
All data used by this software is public information by definition provided in the Polish Constitution - (article 61.)[https://www.sejm.gov.pl/prawo/konst/polski/kon1.htm], and can be acquired by either checking above links on the gov website, or by writing to the Ministry ((if something happened to be missing))[placeholder_for_post_about_missing_points_column]
|
||||||
|
|
||||||
|
This project is a website mimicking an official driver's license theoritical exam (for different license categories) with a seperate media server, connected using drizzle ORM to a SQLite database
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
This project utilizes `pnpm`, thus it is recommended
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm install
|
||||||
|
```
|
||||||
|
|
||||||
## Development Server
|
## Development Server
|
||||||
|
|
||||||
|
|
|
||||||
29
components/EndModal.vue
Normal file
29
components/EndModal.vue
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps<{ showModal: boolean }>();
|
||||||
|
const endModal = useTemplateRef('endModal');
|
||||||
|
|
||||||
|
const emit = defineEmits(['hideEndModal', 'endExam']);
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
if (props.showModal && endModal.value?.open == false) {
|
||||||
|
endModal.value?.showModal();
|
||||||
|
emit('hideEndModal');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<dialog
|
||||||
|
ref="endModal"
|
||||||
|
class="flex justify-center items-center backdrop-blur-sm modal"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col p-3 bg-base rounded-md gap-3 modal-box min-w-fit">
|
||||||
|
<h1 class="text-[1.5rem]">Koniec egzaminu</h1>
|
||||||
|
<div class="*:inline">Czy na pewno chcesz zakończyć egzamin?</div>
|
||||||
|
<div class="flex flex-row gap-2 justify-around">
|
||||||
|
<div class="btn btn-lg btn-success" @click="emit('endExam')">Tak</div>
|
||||||
|
<div class="btn btn-lg btn-error" @click="endModal?.close()">Nie</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
</template>
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineProps<{
|
const props = defineProps<{
|
||||||
countBasic: number;
|
countBasic: number;
|
||||||
countAdvanced: number;
|
countAdvanced: number;
|
||||||
now: string | null | undefined;
|
now: string | null | undefined;
|
||||||
|
|
@ -13,14 +13,23 @@ const emit = defineEmits<{
|
||||||
endExam: [];
|
endExam: [];
|
||||||
nextQuestion: [];
|
nextQuestion: [];
|
||||||
nextTime: [];
|
nextTime: [];
|
||||||
|
showEndModal: [];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
function tryEndExam() {
|
||||||
|
if (props.ending == false) {
|
||||||
|
emit('showEndModal');
|
||||||
|
} else {
|
||||||
|
emit('endExam');
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="flex flex-col items-stretch p-4 gap-10 border-l border-base-300 bg-base-100"
|
class="flex flex-col items-stretch p-4 gap-10 border-l border-base-300 bg-base-100"
|
||||||
>
|
>
|
||||||
<button class="btn btn-warning btn-xl" @click="emit('endExam')">
|
<button class="btn btn-warning btn-xl" @click="tryEndExam()">
|
||||||
Zakończ egzamin
|
Zakończ egzamin
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,11 @@ const basicStore = useBasicStore();
|
||||||
const advancedStore = useAdvancedStore();
|
const advancedStore = useAdvancedStore();
|
||||||
await callOnce(() => examStore.mildReset(), { mode: 'navigation' });
|
await callOnce(() => examStore.mildReset(), { mode: 'navigation' });
|
||||||
|
|
||||||
useHead({
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
title: 'Pytanie 1/20',
|
function preventRefresh(e: any) {
|
||||||
});
|
e.preventDefault();
|
||||||
|
e.returnValue = ''; // polyfill for older chrome
|
||||||
|
}
|
||||||
|
|
||||||
const now = ref('basic');
|
const now = ref('basic');
|
||||||
|
|
||||||
|
|
@ -77,6 +79,11 @@ function clickNext() {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
useHead({
|
||||||
|
title: 'Pytanie 1/20',
|
||||||
|
});
|
||||||
|
window.addEventListener('beforeunload', preventRefresh);
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if (isAfter(nowTime.value, timeEnd)) endExam();
|
if (isAfter(nowTime.value, timeEnd)) endExam();
|
||||||
});
|
});
|
||||||
|
|
@ -98,6 +105,10 @@ onMounted(() => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
window.removeEventListener('beforeunload', preventRefresh);
|
||||||
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: dataBasic,
|
data: dataBasic,
|
||||||
error: errorBasic,
|
error: errorBasic,
|
||||||
|
|
@ -196,6 +207,8 @@ function endExam() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
|
const showEndModal = ref(false);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -236,6 +249,7 @@ const loading = ref(false);
|
||||||
:set-basic="time.phase == 'set-basic'"
|
:set-basic="time.phase == 'set-basic'"
|
||||||
:time="time.question"
|
:time="time.question"
|
||||||
:phase="time.phase"
|
:phase="time.phase"
|
||||||
|
@show-end-modal="showEndModal = true"
|
||||||
@next-question="clickNext()"
|
@next-question="clickNext()"
|
||||||
@end-exam="endExam()"
|
@end-exam="endExam()"
|
||||||
@next-time="changeQuestionTimeAfterNext()"
|
@next-time="changeQuestionTimeAfterNext()"
|
||||||
|
|
@ -246,5 +260,10 @@ const loading = ref(false);
|
||||||
An API error occurred: {{ errorBasic }} {{ errorAdvanced }}
|
An API error occurred: {{ errorBasic }} {{ errorAdvanced }}
|
||||||
</div>
|
</div>
|
||||||
<LoadingScreen v-else />
|
<LoadingScreen v-else />
|
||||||
|
<EndModal
|
||||||
|
:show-modal="showEndModal"
|
||||||
|
@hide-end-modal="showEndModal = false"
|
||||||
|
@end-exam="endExam()"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue