Add option for admins to create new courses

This commit is contained in:
2022-11-02 21:30:06 +01:00
parent a0ae63dc6a
commit 0e2309a25b
3 changed files with 137 additions and 5 deletions

123
components/AddCourse.vue Normal file
View File

@@ -0,0 +1,123 @@
<template>
<v-dialog v-model="show" max-width="500" persistent>
<template #activator="{ on, attrs }">
<v-card flat width="100%" class="rounded-lg" v-bind="attrs" v-on="on">
<v-card-text class="text-h6">
<v-icon left x-large>mdi-plus</v-icon>
Kurs hinzufügen
</v-card-text>
</v-card>
</template>
<ValidationObserver ref="addCourseObserver" v-slot="{ invalid }">
<form @submit.prevent="addCourse">
<v-card>
<v-card-title>Neuer Kurs</v-card-title>
<v-card-text>
<ValidationProvider v-slot="{ errors }" name="courseID" rules="required">
<v-text-field
v-model="id"
required
label="ID"
persistent-placeholder
placeholder="ISEF01"
:error-messages="errors"
></v-text-field>
</ValidationProvider>
<ValidationProvider v-slot="{ errors }" name="course" rules="required">
<v-text-field
v-model="title"
required
label="Bezeichnung"
persistent-placeholder
placeholder="Projekt Software Engineering"
:error-messages="errors"
></v-text-field>
</ValidationProvider>
<ValidationProvider v-slot="{ errors }" name="tutor" rules="required|email">
<v-text-field
v-model="tutor"
required
label="Tutor E-Mail"
persistent-placeholder
placeholder="john.johnson@iu.org"
:error-messages="errors"
></v-text-field>
</ValidationProvider>
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn text color="primary" @click="close">Abbrechen</v-btn>
<v-btn type="submit" depressed color="primary" :loading="loading" :disabled="invalid">Hinzufügen</v-btn>
</v-card-actions>
</v-card>
</form>
</ValidationObserver>
</v-dialog>
</template>
<script>
import { doc, setDoc } from 'firebase/firestore'
// We use vee-validate@3 for form validation.
// https://vee-validate.logaretm.com/v3/guide/basics.html
import { ValidationProvider, ValidationObserver, extend } from 'vee-validate'
import { required, email } from 'vee-validate/dist/rules'
// Override the default error message of required fields
extend('required', {
...required,
message: 'Pflichtfeld'
})
extend('email', {
...email,
message: 'Keine gültige E-Mail-Adresse'
})
export default {
name: 'AddCourseDialog',
components: {
ValidationProvider,
ValidationObserver
},
data () {
return {
show: false,
loading: false,
id: '',
title: '',
tutor: ''
}
},
methods: {
addCourse () {
this.loading = true
const courseID = this.id.toLowerCase().trim()
const courseName = this.title.trim()
const tutorEmail = this.tutor.toLowerCase().trim()
const c = { name: courseName, tutor: tutorEmail }
// Add a new document
setDoc(doc(this.$db, `kurse/${courseID}`), c)
.then((docRef) => {
// Successfully added a new course to the database.
this.$store.commit('setCourse', { courseID, courseData: c })
this.$toast({content: `Der Kurs "${courseID.toUpperCase()} - ${courseName}" wurde hinzugefügt!`, color: 'success'})
this.close()
})
.catch((error) => {
// Failed to add a new course to the database; display error message
this.$toast({content: error, color: 'error'})
})
.then(() => { this.loading = false })
},
close () {
this.id = ''
this.title = ''
this.tutor = ''
this.show = false
this.$refs.addCourseObserver.reset()
}
}
}
</script>

View File

@@ -1,6 +1,9 @@
<template> <template>
<v-container fluid> <v-container fluid>
<v-row> <v-row>
<v-col v-if="$store.getters.isAdmin" cols="12">
<AddCourse />
</v-col>
<v-col v-for="(course, id) in courses" :key="id" cols="12" lg="6"> <v-col v-for="(course, id) in courses" :key="id" cols="12" lg="6">
<v-card flat width="100%" class="rounded-lg" @click="openCourse(id)"> <v-card flat width="100%" class="rounded-lg" @click="openCourse(id)">
<v-row no-gutters class="flex-nowrap"> <v-row no-gutters class="flex-nowrap">
@@ -26,16 +29,12 @@
<script> <script>
import _cloneDeep from 'lodash-es/cloneDeep' import _cloneDeep from 'lodash-es/cloneDeep'
import { collection, getDocs } from 'firebase/firestore' import { collection, getDocs } from 'firebase/firestore'
import { demoAccounts } from '~/components/DemoInfoDialog.vue'
export default { export default {
name: 'DashboardPage', name: 'DashboardPage',
layout ({ $auth }) { layout ({ $auth }) {
// Ref: https://firebase.google.com/docs/reference/js/v8/firebase.auth.Auth#currentuser // Ref: https://firebase.google.com/docs/reference/js/v8/firebase.auth.Auth#currentuser
// return $auth.currentUser.emailVerified ? 'default' : 'unverified' return $auth.currentUser.emailVerified ? 'default' : 'unverified'
// TODO: For demo purposes only. Delete in production.
return $auth.currentUser.emailVerified || demoAccounts.includes($auth.currentUser.email) ? 'default' : 'unverified'
}, },
data () { data () {
return { return {

View File

@@ -1,11 +1,15 @@
export const state = () => ({ export const state = () => ({
firebaseInitialized: false, firebaseInitialized: false,
idTokenResult: null,
user: null, user: null,
courses: {}, courses: {},
selectedCourse: undefined selectedCourse: undefined
}) })
export const getters = { export const getters = {
isAdmin (state) {
return state.idTokenResult && state.idTokenResult.claims.admin
},
getCourseByID: (state) => (courseID) => { getCourseByID: (state) => (courseID) => {
return state.courses[courseID] return state.courses[courseID]
} }
@@ -15,12 +19,18 @@ export const mutations = {
initFirebase (state) { initFirebase (state) {
state.firebaseInitialized = true state.firebaseInitialized = true
}, },
setIdTokenResult (state, idTokenResult) {
state.idTokenResult = idTokenResult
},
setUser (state, user) { setUser (state, user) {
state.user = user state.user = user
}, },
setCourses (state, courses) { setCourses (state, courses) {
state.courses = courses state.courses = courses
}, },
setCourse (state, { courseID, courseData }) {
this._vm.$set(state.courses, courseID, courseData)
},
setSelectedCourse (state, courseID) { setSelectedCourse (state, courseID) {
state.selectedCourse = courseID state.selectedCourse = courseID
}, },