implemented settings and user page (darkmode is still missing)

This commit is contained in:
2024-03-24 21:02:56 +01:00
parent acb7bb7cb6
commit 45a4b58f26
36 changed files with 2283 additions and 1313 deletions

View File

@ -26,8 +26,11 @@
<div :class="['label', darkMode ? 'label-darkmode' : 'label-lightmode']">Password:</div>
</label>
<div :class="['input-field', darkMode ? 'input-darkmode' : 'input-lightmode']">
<input type="text" id="password-input" placeholder="*******">
<input type="button" :class="[darkMode ? 'button-darkmode' : 'button-lightmode']" id="show-password-toggle" value="Show">
<input :type="showPassword ? 'text' : 'password'" id="password-input" placeholder="*******">
<input v-if="!showPassword" type="button" :class="[darkMode ? 'button-darkmode' : 'button-lightmode']"
id="show-password-toggle" value="Show" @click="togglePasswordVisibility">
<input v-if="showPassword" type="button" :class="[darkMode ? 'button-darkmode' : 'button-lightmode']"
id="show-password-toggle" value="Hide" @click="togglePasswordVisibility">
</div>
</div>
</div>
@ -37,24 +40,42 @@
</label>
</div>
<div class="buttons">
<input type="button" :class="[darkMode ? 'button-darkmode' : 'button-lightmode']" id="login-button" value="Login" @click="handleLogin">
<input type="button" :class="[darkMode ? 'button-darkmode' : 'button-lightmode']" id="signup-button" value="Signup" @click="testFunctionSignup">
<input type="button" :class="[darkMode ? 'button-darkmode' : 'button-lightmode']" id="login-button" value="Login"
@click="handleLogin">
<!-- <input type="button" :class="[darkMode ? 'button-darkmode' : 'button-lightmode']" id="signup-button" value="Signup" @click="testFunctionSignup"> -->
</div>
</form>
</template>
<script setup>
import { useRouter } from 'vue-router';
import { ref } from 'vue';
// import { useRouter } from 'vue-router';
import { ref, onBeforeUnmount } from 'vue';
import Axios from '../axios.config.js';
import clientsideConfig from '../clientsideConfig.js';
import { useStore } from 'vuex';
const store = useStore();
const { signIn } = useAuth()
const router = useRouter();
// const router = useRouter();
const darkMode = ref(true);
const isError = ref(false);
const showPassword = ref(false);
const errorMsg = ref('');
function setItem(item, value) {
if (process.client) {
localStorage.setItem(item, value)
return true
} else {
return false
}
}
const togglePasswordVisibility = () => {
showPassword.value = !showPassword.value;
}
const handleLogin = async () => {
isError.value = false;
errorMsg.value = '';
@ -82,69 +103,105 @@ const handleLogin = async () => {
// sucessfully logged in
router.push('/home')*/
let res = await signIn( credentials, { callbackUrl: '/home' })
// console.log("res", res)
let resBody = await signIn(credentials, { callbackUrl: '/home' })
try {
const response = await Axios.get(`https://${clientsideConfig.url}:${clientsideConfig.port}/api/login`);
setItem('logged-in-bool', true);
setItem('logged-in-user-id', response.data.id)
setItem('logged-in-user-username', response.data.username)
setItem('logged-in-user-registered', response.data.registered)
setItem('logged-in-user-lastLogin', response.data.lastLogin)
setItem('logged-in-user-fullName', response.data.fullName)
setItem('logged-in-user-email', response.data.email)
setItem('logged-in-user-phonenumber', response.data.phonenumber)
setItem('logged-in-user-address', response.data.address)
setItem('logged-in-user-city', response.data.city)
setItem('logged-in-user-postcode', response.data.postcode)
setItem('logged-in-user-adminBool', response.data.adminBool)
setItem('logged-in-user-technicianBool', response.data.technicianBool)
setItem('logged-in-user-readerBool', response.data.readerBool)
setTimeout(() => {
}, 500);
store.commit('setLocalStorageChanged');
} catch (err) {
console.log(err.response.statusText);
}
} catch (err) {
// handle the error
console.log(err.response.statusText)
isError.value = true;
errorMsg.value = err.response.statusText;
errorMsg.value = 'Username or password is incorrect.';
document.getElementById('password-input').value = '';
}
}
const testFunctionSignup = async () => {
isError.value = false;
errorMsg.value = '';
// const testFunctionSignup = async () => {
// isError.value = false;
// errorMsg.value = '';
const username = 'adm_tueit'
const password = 'SvF=?bfEx7_hV,cMEu4m'
const password_repeat = 'SvF=?bfEx7_hV,cMEu4m'
const fullName = 'administrator'
const email = 'support@tueit.de'
const phonenumber = ''
const address = ''
const city = ''
const postcode = ''
const adminBool = true
const technician1Bool = false
const technician2Bool = false
const technicianMonitoringBool = false
const merchantBool = false
const internBool = true
// const username = 'adm_tueit'
// const password = 'SvF=?bfEx7_hV,cMEu4m'
// const password_repeat = 'SvF=?bfEx7_hV,cMEu4m'
// const fullName = 'administrator'
// const email = 'support@tueit.de'
// const phonenumber = ''
// const address = ''
// const city = ''
// const postcode = ''
// const adminBool = true
// const technician1Bool = false
// const technician2Bool = false
// const technicianMonitoringBool = false
// const merchantBool = false
// const internBool = true
const requestBody = {
username: username,
password: password,
password_repeat: password_repeat,
fullName: fullName,
email: email,
phonenumber: phonenumber,
address: address,
city: city,
postcode: postcode,
adminBool: adminBool,
technician1Bool: technician1Bool,
technician2Bool: technician2Bool,
technicianMonitoringBool: technicianMonitoringBool,
merchantBool: merchantBool,
internBool: internBool,
// const requestBody = {
// username: username,
// password: password,
// password_repeat: password_repeat,
// fullName: fullName,
// email: email,
// phonenumber: phonenumber,
// address: address,
// city: city,
// postcode: postcode,
// adminBool: adminBool,
// technician1Bool: technician1Bool,
// technician2Bool: technician2Bool,
// technicianMonitoringBool: technicianMonitoringBool,
// merchantBool: merchantBool,
// internBool: internBool,
// }
// try {
// let res = await Axios.post(`https://${clientsideConfig.url}:${clientsideConfig.port}/api/signup`, requestBody);
// // something to do with the res?
// // console.log(res)
// } catch (err) {
// // handle the error
// console.log(err.response.statusText)
// isError.value = true;
// errorMsg.value = err.response.statusText;
// }
// }
onMounted(() => {
document.addEventListener('keyup', handleKeyUp);
document.getElementById('username-input').value = '';
document.getElementById('password-input').value = '';
});
onBeforeUnmount(() => {
document.removeEventListener('keyup', handleKeyUp);
});
const handleKeyUp = (event) => {
if (event.key === 'Enter') {
handleLogin();
}
try {
let res = await Axios.post(`https://${clientsideConfig.url}:${clientsideConfig.port}/api/signup`, requestBody);
// something to do with the res?
// console.log(res)
} catch (err) {
// handle the error
console.log(err.response.statusText)
isError.value = true;
errorMsg.value = err.response.statusText;
}
}
};
</script>
<script>
@ -157,8 +214,8 @@ export default {
}
}
}
</script>
</script>
<style scoped>
* {
@ -178,10 +235,12 @@ export default {
padding: 2.5rem 1.875rem;
gap: 1.875rem;
}
.form-darkmode {
border: 0.0625rem solid #000;
background-color: #2c2c2c;
}
.form-lightmode {
border: 0.0625rem solid #8e8e8e;
background-color: #fff;
@ -202,6 +261,7 @@ export default {
width: 3.125rem;
height: 3.125rem;
}
.title-icon>img {
width: 3.125rem;
height: 3.125rem;
@ -210,14 +270,24 @@ export default {
overflow: hidden;
}
#show-password-toggle:hover {
cursor: pointer;
}
.title {
margin: 0;
letter-spacing: 0.05rem;
white-space: nowrap;
font: 400 1.875rem/1.875rem Overpass, sans-serif;
}
.title-darkmode { color: #ffffff; }
.title-lightmode { color: #000000; }
.title-darkmode {
color: #ffffff;
}
.title-lightmode {
color: #000000;
}
@ -259,28 +329,43 @@ label {
width: 1.875rem;
height: 1.875rem;
}
.icon>img {
object-fit: contain;
object-position: center;
overflow: hidden;
}
#username-icon>img {
width: auto;
height: 0.9375rem;
}
}
#password-icon>img {
width: 0.9375rem;
height: auto;
}
.icon-darkmode>img { filter: invert(100%); }
.icon-lightmode>img { filter: invert(0%); }
.icon-darkmode>img {
filter: invert(100%);
}
.icon-lightmode>img {
filter: invert(0%);
}
.label {
letter-spacing: 0.02rem;
font: 400 0.9375rem/1.875rem Overpass, sans-serif;
}
.label-darkmode { color: #ffffff; }
.label-lightmode { color: #000000; }
.label-darkmode {
color: #ffffff;
}
.label-lightmode {
color: #000000;
}
.input-field {
display: flex;
@ -293,11 +378,18 @@ label {
border-radius: 0.3125rem;
padding: 0.1875rem 0.625rem;
box-shadow: 0.0625rem 0.0625rem 0.25rem 0rem rgba(0, 0, 0, 0.25) inset;
}
.input-darkmode { background-color: #212121; }
.input-lightmode { background-color: #EBEBEB; }
}
input[type=text] {
.input-darkmode {
background-color: #212121;
}
.input-lightmode {
background-color: #EBEBEB;
}
input[type=text],
input[type=password] {
width: 100%;
height: 100%;
background-color: #00000000;
@ -360,6 +452,12 @@ input[type=button] {
white-space: nowrap;
font: 600 1.125rem/1.875rem Overpass, sans-serif;
}
.button-darkmode { color: #ffffff; }
.button-lightmode { color: #000000; }
.button-darkmode {
color: #ffffff;
}
.button-lightmode {
color: #000000;
}
</style>

View File

@ -0,0 +1,476 @@
<template>
<section v-if="!addBool" :class="['information', darkMode ? 'section-darkmode' : 'section-lightmode']">
<h2 v-if="!editable" :class="['employee-name', darkMode ? 'h2-darkmode' : 'h2-lightmode']">{{
employee.fullName }}</h2>
<input v-if="editable" v-model="employee.fullName" @change="updateEmpl()"
:class="['data', 'employee-name-input', darkMode ? 'h2-darkmode' : 'h2-lightmode', darkMode ? 'h2-input-darkmode' : 'h2-input-lightmode', 'input']">
<div class="employee-data">
<div class="username-registered-lastLogin">
<div class="data-field" id="username">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Username:</pre>
<pre :class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']"> {{ employee.username }}</pre>
</div>
<div class="data-field" id="registered">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Registered:</pre>
<pre
:class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']"> {{ employee.registered }}</pre>
</div>
<div class="data-field" id="lastLogin">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Last login:</pre>
<pre
:class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']"> {{ employee.lastLogin }}</pre>
</div>
</div>
<div class="info">
<div class="city-phonenumber">
<div class="data-field" id="city">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">City:</pre>
<pre v-if="!editable"
:class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']">{{ employee.city }}</pre>
<input v-if="editable" v-model="employee.city" @change="updateEmpl()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
<div class="data-field" id="phonenumber">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Phonenumber:</pre>
<pre v-if="!editable"
:class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']">{{ employee.phonenumber }}</pre>
<input v-if="editable" v-model="employee.phonenumber" @change="updateEmpl()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
</div>
<div class="postcode-email">
<div class="data-field" id="postcode">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Postcode:</pre>
<pre v-if="!editable"
:class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']">{{ employee.postcode }}</pre>
<input v-if="editable" v-model="employee.postcode" @change="updateEmpl()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
<div class="data-field" id="email">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Email:</pre>
<pre v-if="!editable"
:class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']">{{ employee.email }}</pre>
<input v-if="editable" v-model="employee.email" @change="updateEmpl()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
</div>
<div class="address">
<div class="data-field" id="address">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Address:</pre>
<pre v-if="!editable"
:class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']"> {{ employee.address }}</pre>
<input v-if="editable" v-model="employee.address" @change="updateEmpl()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
<div class="data-field" id="empty">
&nbsp;
</div>
</div>
</div>
</div>
</section>
<section v-if="addBool" :class="['information', darkMode ? 'section-darkmode' : 'section-lightmode']">
<input v-model="newFullName" @change="updateEmployee()"
:class="['data', 'employee-name-input', darkMode ? 'h2-darkmode' : 'h2-lightmode', darkMode ? 'h2-input-darkmode' : 'h2-input-lightmode', 'input']">
<div class="employee-data">
<div class="username-registered-lastLogin">
<div class="data-field" id="username">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Username:</pre>
<input v-model="newUsername" @change="updateEmployee()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
<div class="data-field" id="password">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Password:</pre>
<input v-model="newPassword" @change="updateEmployee()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
<div class="data-field" id="passwordRepeated">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Password repeated:</pre>
<input v-model="newPasswordRepeated" @change="updateEmployee()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
</div>
<div class="info">
<div class="city-phonenumber">
<div class="data-field" id="city">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">City:</pre>
<input v-model="newCity" @change="updateEmployee()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
<div class="data-field" id="phonenumber">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Phonenumber:</pre>
<input v-model="newPhonenumber" @change="updateEmployee()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
</div>
<div class="postcode-email">
<div class="data-field" id="postcode">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Postcode:</pre>
<input v-model="newPostcode" @change="updateEmployee()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
<div class="data-field" id="email">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Email:</pre>
<input v-model="newEmail" @change="updateEmployee()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
</div>
<div class="address">
<div class="data-field" id="address">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Address:</pre>
<input v-model="newAddress" @change="updateEmployee()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
<div class="data-field" id="empty">
&nbsp;
</div>
</div>
</div>
</div>
</section>
</template>
<script setup>
import { ref, onMounted, watch } from 'vue';
import Axios from '../axios.config.js';
import clientsideConfig from '../../clientsideConfig.js';
import { useStore } from 'vuex';
import { computed } from 'vue';
const store = useStore();
const editable = computed(() => store.state.editable);
const chosenEmployeeId = computed(() => store.state.chosenEmployeeId);
const deleteBool = computed(() => store.state.deleteBool);
const addBool = computed(() => store.state.new);
const darkMode = ref(true);
const employee = ref({});
const newUsername = ref('');
const newPassword = ref('');
const newPasswordRepeated = ref('');
const newFullName = ref('');
const newEmail = ref('');
const newPhonenumber = ref('');
const newAddress = ref('');
const newCity = ref('');
const newPostcode = ref('');
// get employee from id
const getEmployeeById = async () => {
if (!addBool.value) {
try {
const response = await Axios.get(
`https://${clientsideConfig.url}:${clientsideConfig.port}/api/getEmployee/${chosenEmployeeId.value}`
);
employee.value = response.data;
} catch (err) {
console.log(err.response.statusText);
}
}
}
// update employee fields in the store
const updateEmployee = () => {
const employee = {
username: newUsername.value,
password: newPassword.value,
passwordRepeated: newPasswordRepeated.value,
fullName: newFullName.value,
email: newEmail.value,
phonenumber: newPhonenumber.value,
address: newAddress.value,
city: newCity.value,
postcode: newPostcode.value
};
store.commit('updateEmployeeComponent', employee);
}
//update data
const updateEmpl = async () => {
if (employee.value.fullName.trim() === "") {
alert("Please add a name!");
return;
}
if (employee.value.city.trim() === "") {
alert("Please add a city!");
return;
}
if (employee.value.address.trim() === "") {
alert("Please add an address!");
return;
}
if (!validateEMail(employee.value.email)) {
alert("Please add a valid email!");
return;
}
if (!validatePhonenumber(employee.value.phonenumber)) {
alert("Please add a valid phonenumber!");
return;
}
if (!validatePostcode(employee.value.postcode)) {
alert("Please add a valid postcode!");
return;
}
try {
await Axios.put(
`https://${clientsideConfig.url}:${clientsideConfig.port}/api/updateEmployee`,
{
id: employee.value.id,
username: employee.value.username,
fullName: employee.value.fullName,
email: employee.value.email,
phonenumber: employee.value.phonenumber,
address: employee.value.address,
city: employee.value.city,
postcode: employee.value.postcode,
adminBool: employee.value.adminBool,
technicianBool: employee.value.technicianBool,
readerBool: employee.value.readerBool,
}
)
await getEmployeeById();
} catch (err) {
console.log(err.response.statusText);
}
}
const confirmDeleteEmployee = async () => {
if (deleteBool.value === true) {
if (confirm("Do you really want to delete this employee? It cannot be undone!")) {
try {
await Axios.delete(`https://${clientsideConfig.url}:${clientsideConfig.port}/api/deleteEmployee/${chosenEmployeeId.value}`);
store.commit('undoDelete');
store.commit('resetStore');
store.commit('changeToEmployeelist');
} catch (err) {
console.log(err.response.statusText);
}
} else {
store.commit('undoDelete');
}
}
}
// to validate the email address
const validateEMail = (email) => {
const emailRegex = new RegExp(/^[A-Za-z0-9_!#$%&'*+\/=?`{|}~^.-]+@[A-Za-z0-9.-]+$/, "gm");
if (email === "") {
return true
}
return emailRegex.test(email);
}
// to validate the phonenumber
const validatePhonenumber = (number) => {
const mobilephonenumberRegex = new RegExp(/^(((((00|\+){1,2})49([ \-/]?|[ \()/]?))|0)[1]([0-2]|[4-7])([0-9]{1})([ \-/]?|[ \()/]?)([0-9]{8}))$/, "gm");
const landlineRegex = new RegExp(/^0(30|40|69|89|20[12389]|21[24]|228|234|335|340|3[3-9][15]|906|[2-9][1-9]1|3(?:3(?:[0237][127]|0[3-6]|2[89]|3[458]|[46][1246]|7[589]|8[1256]|9[145])|4(?:[2347][135]|[34]7|[69][146]|48|62|76|93)|5(?:[04679][14]|[238][135]|[2469]2|[4789]6|[278]8|63|73|37|29)|6(?:[024689][13]|[03789]5|06|2[2489]|3[1246]|44|47|7[1279]|82|86)|7(?:[236][135]|2[2467]|37|4[145]|62|64|7[1-4])|8(?:[234678]1|3[468]|4[347]|6[035-9]|7[467]|83|86)|9(?:[236][135]|[04689]4|[04789]1|[03468]7|02|09|28|4[369]|6[2689]|73|76|96|98))|3[3-9][0-9]{3}|13[078]|180[235]|18[01]|19[0-9]{3}|[789]00|[2-9][0-9]{3})([0-9]{1,})$/, "gm");
if (number === "") {
return true
}
if (mobilephonenumberRegex.test(number)) {
return true
} else if (landlineRegex.test(number)) {
return true;
}
return false;
}
// to validate the postcode
const validatePostcode = (postcode) => {
const postcodeRegex = new RegExp(/^\d{5}$/);
if (postcode === "") {
return true
}
return postcodeRegex.test(postcode);
}
watch(deleteBool, confirmDeleteEmployee);
onMounted(() => {
getEmployeeById();
});
</script>
<script>
export default {
name: "Employee",
}
</script>
<style scoped>
.information {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
padding: 1.25rem 1.875rem;
border-radius: 0.625rem;
box-shadow: 0.25rem 0.25rem 0.25rem 0rem rgba(0, 0, 0, 0.25);
}
.section-darkmode {
background-color: #2c2c2c;
}
.section-lightmode {
background-color: #fff;
}
.employee-name {
align-self: stretch;
padding: 1rem 0;
letter-spacing: 5%;
text-decoration-line: underline;
font: italic 400 1rem/187.5% Overpass, -apple-system, Roboto, Helvetica,
sans-serif;
}
.employee-name-input {
padding: 1rem 0;
margin: 1rem;
font-size: initial;
letter-spacing: 5%;
text-decoration-line: underline;
font: italic 400 1rem/187.5% Overpass, -apple-system, Roboto, Helvetica,
sans-serif;
}
.h2-darkmode {
color: #fff;
}
.h2-lightmode {
color: #000;
}
.data-field {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
width: 100%;
padding: 0.8rem 1.875rem;
gap: 1.25rem;
border-radius: 0.625rem;
}
.h2-input-darkmode {
background-color: #212121;
}
.h2-input-lightmode {
background-color: #EBEBEB;
}
.data-field#street-name {
width: 70%;
}
.data-field#street-no {
width: 30%;
}
.label {
letter-spacing: 5%;
font: 400 0.875rem/1.875rem Overpass, sans-serif;
}
.pre-darkmode {
color: #fff;
}
.pre-lightmode {
color: #000;
}
.input {
border: none;
}
.data {
display: flex;
overflow-x: auto;
align-items: flex-start;
padding: 0 0.625rem;
border-radius: 0.3125rem;
box-shadow: 0.0625rem 0.0625rem 0.25rem 0rem rgba(0, 0, 0, 0.25) inset;
letter-spacing: 5%;
font: 400 0.75rem/250% Overpass, sans-serif;
}
.data-darkmode {
background-color: #212121;
color: #fff;
}
.data-lightmode {
background-color: #EBEBEB;
color: #000;
}
.data#notes,
.data#description {
align-self: stretch;
/* width: 45%; */
scrollbar-width: none;
overflow-x: auto;
}
.employee-data {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
align-self: stretch;
}
.username-registered-lastLogin,
.info {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
line-height: normal;
width: 50%;
padding: 0 0;
border-radius: 0.3125rem;
}
.additional {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
line-height: normal;
width: 50%;
padding: 0rem 0.625rem;
border-radius: 0.3125rem;
}
.area-title {
letter-spacing: 5%;
font: 400 0.875rem/1.875rem Overpass, sans-serif;
}
.h3-darkmode {
color: #fff;
}
.h3-lightmode {
color: #000;
}
.city-phonenumber,
.postcode-email {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
align-self: stretch;
padding: 0 1.875rem 0 0;
gap: 0.625rem;
}
</style>

View File

@ -0,0 +1,485 @@
<template>
<section v-if="!addBool" :class="['group-information', darkMode ? 'section-darkmode' : 'section-lightmode']">
<div :class="['label', darkMode ? 'div-darkmode' : 'div-lightmode']" id="group">Groups:</div>
<div class="asset-data">
<div class="checkbox-container">
<div class="checkbox-group">
<label :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']" for="admin-checkbox">Admin</label>
<input :readonly="!editable" id="admin-checkbox" type="checkbox" v-model="adminBoolean"
@click="toggleAdminBool()">
</div>
<div class="checkbox-group">
<label :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']" for="technician-checkbox">Technician</label>
<input :readonly="!editable" id="technician-checkbox" type="checkbox"
v-model="technicianBoolean" @click="toggleTechnicianBool()">
</div>
<div class="checkbox-group">
<label :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']" for="reader-checkbox">Reader</label>
<input :readonly="!editable" id="reader-checkbox" type="checkbox" v-model="readerBoolean"
@click="toggleReaderBool()">
</div>
</div>
</div>
</section>
<section v-if="addBool" :class="['group-information', darkMode ? 'section-darkmode' : 'section-lightmode']">
<div :class="['label', darkMode ? 'div-darkmode' : 'div-lightmode']" id="group">Groups:</div>
<div class="asset-data">
<div class="checkbox-container">
<div class="checkbox-group">
<label :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']" for="admin-checkbox">Admin</label>
<input id="admin-checkbox" type="checkbox" v-model="newAdminBool">
</div>
<div class="checkbox-group">
<label :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']" for="technician-checkbox">Technician</label>
<input id="technician-checkbox" type="checkbox" v-model="newTechnicianBool">
</div>
<div class="checkbox-group">
<label :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']" for="reader-checkbox">Reader</label>
<input id="reader-checkbox" type="checkbox" v-model="newReaderBool">
</div>
</div>
</div>
</section>
<section v-if="addBool" id="saveNewEmployee">
<button :class="[darkMode ? 'saveNewEmployee-darkmode' : 'saveNewEmployee-lightmode']"
@click="addEmployee()">Save</button>
</section>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import Axios from '../axios.config.js';
import clientsideConfig from '../../clientsideConfig.js';
import { useStore } from 'vuex';
import { computed } from 'vue';
const store = useStore();
const editable = computed(() => store.state.editable);
const chosenEmployeeId = computed(() => store.state.chosenEmployeeId);
const addBool = computed(() => store.state.new);
const newUsernameEmp = computed(() => store.state.newUsernameEmp);
const newPasswordEmp = computed(() => store.state.newPasswordEmp);
const newPasswordRepeatedEmp = computed(() => store.state.newPasswordRepeatedEmp);
const newFullNameEmp = computed(() => store.state.newFullNameEmp);
const newEmailEmp = computed(() => store.state.newEmailEmp);
const newPhonenumberEmp = computed(() => store.state.newPhonenumberEmp);
const newAddressEmp = computed(() => store.state.newAddressEmp);
const newCityEmp = computed(() => store.state.newCityEmp);
const newPostcodeEmp = computed(() => store.state.newPostcodeEmp);
const darkMode = ref(true)
const employee = ref({});
const adminBoolean = ref(false);
const technicianBoolean = ref(false);
const readerBoolean = ref(false);
const newAdminBool = ref(false);
const newTechnicianBool = ref(false);
const newReaderBool = ref(false);
const employees = ref([]);
// get employee from id
const getEmployeeById = async () => {
if (!addBool.value) {
try {
const response = await Axios.get(
`https://${clientsideConfig.url}:${clientsideConfig.port}/api/getEmployee/${chosenEmployeeId.value}`
);
employee.value = response.data;
if (employee.value.adminBool == 1) {
adminBoolean.value = true;
};
if (employee.value.technicianBool == 1) {
technicianBoolean.value = true;
};
if (employee.value.readerBool == 1) {
readerBoolean.value = true;
};
} catch (err) {
console.log(err.response.statusText);
}
}
}
const toggleTechnicianBool = () => {
technicianBoolean.value = !technicianBoolean.value;
update();
}
const toggleAdminBool = () => {
adminBoolean.value = !adminBoolean.value;
update();
}
const toggleReaderBool = () => {
readerBoolean.value = !readerBoolean.value;
update();
}
//update data
const update = async () => {
if (adminBoolean.value) {
employee.value.adminBool = 1;
} else {
employee.value.adminBool = 0;
}
if (technicianBoolean.value) {
employee.value.technicianBool = 1;
} else {
employee.value.technicianBool = 0;
}
if (readerBoolean.value) {
employee.value.readerBool = 1;
} else {
employee.value.readerBool = 0;
}
try {
await Axios.put(
`https://${clientsideConfig.url}:${clientsideConfig.port}/api/updateEmployee`,
{
id: employee.value.id,
username: employee.value.username,
fullName: employee.value.fullName,
email: employee.value.email,
phonenumber: employee.value.phonenumber,
address: employee.value.address,
city: employee.value.city,
postcode: employee.value.postcode,
adminBool: employee.value.adminBool,
technicianBool: employee.value.technicianBool,
readerBool: employee.value.readerBool,
}
);
} catch (err) {
console.log(err.response.statusText);
}
await getEmployeeById();
}
// add new employee
const addEmployee = async () => {
// check if all input data is valid
if (newUsernameEmp.value.trim() === "") {
alert("Please add an username!");
return;
} else {
var counter = 0;
// check if the username already exists
employees.value.forEach(empl => {
if (empl.username === newUsernameEmp.value) {
counter += 1;
}
});
if (counter == 1) {
alert("This username already exists. Please choose an unique username or modify respectively delete the old one!");
return;
}
}
if (newPasswordEmp.value.trim() === "") {
alert("Please add a password!");
return;
}
// username min length 5
if (!newUsernameEmp.value || newUsernameEmp.value.length < 5) {
alert("Please choose an username with minimal five characters!");
return
}
// password min 8 chars
if (!newPasswordEmp.value || newPasswordEmp.value.length < 8) {
alert("Please choose a password with minimal eight characters!");
return
}
// password (repeat) must match
if (
!newPasswordRepeatedEmp.value ||
newPasswordEmp.value != newPasswordRepeatedEmp.value
) {
alert("Your passwords don't match.");
return
}
if (newFullNameEmp.value.length === 0) {
alert("Please add a name!");
return;
}
if (newCityEmp.value.length === 0) {
alert("Please add a city!");
return;
}
if (newAddressEmp.value.length === 0) {
alert("Please add an address!");
return;
}
if (!validateEMail(newEmailEmp.value)) {
alert("Please add a valid email!");
return;
}
if (!validatePhonenumber(newPhonenumberEmp.value)) {
alert("Please add a valid phonenumber!");
return;
}
if (!validatePostcode(newPostcodeEmp.value)) {
alert("Please add a valid postcode!");
return;
}
if ((newPhonenumberEmp.value.length === 0) && (newEmailEmp.value.length === 0)) {
alert("Please add a phonenumber or an email!");
return;
}
if (! (newAdminBool.value || newTechnicianBool.value || newReaderBool.value)) {
alert("Please choose at least one group!");
return;
}
try {
let res = await Axios.post(`https://${clientsideConfig.url}:${clientsideConfig.port}/api/signup`,
{
username: newUsernameEmp.value,
password: newPasswordEmp.value,
password_repeat: newPasswordRepeatedEmp.value,
fullName: newFullNameEmp.value,
email: newEmailEmp.value,
phonenumber: newPhonenumberEmp.value,
address: newAddressEmp.value,
city: newCityEmp.value,
postcode: newPostcodeEmp.value,
adminBool: newAdminBool.value,
technicianBool: newTechnicianBool.value,
readerBool: newReaderBool.value,
});
store.commit('resetStore');
store.commit('changeToEmployeelist');
} catch (err) {
console.log(err.response.statusText);
}
}
//get all employees
const getEmployees = async () => {
try {
const response = await Axios.get(`https://${clientsideConfig.url}:${clientsideConfig.port}/api/getAllEmployees`);
employees.value = response.data;
} catch (err) {
console.log(err.response.statusText);
}
}
// to validate the email address
const validateEMail = (email) => {
const emailRegex = new RegExp(/^[A-Za-z0-9_!#$%&'*+\/=?`{|}~^.-]+@[A-Za-z0-9.-]+$/, "gm");
if (email === "") {
return true
}
return emailRegex.test(email);
}
// to validate the phonenumber
const validatePhonenumber = (number) => {
const mobilephonenumberRegex = new RegExp(/^(((((00|\+){1,2})49([ \-/]?|[ \()/]?))|0)[1]([0-2]|[4-7])([0-9]{1})([ \-/]?|[ \()/]?)([0-9]{8}))$/, "gm");
const landlineRegex = new RegExp(/^0(30|40|69|89|20[12389]|21[24]|228|234|335|340|3[3-9][15]|906|[2-9][1-9]1|3(?:3(?:[0237][127]|0[3-6]|2[89]|3[458]|[46][1246]|7[589]|8[1256]|9[145])|4(?:[2347][135]|[34]7|[69][146]|48|62|76|93)|5(?:[04679][14]|[238][135]|[2469]2|[4789]6|[278]8|63|73|37|29)|6(?:[024689][13]|[03789]5|06|2[2489]|3[1246]|44|47|7[1279]|82|86)|7(?:[236][135]|2[2467]|37|4[145]|62|64|7[1-4])|8(?:[234678]1|3[468]|4[347]|6[035-9]|7[467]|83|86)|9(?:[236][135]|[04689]4|[04789]1|[03468]7|02|09|28|4[369]|6[2689]|73|76|96|98))|3[3-9][0-9]{3}|13[078]|180[235]|18[01]|19[0-9]{3}|[789]00|[2-9][0-9]{3})([0-9]{1,})$/, "gm");
if (number === "") {
return true
}
if (mobilephonenumberRegex.test(number)) {
return true
} else if (landlineRegex.test(number)) {
return true;
}
return false;
}
// to validate the postcode
const validatePostcode = (postcode) => {
const postcodeRegex = new RegExp(/^\d{5}$/);
if (postcode === "") {
return true
}
return postcodeRegex.test(postcode);
}
// include delay to avoid 503 error
const triggerBackendCallsWithDelay = async (fetchDataFunc) => {
setTimeout(() => {
fetchDataFunc();
}, 1000);
}
onMounted(() => {
triggerBackendCallsWithDelay(getEmployeeById);
triggerBackendCallsWithDelay(getEmployees);
});
</script>
<script>
export default {
name: "EmployeeGroups",
};
</script>
<style scoped>
.group-information {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
padding: 1.25rem 1.875rem;
border-radius: 0.625rem;
box-shadow: 0.25rem 0.25rem 0.25rem 0rem rgba(0, 0, 0, 0.25);
}
.section-darkmode {
background-color: #2c2c2c;
}
.section-lightmode {
background-color: #fff;
}
.data-field {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
width: 100%;
padding: 0.8rem 1.875rem;
gap: 1.25rem;
border-radius: 0.625rem;
}
.label {
letter-spacing: 5%;
font: 400 0.875rem/1.875rem Overpass, sans-serif;
}
.div-darkmode {
color: #fff;
}
.div-lightmode {
color: #000;
}
.label#network {
padding-top: 1rem;
padding-bottom: 1rem;
}
.data {
display: flex;
flex-direction: row;
align-items: flex-start;
padding: 0 0.625rem;
border-radius: 0.3125rem;
box-shadow: 0.0625rem 0.0625rem 0.25rem 0rem rgba(0, 0, 0, 0.25) inset;
letter-spacing: 5%;
font: 400 0.75rem/250% Overpass, sans-serif;
}
.data-darkmode {
background-color: #212121;
color: #fff;
}
.data-lightmode {
background-color: #EBEBEB;
color: #000;
}
.asset-data {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
align-self: stretch;
}
.IPv4-MAC,
.IPv6-subnetmask {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
line-height: normal;
width: 50%;
padding: 0 0;
border-radius: 0.3125rem;
}
.saveNewEmployee-darkmode {
background: #2c2c2c;
color: #fff;
font: 400 0.875rem/1.875rem Overpass, sans-serif;
border: none;
padding: 1rem 1.875rem;
width: 8%;
border-radius: 0.625rem;
box-shadow: 0.25rem 0.25rem 0.25rem 0rem rgba(0, 0, 0, 0.25);
}
.saveNewEmployee-lightmode {
background: #EBEBEB;
color: #212121;
font: 400 0.875rem/1.875rem Overpass, sans-serif;
border: none;
padding: 1rem 1.875rem;
width: 8%;
border-radius: 0.625rem;
box-shadow: 0.25rem 0.25rem 0.25rem 0rem rgba(0, 0, 0, 0.25);
}
.saveNewEmployee-darkmode:hover {
background-color: #444444;
cursor: pointer;
}
.saveNewEmployee-lightmode:hover {
background-color: #ACACAC;
cursor: pointer;
}
#saveNewEmployee {
text-align: center;
}
.input {
border: none;
}
.checkbox-container {
padding-bottom: 0.8rem;
display: flex;
justify-content: center;
}
.checkbox-group {
display: flex;
flex-direction: column;
align-items: center;
width: 20rem;
}
.checkbox-group label {
margin-bottom: 5px;
}
.checkbox-group input {
margin-bottom: 10px;
}
.label {
letter-spacing: 5%;
font: 400 0.875rem/1.875rem Overpass, sans-serif;
}
.pre-darkmode {
color: #fff;
}
.pre-lightmode {
color: #000;
}
input[type=checkbox]{
accent-color: #000;
}
</style>

View File

@ -15,17 +15,17 @@
:class="['table-row', darkMode ? 'tr-darkmode' : 'tr-lightmode']">
<td
:class="['Name', darkMode ? 'td-darkmode' : 'td-lightmode', darkMode ? 'Name-darkmode' : 'Name-lightmode']">
<nuxt-link to="/assets" id="nuxt-link" class="button"
<nuxt-link to="/employees" id="nuxt-link" class="button"
:class="[darkMode ? 'button-darkmode' : 'button-lightmode']"
@click="goToChosenAsset(u.id)">
@click="goToChosenEmployee(u.id)">
{{ u.fullName }}
</nuxt-link>
</td>
<td
:class="['Username', darkMode ? 'td-darkmode' : 'td-lightmode', darkMode ? 'Username-darkmode' : 'Username-lightmode']">
<nuxt-link to="/assets" id="nuxt-link" class="button"
<nuxt-link to="/employees" id="nuxt-link" class="button"
:class="[darkMode ? 'button-darkmode' : 'button-lightmode']"
@click="goToChosenAsset(u.id)">
@click="goToChosenEmployee(u.id)">
{{ u.username }}
</nuxt-link>
</td>
@ -45,7 +45,7 @@ import { computed } from 'vue';
// get accesss to the store
const store = useStore()
const goToChosenAsset = (id) => {
const goToChosenEmployee = (id) => {
store.commit('setChosenEmployee', id);
store.commit('changeToEmployee');
};

View File

@ -45,7 +45,7 @@
<td v-if="!editable" :class="['Comments', darkMode ? 'td-darkmode' : 'td-lightmode']"> {{ todo.commets
}}</td>
<td v-if="editable" :class="['Comments', darkMode ? 'td-darkmode' : 'td-lightmode']"> <input type="text"
v-model="todo.commets" @change="updateMVTTodo(todo)"
v-model="todo.commets" @change="updateMVTTodo(todo)"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']"> <button
:class="[darkMode ? 'deleteMvtTodos-darkmode' : 'deleteMvtTodos-lightmode']"
@click="deleteMVTTodo(todo.primaryID)">-</button>
@ -149,6 +149,8 @@ import Axios from '../axios.config.js';
import clientsideConfig from '../../clientsideConfig.js';
import { useStore } from 'vuex';
import { computed } from 'vue';
// import VueInputAutowidth from 'vue-input-autowidth';
// Vue.use(VueInputAutowidth);
const store = useStore();
const addBool = computed(() => store.state.new);

View File

@ -2,32 +2,243 @@
<section :class="['userAccount', darkMode ? 'section-darkmode' : 'section-lightmode']">
<h2 :class="['heading', darkMode ? 'heading-darkmode' : 'heading-lightmode']">Account:</h2>
<div class="userData">
<div class="data-field" id="email">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">E-Mail:</pre>
<pre :class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']">...</pre>
<div class="username-email">
<div class="data-field" id="username">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Username:</pre>
<pre v-if="!editable"
:class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']">{{ loggedInUserUsername }}</pre>
<input v-if="editable" v-model="loggedInUserUsername" @change="updateUsername()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
<div class="data-field" id="email">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Email:</pre>
<pre v-if="!editable"
:class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']">{{ loggedInUserEmail }}</pre>
<input v-if="editable" v-model="loggedInUserEmail" @change="updateUser()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
<input v-if="editable" :class="[darkMode ? 'input-darkmode' : '', !darkMode ? 'input-lightmode' : '',]"
type="button" id="changePassword" value="Change Password" @click="changePassword">
</div>
<div class="data-field" id="password">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Password:</pre>
<pre :class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']">*******</pre>
<div v-if="changePasswordBool && editable" class="password">
<div class="data-field" id="password">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">New Password:</pre>
<input v-if="editable" v-model="loggedInUserNewPassword"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
<div class="data-field" id="passwordRepeated">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Repeat:</pre>
<input v-if="editable" v-model="loggedInUserNewPasswordRepeated"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
<input :class="[darkMode ? 'input-darkmode' : '', !darkMode ? 'input-lightmode' : '',]" type="button"
id="savePassword" value="Save Password" @click="savePassword">
</div>
</div>
</section>
</template>
<script setup>
import { ref } from 'vue';
import { ref, onMounted } from 'vue';
import { useStore } from 'vuex';
import { computed } from 'vue';
import Axios from '../axios.config.js';
import clientsideConfig from '../../clientsideConfig.js';
const store = useStore();
const editable = computed(() => store.state.editable);
const changePasswordBool = ref(false);
const loggedInUserId = ref('');
const loggedInUserUsername = ref('');
const loggedInUserRegistered = ref('');
const loggedInUserLastLogin = ref('');
const loggedInUserFullName = ref('');
const loggedInUserEmail = ref('');
const loggedInUserPhonenumber = ref('');
const loggedInUserAddress = ref('');
const loggedInUserCity = ref('');
const loggedInUserPostcode = ref('');
const loggedInUserAdminBool = ref('');
const loggedInUserTechnicianBool = ref('');
const loggedInUserReaderBool = ref('');
const loggedInUserNewPassword = ref('');
const loggedInUserNewPasswordRepeated = ref('');
const employees = ref([]);
const darkMode = ref(true)
const changePassword = () => {
changePasswordBool.value = !changePasswordBool.value
loggedInUserNewPassword.value = '';
loggedInUserNewPasswordRepeated.value = '';
}
const savePassword = async () => {
// hier weiter machen
if (loggedInUserNewPassword.value.length < 8) {
alert("Please choose a password with minimal eight characters!");
return
}
// password (repeat) must match
if (loggedInUserNewPassword.value != loggedInUserNewPasswordRepeated.value) {
alert("Your passwords don't match.");
return
}
try {
await Axios.put(`https://${clientsideConfig.url}:${clientsideConfig.port}/api/updatePasswordEmployee`,
{
id: loggedInUserId.value,
password: loggedInUserNewPassword.value,
}
)
alert("Password successfully updatet!");
changePasswordBool.value = false;
loggedInUserNewPassword.value = '';
loggedInUserNewPasswordRepeated.value = '';
} catch (err) {
console.log(err);
};
}
const getSession = async () => {
loggedInUserId.value = getItem('logged-in-user-id');
loggedInUserUsername.value = getItem('logged-in-user-username');
loggedInUserRegistered.value = getItem('logged-in-user-registered');
loggedInUserLastLogin.value = getItem('logged-in-user-lastLogin');
loggedInUserFullName.value = getItem('logged-in-user-fullName');
loggedInUserEmail.value = getItem('logged-in-user-email');
loggedInUserPhonenumber.value = getItem('logged-in-user-phonenumber');
loggedInUserAddress.value = getItem('logged-in-user-address');
loggedInUserCity.value = getItem('logged-in-user-city');
loggedInUserPostcode.value = getItem('logged-in-user-postcode');
loggedInUserAdminBool.value = getItem('logged-in-user-adminBool');
loggedInUserTechnicianBool.value = getItem('logged-in-user-technicianBool');
loggedInUserReaderBool.value = getItem('logged-in-user-readerBool');
}
function getItem(item) {
if (process.client) {
return localStorage.getItem(item)
} else {
return undefined
}
}
const updateUsername = async () => {
if (loggedInUserUsername.value.length < 5) {
alert("Your username must have at least five characters!");
loggedInUserUsername.value = getItem('logged-in-user-username');
return;
}
var counter = 0;
// check if the username already exists
employees.value.forEach(empl => {
if (empl.username === loggedInUserUsername.value) {
counter += 1;
}
});
if (counter == 1) {
alert("This username already exists. Please choose an unique username!");
loggedInUserUsername.value = getItem('logged-in-user-username');
return;
}
await updateUser();
}
//update data
const updateUser = async () => {
if (!validateEMail(loggedInUserEmail.value)) {
alert("Please add a valid email!");
loggedInUserEmail.value = getItem('logged-in-user-email');
return;
}
if ((loggedInUserPhonenumber.value.length === 0) && (loggedInUserEmail.value.length === 0)) {
alert("Please add a phonenumber or an email!");
loggedInUserPhonenumber.value = getItem('logged-in-user-phonenumber');
loggedInUserEmail.value = getItem('logged-in-user-email')
return;
}
try {
await Axios.put(
`https://${clientsideConfig.url}:${clientsideConfig.port}/api/updateEmployee`,
{
id: loggedInUserId.value,
username: loggedInUserUsername.value,
fullName: loggedInUserFullName.value,
email: loggedInUserEmail.value,
phonenumber: loggedInUserPhonenumber.value,
address: loggedInUserAddress.value,
city: loggedInUserCity.value,
postcode: loggedInUserPostcode.value,
adminBool: loggedInUserAdminBool.value,
technicianBool: loggedInUserTechnicianBool.value,
readerBool: loggedInUserReaderBool.value,
}
)
setItem('logged-in-user-username', loggedInUserUsername.value)
setItem('logged-in-user-fullName', loggedInUserFullName.value)
setItem('logged-in-user-email', loggedInUserEmail.value)
setItem('logged-in-user-phonenumber', loggedInUserPhonenumber.value)
setItem('logged-in-user-address', loggedInUserAddress.value)
setItem('logged-in-user-city', loggedInUserCity.value)
setItem('logged-in-user-postcode', loggedInUserPostcode.value)
getSession();
store.commit('setLocalStorageChanged');
} catch (err) {
console.log(err.response.statusText);
}
}
// to validate the email address
const validateEMail = (email) => {
const emailRegex = new RegExp(/^[A-Za-z0-9_!#$%&'*+\/=?`{|}~^.-]+@[A-Za-z0-9.-]+$/, "gm");
if (email === "") {
return true
}
return emailRegex.test(email);
}
function setItem(item, value) {
if (process.client) {
localStorage.setItem(item, value)
return true
} else {
return false
}
}
//get all employees
const getEmployees = async () => {
try {
const response = await Axios.get(`https://${clientsideConfig.url}:${clientsideConfig.port}/api/getAllEmployees`);
employees.value = response.data;
} catch (err) {
console.log(err.response.statusText);
}
}
// include delay to avoid 503 error
const triggerBackendCallsWithDelay = async (fetchDataFunc) => {
setTimeout(() => {
fetchDataFunc();
}, 1000);
}
onMounted(async () => {
await getSession();
await triggerBackendCallsWithDelay(getEmployees);
});
</script>
<script>
export default {
name: "UserAccount",
};
</script>
</script>
<style scoped>
.userAccount {
display: flex;
@ -53,6 +264,47 @@ export default {
background-color: #fff;
}
.input-darkmode {
color: #fff;
background-color: #212121;
}
input#changePassword:hover,
input#savePassword:hover {
background-color: #454545;
}
.input-lightmode {
color: #212121;
;
background-color: #EBEBEB;
}
.data-darkmode {
background-color: #212121;
color: #fff;
}
.data-lightmode {
background-color: #EBEBEB;
color: #000;
}
.data {
display: flex;
flex-direction: row;
align-items: flex-start;
padding: 0 0.625rem;
border-radius: 0.3125rem;
box-shadow: 0.0625rem 0.0625rem 0.25rem 0rem rgba(0, 0, 0, 0.25) inset;
letter-spacing: 5%;
font: 400 0.75rem/250% Overpass, sans-serif;
}
.input {
border: none;
}
.heading {
letter-spacing: 5%;
font: 400 1rem/2rem Overpass, sans-serif;
@ -66,9 +318,21 @@ export default {
color: #000;
}
.userData {
.username-email,
.password {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
line-height: normal;
width: 50%;
padding: 0 1rem;
border-radius: 0.3125rem;
}
.userData {
display: flex;
flex-direction: row;
align-content: center;
gap: 0.625rem
}
@ -137,4 +401,22 @@ export default {
.label {
width: 6.25rem;
}
input#changePassword,
input#savePassword {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
width: 10rem;
height: 2.5rem;
margin-top: 1rem;
border-radius: 0.625rem;
border: none;
text-align: center;
letter-spacing: 5%;
font: 400 0.875rem/2rem Overpass, sans-serif;
margin-right: 1.25rem;
box-shadow: 0.25rem 0.25rem 0.25rem 0rem rgba(0, 0, 0, 0.25);
}
</style>

View File

@ -5,28 +5,221 @@
<div class="rectangle-container">
<div :class="['rectangle', darkMode ? 'rectangle-darkmode' : 'rectangle-lightmode']"></div>
</div>
<div class="data-field" id="username">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Username:</pre>
<pre :class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']">...</pre>
<div class="fullname-registered-lastLogin">
<div class="data-field" id="fullName">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Full name:</pre>
<pre v-if="!editable"
:class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']">{{ loggedInUserFullName }}</pre>
<input v-if="editable" v-model="loggedInUserFullName" @change="updateUser()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
<div class="data-field" id="registered">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Registered:</pre>
<pre
:class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']"> {{ loggedInUserRegistered }}</pre>
</div>
<div class="data-field" id="lastLogin">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Last login:</pre>
<pre
:class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']"> {{ loggedInUserLastLogin }}</pre>
</div>
</div>
<div class="info">
<div class="city-phonenumber">
<div class="data-field" id="city">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">City:</pre>
<pre v-if="!editable"
:class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']">{{ loggedInUserCity }}</pre>
<input v-if="editable" v-model="loggedInUserCity" @change="updateUser()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
<div class="data-field" id="phonenumber">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Phonenumber:</pre>
<pre v-if="!editable"
:class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']">{{ loggedInUserPhonenumber }}</pre>
<input v-if="editable" v-model="loggedInUserPhonenumber" @change="updateUser()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
</div>
<div class="postcode-address">
<div class="data-field" id="postcode">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Postcode:</pre>
<pre v-if="!editable"
:class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']">{{ loggedInUserPostcode }}</pre>
<input v-if="editable" v-model="loggedInUserPostcode" @change="updateUser()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
<div class="data-field" id="address">
<pre :class="['label', darkMode ? 'pre-darkmode' : 'pre-lightmode']">Address:</pre>
<pre v-if="!editable"
:class="['data', darkMode ? 'data-darkmode' : 'data-lightmode']">{{ loggedInUserAddress }}</pre>
<input v-if="editable" v-model="loggedInUserAddress" @change="updateUser()"
:class="['data', 'input', darkMode ? 'data-darkmode' : 'data-lightmode']">
</div>
</div>
</div>
</div>
</section>
</template>
<script setup>
import { ref } from 'vue';
import { useStore } from 'vuex';
import { computed } from 'vue';
import Axios from '../axios.config.js';
import clientsideConfig from '../../clientsideConfig.js';
const store = useStore();
const editable = computed(() => store.state.editable);
const loggedInUserId = ref('');
const loggedInUserUsername = ref('');
const loggedInUserRegistered = ref('');
const loggedInUserLastLogin = ref('');
const loggedInUserFullName = ref('');
const loggedInUserEmail = ref('');
const loggedInUserPhonenumber = ref('');
const loggedInUserAddress = ref('');
const loggedInUserCity = ref('');
const loggedInUserPostcode = ref('');
const loggedInUserAdminBool = ref('');
const loggedInUserTechnicianBool = ref('');
const loggedInUserReaderBool = ref('');
function getItem(item) {
if (process.client) {
return localStorage.getItem(item)
} else {
return undefined
}
}
const getSession = async () => {
loggedInUserId.value = getItem('logged-in-user-id');
loggedInUserUsername.value = getItem('logged-in-user-username');
loggedInUserRegistered.value = getItem('logged-in-user-registered');
loggedInUserLastLogin.value = getItem('logged-in-user-lastLogin');
loggedInUserFullName.value = getItem('logged-in-user-fullName');
loggedInUserEmail.value = getItem('logged-in-user-email');
loggedInUserPhonenumber.value = getItem('logged-in-user-phonenumber');
loggedInUserAddress.value = getItem('logged-in-user-address');
loggedInUserCity.value = getItem('logged-in-user-city');
loggedInUserPostcode.value = getItem('logged-in-user-postcode');
loggedInUserAdminBool.value = getItem('logged-in-user-adminBool');
loggedInUserTechnicianBool.value = getItem('logged-in-user-technicianBool');
loggedInUserReaderBool.value = getItem('logged-in-user-readerBool');
}
const darkMode = ref(true)
//update data
const updateUser = async () => {
if (loggedInUserFullName.value.length === 0) {
alert("Please add a valid name!");
loggedInUserFullName.value = getItem('logged-in-user-fullName');
return;
}
if (loggedInUserCity.value.length === 0) {
alert("Please add a city!");
loggedInUserCity.value = getItem('logged-in-user-city');
return;
}
if (loggedInUserAddress.value.length === 0) {
alert("Please add an address!");
loggedInUserAddress.value = getItem('logged-in-user-address');
return;
}
if (!validatePhonenumber(loggedInUserPhonenumber.value)) {
alert("Please add a valid phonenumber!");
loggedInUserPhonenumber.value = getItem('logged-in-user-phonenumber');
return;
}
if (!validatePostcode(loggedInUserPostcode.value)) {
alert("Please add a valid postcode!");
loggedInUserPostcode.value = getItem('logged-in-user-postcode');
return;
}
if ((loggedInUserPhonenumber.value.length === 0) && (loggedInUserEmail.value.length === 0)) {
alert("Please add a phonenumber or an email!");
loggedInUserPhonenumber.value = getItem('logged-in-user-phonenumber');
loggedInUserEmail.value = getItem('logged-in-user-email')
return;
}
try {
await Axios.put(
`https://${clientsideConfig.url}:${clientsideConfig.port}/api/updateEmployee`,
{
id: loggedInUserId.value,
username: loggedInUserUsername.value,
fullName: loggedInUserFullName.value,
email: loggedInUserEmail.value,
phonenumber: loggedInUserPhonenumber.value,
address: loggedInUserAddress.value,
city: loggedInUserCity.value,
postcode: loggedInUserPostcode.value,
adminBool: loggedInUserAdminBool.value,
technicianBool: loggedInUserTechnicianBool.value,
readerBool: loggedInUserReaderBool.value,
}
)
setItem('logged-in-user-username', loggedInUserUsername.value)
setItem('logged-in-user-fullName', loggedInUserFullName.value)
setItem('logged-in-user-email', loggedInUserEmail.value)
setItem('logged-in-user-phonenumber', loggedInUserPhonenumber.value)
setItem('logged-in-user-address', loggedInUserAddress.value)
setItem('logged-in-user-city', loggedInUserCity.value)
setItem('logged-in-user-postcode', loggedInUserPostcode.value)
getSession();
} catch (err) {
console.log(err.response.statusText);
}
}
function setItem(item, value) {
if (process.client) {
localStorage.setItem(item, value)
return true
} else {
return false
}
}
// to validate the phonenumber
const validatePhonenumber = (number) => {
const mobilephonenumberRegex = new RegExp(/^(((((00|\+){1,2})49([ \-/]?|[ \()/]?))|0)[1]([0-2]|[4-7])([0-9]{1})([ \-/]?|[ \()/]?)([0-9]{8}))$/, "gm");
const landlineRegex = new RegExp(/^0(30|40|69|89|20[12389]|21[24]|228|234|335|340|3[3-9][15]|906|[2-9][1-9]1|3(?:3(?:[0237][127]|0[3-6]|2[89]|3[458]|[46][1246]|7[589]|8[1256]|9[145])|4(?:[2347][135]|[34]7|[69][146]|48|62|76|93)|5(?:[04679][14]|[238][135]|[2469]2|[4789]6|[278]8|63|73|37|29)|6(?:[024689][13]|[03789]5|06|2[2489]|3[1246]|44|47|7[1279]|82|86)|7(?:[236][135]|2[2467]|37|4[145]|62|64|7[1-4])|8(?:[234678]1|3[468]|4[347]|6[035-9]|7[467]|83|86)|9(?:[236][135]|[04689]4|[04789]1|[03468]7|02|09|28|4[369]|6[2689]|73|76|96|98))|3[3-9][0-9]{3}|13[078]|180[235]|18[01]|19[0-9]{3}|[789]00|[2-9][0-9]{3})([0-9]{1,})$/, "gm");
if (number === "") {
return true
}
if (mobilephonenumberRegex.test(number)) {
return true
} else if (landlineRegex.test(number)) {
return true;
}
return false;
}
// to validate the postcode
const validatePostcode = (postcode) => {
const postcodeRegex = new RegExp(/^\d{5}$/);
if (postcode === "") {
return true
}
return postcodeRegex.test(postcode);
}
onMounted(async () => {
await getSession();
});
</script>
<script>
export default {
name: "UserProfile",
};
</script>
</script>
<style scoped>
.userProfile {
display: flex;
@ -52,11 +245,19 @@ export default {
background-color: #fff;
}
.input {
border: none;
}
.heading {
letter-spacing: 5%;
font: 400 1rem/2rem Overpass, sans-serif;
}
.div#address.data-field {
padding-left: 3rem;
}
.heading-darkmode {
color: #fff;
}
@ -65,6 +266,18 @@ export default {
color: #000;
}
.fullname-registered-lastLogin,
.info {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
line-height: normal;
width: 50%;
padding: 0 1rem;
border-radius: 0.3125rem;
}
.userData {
display: flex;
flex-direction: row;
@ -74,6 +287,26 @@ export default {
gap: 3.125rem
}
.city-phonenumber {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
align-self: stretch;
padding: 0 1.875rem 0 0;
gap: 0.625rem;
}
.postcode-address {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
align-self: stretch;
padding: 0 1.875rem 0 0;
gap: 0.625rem;
}
.rectangle-container {
display: flex;
}

View File

@ -1,4 +1,4 @@
<template>
<!-- <template>
<div :class="['data', darkMode ? 'div-darkmode' : 'div-lightmode']">
<div :class="['label', darkMode ? 'label-darkmode' : 'label-lightmode']">Rights:</div>
<table class="data-table" id="user-rights-list">
@ -212,4 +212,4 @@ th {
.label-lightmode {
color: #000;
}
</style>
</style> -->