Skip to content
Snippets Groups Projects
Commit 684263c2 authored by Anders Høvik's avatar Anders Høvik
Browse files

Merge branch 'main' into feature/update-user-settings-layout

parents 161f9288 b050d1ed
No related branches found
No related tags found
1 merge request!30Feature/update user settings layout
Showing
with 836 additions and 50 deletions
spec.json 0 → 100644
{
"openapi": "3.0.1",
"info": {
"title": "Sparesti API",
"description": "The Sparesti API",
"version": "3.0"
},
"servers": [
{
"url": "http://localhost:8080",
"description": "Generated server url"
}
],
"security": [
{
"Bearer Authentication": []
}
],
"tags": [
{
"name": "Authentication",
"description": "User authentication"
},
{
"name": "Leaderboard",
"description": "Retrieving leaderboard data"
}
],
"paths": {
"/api/auth/valid-email/{email}": {
"post": {
"tags": [
"Authentication"
],
"summary": "Validate email",
"description": "Check that the given email is valid",
"operationId": "validateEmail",
"parameters": [
{
"name": "email",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"409": {
"description": "Email already exists",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/ExceptionResponse"
}
}
}
},
"200": {
"description": "Email is valid",
"content": {
"*/*": {
"schema": {
"type": "object"
}
}
}
}
},
"security": []
}
},
"/api/auth/signup": {
"post": {
"tags": [
"Authentication"
],
"summary": "User Signup",
"description": "Sign up a new user",
"operationId": "signup",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SignUpRequest"
}
}
},
"required": true
},
"responses": {
"201": {
"description": "Successfully signed up",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthenticationResponse"
}
}
}
},
"409": {
"description": "Email already exists",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ExceptionResponse"
}
}
}
}
},
"security": []
}
},
"/api/auth/login": {
"post": {
"tags": [
"Authentication"
],
"summary": "User Login",
"description": "Log in with an existing user",
"operationId": "login",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successfully logged in",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthenticationResponse"
}
}
}
},
"401": {
"description": "Invalid credentials",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ExceptionResponse"
}
}
}
},
"404": {
"description": "User not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ExceptionResponse"
}
}
}
}
},
"security": []
}
},
"/api/users": {
"patch": {
"tags": [
"user-controller"
],
"summary": "Update profile",
"description": "Update the profile of the authenticated user",
"operationId": "update",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserUpdateDTO"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successfully updated profile",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserDTO"
}
}
}
}
}
}
},
"/api/users/{userId}/profile": {
"get": {
"tags": [
"user-controller"
],
"summary": "Get profile",
"description": "Get user profile",
"operationId": "getProfile",
"parameters": [
{
"name": "userId",
"in": "path",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
}
}
],
"responses": {
"200": {
"description": "Successfully got profile",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProfileDTO"
}
}
}
}
}
}
},
"/api/users/me": {
"get": {
"tags": [
"user-controller"
],
"summary": "Get user",
"description": "Get user information",
"operationId": "getUser",
"responses": {
"200": {
"description": "Successfully got user",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserDTO"
}
}
}
}
}
}
},
"/api/leaderboard": {
"get": {
"tags": [
"Leaderboard"
],
"operationId": "getLeaderboard",
"parameters": [
{
"name": "type",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "filter",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "entryCount",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"format": "int32",
"default": 10
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LeaderboardDTO"
}
}
}
}
}
}
},
"/api/leaderboard/surrounding": {
"get": {
"tags": [
"Leaderboard"
],
"operationId": "getSurrounding",
"parameters": [
{
"name": "type",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "filter",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "entryCount",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"format": "int32",
"default": 10
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LeaderboardDTO"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"ExceptionResponse": {
"type": "object",
"properties": {
"status": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
}
}
},
"SignUpRequest": {
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"email": {
"type": "string"
},
"password": {
"type": "string"
},
"commitment": {
"type": "string"
},
"experience": {
"type": "string"
},
"challengeTypes": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"AuthenticationResponse": {
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"role": {
"type": "string"
},
"token": {
"type": "string"
}
}
},
"LoginRequest": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"password": {
"type": "string"
}
}
},
"UserUpdateDTO": {
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"email": {
"type": "string"
},
"password": {
"type": "string"
},
"commitment": {
"type": "string"
},
"experience": {
"type": "string"
},
"challengeTypes": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"UserDTO": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"email": {
"type": "string"
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"role": {
"type": "string"
}
}
},
"ProfileDTO": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"createdAt": {
"type": "string",
"format": "date-time"
}
}
},
"LeaderboardDTO": {
"type": "object",
"properties": {
"type": {
"type": "string"
},
"filter": {
"type": "string"
},
"entries": {
"type": "array",
"items": {
"$ref": "#/components/schemas/LeaderboardEntryDTO"
}
}
}
},
"LeaderboardEntryDTO": {
"type": "object",
"properties": {
"user": {
"$ref": "#/components/schemas/UserDTO"
},
"score": {
"type": "integer",
"format": "int32"
}
}
}
},
"securitySchemes": {
"Bearer Authentication": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT"
}
}
}
}
\ No newline at end of file
<script setup lang="ts"> <script setup lang="ts">
import { RouterView } from 'vue-router' import { RouterView } from 'vue-router'
import ErrorBoundaryCatcher from '@/components/Exceptions/ErrorBoundaryCatcher.vue'; // import ErrorBoundaryCatcher from '@/components/Exceptions/ErrorBoundaryCatcher.vue';
</script> </script>
<template> <template>
......
...@@ -9,7 +9,14 @@ export type { OpenAPIConfig } from './core/OpenAPI'; ...@@ -9,7 +9,14 @@ export type { OpenAPIConfig } from './core/OpenAPI';
export type { AuthenticationResponse } from './models/AuthenticationResponse'; export type { AuthenticationResponse } from './models/AuthenticationResponse';
export type { ExceptionResponse } from './models/ExceptionResponse'; export type { ExceptionResponse } from './models/ExceptionResponse';
export type { LeaderboardDTO } from './models/LeaderboardDTO';
export type { LeaderboardEntryDTO } from './models/LeaderboardEntryDTO';
export type { LoginRequest } from './models/LoginRequest'; export type { LoginRequest } from './models/LoginRequest';
export type { ProfileDTO } from './models/ProfileDTO';
export type { SignUpRequest } from './models/SignUpRequest'; export type { SignUpRequest } from './models/SignUpRequest';
export type { UserDTO } from './models/UserDTO';
export type { UserUpdateDTO } from './models/UserUpdateDTO';
export { AuthenticationService } from './services/AuthenticationService'; export { AuthenticationService } from './services/AuthenticationService';
export { LeaderboardService } from './services/LeaderboardService';
export { UserControllerService } from './services/UserControllerService';
/* generated using openapi-typescript-codegen -- do not edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { LeaderboardEntryDTO } from './LeaderboardEntryDTO';
export type LeaderboardDTO = {
type?: string;
filter?: string;
entries?: Array<LeaderboardEntryDTO>;
};
/* generated using openapi-typescript-codegen -- do not edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { UserDTO } from './UserDTO';
export type LeaderboardEntryDTO = {
user?: UserDTO;
score?: number;
};
/* generated using openapi-typescript-codegen -- do not edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type ProfileDTO = {
id?: number;
firstName?: string;
lastName?: string;
createdAt?: string;
};
...@@ -7,8 +7,8 @@ export type SignUpRequest = { ...@@ -7,8 +7,8 @@ export type SignUpRequest = {
lastName?: string; lastName?: string;
email?: string; email?: string;
password?: string; password?: string;
changeWilling?: string; commitment?: string;
experience?: string; experience?: string;
challenges?: Array<string>; challengeTypes?: Array<string>;
}; };
/* generated using openapi-typescript-codegen -- do not edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type UserDTO = {
id?: number;
firstName?: string;
lastName?: string;
email?: string;
createdAt?: string;
role?: string;
};
/* generated using openapi-typescript-codegen -- do not edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type UserUpdateDTO = {
firstName?: string;
lastName?: string;
email?: string;
password?: string;
commitment?: string;
experience?: string;
challengeTypes?: Array<string>;
};
/* generated using openapi-typescript-codegen -- do not edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { LeaderboardDTO } from '../models/LeaderboardDTO';
import type { CancelablePromise } from '../core/CancelablePromise';
import { OpenAPI } from '../core/OpenAPI';
import { request as __request } from '../core/request';
export class LeaderboardService {
/**
* @returns LeaderboardDTO OK
* @throws ApiError
*/
public static getLeaderboard({
type,
filter,
entryCount = 10,
}: {
type: string,
filter: string,
entryCount?: number,
}): CancelablePromise<LeaderboardDTO> {
return __request(OpenAPI, {
method: 'GET',
url: '/api/leaderboard',
query: {
'type': type,
'filter': filter,
'entryCount': entryCount,
},
});
}
/**
* @returns LeaderboardDTO OK
* @throws ApiError
*/
public static getSurrounding({
type,
filter,
entryCount = 10,
}: {
type: string,
filter: string,
entryCount?: number,
}): CancelablePromise<LeaderboardDTO> {
return __request(OpenAPI, {
method: 'GET',
url: '/api/leaderboard/surrounding',
query: {
'type': type,
'filter': filter,
'entryCount': entryCount,
},
});
}
}
/* generated using openapi-typescript-codegen -- do not edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { ProfileDTO } from '../models/ProfileDTO';
import type { UserDTO } from '../models/UserDTO';
import type { UserUpdateDTO } from '../models/UserUpdateDTO';
import type { CancelablePromise } from '../core/CancelablePromise';
import { OpenAPI } from '../core/OpenAPI';
import { request as __request } from '../core/request';
export class UserControllerService {
/**
* Update profile
* Update the profile of the authenticated user
* @returns UserDTO Successfully updated profile
* @throws ApiError
*/
public static update({
requestBody,
}: {
requestBody: UserUpdateDTO,
}): CancelablePromise<UserDTO> {
return __request(OpenAPI, {
method: 'PATCH',
url: '/api/users',
body: requestBody,
mediaType: 'application/json',
});
}
/**
* Get profile
* Get user profile
* @returns ProfileDTO Successfully got profile
* @throws ApiError
*/
public static getProfile({
userId,
}: {
userId: number,
}): CancelablePromise<ProfileDTO> {
return __request(OpenAPI, {
method: 'GET',
url: '/api/users/{userId}/profile',
path: {
'userId': userId,
},
});
}
/**
* Get user
* Get user information
* @returns UserDTO Successfully got user
* @throws ApiError
*/
public static getUser(): CancelablePromise<UserDTO> {
return __request(OpenAPI, {
method: 'GET',
url: '/api/users/me',
});
}
}
...@@ -22,6 +22,7 @@ const onChangedChallengeEvent = (value) => { ...@@ -22,6 +22,7 @@ const onChangedChallengeEvent = (value) => {
console.log('Reached') console.log('Reached')
chosenChallenges.value = chosenChallenges.value.filter(item => item !== value[0]); chosenChallenges.value = chosenChallenges.value.filter(item => item !== value[0]);
} }
console.log(chosenChallenges.value)
} }
const onClick = () => { const onClick = () => {
......
...@@ -22,10 +22,6 @@ const props = defineProps({ ...@@ -22,10 +22,6 @@ const props = defineProps({
type: String, type: String,
default: "" default: ""
}, },
isValid: {
type: Boolean,
default: false
},
min: { min: {
type: String, type: String,
required: false required: false
...@@ -33,6 +29,14 @@ const props = defineProps({ ...@@ -33,6 +29,14 @@ const props = defineProps({
pattern: { pattern: {
type: String, type: String,
default: null default: null
},
validMessage: {
type: String,
default: ''
},
invalidMessage: {
type: String,
default: ''
} }
}); });
...@@ -44,17 +48,16 @@ const onInputEvent = (event: any) => { ...@@ -44,17 +48,16 @@ const onInputEvent = (event: any) => {
<template> <template>
<div> <div>
<label :for="inputId">{{ label }}</label> <label :for="inputId">{{ label }}</label>
<input :value="props.modelValue" <input :value="modelValue"
@input="onInputEvent" @input="onInputEvent"
:type="props.type" :type="type"
class="form-control" class="form-control"
:placeholder="props.placeholder" :placeholder="placeholder"
:id="inputId" required :id="inputId" required
:min="min" :min="min"
:pattern="pattern" :pattern="pattern"/>
/> <div class="valid-feedback">{{ validMessage }}</div>
<div v-if="props.isValid" class="invalid-feedback">Invalid {{ label }}</div> <div class="invalid-feedback">{{ invalidMessage }}</div>
<div v-else class="valid-feedback">Valid {{ label }}</div>
</div> </div>
</template> </template>
......
...@@ -8,8 +8,8 @@ import { useRouter, useRoute } from 'vue-router'; ...@@ -8,8 +8,8 @@ import { useRouter, useRoute } from 'vue-router';
import handleUnknownError from '@/components/Exceptions/unkownErrorHandler'; import handleUnknownError from '@/components/Exceptions/unkownErrorHandler';
import { useErrorStore } from '@/stores/ErrorStore'; import { useErrorStore } from '@/stores/ErrorStore';
const emailRef = ref() const emailRef = ref('')
const passwordRef = ref() const passwordRef = ref('')
const formRef = ref() const formRef = ref()
let errorMsg = ref(''); let errorMsg = ref('');
...@@ -19,13 +19,18 @@ const userStore = useUserInfoStore(); ...@@ -19,13 +19,18 @@ const userStore = useUserInfoStore();
const handleEmailInputEvent = (newValue: any) => { const handleEmailInputEvent = (newValue: any) => {
emailRef.value = newValue emailRef.value = newValue
console.log(emailRef.value)
} }
const handlePasswordInputEvent = (newValue: any) => { const handlePasswordInputEvent = (newValue: any) => {
passwordRef.value = newValue passwordRef.value = newValue
console.log(passwordRef.value)
} }
const handleSubmit = async () => { const handleSubmit = async () => {
console.log(emailRef.value)
console.log(passwordRef.value)
formRef.value.classList.add("was-validated") formRef.value.classList.add("was-validated")
const loginUserPayload: LoginRequest = { const loginUserPayload: LoginRequest = {
email: emailRef.value, email: emailRef.value,
...@@ -64,11 +69,30 @@ const handleSubmit = async () => { ...@@ -64,11 +69,30 @@ const handleSubmit = async () => {
<h1>Sparesti.no</h1> <h1>Sparesti.no</h1>
</div> </div>
<form ref="formRef" id="loginForm" @submit.prevent="handleSubmit" novalidate> <form ref="formRef" id="loginForm" @submit.prevent="handleSubmit" novalidate>
<BaseInput :model-value="emailRef" @input-change-event="handleEmailInputEvent" id="emailInput" input-id="email"
type="email" label="Email" placeholder="Enter your email" /> <BaseInput :model-value="emailRef"
<BaseInput pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}" :model-value="passwordRef" @input-change-event="handleEmailInputEvent"
@input-change-event="handlePasswordInputEvent" id="passwordInput" input-id="password" type="password" id="emailInput"
label="Password" placeholder="Enter password" /> input-id="email"
type="email"
label="Email"
placeholder="Enter your email"
valid-message="Valid email"
invalid-message="Invalid email"
/>
<BaseInput :model-value="passwordRef"
@input-change-event="handlePasswordInputEvent"
id="passwordInput"
input-id="password"
type="password"
pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}"
label="Password"
placeholder="Enter password"
valid-message="Valid password"
invalid-message="Password must be between 4 and 16 characters and contain one capital letter, small letter and a number"
/>
<p class="text-danger">{{ errorMsg }}</p> <p class="text-danger">{{ errorMsg }}</p>
<button1 id="confirmButton" type="submit" @click="handleSubmit" button-text="Login"></button1> <button1 id="confirmButton" type="submit" @click="handleSubmit" button-text="Login"></button1>
</form> </form>
......
...@@ -36,7 +36,7 @@ export default { ...@@ -36,7 +36,7 @@ export default {
</script> </script>
<template> <template>
<div class="container"> <div class="cont">
<div class="row"> <div class="row">
<div class="col-lg-4 blue-background overflow-auto" :style="{ 'max-height': bluePanelMaxHeight }"> <div class="col-lg-4 blue-background overflow-auto" :style="{ 'max-height': bluePanelMaxHeight }">
<h3 style="color: white; margin-bottom: 16px">Your saving goals</h3> <h3 style="color: white; margin-bottom: 16px">Your saving goals</h3>
...@@ -53,9 +53,10 @@ export default { ...@@ -53,9 +53,10 @@ export default {
</template> </template>
<style scoped> <style scoped>
.container { .cont {
padding-left: 10px;
margin: 0; margin: 0;
width: 100%; width: 98%;
box-sizing: unset; box-sizing: unset;
} }
......
...@@ -4,6 +4,7 @@ interface Step { ...@@ -4,6 +4,7 @@ interface Step {
showPanel: boolean; showPanel: boolean;
description: string; description: string;
percentFinished: number; percentFinished: number;
unFinished: boolean;
} }
export default { export default {
data() { data() {
...@@ -13,18 +14,28 @@ export default { ...@@ -13,18 +14,28 @@ export default {
title: 'Spain trip' as string, title: 'Spain trip' as string,
//This will be changed to info gathered from backend //This will be changed to info gathered from backend
steps: [ steps: [
{ title: 'Challenge 1', showPanel: false, description: 'Save 50kr on coffee in 3 days', percentFinished: 22 }, { title: 'Challenge 1', showPanel: false, description: 'Save 50kr on coffee in 3 days', percentFinished: 22, unFinished: false },
{ title: 'Challenge 2', showPanel: false, description: 'Save 500kr on food in 7 days', percentFinished: 73 }, { title: 'Challenge 2', showPanel: false, description: 'Save 500kr on food in 7 days', percentFinished: 73, unFinished: false },
{ title: 'Challenge 3', showPanel: false, description: 'Save 350kr on clothes in 5 days', percentFinished: 50 }, { title: 'Challenge 3', showPanel: false, description: 'Save 350kr on clothes in 5 days', percentFinished: 50, unFinished: true },
{ title: 'Challenge 4', showPanel: false, description: 'Save 150kr on coffee in 4 days', percentFinished: 10 }, { title: 'Challenge 4', showPanel: false, description: 'Save 150kr on coffee in 4 days', percentFinished: 10, unFinished: true },
{ title: 'Challenge 5', showPanel: false, description: 'Save 50kr on coffee in 3 days', percentFinished: 90 } { title: 'Challenge 5', showPanel: false, description: 'Save 50kr on coffee in 3 days', percentFinished: 90, unFinished: true }
] ]
, ,
bluePanelMaxHeight: 'auto' as string bluePanelMaxHeight: 'auto' as string
}; };
}, },
mounted() { mounted() {
this.togglePanel(this.steps[2]); setTimeout(() => {
this.togglePanel(this.steps[2]);
}, 500);
},
computed: {
computeImageFilter() {
return (step: Step) => {
return step.unFinished ? 'none' : 'grayscale(100%)';
};
}
}, },
methods: { methods: {
togglePanel(step: Step) { togglePanel(step: Step) {
...@@ -40,12 +51,8 @@ export default { ...@@ -40,12 +51,8 @@ export default {
if (step.showPanel) { if (step.showPanel) {
this.$nextTick(() => { this.$nextTick(() => {
const panel = document.getElementById(`panel-${this.steps.indexOf(step)}`); const panel = document.getElementById(`panel-${this.steps.indexOf(step)}`);
console.log(panel);
if (panel) { if (panel) {
setTimeout(() => { panel.scrollIntoView({ behavior: 'smooth', block: 'center' });
panel.scrollIntoView({ behavior: 'smooth', block: 'center' });
console.log('I should have scrolled');
}, 100); // Wait for 1 second before scrolling
} }
}); });
} }
...@@ -56,11 +63,24 @@ export default { ...@@ -56,11 +63,24 @@ export default {
<template> <template>
<div class="col-lg-8"> <div class="col-lg-8">
<div class="SavingGoalTitle text-center">{{title}}</div> <div class="SavingGoalTitle text-center">
{{title}}
<br>
<p class="d-inline-flex gap-1">
<button class="btn btn-primary" type="button" data-bs-toggle="collapse" data-bs-target="#collapseExample" aria-expanded="false" aria-controls="collapseExample" style="font-size: 25px;">
See more info
</button>
</p>
<div class="collapse" id="collapseExample">
<div class="card card-body bg-primary mx-auto" style="width: 80%;">
Total saved: 20kr
</div>
</div>
</div>
<ul class="timeline"> <ul class="timeline">
<li v-for="(step, index) in steps" :key="index" :class="{ 'timeline-inverted': index % 2 !== 0 }"> <li v-for="(step, index) in steps" :key="index" :class="{ 'timeline-inverted': index % 2 !== 0 }">
<div class="timeline-image z-1" @click="togglePanel(step)"> <div class="timeline-image z-1" @click="togglePanel(step)">
<img class="circular-image" :src="step.showPanel ? altImage : image" alt=""> <img class="circular-image" :src="step.showPanel ? altImage : image" :style="{ filter: computeImageFilter(step) }" alt="">
</div> </div>
<div class="timeline-panel z-3" :id="'panel-' + index" v-show="step.showPanel"> <div class="timeline-panel z-3" :id="'panel-' + index" v-show="step.showPanel">
<div class="timeline-heading"> <div class="timeline-heading">
...@@ -95,9 +115,8 @@ export default { ...@@ -95,9 +115,8 @@ export default {
<style scoped> <style scoped>
.col-lg-8 { .col-lg-8 {
width: 63%; width: 58%;
margin-bottom: 20px; margin-bottom: 20px;
max-height: 1000px;
} }
.SavingGoalTitle { .SavingGoalTitle {
......
...@@ -5,15 +5,18 @@ import { ref } from 'vue' ...@@ -5,15 +5,18 @@ import { ref } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
const router = useRouter(); const router = useRouter();
const firstNameRef = ref('') const firstNameRef = ref('')
const surnameRef = ref('') const surnameRef = ref('')
const emailRef = ref('') const emailRef = ref('')
const passwordRef = ref('') const passwordRef = ref('')
const confirmPasswordRef = ref('') const confirmPasswordRef = ref('')
const formRef = ref() const formRef = ref()
let samePasswords = ref(true)
const handleFirstNameInputEvent = (newValue: any) => { const handleFirstNameInputEvent = (newValue: any) => {
firstNameRef.value = newValue firstNameRef.value = newValue
console.log(firstNameRef.value)
} }
const handleSurnameInputEvent = (newValue: any) => { const handleSurnameInputEvent = (newValue: any) => {
...@@ -26,21 +29,30 @@ const handleEmailInputEvent = (newValue: any) => { ...@@ -26,21 +29,30 @@ const handleEmailInputEvent = (newValue: any) => {
const handlePasswordInputEvent = (newValue: any) => { const handlePasswordInputEvent = (newValue: any) => {
passwordRef.value = newValue passwordRef.value = newValue
console.log(passwordRef.value)
} }
const handleConfirmPasswordInputEvent = (newValue: any) => { const handleConfirmPasswordInputEvent = (newValue: any) => {
confirmPasswordRef.value = newValue confirmPasswordRef.value = newValue
console.log(confirmPasswordRef.value)
} }
const handleSubmit = () => { const handleSubmit = async () => {
console.log(firstNameRef.value)
samePasswords.value = (passwordRef.value === confirmPasswordRef.value)
console.log(samePasswords.value)
const form = formRef.value; const form = formRef.value;
// Check if the form is valid // Check if the form is valid
if (form.checkValidity()) { if (form.checkValidity()) {
// Form is valid, submit the form or perform other actions // Form is valid, submit the form or perform other actions
console.log('Form is valid'); console.log('Form is valid');
} else {
console.log('Form is not valid');
} }
formRef.value.classList.add("was-validated") formRef.value.classList.add("was-validated")
} }
...@@ -49,46 +61,54 @@ const handleSubmit = () => { ...@@ -49,46 +61,54 @@ const handleSubmit = () => {
<template> <template>
<div class="container"> <div class="container">
<form ref="formRef" id="signUpForm" @submit.prevent="handleSubmit"> <form ref="formRef" id="signUpForm" @submit.prevent="handleSubmit">
<BaseInput :model-value="firstNameRef.value" <BaseInput :model-value="firstNameRef"
@input-change-event="handleFirstNameInputEvent" @input-change-event="handleFirstNameInputEvent"
ref="firstNameRef" ref="firstNameRef"
id="firstNameInput" id="firstNameInput"
input-id="first-name" input-id="first-name"
type="text" type="text"
label="First name" label="First name"
placeholder="Enter your first name"/> placeholder="Enter your first name"
<BaseInput :model-value="surnameRef.value" invalid-message="Please enter your first name"/>
<BaseInput :model-value="surnameRef"
@input-change-event="handleSurnameInputEvent" @input-change-event="handleSurnameInputEvent"
ref="surnameRef" ref="surnameRef"
id="surnameInput" id="surnameInput"
input-id="surname" input-id="surname"
type="text" type="text"
label="Surname" label="Surname"
placeholder="Enter your surname"/> placeholder="Enter your surname"
<BaseInput :model-value="emailRef.value" invalid-message="Please enter your surname"/>
<BaseInput :model-value="emailRef"
@input-change-event="handleEmailInputEvent" @input-change-event="handleEmailInputEvent"
ref="emailRef" ref="emailRef"
id="emailInput" id="emailInput"
input-id="email" input-id="email"
type="email" type="email"
label="Email" label="Email"
placeholder="Enter your email"/> placeholder="Enter your email"
<BaseInput :model-value="passwordRef.value" invalid-message="Invalid email"/>
<BaseInput :model-value="passwordRef"
@input-change-event="handlePasswordInputEvent" @input-change-event="handlePasswordInputEvent"
ref="passwordRef" ref="passwordRef"
id="passwordInput" id="passwordInput"
input-id="password" input-id="password"
type="password" type="password"
pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}"
label="Password" label="Password"
placeholder="Enter password"/> placeholder="Enter password"
<BaseInput :model-value="confirmPasswordRef.value" 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" @input-change-event="handleConfirmPasswordInputEvent"
ref="confirmPasswordRef" ref="confirmPasswordRef"
id="confirmPasswordInput" id="confirmPasswordInput"
input-id="confirmPassword" input-id="confirmPassword"
type="password" type="password"
pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}"
label="Confirm Password" label="Confirm Password"
placeholder="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>
<button1 id="confirmButton" @click="handleSubmit" button-text="Sign up"></button1> <button1 id="confirmButton" @click="handleSubmit" button-text="Sign up"></button1>
</form> </form>
</div> </div>
......
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