diff --git a/src/components/FormLogin.vue b/src/components/FormLogin.vue index df5c5f49ba17cf284a3f6d40a6b6de3b5e123479..2f1fbb925161bf0d240759c520189196c30bb3f1 100644 --- a/src/components/FormLogin.vue +++ b/src/components/FormLogin.vue @@ -4,6 +4,7 @@ import { useUserStore } from '@/stores/userStore' import ModalComponent from '@/components/ModalComponent.vue' import axios from 'axios' +// Constants for logging in const username = ref<string>('') const password = ref<string>('') const showPassword = ref<boolean>(false) @@ -12,24 +13,30 @@ const isModalOpen = ref<boolean>(false) const resetEmail = ref<string>('') const emailRegex = /^[a-zA-Z0-9_+&*-]+(?:\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,7}$/ +// Store for user data const userStore = useUserStore() +// Computed properties for form validation const isEmailValid = computed(() => emailRegex.test(resetEmail.value)) const isSendingEmail = ref(false) const successMessage = ref<string | null>(null) const modalErrorMessage = ref<string | null>(null) +// Function to submit form const submitForm = () => { userStore.login(username.value, password.value) } +// Function to toggle show password const toggleShowPassword = () => { showPassword.value = !showPassword.value } +// Function to submit reset email const submitReset = async () => { isSendingEmail.value = true + // Send request to backend to reset password await axios .post('http://localhost:8080/forgotPassword/changePasswordRequest', { email: resetEmail.value @@ -46,6 +53,7 @@ const submitReset = async () => { isSendingEmail.value = false } +// Function to close modal and reset values const closeModal = () => { isModalOpen.value = false isSendingEmail.value = false @@ -54,6 +62,7 @@ const closeModal = () => { successMessage.value = null } +// Watch for error message from store watch( () => userStore.errorMessage, (newValue: string) => { diff --git a/src/components/FormRegister.vue b/src/components/FormRegister.vue index 5d8e75434066ff02c4e0db27d7fd308b722435cb..731f59da114c628dc073bd3632b7d8c4df005634 100644 --- a/src/components/FormRegister.vue +++ b/src/components/FormRegister.vue @@ -3,6 +3,7 @@ import { computed, ref, watch } from 'vue' import { useUserStore } from '@/stores/userStore' import ToolTip from '@/components/ToolTip.vue' +// constants for registering a new user const firstName = ref<string>('') const lastName = ref<string>('') const email = ref<string>('') @@ -10,24 +11,29 @@ const username = ref<string>('') const password = ref<string>('') const confirm = ref<string>('') +// reactive variables for form validation const showPassword = ref<boolean>(false) const errorMessage = ref<string>('') const passwordValidations = ref<string[]>([]) +// store for user data const userStore = useUserStore() +// regex for validating user input const nameRegex = /^[æÆøØåÅa-zA-Z,.'-][æÆøØåÅa-zA-Z ,.'-]{0,29}$/ const emailRegex = /^[æÆøØåÅa-zA-Z0-9_+&*-]+(?:\.[æÆøØåÅa-zA-Z0-9_+&*-]+)*@(?:[æÆøØåÅa-zA-Z0-9-]+\.)+[æÆøØåÅa-zA-Z]{2,7}$/ const usernameRegex = /^[ÆØÅæøåA-Za-z][æÆøØåÅA-Za-z0-9_]{2,29}$/ const passwordRegex = /^(?=.*[0-9])(?=.*[a-zæøå])(?=.*[ÆØÅA-Z])(?=.*[@#$%^&+=!])(?=\S+$).{8,30}$/ +// computed properties for form validation const isFirstNameValid = computed(() => nameRegex.test(firstName.value) && firstName.value) const isLastNameValid = computed(() => nameRegex.test(lastName.value) && lastName.value) const isEmailValid = computed(() => emailRegex.test(email.value)) const isUsernameValid = computed(() => usernameRegex.test(username.value)) const isPasswordValid = computed(() => passwordRegex.test(password.value)) +// computed property for checking if form is invalid const isFormInvalid = computed( () => [isFirstNameValid, isLastNameValid, isEmailValid, isUsernameValid, isPasswordValid].some( @@ -35,23 +41,27 @@ const isFormInvalid = computed( ) || password.value !== confirm.value ) +// function for submitting form with user data const submitForm = () => { userStore.register(firstName.value, lastName.value, email.value, username.value, password.value) } +// function for toggling show password const toggleShowPassword = () => { showPassword.value = !showPassword.value } +// function for validating password const validatePassword = () => { - const messages = [] - const lengthValid = password.value.length >= 8 && password.value.length <= 30 - const numberValid = /[0-9]/.test(password.value) - const lowercaseValid = /[a-zæøå]/.test(password.value) - const uppercaseValid = /[ÆØÅA-Z]/.test(password.value) - const specialCharacterValid = /[@#$%^&+=!]/.test(password.value) - const noSpacesValid = !/\s/.test(password.value) + const messages = [] // array for storing error messages + const lengthValid = password.value.length >= 8 && password.value.length <= 30 // check if password length is valid + const numberValid = /[0-9]/.test(password.value) // check if password contains a number + const lowercaseValid = /[a-zæøå]/.test(password.value) // check if password contains a lowercase letter + const uppercaseValid = /[ÆØÅA-Z]/.test(password.value) // check if password contains an uppercase letter + const specialCharacterValid = /[@#$%^&+=!]/.test(password.value) // check if password contains a special character + const noSpacesValid = !/\s/.test(password.value) // check if password contains no spaces + // add error messages to array if validation fails if (!lengthValid) { messages.push('Må være mellom 8 og 30 karakterer. ') } @@ -74,8 +84,10 @@ const validatePassword = () => { passwordValidations.value = messages } +// watch for changes in password input watch(password, validatePassword) +// watch for changes in error message from user store watch( () => userStore.errorMessage, (newValue: string) => { diff --git a/src/types/CredentialCreationOptions.ts b/src/types/CredentialCreationOptions.ts index b6fdd7a76510ca4033a1c763a2ca9545797ab1b5..9d3e0fc62b0360e316643256d3140bf33fc6c618 100644 --- a/src/types/CredentialCreationOptions.ts +++ b/src/types/CredentialCreationOptions.ts @@ -1,3 +1,4 @@ +// Definition of the CredentialCreationOptions type export interface CredentialCreationOptions { publicKey: PublicKeyCredentialCreationOptions } diff --git a/src/types/challengeConfig.ts b/src/types/challengeConfig.ts index 1cce65fc037bc067404b61fe185f6e1084656ed5..62d6614f87a5e4546327c70398bd7eb72fdfbb89 100644 --- a/src/types/challengeConfig.ts +++ b/src/types/challengeConfig.ts @@ -1,9 +1,10 @@ +// Definition of the ChallengeConfig type export interface ChallengeConfig { - experience: string - motivation: string + experience: string // Mapping to an enum in Java, but TypeScript uses string + motivation: string // Mapping to an enum in Java, but TypeScript uses string challengeTypeConfigs: { - type: string - generalAmount: number | null - specificAmount: number | null + type: string // Mapping to an enum in Java, but TypeScript uses string + generalAmount: number | null // BigDecimal in Java, but TypeScript uses number + specificAmount: number | null // BigDecimal in Java, but TypeScript uses number }[] } diff --git a/src/views/BiometricLoginView.vue b/src/views/BiometricLoginView.vue index 15d669023dc049728d7ceff61eea7e6c2c00ad20..a4a9cf1b4fcfe7ec291805a8dd80cf5c92efe1b8 100644 --- a/src/views/BiometricLoginView.vue +++ b/src/views/BiometricLoginView.vue @@ -6,11 +6,13 @@ import { useUserStore } from '@/stores/userStore' const route = useRoute() const username = route.params.username as string +// Function to remove bio credential from local storage const removeBioCredential = () => { localStorage.removeItem('spareStiUsername') router.push({ name: 'login' }) } +// Function to login with biometric const bioLogin = () => { useUserStore().bioLogin(username) } diff --git a/src/views/ConfigAccountNumberView.vue b/src/views/ConfigAccountNumberView.vue index a869677084d0673fa9c63044977a93682538cfe3..ea067d77453e4318166b091af295b228e457918f 100644 --- a/src/views/ConfigAccountNumberView.vue +++ b/src/views/ConfigAccountNumberView.vue @@ -72,6 +72,7 @@ const userConfigStore = useUserConfigStore() const spendingAccount = ref('') const savingsAccount = ref('') +// Check if the form is valid, the account numbers should be 11 digits long const isFormValid = computed(() => { return ( spendingAccount.value.replace(/\./g, '').length === MAX_DIGITS && @@ -79,6 +80,7 @@ const isFormValid = computed(() => { ) }) +// Save the account numbers to the store async function onButtonClick() { const savingAccountNumber = parseInt(savingsAccount.value.replace(/\./g, '')) const spendingAccountNumber = parseInt(spendingAccount.value.replace(/\./g, '')) @@ -86,9 +88,11 @@ async function onButtonClick() { userConfigStore.setAccount('SAVING', savingAccountNumber) userConfigStore.setAccount('SPENDING', spendingAccountNumber) + // Create a new user config await userConfigStore.createConfig() } +// Restrict the input to numbers only function restrictToNumbers(event: InputEvent, type: string) { const inputValue = (event.target as HTMLInputElement)?.value if (inputValue !== undefined) { @@ -102,6 +106,7 @@ function restrictToNumbers(event: InputEvent, type: string) { } } +// Apply formatting to the account number function applyFormatting(type: string) { if (type === 'spending') { spendingAccount.value = formatAccount(spendingAccount.value) @@ -110,6 +115,7 @@ function applyFormatting(type: string) { } } +// Remove formatting from the account number function removeFormatting(type: string) { if (type === 'spending') { spendingAccount.value = removeFormat(spendingAccount.value) @@ -118,10 +124,12 @@ function removeFormatting(type: string) { } } +// Format the account number to 1234.56.78901 function formatAccount(value: string): string { return value.replace(/\D/g, '').replace(/^(.{4})(.{2})(.*)$/, '$1.$2.$3') } +// Remove the formatting from the account number function removeFormat(value: string): string { return value.replace(/\./g, '') } diff --git a/src/views/ConfigBiometricView.vue b/src/views/ConfigBiometricView.vue index 0a6647a0a8117882470a08a5725d7d49b0151f6b..e0dd313d42fd421e9d284485ed57682b6fa8f0c3 100644 --- a/src/views/ConfigBiometricView.vue +++ b/src/views/ConfigBiometricView.vue @@ -18,6 +18,7 @@ import router from '@/router' const userStore = useUserStore() +// Function to register biometric authentication const bioRegister = async () => { await userStore.bioRegister() await router.push({ name: 'configurations1' }) diff --git a/src/views/ConfigFamiliarWithSavingsView.vue b/src/views/ConfigFamiliarWithSavingsView.vue index 5153c3ac65cedf57806206624ed5a8abee92fa02..6e98645fa47b224677569d37faf6ec766309148c 100644 --- a/src/views/ConfigFamiliarWithSavingsView.vue +++ b/src/views/ConfigFamiliarWithSavingsView.vue @@ -73,6 +73,7 @@ import SpareComponent from '@/components/SpareComponent.vue' const selectedOption = ref<string | null>(null) const userConfigStore = useUserConfigStore() +// Set experience value based on selected option const selectOption = (option: string) => { selectedOption.value = option let experienceValue = '' @@ -92,6 +93,7 @@ const selectOption = (option: string) => { userConfigStore.setExperience(experienceValue) } +// Navigate to next configuration page if option is selected const onButtonClick = () => { if (selectedOption.value) { router.push({ name: 'configurations3' }) diff --git a/src/views/ConfigHabitChangeView.vue b/src/views/ConfigHabitChangeView.vue index 937398bdc6f082b3b27344d241dc940545583432..e6b4e9b3ab3763b0535d9e74705ce5d237495178 100644 --- a/src/views/ConfigHabitChangeView.vue +++ b/src/views/ConfigHabitChangeView.vue @@ -73,6 +73,7 @@ import SpareComponent from '@/components/SpareComponent.vue' const selectedOption = ref<string | null>(null) const userConfigStore = useUserConfigStore() +// Set motivation value based on selected option const selectOption = (option: string) => { selectedOption.value = option let motivationValue = '' @@ -92,6 +93,7 @@ const selectOption = (option: string) => { userConfigStore.setMotivation(motivationValue) } +// Navigates to the next configuration view if an option is selected const onButtonClick = () => { if (selectedOption.value) { router.push({ name: 'configurations2' }) diff --git a/src/views/ConfigSpendingItemsAmountView.vue b/src/views/ConfigSpendingItemsAmountView.vue index 0b1e3e4e9280b21e52fba9d066e51a46211d195d..1a0f11a12fd6547b4849d74a677f700d4fb9cbf5 100644 --- a/src/views/ConfigSpendingItemsAmountView.vue +++ b/src/views/ConfigSpendingItemsAmountView.vue @@ -107,6 +107,7 @@ const amounts = ref(options.value.map(() => '')) const isAllAmountsFilled = computed(() => amounts.value.every((amount) => amount.trim() !== '')) +// Save the amounts to the user config store and navigate to the next page const onButtonClick = () => { options.value.forEach((option, index) => { userConfigStore.challengeConfig.challengeTypeConfigs[index].specificAmount = @@ -115,6 +116,7 @@ const onButtonClick = () => { router.push({ name: 'configurations5' }) } +// Filter the input to only allow numbers and commas const filterAmount = (index: number, event: Event) => { const input = event.target as HTMLInputElement let filteredValue = input.value.replace(/[^\d,]/g, '') @@ -122,9 +124,11 @@ const filterAmount = (index: number, event: Event) => { amounts.value[index] = filteredValue } +// Split the options into two boxes const firstBoxOptions = computed(() => options.value.slice(0, 6)) const secondBoxOptions = computed(() => (options.value.length > 6 ? options.value.slice(6) : [])) +// Show the second box if there are more than 6 options const showFirstBox = computed(() => options.value.length > 0) const showSecondBox = computed(() => options.value.length > 6) </script> diff --git a/src/views/ConfigSpendingItemsTotalAmountView.vue b/src/views/ConfigSpendingItemsTotalAmountView.vue index d3f0c9ecacfab72ab96a755663a121f6ff4ce575..048dcd6e766255d70a13aac9b0a967d8b31d0adc 100644 --- a/src/views/ConfigSpendingItemsTotalAmountView.vue +++ b/src/views/ConfigSpendingItemsTotalAmountView.vue @@ -103,6 +103,7 @@ const amounts = ref(options.value.map(() => '')) const isAllAmountsFilled = computed(() => amounts.value.every((amount) => amount.trim() !== '')) +// Update the general amount for each challenge type const onButtonClick = async () => { options.value.forEach((option, index) => { userConfigStore.challengeConfig.challengeTypeConfigs[index].generalAmount = @@ -112,6 +113,7 @@ const onButtonClick = async () => { await router.push({ name: 'configurations6' }) } +// Filter the input to only allow numbers and commas const filterAmount = (index: number, event: Event) => { const input = event.target as HTMLInputElement let filteredValue = input.value.replace(/[^\d,]/g, '') @@ -119,9 +121,11 @@ const filterAmount = (index: number, event: Event) => { amounts.value[index] = filteredValue } +// Split the options into two boxes const firstBoxOptions = computed(() => options.value.slice(0, 6)) const secondBoxOptions = computed(() => (options.value.length > 6 ? options.value.slice(6) : [])) +// Show the second box if there are more than 6 options const showFirstBox = computed(() => options.value.length > 0) const showSecondBox = computed(() => options.value.length > 6) </script> diff --git a/src/views/ConfigSpendingItemsView.vue b/src/views/ConfigSpendingItemsView.vue index f95b2915ae3600577ceb4a48eeab3e6cf8c2769f..af3d28f43cef556627963b6c55c026addde21bed 100644 --- a/src/views/ConfigSpendingItemsView.vue +++ b/src/views/ConfigSpendingItemsView.vue @@ -99,6 +99,7 @@ const userConfigStore = useUserConfigStore() const selectedOptions = ref<string[]>([]) const customOptions = ref(['', '', '', '', '', '']) +// Toggles the option in the selectedOptions array const toggleOption = (option: string) => { const index = selectedOptions.value.indexOf(option) if (index === -1) { @@ -108,12 +109,14 @@ const toggleOption = (option: string) => { } } +// Check if the form is valid const isFormValid = computed(() => { const predefinedSelected = selectedOptions.value.length > 0 const customFilled = customOptions.value.some((option) => option.trim() !== '') return predefinedSelected || customFilled }) +// Save the selected options to the store and navigate to the next page const onButtonClick = () => { if (!isFormValid.value) { console.error('Form is not valid') diff --git a/src/views/ResetPasswordView.vue b/src/views/ResetPasswordView.vue index 1558f00d20fd122a9a4dcca02795fff1b41ca803..3668894e28da92ad99bc583ddc9a42b748408e92 100644 --- a/src/views/ResetPasswordView.vue +++ b/src/views/ResetPasswordView.vue @@ -87,14 +87,16 @@ const canResetPassword = computed(() => { return isPasswordValid.value && newPassword.value === confirm.value && confirm.value !== '' }) +// Function to reset password const resetPassword = async () => { - isModalOpen.value = true + isModalOpen.value = true // Open modal + // Send request to backend to reset password try { await axios.post('http://localhost:8080/forgotPassword/resetPassword', { - resetID: resetID.value, - userID: userID.value, - newPassword: newPassword.value + resetID: resetID.value, // Reset ID + userID: userID.value, // User ID + newPassword: newPassword.value // New password }) } catch (error) { const err = error as Error @@ -102,10 +104,12 @@ const resetPassword = async () => { } } +// Function to toggle show password const toggleShowPassword = () => { - showPassword.value = !showPassword.value + showPassword.value = !showPassword.value // show password } +// Function to go to login page const goToLogin = () => { isModalOpen.value = false router.push('/logginn')