diff --git a/src/app/modules/profile/profile-info/profile-info.component.html b/src/app/modules/profile/profile-info/profile-info.component.html index fb6f56f3e7d8b8f96a824ec07901bd85be1499ea..b55befbc7088dd112f3f68c5e8916e7bde8c325d 100644 --- a/src/app/modules/profile/profile-info/profile-info.component.html +++ b/src/app/modules/profile/profile-info/profile-info.component.html @@ -5,35 +5,41 @@ <div class="container"> <div class="grid-profile"> <div class="profile_info"> - <img src="https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_1280.png" - alt="profile picture"> + <img + src="https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_1280.png" + alt="profile picture" + /> <h3>User Name</h3> </div> - <hr> + <hr /> <div class="profile_stats"> - <img src="https://img.uxcel.com/tags/key-performance-indicator-kpi-1698250709411-2x.jpg" - alt="stats"> + <img + src="https://img.uxcel.com/tags/key-performance-indicator-kpi-1698250709411-2x.jpg" + alt="stats" + /> </div> </div> </div> - - <h3>Your quizzes</h3> - <div class="grid"> - <!-- <form [formGroup]="form" (ngSubmit)="submitForm()"> --> - <form> - <div class="form-group"> - <input type="text" class="inputRecherche" placeholder="Search a quiz..." - formControlName="quizName" /> - </div> - </form> - <div class="container"> - <div class="scrollable-list"> - <app-quiz-list [quizList]="quizList"></app-quiz-list> - </div> - <div class="new-quiz"> - <button class="blueButton" (click)="newQuiz()">Create a new quiz</button> + <app-sign *ngIf="!isLogged"></app-sign> + <div *ngIf="isLogged"> + <h3>Your quizzes</h3> + <div class="grid"> + <!-- <form [formGroup]="form" (ngSubmit)="submitForm()"> --> + <form> + <div class="form-group"> + <input type="text" class="inputRecherche" placeholder="Search a quiz..." + formControlName="quizName" /> + </div> + </form> + <div class="container"> + <div class="scrollable-list"> + <app-quiz-list [quizList]="quizList"></app-quiz-list> + </div> + <div class="new-quiz"> + <button class="blueButton" (click)="newQuiz()">Create a new quiz</button> + </div> </div> </div> </div> </div> -</div> \ No newline at end of file +</div> diff --git a/src/app/modules/profile/profile-info/profile-info.component.ts b/src/app/modules/profile/profile-info/profile-info.component.ts index c7d2854bf84c194cfe8b723813ba6fbdfee82f09..851e21509d01e98edab3cc9baeb7ddd3814e37eb 100644 --- a/src/app/modules/profile/profile-info/profile-info.component.ts +++ b/src/app/modules/profile/profile-info/profile-info.component.ts @@ -1,42 +1,42 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; - - +import { CookieService } from '../../../services/cookie.service'; +import { UserService } from '../../../services/user.service'; @Component({ - selector: 'app-profile-info', - templateUrl: './profile-info.component.html', - styleUrl: './profile-info.component.css' + selector: 'app-profile-info', + templateUrl: './profile-info.component.html', + styleUrl: './profile-info.component.css', }) -export class ProfileInfoComponent { - quizList: any[] = []; - constructor( - private router: Router - ) { } - - ngOnInit(): void { - this.quizList = [ - { title: 'Quiz 1', content: 'Quiz 1 Content' }, - { title: 'Quiz 2', content: 'Quiz 2 Content' }, - { title: 'Quiz 3', content: 'Quiz 3 Content' }, - { title: 'Quiz 4', content: 'Quiz 4 Content' }, - { title: 'Quiz 5', content: 'Quiz 5 Content' }, - { title: 'Quiz 6', content: 'Quiz 6 Content' }, - { title: 'Quiz 7', content: 'Quiz 7 Content' }, - { title: 'Quiz 8', content: 'Quiz 8 Content' }, - { title: 'Quiz 9', content: 'Quiz 9 Content' }, - { title: 'Quiz 10', content: 'Quiz 10 Content' }, - { title: 'Quiz 11', content: 'Quiz 11 Content' }, - { title: 'Quiz 12', content: 'Quiz 12 Content' }, - { title: 'Quiz 13', content: 'Quiz 13 Content' }, - { title: 'Quiz 14', content: 'Quiz 14 Content' }, - { title: 'Quiz 15', content: 'Quiz 15 Content' } - ]; - } +export class ProfileInfoComponent implements OnInit { + quizList: any[] = []; + isLogged: boolean = false; + constructor(private router: Router, private cookieService: CookieService, private userSerivce: UserService) {} - newQuiz() { - console.log('Create new quiz'); - this.router.navigate(['profile/create-custom-quiz']); - } + ngOnInit(): void { + this.quizList = [ + { title: 'Quiz 1', content: 'Quiz 1 Content' }, + { title: 'Quiz 2', content: 'Quiz 2 Content' }, + { title: 'Quiz 3', content: 'Quiz 3 Content' }, + { title: 'Quiz 4', content: 'Quiz 4 Content' }, + { title: 'Quiz 5', content: 'Quiz 5 Content' }, + { title: 'Quiz 6', content: 'Quiz 6 Content' }, + { title: 'Quiz 7', content: 'Quiz 7 Content' }, + { title: 'Quiz 8', content: 'Quiz 8 Content' }, + { title: 'Quiz 9', content: 'Quiz 9 Content' }, + { title: 'Quiz 10', content: 'Quiz 10 Content' }, + { title: 'Quiz 11', content: 'Quiz 11 Content' }, + { title: 'Quiz 12', content: 'Quiz 12 Content' }, + { title: 'Quiz 13', content: 'Quiz 13 Content' }, + { title: 'Quiz 14', content: 'Quiz 14 Content' }, + { title: 'Quiz 15', content: 'Quiz 15 Content' }, + ]; + this.userSerivce.getMe().subscribe((data) => { + this.isLogged = true; + }); + } + newQuiz() { + this.router.navigate(['/create-custom-quiz']); + } } diff --git a/src/app/modules/profile/profile.module.ts b/src/app/modules/profile/profile.module.ts index e34bddb998c98733dbf24a4c833f999416c0d60e..1f1b7cfe44b4c287a42a600461487f15509bdac4 100644 --- a/src/app/modules/profile/profile.module.ts +++ b/src/app/modules/profile/profile.module.ts @@ -6,9 +6,10 @@ import { CreateCustomQuizComponent } from './create-custom-quiz/create-custom-qu import { ReactiveFormsModule } from '@angular/forms'; import { MatIconModule } from '@angular/material/icon'; import { SharedModule } from '../../shared/shared.module'; +import { SignComponent } from './sign/sign.component'; @NgModule({ - declarations: [ProfileQuizListComponent, ProfileInfoComponent, CreateCustomQuizComponent], + declarations: [ProfileQuizListComponent, ProfileInfoComponent, CreateCustomQuizComponent, SignComponent], imports: [CommonModule, ReactiveFormsModule, MatIconModule, SharedModule], }) -export class ProfileModule { } +export class ProfileModule {} diff --git a/src/app/modules/profile/sign/sign.component.css b/src/app/modules/profile/sign/sign.component.css new file mode 100644 index 0000000000000000000000000000000000000000..9528daa3e02a56b191062d3b7f158ef8c7ac88b6 --- /dev/null +++ b/src/app/modules/profile/sign/sign.component.css @@ -0,0 +1,38 @@ +.button-header { + background-color: #ffffff; + border-radius: 10px; + width: 80%; + height: 10%; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; + padding: 1rem; +} + +.button-header > button { + background: none; + border: none; + height: 80%; + width: 100%; + padding: 10px 20px; + font-size: 16px; + cursor: pointer; + border-bottom: 3px solid #b9b9b9; + color: #b9b9b9; +} + +.button-header > button:hover { + border-bottom-color: #2b73fe; + color: #2b73fe; +} + +.login-signup-button { + height: 100%; + width: 80%; +} + +.wrong { + color: red; + font-size: 12px; + margin-top: 5px; +} diff --git a/src/app/modules/profile/sign/sign.component.html b/src/app/modules/profile/sign/sign.component.html new file mode 100644 index 0000000000000000000000000000000000000000..9db6a8ae4b95ff8acce1630a32f36252c965d99b --- /dev/null +++ b/src/app/modules/profile/sign/sign.component.html @@ -0,0 +1,38 @@ +<p>sign works!</p> +<div class="button-header"> + <button (click)="showLogin()">LOGIN</button> + <button (click)="showSignup()">SIGNUP</button> +</div> +<div class="content"> + <form [formGroup]="formGroup"> + <input + formControlName="email" + placeholder="EMAIL" + (blur)="checkValidity('email')" + [ngClass]="{ wrong: !formGroup.get('email')?.valid && formGroup.get('email')?.touched }" + /> + <input + formControlName="password" + placeholder="PASSWORD" + (blur)="checkValidity('password')" + [ngClass]="{ wrong: !formGroup.get('password')?.valid && formGroup.get('password')?.touched }" + /> + <input + formControlName="confirm_password" + placeholder="CONFIRM PASSWORD" + *ngIf="signup" + (blur)="checkValidity('confirm_password')" + [ngClass]="{ + wrong: + formGroup.get('confirm_password')?.errors?.['missMatch'] && formGroup.get('confirm_password')?.touched + }" + /> + </form> + <button + [disabled]="!formGroup.valid || (signup && formGroup.get('confirm_password')?.errors?.['missMatch'])" + (click)="submit()" + [ngClass]="{ valid: formGroup.valid }" + > + @if (login) { LOGIN } @else { SIGNUP } + </button> +</div> diff --git a/src/app/modules/profile/sign/sign.component.ts b/src/app/modules/profile/sign/sign.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..4cc90eb955c94b6e7d1f72bd006b41af33a3ef0b --- /dev/null +++ b/src/app/modules/profile/sign/sign.component.ts @@ -0,0 +1,112 @@ +import { Component, OnInit } from '@angular/core'; +import { AbstractControl, FormBuilder, FormGroup, ValidationErrors, ValidatorFn, Validators } from '@angular/forms'; +import { UserService } from '../../../services/user.service'; +import { Router } from '@angular/router'; +import Swal from 'sweetalert2'; + +@Component({ + selector: 'app-sign', + templateUrl: './sign.component.html', + styleUrl: './sign.component.css', +}) +export class SignComponent implements OnInit { + constructor(private fb: FormBuilder, private userService: UserService, private router: Router) {} + formGroup: FormGroup = new FormGroup({}); + login: boolean = true; + signup: boolean = false; + ngOnInit(): void { + this.formGroup = new FormGroup( + { + email: this.fb.control(null, [Validators.required]), + password: this.fb.control(null, [Validators.required, Validators.minLength(8)]), + confirm_password: this.fb.control(''), + }, + { validators: this.passwordMatchValidator() } + ); + } + + passwordMatchValidator(): ValidatorFn { + return (control: AbstractControl): ValidationErrors | null => { + if (!this.signup) { + return null; + } + const password = control.get('password')?.value; + const confirmPassword = control.get('confirm_password')?.value; + + if (password !== confirmPassword) { + control.get('confirm_password')?.setErrors({ missMatch: true }); + return { missMatch: true }; + } + control.get('confirm_password')?.setErrors(null); + return null; + }; + } + + showLogin() { + this.formGroup.get('confirm_password')?.clearValidators(); + this.formGroup.get('email')?.clearValidators(); + this.formGroup.get('email')?.addValidators([Validators.required]); + this.formGroup.reset(); + this.login = true; + this.signup = false; + } + + showSignup() { + this.formGroup + .get('confirm_password') + ?.addValidators([Validators.required, Validators.minLength(8), this.passwordValidators]); + this.formGroup.get('email')?.addValidators([Validators.required, Validators.email]); + this.formGroup.reset(); + this.login = false; + this.signup = true; + } + + passwordValidators(formArray: AbstractControl): ValidationErrors | null { + const samePassword = formArray.get('password')?.value === formArray.get('confirm_password')?.value; + return { samePassword: samePassword }; + } + + submit() { + console.log('formGroup : ', this.formGroup.value); + if (this.signup) { + this.userService + .createUser(this.formGroup.get('email')?.value, this.formGroup.get('password')?.value) + .subscribe({ + next: (data) => { + Swal.fire({ + position: 'top-end', + icon: 'success', + title: 'Your account has been created', + showConfirmButton: false, + timer: 1000, + }); + this.showLogin(); + }, + }); + } else if (this.login) { + this.userService + .loginUser(this.formGroup.get('email')?.value, this.formGroup.get('password')?.value) + .subscribe({ + next: (data: any) => { + if (data['success']) { + this.router.navigate(['/profile']); + } + }, + }); + } + } + + checkValidity(controlName: string) { + const control = this.formGroup.get(controlName); + if (control) { + control.markAsTouched(); + } + } + + matchPasswords(control: any): { [key: string]: boolean } | null { + if (this.formGroup) { + return control.value === this.formGroup.get('password')?.value ? null : { mismatch: true }; + } + return null; + } +} diff --git a/src/app/services/cookie.service.ts b/src/app/services/cookie.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..9148c8baae3de673fc15bfc80ea4574eda6bb7d9 --- /dev/null +++ b/src/app/services/cookie.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root', +}) +export class CookieService { + getCookie(name: string): string | null { + const matches = document.cookie.match( + new RegExp('(?:^|; )' + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + '=([^;]*)') + ); + return matches ? decodeURIComponent(matches[1]) : null; + } + + hasCookie(name: string): boolean { + return this.getCookie(name) !== null; + } +} diff --git a/src/app/services/user.service.ts b/src/app/services/user.service.ts index 3569db9f808ed8b93fac91a74db8c8269cc0ce60..1dfdc805dad05bd17bee69e840a31ba47e3aa8e3 100644 --- a/src/app/services/user.service.ts +++ b/src/app/services/user.service.ts @@ -1,9 +1,26 @@ +import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class UserService { + constructor(private http: HttpClient) {} + private apiUrl = 'https://klebert-host.com:33037'; + public createUser(email: string, password: string) { + const username = email.split('@')[0]; + return this.http.post(`${this.apiUrl}/user`, { username: username, email: email, password: password }); + } - constructor() { } + public loginUser(login: string, password: string) { + return this.http.post( + `${this.apiUrl}/auth/login`, + { login: login, password: password }, + { withCredentials: true } + ); + } + + public getMe() { + return this.http.get(`${this.apiUrl}/user/me`, { withCredentials: true }); + } }