Add Score board page to visualize progress of exercises

This commit is contained in:
2024-09-22 21:29:23 +02:00
parent a55248ecef
commit 6aae064902
7 changed files with 132 additions and 2 deletions

View File

@@ -59,6 +59,7 @@ const navRail = defineModel("navRail", { type: Boolean })
<div v-else></div> <div v-else></div>
</v-list-subheader> </v-list-subheader>
<v-list-item :title="$t('menu.helpInstructions')" prepend-icon="mdi-chat-question" to="/help" link /> <v-list-item :title="$t('menu.helpInstructions')" prepend-icon="mdi-chat-question" to="/help" link />
<v-list-item :title="$t('menu.scoreBoard')" prepend-icon="mdi-podium-gold" to="/scoreBoard" link />
<v-list-item :title="$t('menu.preferences')" prepend-icon="mdi-cog" to="/preferences" link /> <v-list-item :title="$t('menu.preferences')" prepend-icon="mdi-cog" to="/preferences" link />
</v-list> </v-list>
</template> </template>

View File

@@ -0,0 +1,11 @@
import { useLocalStorage } from "@vueuse/core";
import { defineStore } from "pinia";
const useScoreStore = defineStore("scoreStore", {
state: () => ({
progressGroup0: useLocalStorage("hackmycart/scoreStore/progressGroup0", 0),
progressGroup1: useLocalStorage("hackmycart/scoreStore/progressGroup1", 0),
progressGroup2: useLocalStorage("hackmycart/scoreStore/progressGroup2", 0),
progressGroup3: useLocalStorage("hackmycart/scoreStore/progressGroup3", 0),
})
})

View File

@@ -9,7 +9,8 @@
"systemAndHelp": "System & Hilfe", "systemAndHelp": "System & Hilfe",
"helpInstructions": "Hilfestellung", "helpInstructions": "Hilfestellung",
"preferences": "Einstellungen", "preferences": "Einstellungen",
"logout": "Ausloggen" "logout": "Ausloggen",
"scoreBoard": "Score Board"
}, },
"preferences": { "preferences": {
"pageSetup": "Seiteneinstellungen", "pageSetup": "Seiteneinstellungen",
@@ -102,5 +103,12 @@
"title": "Datenbank zurücksetzen?", "title": "Datenbank zurücksetzen?",
"description": "Soll die Datenbank des Servers wirklich zurückgesetzt werden? Dies kann nicht rückgänig gemacht werden!" "description": "Soll die Datenbank des Servers wirklich zurückgesetzt werden? Dies kann nicht rückgänig gemacht werden!"
} }
},
"scoreBoard": {
"exerciseGroup0": "Aufgabengruppe 0: Den Shop kennenlernen",
"exerciseGroup1": "Aufgabengruppe 1: SQL Injections",
"exerciseGroup2": "Aufgabengruppe 2: Broken Access Control",
"exerciseGroup3": "Aufgabengruppe 3: Cross-Site Scripting (XSS)",
"exercise": "Aufgabe {0}"
} }
} }

View File

@@ -9,7 +9,8 @@
"systemAndHelp": "System & Help", "systemAndHelp": "System & Help",
"helpInstructions": "Help instructions", "helpInstructions": "Help instructions",
"preferences": "Preferences", "preferences": "Preferences",
"logout": "Logout" "logout": "Logout",
"scoreBoard": "Score Board"
}, },
"preferences": { "preferences": {
"pageSetup": "Page setup", "pageSetup": "Page setup",
@@ -102,5 +103,12 @@
"title": "Reset database?", "title": "Reset database?",
"description": "Do you really want to reset the server database? This can't be undone!" "description": "Do you really want to reset the server database? This can't be undone!"
} }
},
"scoreBoard": {
"exerciseGroup0": "Exercise Group 0: Getting Started",
"exerciseGroup1": "Exercise Group 1: SQL Injections",
"exerciseGroup2": "Exercise Group 2: Broken Access Control",
"exerciseGroup3": "Exercise Group 3: Cross-Site Scripting (XSS)",
"exercise": "Exercise {0}"
} }
} }

View File

@@ -0,0 +1,51 @@
<script setup lang="ts">
import scoreCard from './scoreCard.vue';
</script>
<template>
<v-container max-width="1000">
<v-row>
<v-col>
<score-card
:title="$t('scoreBoard.exerciseGroup0')"
:progress="2"
:total-steps="2"
:step-names="['Registrieren', 'Bestellung ausführen']"
/>
</v-col>
</v-row>
<v-row>
<v-col>
<score-card
:title="$t('scoreBoard.exerciseGroup1')"
:progress="1"
:total-steps="4"
:step-names="['', '']"
/>
</v-col>
</v-row>
<v-row>
<v-col>
<score-card
:title="$t('scoreBoard.exerciseGroup2')"
:progress="1"
:total-steps="4"
:step-names="['', '']"
/>
</v-col>
</v-row>
<v-row>
<v-col>
<score-card
:title="$t('scoreBoard.exerciseGroup3')"
:progress="0"
:total-steps="3"
:step-names="['', '', '']"
/>
</v-col>
</v-row>
</v-container>
</template>

View File

@@ -0,0 +1,49 @@
<script setup lang="ts">
import cardView from '@/components/cardView.vue';
const props = defineProps({
exerciseGroup: String,
progress: Number,
totalSteps: Number,
stepNames: Array<String>
})
function getDotColor(step: number) {
if (props.progress >= step) {
return "green"
} else {
return "grey"
}
}
function getIcon(step: number) {
if (props.progress >= step) {
return "mdi-check"
} else {
return "mdi-pencil"
}
}
</script>
<template>
<card-view :title="exerciseGroup" >
<v-timeline
direction="horizontal"
side="end"
class="pb-3"
>
<v-timeline-item
v-for="step in totalSteps"
:dot-color="getDotColor(step)"
:icon="getIcon(step)"
>
{{ stepNames[step - 1] }}
<template #opposite>
{{ $t('scoreBoard.exercise', [step]) }}
</template>
</v-timeline-item>
</v-timeline>
</card-view>
</template>

View File

@@ -5,6 +5,7 @@ import ProductsPage from "@/pages/productsPage/index.vue";
import LoginPage from "@/pages/loginPage/index.vue" import LoginPage from "@/pages/loginPage/index.vue"
import BasketPage from "@/pages/basketPage/index.vue" import BasketPage from "@/pages/basketPage/index.vue"
import HelpPage from "@/pages/helpPage/index.vue" import HelpPage from "@/pages/helpPage/index.vue"
import ScoreBoardPage from "@/pages/scoreBoardPage/index.vue"
const routes = [ const routes = [
{ path: '/', component: ProductsPage }, { path: '/', component: ProductsPage },
@@ -13,6 +14,7 @@ const routes = [
{ path: '/preferences', component: PreferencesPage }, { path: '/preferences', component: PreferencesPage },
{ path: '/login', component: LoginPage }, { path: '/login', component: LoginPage },
{ path: '/basket', component: BasketPage }, { path: '/basket', component: BasketPage },
{ path: '/scoreboard', component: ScoreBoardPage },
{ path: '/help', component: HelpPage } { path: '/help', component: HelpPage }
] ]