Add user-specific quiz statistics

This commit is contained in:
2022-11-05 18:44:42 +01:00
parent f5d0734e84
commit cc20ed870c
5 changed files with 156 additions and 12 deletions

View File

@@ -1,13 +1,27 @@
<template> <template>
<v-container fluid> <v-card>
<v-subheader class="text-h5 text--primary">Challenge</v-subheader> <v-card-title>
<v-divider></v-divider> Spiele {{ games.won + games.lost + games.tie }}
</v-card-title>
<v-card-subtitle>
<div>Siege: {{ games.won }}</div>
<div>Unentschieden: {{ games.lost }}</div>
<div>Niederlagen: {{ games.tie }}</div>
<div>Fragen: {{ games.questionsCorrect + games.questionsIncorrect }}</div>
<div>Richtig: {{ questionsCorrectPercent }}%</div>
</v-card-subtitle>
<v-card-text>
{{ text }}
</v-card-text>
<v-card-text>
<v-btn depressed color="success" class="my-3" @click="playVersus"> <v-btn depressed color="success" class="my-3" @click="playVersus">
<v-icon left>mdi-play</v-icon> <v-icon left>mdi-play</v-icon>
Quiz Spielen Spielen
</v-btn> </v-btn>
</v-card-text>
<v-divider></v-divider>
<AddClosedEndedQuestion /> <AddClosedEndedQuestion />
</v-container> </v-card>
</template> </template>
<script> <script>
@@ -23,7 +37,22 @@ export default {
return { return {
} }
}, },
created () { computed: {
games () {
return this.$store.state.user.games[this.courseId]
},
questionsCorrectPercent () {
const percent = (this.games.questionsCorrect / (this.games.questionsCorrect + this.games.questionsIncorrect)) * 100
// percent will be NaN if the student hasn't played any games yet
return percent ? Math.round(parseFloat(percent)) : 100 // Convert to float, then round to closest int
},
text () {
if (this.questionsAnswered >= 20 && this.questionsCorrectPercent >= 90) {
return 'Du scheinst gut auf die Klausur vorbereitet zu sein. Viel Glück!'
} else {
return 'Wir empfehlen Dir noch ein wenig zu üben, bevor du zur Klausur antrittst.'
}
}
}, },
methods: { methods: {
playVersus () { playVersus () {

View File

@@ -0,0 +1,58 @@
<template>
<v-dialog v-model="show" persistent width="500">
<v-card class="mx-auto">
<v-card-title class="justify-center">{{ title }}</v-card-title>
<v-card-text>
<v-row no-gutters class="text-h4 text--primary">
<v-col cols="5" class="d-flex justify-end">{{ result.correctAnswersPl1 }}</v-col>
<v-col cols="2" class="d-flex justify-center">:</v-col>
<v-col cols="5" class="d-flex justify-start">{{ result.correctAnswersPl2 }}</v-col>
</v-row>
<v-row no-gutters class="text-subtitle-1">
<v-col cols="5" class="d-flex justify-end">{{ game.player1name }}</v-col>
<v-col cols="2" class="d-flex justify-center"></v-col>
<v-col cols="5" class="d-flex justify-start">{{ game.player2name }}</v-col>
</v-row>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn depressed block color="primary" :to="`/courses/${courseId}`">Abschließen</v-btn>
<v-spacer></v-spacer>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
import { Game } from '~/plugins/game'
export default {
props: {
game: {
type: Game,
required: true
},
courseId: {
type: String,
required: true
}
},
data () {
return {
show: false
}
},
computed: {
result () {
return this.game.getResult()
},
title () {
if (this.result.tie) return 'Unentschieden!'
else return this.result.winner === this.playerNumber ? 'Gewonnen!' : 'Verloren :('
},
playerNumber () {
return this.game.player1id === this.$auth.currentUser.uid ? 1 : 2
}
}
}
</script>

View File

@@ -1,7 +1,7 @@
export class Game { export class Game {
constructor (id, questions, created, player1id, player1name, player1answers, player2id, player2name, player2answers) { constructor (id, questions, created, player1id, player1name, player1answers, player2id, player2name, player2answers) {
this.id = id this.id = id
this.questions = questions this.questionIds = questions
this.created = created this.created = created
this.player1id = player1id this.player1id = player1id
this.player1name = player1name this.player1name = player1name
@@ -10,13 +10,38 @@ export class Game {
this.player2name = player2name this.player2name = player2name
this.player2answers = player2answers this.player2answers = player2answers
} }
getResult () {
if (!this.questions) return {}
const qs = this.questions
function countCorrectAnswers(answersGiven) {
let i = 0
answersGiven.forEach(a => {
const q = qs.find(e => e.id === a.frage)
if (q && a.antwort === q.correctAnswer) i++
})
return i
}
const correctAnswersPl1 = countCorrectAnswers(this.player1answers)
const correctAnswersPl2 = countCorrectAnswers(this.player2answers)
return {
winner: correctAnswersPl1 > correctAnswersPl2 ? 1 : 2,
loser: correctAnswersPl1 > correctAnswersPl2 ? 2 : 1,
tie: correctAnswersPl1 === correctAnswersPl2,
correctAnswersPl1,
correctAnswersPl2
}
}
} }
// Firestore data converter // Firestore data converter
export const GameConverter = { export const GameConverter = {
toFirestore: (game) => { toFirestore: (game) => {
return { return {
fragen: game.questions, fragen: game.questionIds,
erstellt: game.created, erstellt: game.created,
spieler1id: game.player1id, spieler1id: game.player1id,
spieler1name: game.player1name, spieler1name: game.player1name,

View File

@@ -1,20 +1,48 @@
export class User { export class User {
constructor (displayName, courses, gamesStarted) { constructor (displayName, courses, games, gamesStarted) {
this.displayName = displayName this.displayName = displayName
this.courses = courses this.courses = courses
this.games = {}
this.gamesStarted = [] this.gamesStarted = []
if (games) this.setGames(games)
if (gamesStarted && gamesStarted.length > 0) { if (gamesStarted && gamesStarted.length > 0) {
gamesStarted.forEach(e => { gamesStarted.forEach(e => {
this.gamesStarted.push({ course: e.kurs, game: e.spiel }) this.gamesStarted.push({ course: e.kurs, game: e.spiel })
}) })
} }
} }
setGames (gamesObj) {
for (const [key, value] of Object.entries(gamesObj)) {
const obj = {
won: value.gewonnen || 0,
lost: value.verloren || 0,
tie: value.unentschieden || 0,
questionsCorrect: value.fragenRichtig || 0,
questionsIncorrect: value.fragenFalsch || 0
}
this.games[key] = obj
}
}
} }
// Firestore data converter // Firestore data converter
export const UserConverter = { export const UserConverter = {
toFirestore: (user) => { toFirestore: (user) => {
const spiele = {}
for (const [key, value] of Object.entries(user.games)) {
const obj = {
gewonnen: value.won || 0,
verloren: value.lost || 0,
unentschieden: value.tie || 0,
fragenRichtig: value.questionsCorrect || 0,
fragenFalsch: value.questionsIncorrect || 0
}
spiele[key] = obj
}
const spieleBegonnen = [] const spieleBegonnen = []
user.gamesStarted.forEach(e => { user.gamesStarted.forEach(e => {
spieleBegonnen.push({ kurs: e.course, spiel: e.game }) spieleBegonnen.push({ kurs: e.course, spiel: e.game })
@@ -23,11 +51,12 @@ export const UserConverter = {
return { return {
anzeigename: user.displayName, anzeigename: user.displayName,
kurse: user.courses, kurse: user.courses,
spiele,
spieleBegonnen spieleBegonnen
} }
}, },
fromFirestore: (snapshot, options) => { fromFirestore: (snapshot, options) => {
const data = snapshot.data(options) const data = snapshot.data(options)
return new User(data.anzeigename, data.kurse, data.spieleBegonnen) return new User(data.anzeigename, data.kurse, data.spiele, data.spieleBegonnen)
} }
} }

View File

@@ -37,6 +37,9 @@ export const mutations = {
setCourses (state, courses) { setCourses (state, courses) {
state.courses = courses state.courses = courses
}, },
initCourse (state, courseID) {
state.user.setGames({ [courseID]: {} })
},
addFavoriteCourse (state, courseID) { addFavoriteCourse (state, courseID) {
state.user.courses.push(courseID) state.user.courses.push(courseID)
}, },