Implemented creation and updating of users.
This commit is contained in:
@@ -99,13 +99,40 @@ export const useEmployee = defineStore({
|
|||||||
/** TODO: #23 Persist user if password is changed */
|
/** TODO: #23 Persist user if password is changed */
|
||||||
async persist() {
|
async persist() {
|
||||||
try {
|
try {
|
||||||
const result = await axios.patch('employees/'+this.employee.id, this.employee,
|
let result
|
||||||
{
|
|
||||||
headers: {
|
if(isNaN(this.user.id) && this.user.username.length > 0){
|
||||||
'Authorization': 'Bearer '+user.token
|
result = await axios.post(
|
||||||
|
'users',
|
||||||
|
{
|
||||||
|
username: this.user.username,
|
||||||
|
password: this.user.password
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: user.header
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else if (this.user.password.length > 0 && this.user.password === this.user.passwordConfirm){
|
||||||
|
result = await axios.patch(
|
||||||
|
'users/'+this.user.id,
|
||||||
|
{
|
||||||
|
password: this.user.password
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: user.header
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
result = await axios.patch(
|
||||||
|
'employees/'+this.employee.id,
|
||||||
|
this.employee,
|
||||||
|
{
|
||||||
|
headers: user.header
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
Object.assign(this.clean.employee, this.employee)
|
Object.assign(this.clean.employee, this.employee)
|
||||||
Object.assign(this.clean.user, this.user)
|
Object.assign(this.clean.user, this.user)
|
||||||
notifications.add('success', result.statusText)
|
notifications.add('success', result.statusText)
|
||||||
@@ -115,6 +142,10 @@ export const useEmployee = defineStore({
|
|||||||
else console.log(error)
|
else console.log(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getters: {
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ export const useUser = defineStore({
|
|||||||
|
|
||||||
getters: {
|
getters: {
|
||||||
isAdmin: (state) => state.role === 'admin',
|
isAdmin: (state) => state.role === 'admin',
|
||||||
|
header: (state) => {
|
||||||
|
return { 'Authorization': 'Bearer '+state.token }
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<VProfileControls class="mb-5" :isActive="editEmployee" @save="onUpdateEmployee" @toggleEdit="onToggleEdit" />
|
<VProfileControls class="mb-5" :isActive="editEmployee || createUser" @save="onUpdateEmployee" @toggleEdit="onToggleEdit" />
|
||||||
|
|
||||||
|
<h5>Clean State</h5>
|
||||||
|
{{ state.clean.user }}
|
||||||
|
<br>
|
||||||
|
<h5>Dirty State</h5>
|
||||||
|
{{ state.user }}
|
||||||
|
|
||||||
<form @keydown.enter="onEnter" class="text-start">
|
<form @keydown.enter="onEnter" class="text-start">
|
||||||
<div class="row mb-5">
|
<div class="row mb-5">
|
||||||
@@ -10,10 +16,10 @@
|
|||||||
<label for="first-name" class="form-label">Vorname:</label>
|
<label for="first-name" class="form-label">Vorname:</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
v-model="state.employee.firstName"
|
v-model.trim="state.employee.firstName"
|
||||||
id="first-name"
|
id="first-name"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
:class="{'is-invalid' : classIsInvalid('employee', 'firstName')}"
|
:class="classIsInvalid(v$.employee.firstName)"
|
||||||
:disabled="!editEmployee"
|
:disabled="!editEmployee"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -24,24 +30,35 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label for="last-name" class="form-label">Nachname:</label>
|
<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">
|
<input type="text" v-model.trim="state.employee.lastName" id="last-name" class="form-control" :disabled="!editEmployee">
|
||||||
|
|
||||||
<label for="shorthand" class="form-label">Kürzel:</label>
|
<label for="shorthand" class="form-label">Kürzel:</label>
|
||||||
<input type="text" v-model="state.employee.shorthand" id="shorthand" class="form-control" :disabled="!editEmployee">
|
<input
|
||||||
|
type="text"
|
||||||
|
v-model.trim="state.employee.shorthand"
|
||||||
|
id="shorthand"
|
||||||
|
class="form-control"
|
||||||
|
:class="classIsInvalid(v$.employee.shorthand)"
|
||||||
|
:disabled="!editEmployee"
|
||||||
|
>
|
||||||
|
<div v-for="(error) in v$.employee.shorthand.$errors" class="invalid-feedback" id="shorthandFeedback">
|
||||||
|
{{ error.$message }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col ps-5 border-start">
|
<div class="col ps-5 border-start">
|
||||||
<h4 class="">Kontaktdaten</h4>
|
<h4 class="">Kontaktdaten</h4>
|
||||||
<label for="phone" class="form-label">Telefonnummer:</label>
|
<label for="phone" class="form-label">Telefonnummer:</label>
|
||||||
<input type="phone" v-model="state.employee.phone" id="phone" class="form-control" :disabled="!editEmployee">
|
<input type="phone" v-model.trim="state.employee.phone" id="phone" class="form-control" :disabled="!editEmployee">
|
||||||
<label for="mobile" class="form-label">Handynummer:</label>
|
<label for="mobile" class="form-label">Handynummer:</label>
|
||||||
<input type="mobile" v-model="state.employee.mobile" id="mobile" class="form-control" :disabled="!editEmployee">
|
<input type="mobile" v-model.trim="state.employee.mobile" id="mobile" class="form-control" :disabled="!editEmployee">
|
||||||
<label for="email" class="form-label">E-Mail-Adresse:</label>
|
<label for="email" class="form-label">E-Mail-Adresse:</label>
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
v-model="state.employee.email"
|
v-model.trim="state.employee.email"
|
||||||
id="email"
|
id="email"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
:class="{'is-invalid': classIsInvalid('employee', 'email')}" :disabled="!editEmployee"
|
:class="classIsInvalid(v$.employee.email)"
|
||||||
|
:disabled="!editEmployee"
|
||||||
>
|
>
|
||||||
<div v-for="(error) in v$.employee.email.$errors" class="invalid-feedback" id="emailFeedback">
|
<div v-for="(error) in v$.employee.email.$errors" class="invalid-feedback" id="emailFeedback">
|
||||||
{{error.$message}}
|
{{error.$message}}
|
||||||
@@ -53,7 +70,14 @@
|
|||||||
<div class="col pe-5">
|
<div class="col pe-5">
|
||||||
<h4 class="">Vertragsinformationen:</h4>
|
<h4 class="">Vertragsinformationen:</h4>
|
||||||
<label for="contract-hours" class="form-label">Wochenstunden:</label>
|
<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">
|
<input
|
||||||
|
type="number"
|
||||||
|
v-model.number="state.employee.contractHours"
|
||||||
|
id="contract-hours"
|
||||||
|
class="form-control"
|
||||||
|
:class="classIsInvalid(v$.employee.contractHours)"
|
||||||
|
:disabled="!editEmployee"
|
||||||
|
>
|
||||||
<div v-for="(error) in v$.employee.contractHours.$errors" class="invalid-feedback" id="contractHoursFeedback">
|
<div v-for="(error) in v$.employee.contractHours.$errors" class="invalid-feedback" id="contractHoursFeedback">
|
||||||
{{error.$message}}
|
{{error.$message}}
|
||||||
</div>
|
</div>
|
||||||
@@ -62,39 +86,54 @@
|
|||||||
<h4>Benutzerinformationen:</h4>
|
<h4>Benutzerinformationen:</h4>
|
||||||
<template v-if="state.employee.hasUser || createUser">
|
<template v-if="state.employee.hasUser || createUser">
|
||||||
<label for="username" class="form-label">Benutzername:</label>
|
<label for="username" class="form-label">Benutzername:</label>
|
||||||
<input type="text" v-model="state.user.username" id="username" class="form-control" :disabled="!createUser" >
|
<input
|
||||||
|
type="text"
|
||||||
|
v-model.trim="state.user.username"
|
||||||
|
id="username"
|
||||||
|
class="form-control"
|
||||||
|
:class="classIsInvalid(v$.user.username)"
|
||||||
|
:disabled="!createUser"
|
||||||
|
>
|
||||||
|
<div v-for="(error) in v$.user.username.$errors" class="invalid-feedback" id="usernameFeedback">
|
||||||
|
{{ error.$message }}
|
||||||
|
</div>
|
||||||
<label for="password" class="form-label">Neues Passwort:</label>
|
<label for="password" class="form-label">Neues Passwort:</label>
|
||||||
<input type="password" v-model="state.user.password" id="password" class="form-control" :disabled="!editEmployee">
|
<input
|
||||||
<div id="passwordFeedback" class="invalid-feedback">
|
type="password"
|
||||||
{{}}
|
v-model="state.user.password"
|
||||||
|
id="password"
|
||||||
|
class="form-control"
|
||||||
|
:class="classIsInvalid(v$.user.password)"
|
||||||
|
:disabled="!editEmployee && !createUser"
|
||||||
|
>
|
||||||
|
<div v-for="(error) in v$.user.password.$errors" id="passwordFeedback" class="invalid-feedback">
|
||||||
|
{{error.$message}}
|
||||||
</div>
|
</div>
|
||||||
<label for="password-repeat" class="form-label">Neues Passwort wiederholen:</label>
|
<label for="password-repeat" class="form-label">Neues Passwort wiederholen:</label>
|
||||||
<input type="password" v-model="state.user.passwordConfirm" id="password-repeat" class="form-control mb-3" :class="{'is-invalid': classIsInvalid('user', 'passwordConfirm')}" :disabled="!editEmployee" >
|
<input
|
||||||
|
type="password"
|
||||||
|
v-model="state.user.passwordConfirm"
|
||||||
|
id="password-repeat"
|
||||||
|
class="form-control mb-3"
|
||||||
|
:class="classIsInvalid(v$.user.passwordConfirm)"
|
||||||
|
:disabled="!editEmployee && !createUser"
|
||||||
|
>
|
||||||
<div v-for="(error) in v$.user.passwordConfirm.$errors" class="invalid-feedback" id="passwordRepeatFeedback">
|
<div v-for="(error) in v$.user.passwordConfirm.$errors" class="invalid-feedback" id="passwordRepeatFeedback">
|
||||||
{{error.$message}}
|
{{error.$message}}
|
||||||
</div>
|
</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>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<p>Kein Benutzer vorhanden</p>
|
<p>Kein Benutzer vorhanden</p>
|
||||||
<button class="btn btn-primary" @click="createUser=true">Benutzer erstellen</button>
|
<button class="btn btn-primary" @click="onCreateUser()">Benutzer erstellen</button>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<VProfileControls class="mt-5" :isActive="editEmployee || createUser" @save="onUpdateEmployee" @toggleEdit="onToggleEdit" />
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -104,7 +143,7 @@ import { onMounted, computed, ref, watch } from 'vue'
|
|||||||
import { useEmployee } from '@/stores/employee'
|
import { useEmployee } from '@/stores/employee'
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import useVuelidate from '@vuelidate/core'
|
import useVuelidate from '@vuelidate/core'
|
||||||
import { required, email, between, decimal, sameAs, helpers } from '@vuelidate/validators'
|
import { required, email, between, decimal, sameAs, helpers, requiredIf } from '@vuelidate/validators'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const state = useEmployee()
|
const state = useEmployee()
|
||||||
@@ -114,19 +153,28 @@ const editEmployee = ref(false)
|
|||||||
const rules = computed(() => ({
|
const rules = computed(() => ({
|
||||||
employee: {
|
employee: {
|
||||||
firstName: {
|
firstName: {
|
||||||
required: helpers.withMessage('Vorname ist erforderlich.', required)
|
required: required
|
||||||
|
},
|
||||||
|
shorthand: {
|
||||||
|
required: required
|
||||||
},
|
},
|
||||||
email: {
|
email: {
|
||||||
email: helpers.withMessage('Muss eine korrekte E-Mail-Adresse enthalten.', email)
|
email: email
|
||||||
},
|
},
|
||||||
contractHours: {
|
contractHours: {
|
||||||
decimal,
|
decimal,
|
||||||
betweenValue: helpers.withMessage('Vertragsstunden müssen zwischen 0 und 40 liegen', between(0, 40))
|
betweenValue: between(0, 40)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
user: {
|
user: {
|
||||||
|
username: {
|
||||||
|
requiredIf: requiredIf(() => createUser.value && isNaN(state.user.id))
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
requiredIf: requiredIf(() => createUser.value && isNaN(state.user.id))
|
||||||
|
},
|
||||||
passwordConfirm: {
|
passwordConfirm: {
|
||||||
sameAs: helpers.withMessage('Die eingebebenen Passwörter müssen übereinstimmen', sameAs(state.user.password))
|
sameAs: sameAs(state.user.password)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
@@ -153,11 +201,20 @@ function onEnter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onToggleEdit() {
|
function onToggleEdit() {
|
||||||
editEmployee.value = !editEmployee.value
|
if(createUser.value) {
|
||||||
|
editEmployee.value = false
|
||||||
|
createUser.value = false
|
||||||
|
}
|
||||||
|
else editEmployee.value = !editEmployee.value
|
||||||
|
|
||||||
v$.value.$reset()
|
v$.value.$reset()
|
||||||
state.reset()
|
state.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onCreateUser() {
|
||||||
|
createUser.value = true
|
||||||
|
}
|
||||||
|
|
||||||
watch(() => [route.params, route.name], ([newParam, newName], [oldParam, oldName]) => {
|
watch(() => [route.params, route.name], ([newParam, newName], [oldParam, oldName]) => {
|
||||||
if(newName === oldName && newParam !== oldParam) {
|
if(newName === oldName && newParam !== oldParam) {
|
||||||
state.fetchFromApi(route.params.id)
|
state.fetchFromApi(route.params.id)
|
||||||
@@ -165,16 +222,9 @@ watch(() => [route.params, route.name], ([newParam, newName], [oldParam, oldName
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
function classIsInvalid<E extends 'user' | 'employee'>(entity: E, field: E extends 'user' ? 'passwordConfirm' : 'firstName' | 'email' | 'contractHours') : boolean {
|
function classIsInvalid(object : any) : string {
|
||||||
if(entity === 'user'){
|
|
||||||
let fU = field as 'passwordConfirm'
|
return object.$dirty && object.$invalid ? 'is-invalid' : ''
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user