feat: enhance onboarding process with email handling and verification UI
This commit is contained in:
parent
aacbad3357
commit
bfdb76cabe
11
frontend/src/app/model/onboarding.ts
Normal file
11
frontend/src/app/model/onboarding.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import {verify_email} from "./util";
|
||||||
|
|
||||||
|
export interface Onboarding {
|
||||||
|
notifications: boolean;
|
||||||
|
mail: string;
|
||||||
|
verified: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function verify_onboarding(state: Onboarding): boolean {
|
||||||
|
return state.verified && verify_email(state.mail);
|
||||||
|
}
|
@ -14,6 +14,10 @@ img {
|
|||||||
padding: 0 1.5rem;
|
padding: 0 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content > p {
|
||||||
|
font-size: 1.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
.button-container {
|
.button-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -2,6 +2,7 @@ import {Component} from '@angular/core';
|
|||||||
import {RouterLink} from "@angular/router";
|
import {RouterLink} from "@angular/router";
|
||||||
import {TextButtonComponent} from "../../../atomic/text-button/text-button.component";
|
import {TextButtonComponent} from "../../../atomic/text-button/text-button.component";
|
||||||
import {TextLinkComponent} from "../../../atomic/text-link/text-link.component";
|
import {TextLinkComponent} from "../../../atomic/text-link/text-link.component";
|
||||||
|
import {Onboarding} from "../../../model/onboarding";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-notification',
|
selector: 'app-notification',
|
||||||
@ -15,10 +16,34 @@ import {TextLinkComponent} from "../../../atomic/text-link/text-link.component";
|
|||||||
})
|
})
|
||||||
export class NotificationComponent {
|
export class NotificationComponent {
|
||||||
enable_notifications() {
|
enable_notifications() {
|
||||||
localStorage.setItem('get_notifications', 'true');
|
let onboarding_raw = localStorage.getItem('onboarding');
|
||||||
|
let onboarding: Onboarding;
|
||||||
|
if (!onboarding_raw) {
|
||||||
|
onboarding = {
|
||||||
|
notifications: true,
|
||||||
|
mail: '',
|
||||||
|
verified: false
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
onboarding = JSON.parse(onboarding_raw);
|
||||||
|
onboarding.notifications = true;
|
||||||
|
}
|
||||||
|
localStorage.setItem('onboarding', JSON.stringify(onboarding));
|
||||||
}
|
}
|
||||||
|
|
||||||
disable_notifications() {
|
disable_notifications() {
|
||||||
localStorage.setItem('get_notifications', 'false');
|
let onboarding_raw = localStorage.getItem('onboarding');
|
||||||
|
let onboarding: Onboarding;
|
||||||
|
if (!onboarding_raw) {
|
||||||
|
onboarding = {
|
||||||
|
notifications: false,
|
||||||
|
mail: '',
|
||||||
|
verified: false
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
onboarding = JSON.parse(onboarding_raw);
|
||||||
|
onboarding.notifications = false;
|
||||||
|
}
|
||||||
|
localStorage.setItem('onboarding', JSON.stringify(onboarding));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,9 @@
|
|||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 1.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
<atomic-email-field [(value)]="mail"></atomic-email-field>
|
<atomic-email-field [(value)]="mail"></atomic-email-field>
|
||||||
</div>
|
</div>
|
||||||
<div class="button-container">
|
<div class="button-container">
|
||||||
<atomic-text-button [text]="'Weiter'"
|
<atomic-text-button (click)="set_mail()" [disabled]="!verify_mail()" [text]="'Weiter'">
|
||||||
[routerLink]="'/onboarding/verification'"></atomic-text-button>
|
</atomic-text-button>
|
||||||
<atomic-text-link [text]="'Stattdessen anmelden'" [routerLink]="'/login'"></atomic-text-link>
|
<atomic-text-link [text]="'Stattdessen anmelden'" [routerLink]="'/login'"></atomic-text-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -1,8 +1,10 @@
|
|||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
import {EmailFieldComponent} from "../../../atomic/input/email-field/email-field.component";
|
import {EmailFieldComponent} from "../../../atomic/input/email-field/email-field.component";
|
||||||
import {TextLinkComponent} from "../../../atomic/text-link/text-link.component";
|
import {TextLinkComponent} from "../../../atomic/text-link/text-link.component";
|
||||||
import {RouterLink} from "@angular/router";
|
import {Router, RouterLink} from "@angular/router";
|
||||||
import {TextButtonComponent} from "../../../atomic/text-button/text-button.component";
|
import {TextButtonComponent} from "../../../atomic/text-button/text-button.component";
|
||||||
|
import {Onboarding} from "../../../model/onboarding";
|
||||||
|
import {verify_email} from "../../../model/util";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-registration',
|
selector: 'app-registration',
|
||||||
@ -16,5 +18,46 @@ import {TextButtonComponent} from "../../../atomic/text-button/text-button.compo
|
|||||||
styleUrl: './registration.component.css'
|
styleUrl: './registration.component.css'
|
||||||
})
|
})
|
||||||
export class RegistrationComponent {
|
export class RegistrationComponent {
|
||||||
mail?: string;
|
mail: string = '';
|
||||||
|
|
||||||
|
constructor(private router: Router) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
let onboarding_raw = localStorage.getItem('onboarding');
|
||||||
|
if (onboarding_raw) {
|
||||||
|
let onboarding: Onboarding = JSON.parse(onboarding_raw);
|
||||||
|
this.mail = onboarding.mail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_mail() {
|
||||||
|
return verify_email(this.mail);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_mail() {
|
||||||
|
if (!this.mail || !this.verify_mail()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let onboarding_raw = localStorage.getItem('onboarding');
|
||||||
|
let onboarding: Onboarding;
|
||||||
|
if (!onboarding_raw) {
|
||||||
|
onboarding = {
|
||||||
|
notifications: false,
|
||||||
|
mail: this.mail,
|
||||||
|
verified: false
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
onboarding = JSON.parse(onboarding_raw);
|
||||||
|
if (onboarding.mail === this.mail) {
|
||||||
|
this.router.navigateByUrl('/onboarding/verification').then(_ => {
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onboarding.mail = this.mail;
|
||||||
|
}
|
||||||
|
localStorage.setItem('onboarding', JSON.stringify(onboarding));
|
||||||
|
this.router.navigateByUrl('/onboarding/verification').then(_ => {
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
.back-button-container {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
justify-content: center;
|
||||||
|
justify-items: center;
|
||||||
|
height: 85vh;
|
||||||
|
row-gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 25rem;
|
||||||
|
text-align: start;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
margin-left: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container > p {
|
||||||
|
line-height: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container > p:nth-last-child(2) {
|
||||||
|
margin-top: 3rem;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
column-gap: 1.3rem;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic-text-button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-container > atomic-text-link {
|
||||||
|
font-size: 1.3rem;
|
||||||
|
}
|
@ -1 +1,19 @@
|
|||||||
<p>verification works!</p>
|
<div class="back-button-container">
|
||||||
|
<atomic-text-link [routerLink]="'/onboarding/registration'" [text]="'< Zurück'"
|
||||||
|
id="back-button"></atomic-text-link>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<h1>Verifizieren</h1>
|
||||||
|
<div class="form-container">
|
||||||
|
<p>Wir haben dir eine E-Mail geschickt.</p>
|
||||||
|
<p>Bitte verifiziere deine E-Mail Adresse.</p>
|
||||||
|
<p>Dann geht es hier
|
||||||
|
<i>automatisch</i>
|
||||||
|
weiter.
|
||||||
|
</p>
|
||||||
|
<div class="button-container">
|
||||||
|
<p>Noch keine E-Mail erhalten? Auch im Spam Ordner nicht?</p>
|
||||||
|
<atomic-text-link (click)="tbd()" [text]="'Erneut senden'"></atomic-text-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -1,11 +1,19 @@
|
|||||||
import { Component } from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
|
import {TextLinkComponent} from "../../../atomic/text-link/text-link.component";
|
||||||
|
import {RouterLink} from "@angular/router";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-verification',
|
selector: 'app-verification',
|
||||||
imports: [],
|
imports: [
|
||||||
templateUrl: './verification.component.html',
|
TextLinkComponent,
|
||||||
styleUrl: './verification.component.css'
|
RouterLink
|
||||||
|
],
|
||||||
|
templateUrl: './verification.component.html',
|
||||||
|
styleUrl: './verification.component.css'
|
||||||
})
|
})
|
||||||
export class VerificationComponent {
|
export class VerificationComponent {
|
||||||
|
// TODO: Implement the E-Mail verification re-send logic
|
||||||
|
tbd() {
|
||||||
|
alert('E-Mail sent message - TBD');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user