Added vuelidator to the project, implemented update of Employeeprofile

This commit is contained in:
Sockenklaus
2021-10-31 01:10:41 +02:00
parent 4a0a9c173b
commit 5a65b596ee
4 changed files with 305 additions and 88 deletions

View File

@@ -1,20 +1,23 @@
<script setup lang="ts">
import { ref } from 'vue'
import type { Ref } from 'vue'
import { toRef } from 'vue'
const isActive : Ref<boolean> = ref(false)
const props = defineProps(['isActive'])
const emit = defineEmits(['save', 'toggleEdit'])
const isActive = toRef(props, 'isActive')
function onEdit() {
isActive.value = true
emit('toggleEdit')
}
function onSave() {
emit('save')
}
function onCancel() {
isActive.value = false
emit('toggleEdit')
}
</script>
@@ -28,12 +31,12 @@ function onCancel() {
<button v-if="!isActive" type="button" @click="onEdit" class="btn btn-primary ms-auto">
<i class="bi bi-pen"></i>
Bearbeiten
Mitarbeiter bearbeiten
</button>
<button v-if="isActive" type="button" @click="onSave" class="btn btn-success ms-auto">
<i class="bi bi-save"></i>
Speichern
Mitarbeiter speichern
</button>
<button v-if="isActive" type="button" @click="onCancel" class="btn btn-outline-secondary ms-3">

View File

@@ -1,3 +1,102 @@
<template>
<VProfileControls class="mb-5" :isActive="editEmployee" @save="onUpdateEmployee" @toggleEdit="onToggleEdit" />
<form @keydown.enter="onEnter" class="text-start">
<div class="row mb-5">
<div class="col pe-5">
<h4 class="">Persönliche Informationen</h4>
<label for="first-name" class="form-label">Vorname:</label>
<input
type="text"
v-model="state.employee.firstName"
id="first-name"
class="form-control"
:class="{'is-invalid' : classIsInvalid('employee', 'firstName')}"
:disabled="!editEmployee"
>
<div
v-for="(error) in v$.employee.firstName.$errors"
class="invalid-feedback"
id="firstNameFeedback">
{{error.$message}}
</div>
<label for="last-name" class="form-label">Nachname:</label>
<input type="text" v-model="state.employee.lastName" id="last-name" class="form-control" :disabled="!editEmployee">
<label for="shorthand" class="form-label">Kürzel:</label>
<input type="text" v-model="state.employee.shorthand" id="shorthand" class="form-control" :disabled="!editEmployee">
</div>
<div class="col ps-5 border-start">
<h4 class="">Kontaktdaten</h4>
<label for="phone" class="form-label">Telefonnummer:</label>
<input type="phone" v-model="state.employee.phone" id="phone" class="form-control" :disabled="!editEmployee">
<label for="mobile" class="form-label">Handynummer:</label>
<input type="mobile" v-model="state.employee.mobile" id="mobile" class="form-control" :disabled="!editEmployee">
<label for="email" class="form-label">E-Mail-Adresse:</label>
<input
type="email"
v-model="state.employee.email"
id="email"
class="form-control"
:class="{'is-invalid': classIsInvalid('employee', 'email')}" :disabled="!editEmployee"
>
<div v-for="(error) in v$.employee.email.$errors" class="invalid-feedback" id="emailFeedback">
{{error.$message}}
</div>
</div>
</div>
<div class="row">
<div class="col pe-5">
<h4 class="">Vertragsinformationen:</h4>
<label for="contract-hours" class="form-label">Wochenstunden:</label>
<input type="number" v-model="state.employee.contractHours" id="contract-hours" class="form-control" :class="{'is-invalid' : classIsInvalid('employee', 'contractHours')}" :disabled="!editEmployee">
<div v-for="(error) in v$.employee.contractHours.$errors" class="invalid-feedback" id="contractHoursFeedback">
{{error.$message}}
</div>
</div>
<div class="col ps-5 border-start">
<h4>Benutzerinformationen:</h4>
<template v-if="state.employee.hasUser || createUser">
<label for="username" class="form-label">Benutzername:</label>
<input type="text" v-model="state.user.username" id="username" class="form-control" :disabled="!createUser" >
<label for="password" class="form-label">Neues Passwort:</label>
<input type="password" v-model="state.user.password" id="password" class="form-control" :disabled="!editEmployee">
<div id="passwordFeedback" class="invalid-feedback">
{{}}
</div>
<label for="password-repeat" class="form-label">Neues Passwort wiederholen:</label>
<input type="password" v-model="state.user.passwordRepeat" id="password-repeat" class="form-control mb-3" :class="{'is-invalid': classIsInvalid('user', 'passwordRepeat')}" :disabled="!editEmployee" >
<div v-for="(error) in v$.user.passwordRepeat.$errors" class="invalid-feedback" id="passwordRepeatFeedback">
{{error.$message}}
</div>
<template v-if="createUser">
<button class="btn btn-success me-3">
<i class="bi bi-save"></i>
Benutzer speichern
</button>
<button class="btn btn-outline-secondary" @click="createUser = false">
<i class="bi bi-x-lg"></i>
Abbrecchen
</button>
</template>
</template>
<template v-else>
<p>Kein Benutzer vorhanden</p>
<button class="btn btn-primary" @click="createUser=true">Benutzer erstellen</button>
</template>
</div>
</div>
</form>
</template>
<script setup lang="ts">
type ResultData = {
@@ -19,59 +118,124 @@ type ResultData = {
}
import VProfileControls from '@/components/VProfileControls.vue';
import { reactive, onMounted, computed, watch } from 'vue'
import { reactive, onMounted, computed, ref, watch } from 'vue'
import { useUser } from '@/stores/user';
import axios from '@/axios'
import { useNotifications } from '@/stores/notifications';
import { useRoute, useRouter } from 'vue-router';
import { useRoute } from 'vue-router';
import useVuelidate from '@vuelidate/core'
import { required, email, between, decimal, sameAs, helpers } from '@vuelidate/validators'
const userStore = useUser()
const useNotification = useNotifications()
const route = useRoute()
const employee = reactive({
id: NaN,
firstName: '',
lastName: '',
shorthand: '',
phone: '',
mobile: '',
email: '',
contractHours: '',
hasUser: false
const editEmployee = ref(false)
let state = reactive({
employee: {
id: NaN,
firstName: '',
lastName: '',
shorthand: '',
phone: '',
mobile: '',
email: '',
contractHours: '',
hasUser: false
},
user: {
id: NaN,
username: '',
password: '',
passwordRepeat: ''
}
})
const user = reactive({
id: NaN,
username: '',
password: '',
passwordRepeat: ''
})
const rules = computed(() => ({
employee: {
firstName: {
required: helpers.withMessage('Vorname ist erforderlich.', required)
},
email: {
email: helpers.withMessage('Muss eine korrekte E-Mail-Adresse enthalten.', email)
},
contractHours: {
decimal,
betweenValue: helpers.withMessage('Vertragsstunden müssen zwischen 0 und 40 liegen', between(0, 40))
}
},
user: {
passwordRepeat: {
sameAs: helpers.withMessage('Die eingebebenen Passwörter müssen übereinstimmen', sameAs(state.user.password))
}
}
}))
function onUpdate() {
const v$ = useVuelidate(rules, state)
const createUser = ref(false)
async function onUpdateEmployee() {
if(await v$.value.$validate()){
if(state.user.password !== undefined && state.user.password.length > 0){
// push user
}
try {
const result = await axios.patch('employees/'+state.employee.id, state.employee,
{
headers: {
'Authorization': 'Bearer '+userStore.token
}
}
)
onToggleEdit()
}
catch(error){
if(error instanceof Error) useNotification.add('danger', error.message)
else console.log(error)
}
}
}
function onEnter() {
console.log("hi")
onUpdateEmployee
}
function onToggleEdit() {
editEmployee.value = !editEmployee.value
v$.value.$reset()
getEmployee()
}
watch(() => [route.params, route.name], ([newParam, newName], [oldParam, oldName]) => {
if(newName === oldName && newParam !== oldParam) {
getEmployee()
createUser.value = false
}
})
function classIsInvalid<E extends 'user' | 'employee'>(entity: E, field: E extends 'user' ? 'passwordRepeat' : 'firstName' | 'email' | 'contractHours') : boolean {
if(entity === 'user'){
let fU = field as 'passwordRepeat'
return v$.value.user[fU].$dirty && v$.value.user[fU].$invalid
}
else if (entity === 'employee') {
let fE = field as 'firstName' | 'email' | 'contractHours'
return v$.value.employee[fE].$dirty && v$.value.employee[fE].$invalid
}
return false
}
async function getEmployee() {
try {
const data : ResultData = await <ResultData>(await axios.get('employees/'+route.params.id, {
headers: {
'Authorization': 'Bearer '+useUser().token
'Authorization': 'Bearer '+userStore.token
}
})).data
Object.assign(employee, data.employee)
Object.assign(user, data.user)
Object.assign(state, data)
}
catch(err){
if(err instanceof Error) useNotification.add('danger', err.message, -1)
@@ -84,63 +248,7 @@ onMounted(async () => {
</script>
<template>
<VProfileControls class="mb-5" />
{{employee}}
{{user}}
<form @keydown.enter="onEnter" class="text-start">
<div class="row mb-5">
<div class="col pe-5">
<h4 class="">Persönliche Informationen</h4>
<label for="first-name" class="form-label">Vorname:</label>
<input type="text" v-model="employee.firstName" id="first-name" class="form-control">
<label for="last-name" class="form-label">Nachname:</label>
<input type="text" v-model="employee.lastName" id="last-name" class="form-control">
<label for="shorthand" class="form-label">Kürzel:</label>
<input type="text" v-model="employee.shorthand" id="shorthand" class="form-control">
</div>
<div class="col ps-5 border-start">
<h4 class="">Kontaktdaten</h4>
<label for="phone" class="form-label">Telefonnummer:</label>
<input type="phone" v-model="employee.phone" id="phone" class="form-control">
<label for="mobile" class="form-label">Handynummer:</label>
<input type="mobile" v-model="employee.mobile" id="mobile" class="form-control">
<label for="email" class="form-label">E-Mail-Adresse:</label>
<input type="email" v-model="employee.email" id="email" class="form-control">
</div>
</div>
<div class="row">
<div class="col pe-5">
<h4 class="">Vertragsinformationen:</h4>
<label for="contract-hours" class="form-label">Wochenstunden:</label>
<input type="number" v-model="employee.contractHours" id="contract-hours" class="form-control">
</div>
<div class="col ps-5 border-start">
<template v-if="employee.hasUser">
<h4>Benutzerinformationen:</h4>
<label for="username" class="form-label">Benutzername:</label>
<input type="text" v-model="user.username" id="username" class="form-control" disabled>
<label for="password" class="form-label">Passwort:</label>
<input type="password" v-model="user.password" id="password" class="form-control">
<label for="password-repeat" class="form-label">Passwort wiederholen:</label>
<input type="password" v-model="user.passwordRepeat" id="password-repeat" class="form-control">
</template>
</div>
</div>
</form>
</template>
<style scoped>
@@ -148,4 +256,8 @@ onMounted(async () => {
margin-top: 0.75rem
}
i {
margin-right: 0.25rem;
}
</style>