Skip to content
Snippets Groups Projects
Commit 13445f3c authored by Jens Christian Aanestad's avatar Jens Christian Aanestad
Browse files

Merge branch 'refactor/Configuration' into 'main'

Refactor/configuration

See merge request !25
parents b050d1ed 2465538c
No related branches found
No related tags found
1 merge request!25Refactor/configuration
Pipeline #275804 failed
Showing with 233 additions and 116 deletions
......@@ -4,22 +4,14 @@ import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { useRoute } from 'vue-router'
// Configuration variables
let bankId = ref('')
let commitment = ref('')
let experience = ref('')
let suitableChallenges = ref([])
let savingGoalTitle = ref('')
let sumToSpare = ref(0)
let dueDate = ref(null)
const router = useRouter()
// The configuration steps with path and order value.
const configurationSteps = {'/bank-id': 1, '/commitment': 2, '/experience': 3, '/suitable-challenges': 4, '/first-saving-goal': 5}
const configurationSteps = {'/commitment': 1, '/experience': 2, '/suitable-challenges': 3}
const length = Object.keys(configurationSteps).length
let percentage = ref(1/length);
// Initially pushes to '/bank-id' RouterView and sets current path to this path.
// Initially pushes to the commitment-RouterView and sets current path to this path.
router.push(Object.keys(configurationSteps)[0])
let currentRoute = useRoute()
let currentPath = currentRoute.fullPath
......@@ -30,22 +22,6 @@ const onNewRouteEvent = (path) => {
percentage.value = (1/length) * configurationSteps[path]
}
const onBankIdSelectedEvent = (value) => {
bankId.value = value
}
const onCommitmentSelectedEvent = (value) => {
commitment.value = value
}
const onExperienceSelectedEvent = (value) => {
experience.value = value
}
const onChallengesSelectedEvent = (value) => {
suitableChallenges.value = value
}
</script>
<template>
......@@ -54,12 +30,7 @@ const onChallengesSelectedEvent = (value) => {
<ProgressBar id="progressbar" :percentage="percentage"/>
</div>
<div class="configuration-container">
<RouterView @changeRouterEvent="onNewRouteEvent"
@bankIdSelectedEvent="onBankIdSelectedEvent"
@commitmentSelectedEvent="onCommitmentSelectedEvent"
@experienceSelectedEvent="onExperienceSelectedEvent"
@challengesSelectedEvent="onChallengesSelectedEvent"
/>
<RouterView @changeRouterEvent="onNewRouteEvent"/>
</div>
</div>
</template>
......
<script setup lang="ts">
/*
import Button1 from '@/components/Buttons/Button1.vue'
import { useRouter } from 'vue-router'
import { ref } from 'vue'
......@@ -10,7 +11,7 @@ const vippsRef = ref(false)
const router = useRouter();
const emit = defineEmits(['changeRouterEvent', 'bankIdSelectedEvent']);
const emit = defineEmits(['changeRouterEvent']);
emit('changeRouterEvent', '/bank-id');
const onClick = () => {
......@@ -30,10 +31,11 @@ const onClick = () => {
emit('bankIdSelectedEvent', choice)
router.push('/commitment')
}
*/
</script>
<template>
<!--
<div class="container">
<div>
<h3 class="d-flex align-items-center justify-content-center">
......@@ -62,9 +64,11 @@ const onClick = () => {
</div>
</div>
-->
</template>
<style scoped>
/*
#confirmButton {
margin-bottom: 2rem;
width: 300px;
......@@ -74,4 +78,5 @@ const onClick = () => {
display: flex;
justify-content: center;
}
*/
</style>
\ No newline at end of file
<script setup lang="ts">
import Button1 from '@/components/Buttons/Button1.vue'
import { useRouter } from 'vue-router'
import { ref } from 'vue'
import { useConfigurationStore } from '@/stores/ConfigurationStore'
const router = useRouter();
const emit = defineEmits(['changeRouterEvent', 'commitmentSelectedEvent'])
// Updates progress bar in the parent Configuration component.
const emit = defineEmits(['changeRouterEvent'])
emit('changeRouterEvent', '/commitment')
// Reactive variables for form and radio buttons.
const formRef = ref()
const lowRef = ref('')
const mediumRef = ref('')
const highRef = ref('')
const router = useRouter();
let errorMsg = ref('');
/**
* Validates the commitment form radio buttons and updates the commitment choice in the store.
* If form validation is successful, updates the commitment choice in the store
* and navigates to the '/experience' route. If form validation fails, displays
* an error message prompting the user to select an option before continuing.
*/
const onClick = () => {
const radios = formRef.value.querySelectorAll('input[type="radio"]');
const checkedRadios = Array.from(radios).filter(radio => radio.checked);
if (checkedRadios.length === 0) {
alert('Please select an option.');
return;
const form = formRef.value;
if (form.checkValidity()) {
let choice = '';
if (lowRef.value.checked) choice = 'LITTLE'
else if (mediumRef.value.checked) choice = 'SOME'
else if (highRef.value.checked) choice = 'MUCH'
useConfigurationStore().setCommitment(choice)
router.push('/experience')
}
else {
errorMsg.value = 'Please select an option before continuing'
}
let choice = '';
if (lowRef.value.checked) choice = 'Low'
else if (mediumRef.value.checked) choice = 'Medium'
else if (highRef.value.checked) choice = 'High'
emit('commitmentSelectedEvent', choice)
router.push('/experience')
}
</script>
<template>
<div class="container">
<div>
<h3 class="d-flex align-items-center justify-content-center">
In which degree are you willing to make changes?
</h3>
</div>
<h3 id="commitmentText" class="align-items-center justify-content-center">
In which degree are you willing to make changes?
</h3>
<form class="btn-group-vertical" ref="formRef" @submit.prevent="onClick">
<input ref="lowRef" type="radio" class="btn-check" name="commitment" id="btn-check-outlined" autocomplete="off">
<input ref="lowRef" type="radio" class="btn-check" name="commitment" id="btn-check-outlined" autocomplete="off" required>
<label class="btn btn-outline-primary d-flex align-items-center justify-content-center" for="btn-check-outlined">Low</label>
<input ref="mediumRef" type="radio" class="btn-check" name="commitment" id="btn-check2-outlined" autocomplete="off">
<input ref="mediumRef" type="radio" class="btn-check" name="commitment" id="btn-check2-outlined" autocomplete="off" required>
<label class="btn btn-outline-primary d-flex align-items-center justify-content-center" for="btn-check2-outlined">Medium</label>
<input ref="highRef" type="radio" class="btn-check" name="commitment" id="btn-check3-outlined" autocomplete="off">
<input ref="highRef" type="radio" class="btn-check" name="commitment" id="btn-check3-outlined" autocomplete="off" required>
<label class="btn btn-outline-primary d-flex align-items-center justify-content-center" for="btn-check3-outlined">High</label>
</form>
<p class="text-danger">{{ errorMsg }}</p>
<div class="confirm-button-container">
<button1 id="confirmButton" @click="onClick" button-text="Continue"></button1>
</div>
......@@ -61,6 +65,13 @@ const onClick = () => {
</template>
<style scoped>
div.container {
display: flex;
flex-direction: column;
justify-self: center;
max-width: 500px;
}
#confirmButton {
margin-bottom: 2rem;
width: 300px;
......
......@@ -2,32 +2,40 @@
import Button1 from '@/components/Buttons/Button1.vue'
import { useRouter } from 'vue-router'
import { ref } from 'vue'
import { useConfigurationStore } from '@/stores/ConfigurationStore'
const router = useRouter();
const emit = defineEmits(['changeRouterEvent', 'experienceSelectedEvent'])
// Updates progress bar in the parent Configuration component.
const emit = defineEmits(['changeRouterEvent'])
emit('changeRouterEvent', '/experience')
// Declaration of reactive variables for the form and radio buttons
const formRef = ref()
const beginnerRef = ref('')
const someExperienceRef = ref('')
const expertRef = ref('')
let errorMsg = ref('');
/**
* Validates the experience form radio buttons and updates the commitment choice in the store.
* If form validation is successful, updates the commitment choice in the store
* and navigates to the '/suitable challenges' route. If form validation fails, displays
* an error message prompting the user to select an option before continuing.
*/
const onClick = () => {
const radios = formRef.value.querySelectorAll('input[type="radio"]');
const checkedRadios = Array.from(radios).filter(radio => radio.checked);
if (checkedRadios.length === 0) {
alert('Please select an option.');
return;
const form = formRef.value;
if (form.checkValidity()) {
let choice = ''
if (beginnerRef.value.checked) choice = 'NONE'
else if (someExperienceRef.value.checked) choice = 'SOME'
else if (expertRef.value.checked) choice = 'EXPERT'
useConfigurationStore().setExperience(choice)
router.push('/suitable-challenges')
}
else {
errorMsg.value = 'Please select an option before continuing'
}
let choice = ''
if (beginnerRef.value.checked) choice = 'Beginner'
else if (someExperienceRef.value.checked) choice = 'Some experience'
else if (expertRef.value.checked) choice = 'Expert'
emit('experienceSelectedEvent', choice)
router.push('/suitable-challenges')
}
</script>
......@@ -42,16 +50,16 @@ const onClick = () => {
<form class="btn-group-vertical" ref="formRef" @submit.prevent="onClick">
<input ref="beginnerRef" type="radio" class="btn-check" name="experience" id="btn-check-outlined" autocomplete="off">
<input ref="beginnerRef" type="radio" class="btn-check" name="experience" id="btn-check-outlined" autocomplete="off" required>
<label class="btn btn-outline-primary d-flex align-items-center justify-content-center" for="btn-check-outlined">Beginner</label>
<input ref="someExperienceRef" type="radio" class="btn-check" name="experience" id="btn-check2-outlined" autocomplete="off">
<input ref="someExperienceRef" type="radio" class="btn-check" name="experience" id="btn-check2-outlined" autocomplete="off" required>
<label class="btn btn-outline-primary d-flex align-items-center justify-content-center" for="btn-check2-outlined">Some experience</label>
<input ref="expertRef" type="radio" class="btn-check" name="experience" id="btn-check3-outlined" autocomplete="off">
<input ref="expertRef" type="radio" class="btn-check" name="experience" id="btn-check3-outlined" autocomplete="off" required>
<label class="btn btn-outline-primary d-flex align-items-center justify-content-center" for="btn-check3-outlined">Expert</label>
</form>
<p class="text-danger">{{ errorMsg }}</p>
<div class="confirm-button-container">
<button1 id="confirmButton" @click="onClick" button-text="Continue"></button1>
</div>
......@@ -59,6 +67,13 @@ const onClick = () => {
</template>
<style scoped>
div.container {
display: flex;
flex-direction: column;
justify-self: center;
max-width: 500px;
}
#confirmButton {
margin-bottom: 2rem;
width: 300px;
......
<script setup lang="ts">
/*
import BaseInput from '@/components/InputFields/BaseInput.vue'
import { ref } from 'vue'
import Button1 from '@/components/Buttons/Button1.vue'
......@@ -33,10 +34,11 @@ const getTodayDate = () => {
return `${year}-${month}-${day}`;
};
*/
</script>
<template>
<!--
<div class="container">
<div>
<h3 class="d-flex align-items-center justify-content-center">
......@@ -72,9 +74,11 @@ const getTodayDate = () => {
<button1 id="confirmButton" @click="onClick" button-text="Continue"></button1>
</div>
</div>
-->
</template>
<style scoped>
/*
#confirmButton {
margin-bottom: 2rem;
width: 300px;
......@@ -84,4 +88,5 @@ const getTodayDate = () => {
display: flex;
justify-content: center;
}
*/
</style>
\ No newline at end of file
......@@ -3,15 +3,31 @@ import { useRouter } from 'vue-router'
import ChallangeCheckBox from '@/components/Configuration/ChallangeCheckBox.vue'
import Button1 from '@/components/Buttons/Button1.vue'
import { ref } from 'vue'
import { useConfigurationStore } from '@/stores/ConfigurationStore'
import { useUserInfoStore } from '@/stores/UserStore'
import { AuthenticationService, OpenAPI, SignUpRequest } from '@/api'
import handleUnknownError from '@/components/Exceptions/unkownErrorHandler'
const emit = defineEmits(['changeRouterEvent', 'challengesSelectedEvent'])
emit('changeRouterEvent', '/suitable-challenges')
const router = useRouter();
// Updates progress bar in the parent Configuration component.
const emit = defineEmits(['changeRouterEvent'])
emit('changeRouterEvent', '/suitable-challenges')
// Reactive variables for chosen challenges and error message.
let chosenChallenges = ref([])
let errorMsg = ref('')
// Represents a list of available challenges.
const challenges = ['Make packed lunch', 'Stop shopping', 'Drop coffee',
'Quit subscription', 'Drop car', 'Short showers', 'Exercise outside', 'Make budget']
/**
* Handles the event when a challenge is selected or deselected.
* @param {Array} value - An array containing the challenge value and its checked status.
* The first element is the challenge value, and the second element
* indicates whether the challenge is checked (true) or unchecked (false).
*/
const onChangedChallengeEvent = (value) => {
// if challenge is checked then add it to the chosenChallenges variable
if (value[1]) {
......@@ -19,15 +35,59 @@ const onChangedChallengeEvent = (value) => {
}
// if challenge is unchecked then remove it from the chosenChallenges variable
else {
console.log('Reached')
chosenChallenges.value = chosenChallenges.value.filter(item => item !== value[0]);
}
console.log(chosenChallenges.value)
}
const onClick = () => {
emit('challengesSelectedEvent', chosenChallenges.value)
router.push('/first-saving-goal')
/**
* Retrieves user configuration and signup information, sends a signup request to the backend.
*
* @throws {Error} Throws an error if signup fails.
*/
const onClick = async () => {
try {
// Saves the chosen challenges to the configuration store
useConfigurationStore().setChallenges(chosenChallenges.value)
/*
TODO: 'changeWilling' are updated to 'commitment' in backend, must update it in frontend
const signUpPayLoad: SignUpRequest = {
changeWilling: useConfigurationStore().getCommitment,
experience: useConfigurationStore().getExperience,
challenges: useConfigurationStore().getChallenges,
firstName: useUserInfoStore().getFirstName,
lastName: useUserInfoStore().getLastname,
email: useUserInfoStore().getEmail,
password: useUserInfoStore().getPassword,
};
*/
const signUpPayLoad = {
"commitment": useConfigurationStore().getCommitment,
"experience": useConfigurationStore().getExperience,
"challenges": useConfigurationStore().getChallenges,
"firstName": useUserInfoStore().getFirstName,
"lastName": useUserInfoStore().getLastname,
"email": useUserInfoStore().getEmail,
"password": useUserInfoStore().getPassword,
};
let response = await AuthenticationService.signup({ requestBody: signUpPayLoad });
if (response.token == null) {
errorMsg.value = 'A valid token could not be created';
return;
}
OpenAPI.TOKEN = response.token;
useUserInfoStore().setUserInfo({
accessToken: response.token,
role: response.role,
});
useUserInfoStore().resetPassword()
await router.push({ name: 'home' });
}
catch (error) {
errorMsg.value = handleUnknownError(error);
}
}
</script>
......@@ -46,8 +106,10 @@ const onClick = () => {
/>
</div>
<p class="text-danger">{{ errorMsg }}</p>
<div class="confirm-button-container">
<button1 id="confirmButton" @click="onClick" button-text="Continue"></button1>
<button1 id="confirmButton" @click="onClick" button-text="Finish configuration"></button1>
</div>
</div>
</template>
......
......@@ -54,7 +54,7 @@ const handleSubmit = async () => {
email: emailRef.value,
role: response.role,
});
router.push({ name: 'home' });
await router.push({ name: 'home' });
} catch (error: any) {
errorMsg.value = handleUnknownError(error);
}
......
......@@ -3,8 +3,12 @@ import BaseInput from '@/components/InputFields/BaseInput.vue'
import Button1 from '@/components/Buttons/Button1.vue'
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { AuthenticationService } from '@/api'
import handleUnknownError from '@/components/Exceptions/unkownErrorHandler'
import { useUserInfoStore } from '@/stores/UserStore'
const router = useRouter();
const userStore = useUserInfoStore();
const firstNameRef = ref('')
const surnameRef = ref('')
......@@ -13,10 +17,10 @@ const passwordRef = ref('')
const confirmPasswordRef = ref('')
const formRef = ref()
let samePasswords = ref(true)
let errorMsg = ref('');
const handleFirstNameInputEvent = (newValue: any) => {
firstNameRef.value = newValue
console.log(firstNameRef.value)
}
const handleSurnameInputEvent = (newValue: any) => {
......@@ -29,41 +33,43 @@ const handleEmailInputEvent = (newValue: any) => {
const handlePasswordInputEvent = (newValue: any) => {
passwordRef.value = newValue
console.log(passwordRef.value)
}
const handleConfirmPasswordInputEvent = (newValue: any) => {
confirmPasswordRef.value = newValue
console.log(confirmPasswordRef.value)
}
const handleSubmit = async () => {
console.log(firstNameRef.value)
samePasswords.value = (passwordRef.value === confirmPasswordRef.value)
console.log(samePasswords.value)
const form = formRef.value;
formRef.value.classList.add("was-validated")
// Check if the form is valid
const form = formRef.value;
if (form.checkValidity()) {
// Form is valid, submit the form or perform other actions
console.log('Form is valid');
} else {
console.log('Form is not valid');
if (samePasswords.value) {
try {
let response = await AuthenticationService.validateEmail({email: emailRef.value});
userStore.setUserInfo({
firstname: firstNameRef.value,
lastname: surnameRef.value,
email: emailRef.value,
});
userStore.setPassword(passwordRef.value)
await router.push('/configuration')
} catch (error) {
errorMsg.value = handleUnknownError(error);
}
}
}
formRef.value.classList.add("was-validated")
}
</script>
<template>
<div class="container">
<form ref="formRef" id="signUpForm" @submit.prevent="handleSubmit">
<BaseInput :model-value="firstNameRef"
<form ref="formRef" id="signUpForm" @submit.prevent="handleSubmit" novalidate>
<BaseInput :model-value=firstNameRef
@input-change-event="handleFirstNameInputEvent"
ref="firstNameRef"
id="firstNameInput"
input-id="first-name"
type="text"
......@@ -72,7 +78,6 @@ const handleSubmit = async () => {
invalid-message="Please enter your first name"/>
<BaseInput :model-value="surnameRef"
@input-change-event="handleSurnameInputEvent"
ref="surnameRef"
id="surnameInput"
input-id="surname"
type="text"
......@@ -81,7 +86,6 @@ const handleSubmit = async () => {
invalid-message="Please enter your surname"/>
<BaseInput :model-value="emailRef"
@input-change-event="handleEmailInputEvent"
ref="emailRef"
id="emailInput"
input-id="email"
type="email"
......@@ -90,7 +94,6 @@ const handleSubmit = async () => {
invalid-message="Invalid email"/>
<BaseInput :model-value="passwordRef"
@input-change-event="handlePasswordInputEvent"
ref="passwordRef"
id="passwordInput"
input-id="password"
type="password"
......@@ -100,7 +103,6 @@ const handleSubmit = async () => {
invalid-message="Password must be between 4 and 16 characters and contain one capital letter, small letter and a number"/>
<BaseInput :modelValue="confirmPasswordRef"
@input-change-event="handleConfirmPasswordInputEvent"
ref="confirmPasswordRef"
id="confirmPasswordInput"
input-id="confirmPassword"
type="password"
......@@ -108,7 +110,8 @@ const handleSubmit = async () => {
label="Confirm Password"
placeholder="Confirm password"
invalid-message="Password must be between 4 and 16 characters and contain one capital letter, small letter and a number"/>
<p v-if="samePasswords" class="text-danger">The passwords are not identical</p>
<p class="text-danger">{{ errorMsg }}</p>
<p v-if="!samePasswords" class="text-danger">The passwords are not identical</p>
<button1 id="confirmButton" @click="handleSubmit" button-text="Sign up"></button1>
</form>
</div>
......
import { defineStore } from 'pinia'
export const useConfigurationStore = defineStore('ConfigurationStore', {
state: () => ({
commitment: '',
experience: '',
challenges: []
}),
actions: {
setCommitment(commitment: string) {
this.commitment = commitment
},
setExperience(experience: string) {
this.experience = experience
},
setChallenges(challenges: Array<string>) {
this.challenges = challenges
},
resetConfiguration() {
this.commitment = ''
this.experience = ''
this.challenges = []
}
},
getters: {
getCommitment(): string {
return this.commitment
},
getExperience(): string {
return this.experience
},
getChallenges(): string {
return this.challenges
}
},
persist: {
enabled: true,
}
});
......@@ -75,6 +75,15 @@ export const useUserInfoStore = defineStore('UserInfoStore', {
getPassword(): string {
return this.password
},
getFirstName(): string {
return this.firstname
},
getLastname(): string {
return this.lastname
},
getEmail(): string {
return this.email
},
isLoggedIn(): boolean {
return this.accessToken !== '';
},
......
......@@ -5,7 +5,5 @@ import Footer from '@/components/BaseComponents/Footer.vue'
</script>
<template>
<Menu/>
<Configuration/>
<Footer/>
</template>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment