diff --git a/Frontend/quizz-game/src/app/app-routing.module.ts b/Frontend/quizz-game/src/app/app-routing.module.ts index bb70d1e5b595611dc3e85f5bd8516f05be44f0dc..dd7de336102fed640276db08788a94dd15251e2a 100644 --- a/Frontend/quizz-game/src/app/app-routing.module.ts +++ b/Frontend/quizz-game/src/app/app-routing.module.ts @@ -47,14 +47,6 @@ const routes: Routes = [ path: 'list-questions', component: ListQuestionsComponent }, - { - path: 'create-user', - component: CreateUserComponent - }, - { - path: 'create-question', - component: CreateQuestionComponent - }, { path: 'account-details', component: AccountDetailsComponent diff --git a/Frontend/quizz-game/src/app/app.module.ts b/Frontend/quizz-game/src/app/app.module.ts index abf8b4abcd0a63e5c3cdc0ba431461889dbaf06e..94841c5fb442afa93547de165ae608a5082c5425 100644 --- a/Frontend/quizz-game/src/app/app.module.ts +++ b/Frontend/quizz-game/src/app/app.module.ts @@ -18,6 +18,10 @@ import { CreateUserComponent } from './manage/create-user/create-user.component' import { CreateQuestionComponent } from './manage/create-question/create-question.component'; import { AccountDetailsComponent } from './manage/account-details/account-details.component'; import { AlertAddComponent } from './manage/alert-add/alert-add.component'; +import { LoadingComponent } from './manage/loading/loading.component'; +import { EditUserComponent } from './manage/edit-user/edit-user.component'; +import { EditQuestionComponent } from './manage/edit-question/edit-question.component'; +import { DeleteItemComponent } from './manage/delete-item/delete-item.component'; @@ -34,7 +38,11 @@ import { AlertAddComponent } from './manage/alert-add/alert-add.component'; CreateUserComponent, CreateQuestionComponent, AccountDetailsComponent, - AlertAddComponent + AlertAddComponent, + LoadingComponent, + EditUserComponent, + EditQuestionComponent, + DeleteItemComponent ], imports: [ BrowserModule, diff --git a/Frontend/quizz-game/src/app/login/login.component.html b/Frontend/quizz-game/src/app/login/login.component.html index 59e61036e38c63964427ed127cd302a85c84e0e4..3de2dafc5de1080fc2a4e1e0d5ff55dc2683d990 100644 --- a/Frontend/quizz-game/src/app/login/login.component.html +++ b/Frontend/quizz-game/src/app/login/login.component.html @@ -1,10 +1,3 @@ -<!-- - Heads up! đŸ‘‹ - - Plugins: - - @tailwindcss/forms ---> - <section class="bg-white"> <div class="lg:grid lg:min-h-screen lg:grid-cols-12"> <section diff --git a/Frontend/quizz-game/src/app/login/login.service.ts b/Frontend/quizz-game/src/app/login/login.service.ts index 9aab1e6bb4be38c22edecdc32c39d96295b481b7..c7be5421422cf2cf5f8a1930b31576a3cab45988 100644 --- a/Frontend/quizz-game/src/app/login/login.service.ts +++ b/Frontend/quizz-game/src/app/login/login.service.ts @@ -1,6 +1,7 @@ import { Injectable } from '@angular/core'; import * as CryptoJS from 'crypto-js'; -import {FormControl, FormGroup, Validators} from "@angular/forms"; +import {AbstractControl, FormControl, FormGroup, Validators} from "@angular/forms"; +import {User} from "../manage/list-users/user-model"; export enum ErrorLogin { PassConfirm , @@ -30,31 +31,35 @@ export class LoginService { return hash.toString(CryptoJS.enc.Base64); } - formDataCreate():FormGroup{ + + + + formDataCreate(userInfo?: User):FormGroup{ return new FormGroup({ - username: new FormControl(null, { + username: new FormControl(!userInfo?null:userInfo!!.username, { updateOn: 'change', validators: [Validators.required], }), - firstname: new FormControl(null, { + firstname: new FormControl(!userInfo?null:userInfo!!.firstname, { updateOn: 'change', validators: [Validators.required], }), - lastname: new FormControl(null, { + lastname: new FormControl(!userInfo?null: userInfo!!.lastname, { updateOn: 'change', validators: [Validators.required], }), - email: new FormControl(null, { + email: new FormControl(!userInfo?null:userInfo!!.email, { updateOn: 'change', - validators: [Validators.required], + validators: [Validators.required, Validators.email], }), password: new FormControl(null, { updateOn: 'change', - validators: [Validators.required], + validators: userInfo?[Validators.nullValidator]: [Validators.required], }), - accountType: new FormControl("User", { + accountType: new FormControl(!userInfo?"User": userInfo!!.type === "user"?"User":"Admin", { updateOn: 'change' - }) + }), + passwordConfirm: userInfo ? new FormControl(null, { updateOn: 'change', validators: [Validators.nullValidator] }) : new FormControl(null) }); } } diff --git a/Frontend/quizz-game/src/app/manage/create-user/create-user.component.html b/Frontend/quizz-game/src/app/manage/create-user/create-user.component.html index f880057676fa33f4d43ea7f00cdad101a59a7ede..545886811415a8031ac8ba1d13e376e47644389f 100644 --- a/Frontend/quizz-game/src/app/manage/create-user/create-user.component.html +++ b/Frontend/quizz-game/src/app/manage/create-user/create-user.component.html @@ -9,7 +9,8 @@ Ajouter un utilisateur </h3> <button type="button" - class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center"> + class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center" + (click)="closeModalInterface()"> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" @@ -67,7 +68,7 @@ <!-- Modal footer --> <div class="items-center p-6 border-t border-gray-200 rounded-b"> <button - class="text-white bg-cyan-600 hover:bg-cyan-700 focus:ring-4 focus:ring-cyan-200 font-medium rounded-lg text-sm px-5 py-2.5 text-center" + class="{{(formData.valid && formData.dirty)?'':'opacity-50 pointer-events-none'}} text-white bg-cyan-600 hover:bg-cyan-700 focus:ring-4 focus:ring-cyan-200 font-medium rounded-lg text-sm px-5 py-2.5 text-center" type="submit">Ajouter un utilisateur </button> </div> diff --git a/Frontend/quizz-game/src/app/manage/create-user/create-user.component.ts b/Frontend/quizz-game/src/app/manage/create-user/create-user.component.ts index 7cf7eaf7af63c4932de55308826a4b48de9a5e98..86401d47b8589e22aa5604ae6ff199a16c25de05 100644 --- a/Frontend/quizz-game/src/app/manage/create-user/create-user.component.ts +++ b/Frontend/quizz-game/src/app/manage/create-user/create-user.component.ts @@ -3,46 +3,45 @@ import {FormControl, FormGroup, Validators} from "@angular/forms"; import {ErrorLogin, LoginService} from "../../login/login.service"; import {HttpClient} from "@angular/common/http"; import {ManageService} from "../manage.service"; +import {error} from "@angular/compiler-cli/src/transformers/util"; @Component({ selector: 'app-create-user', templateUrl: './create-user.component.html', styleUrls: ['./create-user.component.css'] }) -export class CreateUserComponent implements OnInit{ +export class CreateUserComponent implements OnInit { formData!: FormGroup; errorOccured!: boolean; - selectedRadio!:string; - @Output() closeModal: EventEmitter<void> = new EventEmitter<void>(); + selectedRadio!: string; + @Output() closeModal: EventEmitter<string> = new EventEmitter<string>(); constructor(private httpClient: HttpClient, private loginService: LoginService, private manageService: ManageService) { } ngOnInit() { - this.errorOccured=false; + this.errorOccured = false; this.formData = this.loginService.formDataCreate(); } addUser(event: Event) { event.preventDefault(); - this.errorOccured=false; - this.formData.value.password = this.loginService.hashPassword(this.formData.value.password); - if(this.formData.value.accountType === "User") - this.formData.value.accountType = 0; - else - this.formData.value.accountType = 1; - this.httpClient.post<any>('http://localhost:30992/api/v1/admin/'+this.manageService.username+'/create-user-account', this.formData.value).subscribe( - response => { - console.log(response); // Affiche la rĂ©ponse du serveur dans la console - // Effectuer une action en fonction de la rĂ©ponse du serveur ici - }, - error => { - this.errorOccured=true; - if(error.error.message === "USER_EXIST"){ - this.loginService.actualError=ErrorLogin.UserNameExist; - } + this.errorOccured = false; + this.manageService.addUser(this.formData).subscribe(() => { + console.log("add user success"); + this.closeModal.emit('success'); + }, error => { + console.log("error add user:", error); + this.errorOccured = true; + if (error.error && error.error.message === "USER_EXIST") { + this.loginService.actualError = ErrorLogin.UserNameExist; + this.closeModal.emit('error') } - ); + }); + } + + closeModalInterface() { + this.closeModal.emit(undefined); } diff --git a/Frontend/quizz-game/src/app/manage/delete-item/delete-item.component.css b/Frontend/quizz-game/src/app/manage/delete-item/delete-item.component.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Frontend/quizz-game/src/app/manage/delete-item/delete-item.component.html b/Frontend/quizz-game/src/app/manage/delete-item/delete-item.component.html new file mode 100644 index 0000000000000000000000000000000000000000..ed6eaaff111b38eae5456c57c64a26204a3ddcda --- /dev/null +++ b/Frontend/quizz-game/src/app/manage/delete-item/delete-item.component.html @@ -0,0 +1 @@ +<p>delete-item works!</p> diff --git a/Frontend/quizz-game/src/app/manage/delete-item/delete-item.component.spec.ts b/Frontend/quizz-game/src/app/manage/delete-item/delete-item.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..fe4522587bc397ef49be5c5699046b6f7990afac --- /dev/null +++ b/Frontend/quizz-game/src/app/manage/delete-item/delete-item.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DeleteItemComponent } from './delete-item.component'; + +describe('DeleteItemComponent', () => { + let component: DeleteItemComponent; + let fixture: ComponentFixture<DeleteItemComponent>; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [DeleteItemComponent] + }); + fixture = TestBed.createComponent(DeleteItemComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Frontend/quizz-game/src/app/manage/delete-item/delete-item.component.ts b/Frontend/quizz-game/src/app/manage/delete-item/delete-item.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..1cf9fa594d898cfac1bc648b6c8e9fc6bac25d45 --- /dev/null +++ b/Frontend/quizz-game/src/app/manage/delete-item/delete-item.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-delete-item', + templateUrl: './delete-item.component.html', + styleUrls: ['./delete-item.component.css'] +}) +export class DeleteItemComponent { + +} diff --git a/Frontend/quizz-game/src/app/manage/edit-question/edit-question.component.css b/Frontend/quizz-game/src/app/manage/edit-question/edit-question.component.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Frontend/quizz-game/src/app/manage/edit-question/edit-question.component.html b/Frontend/quizz-game/src/app/manage/edit-question/edit-question.component.html new file mode 100644 index 0000000000000000000000000000000000000000..0d70d6e981d770f3007a5a5837603ed663b7e2f8 --- /dev/null +++ b/Frontend/quizz-game/src/app/manage/edit-question/edit-question.component.html @@ -0,0 +1 @@ +<p>edit-question works!</p> diff --git a/Frontend/quizz-game/src/app/manage/edit-question/edit-question.component.spec.ts b/Frontend/quizz-game/src/app/manage/edit-question/edit-question.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..bb2ea7278f8b7a18738a273672cf656b1c8ee3af --- /dev/null +++ b/Frontend/quizz-game/src/app/manage/edit-question/edit-question.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EditQuestionComponent } from './edit-question.component'; + +describe('EditQuestionComponent', () => { + let component: EditQuestionComponent; + let fixture: ComponentFixture<EditQuestionComponent>; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [EditQuestionComponent] + }); + fixture = TestBed.createComponent(EditQuestionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Frontend/quizz-game/src/app/manage/edit-question/edit-question.component.ts b/Frontend/quizz-game/src/app/manage/edit-question/edit-question.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..a077a98bd2d9218e535a483c94316c4497ef7a73 --- /dev/null +++ b/Frontend/quizz-game/src/app/manage/edit-question/edit-question.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-edit-question', + templateUrl: './edit-question.component.html', + styleUrls: ['./edit-question.component.css'] +}) +export class EditQuestionComponent { + +} diff --git a/Frontend/quizz-game/src/app/manage/edit-user/edit-user.component.css b/Frontend/quizz-game/src/app/manage/edit-user/edit-user.component.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Frontend/quizz-game/src/app/manage/edit-user/edit-user.component.html b/Frontend/quizz-game/src/app/manage/edit-user/edit-user.component.html new file mode 100644 index 0000000000000000000000000000000000000000..3349221582c20534358a7537d07767cd11aba62f --- /dev/null +++ b/Frontend/quizz-game/src/app/manage/edit-user/edit-user.component.html @@ -0,0 +1,85 @@ +<div + class="overflow-x-hidden overflow-y-auto fixed top-4 left-0 right-0 md:inset-0 z-50 justify-center items-center h-modal sm:h-full"> + <div class="relative w-full max-w-2xl px-4 h-full md:h-auto"> + <!-- Modal content --> + <div class="bg-white rounded-lg shadow relative"> + <!-- Modal header --> + <div class="flex items-start justify-between p-5 border-b rounded-t"> + <h3 class="text-xl font-semibold"> + Modifier un utilisateur + </h3> + <button type="button" + class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center" + (click)="closeModalInterface()"> + <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> + <path fill-rule="evenodd" + d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" + clip-rule="evenodd"></path> + </svg> + </button> + </div> + <!-- Modal body --> + <form [formGroup]="formData" + enctype="multipart/form-data" + (submit)="editUser($event)"> + <div class="p-6 space-y-6"> + + <div class="grid grid-cols-6 gap-6"> + <div class="col-span-6 sm:col-span-3"> + <label for="first-name" class="text-sm font-medium text-gray-900 block mb-2">PrĂ©nom</label> + <input type="text" id="first-name" formControlName="firstname" + class="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-cyan-600 focus:border-cyan-600 block w-full p-2.5" + placeholder="John"> + </div> + <div class="col-span-6 sm:col-span-3"> + <label for="lastname" class="text-sm font-medium text-gray-900 block mb-2">Nom de famille</label> + <input type="text" id="lastname" formControlName="lastname" + class="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-cyan-600 focus:border-cyan-600 block w-full p-2.5" + placeholder="Doe"> + </div> + <div class="col-span-6 sm:col-span-3"> + <label for="email" class="text-sm font-medium text-gray-900 block mb-2">Email</label> + <input type="email" id="email" formControlName="email" + class="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-cyan-600 focus:border-cyan-600 block w-full p-2.5" + placeholder="example@company.com"> + </div> + <div class="col-span-6 sm:col-span-3"> + <label for="username" class="text-sm font-medium text-gray-900 block mb-2">Nom d'utilisateur</label> + <input type="text" id="username" formControlName="username" + class="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-cyan-600 focus:border-cyan-600 block w-full p-2.5" + placeholder="johndoe74"> + </div> + <div class="col-span-6 sm:col-span-3"> + <label for="password" class="text-sm font-medium text-gray-900 block mb-2">Ancien mot de passe</label> + <input type="password" id="password" formControlName="password" + class="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-cyan-600 focus:border-cyan-600 block w-full p-2.5" + placeholder="***********"> + </div> + <div class="col-span-6 sm:col-span-3"> + <label for="password" class="text-sm font-medium text-gray-900 block mb-2">Nouveau mot de passe</label> + <input type="password" id="passwordConfirm" formControlName="passwordConfirm" + class="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-cyan-600 focus:border-cyan-600 block w-full p-2.5" + placeholder="***********"> + </div> + <div class="col-span-6 sm:col-span-3"> + <label for="user" class="text-sm font-medium text-gray-900 block mb-2">Type</label> + <label for="user" class="mr-2">Utilisateur</label> + <input type="radio" id="user" formControlName="accountType" value="User" class="mr-4"> + <label for="admin" class="mr-2">Administrateur</label> + <input type="radio" id="admin" formControlName="accountType" value="Admin" class="mr-4"> + </div> + </div> + </div> + + <!-- Modal footer --> + <div class="items-center p-6 border-t border-gray-200 rounded-b"> + <button + class="{{(formData.valid)?'':'opacity-50 pointer-events-none'}} text-white bg-cyan-600 hover:bg-cyan-700 focus:ring-4 focus:ring-cyan-200 font-medium rounded-lg text-sm px-5 py-2.5 text-center" + type="submit">Appliquer les modifications + </button> + </div> + </form> + + </div> + </div> +</div> diff --git a/Frontend/quizz-game/src/app/manage/edit-user/edit-user.component.spec.ts b/Frontend/quizz-game/src/app/manage/edit-user/edit-user.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..6ebe439d749d488fbb57cbf5b900d3a7823b6278 --- /dev/null +++ b/Frontend/quizz-game/src/app/manage/edit-user/edit-user.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EditUserComponent } from './edit-user.component'; + +describe('EditUserComponent', () => { + let component: EditUserComponent; + let fixture: ComponentFixture<EditUserComponent>; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [EditUserComponent] + }); + fixture = TestBed.createComponent(EditUserComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Frontend/quizz-game/src/app/manage/edit-user/edit-user.component.ts b/Frontend/quizz-game/src/app/manage/edit-user/edit-user.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..e32a2eaf4361ea021b600050435bc64cfee2d782 --- /dev/null +++ b/Frontend/quizz-game/src/app/manage/edit-user/edit-user.component.ts @@ -0,0 +1,74 @@ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {FormControl, FormGroup, Validators} from "@angular/forms"; +import {HttpClient} from "@angular/common/http"; +import {ErrorLogin, LoginService} from "../../login/login.service"; +import {ManageService} from "../manage.service"; +import {User} from "../list-users/user-model"; + +@Component({ + selector: 'app-edit-user', + templateUrl: './edit-user.component.html', + styleUrls: ['./edit-user.component.css'] +}) +export class EditUserComponent implements OnInit { + formData!: FormGroup; + errorOccured!: boolean; + selectedRadio!: string; + @Output() closeModal: EventEmitter<string> = new EventEmitter<string>(); + @Input() user!: User + + constructor(private httpClient: HttpClient, private loginService: LoginService, private manageService: ManageService) { + } + + ngOnInit() { + this.errorOccured = false; + console.log(this.user); + this.formData = this.loginService.formDataCreate(this.user); + this.formData.controls['password'].valueChanges.subscribe(password => { + const passwordConfirmControl = this.formData.get('passwordConfirm'); + const passwordControl = this.formData.get('password'); + if (password !== null && password !== '') { + passwordConfirmControl?.setValidators([Validators.required]); + } else { + passwordControl?.setValidators([Validators.nullValidator]); + passwordConfirmControl?.setValidators([Validators.nullValidator]); + } + passwordConfirmControl?.updateValueAndValidity(); + }); + } + + editUser(event: Event) { + event.preventDefault(); + this.errorOccured = false; + let userEditedInfo=this.formData.value; + console.log("edit user before:" ,userEditedInfo.accountType) + this.manageService.updateUser(this.user.username, userEditedInfo.username, userEditedInfo.firstname, userEditedInfo.lastname, userEditedInfo.email, userEditedInfo.accountType, this.formData.value.passwordConfirm).subscribe(()=>{ + console.log("edit user success"); + this.closeModal.emit('success'); + },error=>{ + console.log("error:", error); + this.closeModal.emit('error') + }); + /* + this.manageService.addUser(this.formData).subscribe(() => { + console.log("add user success"); + this.closeModal.emit('success'); + }, error => { + console.log("error add user:", error); + this.errorOccured = true; + if (error.error && error.error.message === "USER_EXIST") { + this.loginService.actualError = ErrorLogin.UserNameExist; + this.closeModal.emit('error') + } + }); + + */ + } + + closeModalInterface() { + this.closeModal.emit(undefined); + } + + +} + diff --git a/Frontend/quizz-game/src/app/manage/list-users/list-users.component.html b/Frontend/quizz-game/src/app/manage/list-users/list-users.component.html index 8699a1fa3b0fc08c2fb4c1c574ed4b14589d1354..19a6b69d692decbcec151199f93db1e6df434ce3 100644 --- a/Frontend/quizz-game/src/app/manage/list-users/list-users.component.html +++ b/Frontend/quizz-game/src/app/manage/list-users/list-users.component.html @@ -1,3 +1,9 @@ +<div class="absolute top-5 left-0 right-0 flex items-center justify-center h-16"> + <app-alert-add *ngIf="addSuccess"></app-alert-add> + <app-errorlogin *ngIf="errorOccured"></app-errorlogin> +</div> + + <div class="p-4 bg-white block sm:flex items-center justify-between border-b border-gray-200 lg:mt-1.5"> <div class="mb-1 w-full"> <div class="mb-4"> @@ -25,18 +31,16 @@ </li> </ol> </nav> - <h1 class="text-xl sm:text-2xl font-semibold text-gray-900">All users</h1> + <h1 class="text-xl sm:text-2xl font-semibold text-gray-900">Liste des utilisateurs</h1> </div> <div class="sm:flex"> <div class="hidden sm:flex items-center sm:divide-x sm:divide-gray-100 mb-3 sm:mb-0"> - <form class="lg:pr-3" action="#" method="GET"> - <label for="users-search" class="sr-only">Search</label> - <div class="mt-1 relative lg:w-64 xl:w-96"> - <input type="text" name="email" id="users-search" - class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-cyan-600 focus:border-cyan-600 block w-full p-2.5" - placeholder="Search for users"> - </div> - </form> + <label for="users-search" class="sr-only">Search</label> + <div class="mt-1 relative lg:w-64 xl:w-96"> + <input type="text" name="user_search" id="users-search" + class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-cyan-600 focus:border-cyan-600 block w-full p-2.5" + placeholder="Rechercher un utilisateur"> + </div> </div> <div class="flex items-center space-x-2 sm:space-x-3 ml-auto"> <button type="button" (click)="addUser()" @@ -52,47 +56,45 @@ </div> </div> </div> -<div class="flex flex-col w-screen"> +<app-loading *ngIf="loading"></app-loading> +<div class="flex flex-col" *ngIf="!loading"> <div class="overflow-x-auto"> <div class="align-middle inline-block min-w-full"> <div class="shadow overflow-hidden"> + <table class="table-fixed min-w-full divide-y divide-gray-200"> <thead class="bg-gray-100"> <tr> <th scope="col" class="p-4 text-left text-xs font-medium text-gray-500 uppercase"> - Name + Nom </th> <th scope="col" class="p-4 text-left text-xs font-medium text-gray-500 uppercase"> - Position + Nom d'utilisateur </th> <th scope="col" class="p-4 text-left text-xs font-medium text-gray-500 uppercase"> - Country + Email </th> <th scope="col" class="p-4 text-left text-xs font-medium text-gray-500 uppercase"> - Status + Type </th> <th scope="col" class="p-4"> </th> </tr> </thead> <tbody class="bg-white divide-y divide-gray-200"> - <tr class="hover:bg-gray-100" > + <tr class="hover:bg-gray-100" *ngFor="let user of users.slice().reverse()" + [hidden]="user.username === myUsername"> <td class="p-4 flex items-center whitespace-nowrap space-x-6 mr-12 lg:mr-0"> <div class="text-sm font-normal text-gray-500"> - <div class="text-base font-semibold text-gray-900">Nom</div> - <div class="text-sm font-normal text-gray-500">Email</div> - </div> - </td> - <td class="p-4 whitespace-nowrap text-base font-medium text-gray-900">Job</td> - <td class="p-4 whitespace-nowrap text-base font-medium text-gray-900">Pays</td> - <td class="p-4 whitespace-nowrap text-base font-normal text-gray-900"> - <div class="flex items-center"> - Active - <div class="h-2.5 w-2.5 rounded-full bg-green-400 mr-2"></div> + <div class="text-base font-semibold text-gray-900">{{user.firstname}} {{user.lastname}}</div> </div> </td> + <td class="p-4 whitespace-nowrap text-base font-medium text-gray-900">{{user.username}}</td> + <td class="p-4 whitespace-nowrap text-base font-normal text-gray-900">{{user.email}}</td> + <td class="p-4 whitespace-nowrap text-base font-medium text-gray-900">{{user.type}}</td> <td class="p-4 whitespace-nowrap space-x-2"> <button type="button" data-modal-toggle="user-modal" + (click)="editUser(user)" class="text-white bg-cyan-600 hover:bg-cyan-700 focus:ring-4 focus:ring-cyan-200 font-medium rounded-lg text-sm inline-flex items-center px-3 py-2 text-center"> <svg class="mr-2 h-5 w-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"></path> @@ -119,4 +121,9 @@ </div> </div> </div> -<app-create-user *ngIf="modalUser" (closeModal)="closeModal()"></app-create-user> +<div *ngIf="modalUser" class="fixed inset-0 flex items-center justify-center bg-gray-900 bg-opacity-50"> + <app-create-user *ngIf="!userEdited" (closeModal)="closeModal($event)"></app-create-user> + <app-edit-user *ngIf="userEdited" [user]="userEdited" (closeModal)="closeModal($event)"></app-edit-user> +</div> + + diff --git a/Frontend/quizz-game/src/app/manage/list-users/list-users.component.ts b/Frontend/quizz-game/src/app/manage/list-users/list-users.component.ts index 166214fb870ea99b706c0b60e42955c92141789f..90a12de5508d50deffa8903bf035440bd3ec0c55 100644 --- a/Frontend/quizz-game/src/app/manage/list-users/list-users.component.ts +++ b/Frontend/quizz-game/src/app/manage/list-users/list-users.component.ts @@ -1,20 +1,77 @@ -import { Component } from '@angular/core'; +import {Component, OnDestroy, OnInit} from '@angular/core'; +import {ManageService} from "../manage.service"; +import {User} from "./user-model"; +import {Subscription} from "rxjs"; @Component({ selector: 'app-list-users', templateUrl: './list-users.component.html', styleUrls: ['./list-users.component.css'] }) -export class ListUsersComponent { +export class ListUsersComponent implements OnInit, OnDestroy { + myUsername!:string; modalUser=false; - constructor() { + errorOccured!:boolean; + addSuccess!:boolean; + users!: User[] + loading!:boolean; + userEdited!: User; + private usersSub!: Subscription; + + + constructor(private manageService: ManageService) { + } + + ngOnInit(){ + this.myUsername=this.manageService.username; + this.errorOccured=false; + this.addSuccess=false; + this.loading=true; + this.usersSub=this.manageService.users.subscribe((users)=>{ + this.users=users; + }); + this.manageService.fetchUsers().subscribe(()=>{ + this.loading=false; + }) + console.log(this.users); + + + } + + addUser(){ this.modalUser=true; + } - closeModal(){ + editUser(user: User){ + this.userEdited=user; + this.modalUser=true; + } + + closeModal(value: string){ + this.modalUser=false; + console.log(this.users); + if(value === "success") { + this.addSuccess=true; + setTimeout(() => { + this.addSuccess = false; + }, 5000); + + }else if(value === "error"){ + this.errorOccured=true; + setTimeout(() => { + this.errorOccured = false; + }, 5000); + }else{ + return; + } + } + ngOnDestroy() { + if(this.usersSub) + this.usersSub.unsubscribe(); } } diff --git a/Frontend/quizz-game/src/app/manage/list-users/user-model.ts b/Frontend/quizz-game/src/app/manage/list-users/user-model.ts new file mode 100644 index 0000000000000000000000000000000000000000..26076231bb38f9f5fb0d28b43c8c6d2d28d1fe07 --- /dev/null +++ b/Frontend/quizz-game/src/app/manage/list-users/user-model.ts @@ -0,0 +1,10 @@ +export class User { + constructor( + public username: string, + public firstname: string, + public lastname: string, + public email: string, + public type: string, + public password: string + ) {} +} diff --git a/Frontend/quizz-game/src/app/manage/loading/loading.component.css b/Frontend/quizz-game/src/app/manage/loading/loading.component.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Frontend/quizz-game/src/app/manage/loading/loading.component.html b/Frontend/quizz-game/src/app/manage/loading/loading.component.html new file mode 100644 index 0000000000000000000000000000000000000000..d49c6c056c24b6ec2e7719bce0cc70690c2e1f0f --- /dev/null +++ b/Frontend/quizz-game/src/app/manage/loading/loading.component.html @@ -0,0 +1,13 @@ +<div class="flex justify-center items-center"> + <div class="w-12 h-12 relative"> + <div class="absolute inset-0 flex items-center justify-center"> + <div class="w-6 h-6 bg-gray-800 rounded-full animate-bounce"></div> + </div> + <div class="absolute inset-0 flex items-center justify-center"> + <div class="w-10 h-10 bg-gray-600 rounded-full animate-bounce"></div> + </div> + <div class="absolute inset-0 flex items-center justify-center"> + <div class="w-14 h-14 bg-gray-400 rounded-full animate-bounce"></div> + </div> + </div> +</div> diff --git a/Frontend/quizz-game/src/app/manage/loading/loading.component.spec.ts b/Frontend/quizz-game/src/app/manage/loading/loading.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..5bb22ce7fed083abe15a19b0afe36a35d4ac15ad --- /dev/null +++ b/Frontend/quizz-game/src/app/manage/loading/loading.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LoadingComponent } from './loading.component'; + +describe('LoadingComponent', () => { + let component: LoadingComponent; + let fixture: ComponentFixture<LoadingComponent>; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [LoadingComponent] + }); + fixture = TestBed.createComponent(LoadingComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Frontend/quizz-game/src/app/manage/loading/loading.component.ts b/Frontend/quizz-game/src/app/manage/loading/loading.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..2c786e1556d833e0f65b843f05ec4c32ad2f4bad --- /dev/null +++ b/Frontend/quizz-game/src/app/manage/loading/loading.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-loading', + templateUrl: './loading.component.html', + styleUrls: ['./loading.component.css'] +}) +export class LoadingComponent { + +} diff --git a/Frontend/quizz-game/src/app/manage/manage.component.html b/Frontend/quizz-game/src/app/manage/manage.component.html index 8eb972f13b8bd015dcd637c1e55fc6fc9f826e86..9011a9d6ea693aae9a0f8cbc0fc9bad8f689d04f 100644 --- a/Frontend/quizz-game/src/app/manage/manage.component.html +++ b/Frontend/quizz-game/src/app/manage/manage.component.html @@ -1,8 +1,3 @@ -<div class="absolute top-5 left-0 right-0 flex items-center justify-center h-16"> - <app-alert-add></app-alert-add> -</div> - - <div class="flex h-screen"> <div class="w-1/4 flex h-screen flex-col justify-between border-e bg-white"> <div class="px-4 py-6"> diff --git a/Frontend/quizz-game/src/app/manage/manage.service.ts b/Frontend/quizz-game/src/app/manage/manage.service.ts index a516d8580a98d7c9c941dec0ca1d6f7b26558971..eb16718becf891ea6863bf02edd8dd25357d8275 100644 --- a/Frontend/quizz-game/src/app/manage/manage.service.ts +++ b/Frontend/quizz-game/src/app/manage/manage.service.ts @@ -1,23 +1,45 @@ -import { Injectable } from '@angular/core'; +import {Injectable} from '@angular/core'; import {HttpClient} from "@angular/common/http"; -import {ErrorLogin} from "../login/login.service"; +import {BehaviorSubject, map, of, switchMap, take, tap} from "rxjs"; +import {User} from "./list-users/user-model"; +import {FormGroup} from "@angular/forms"; +import {LoginService} from "../login/login.service"; + +interface UserData { + username: string; + firstname: string; + lastname: string; + email: string; + password: string; + type: string; + createdAt: string; + updatedAt: string; +} @Injectable({ providedIn: 'root' }) export class ManageService { - constructor(private httpClient: HttpClient) { } - private _username!:string; + private _username!: string; + private _users = new BehaviorSubject<User[]>([]); + + constructor(private httpClient: HttpClient, private loginService: LoginService) { + } - get username():string{ + get username(): string { return this._username; } - set username(value: string){ - this._username=value; + set username(value: string) { + this._username = value; } - async getUserInfo():Promise<any>{ + + get users() { + return this._users.asObservable(); + } + + async getUserInfo(): Promise<any> { return new Promise<any>((resolve, reject) => { let usernamePost = { username: this.username @@ -32,4 +54,126 @@ export class ManageService { ); }); } + + fetchUsers() { + return this.httpClient + .get<{ users: UserData[] }>( + 'http://localhost:30992/api/v1/admin/' + this.username + '/list-users' + ) + .pipe( + map((resDonnee) => { + const usersData=resDonnee.users; + const users:User[] = []; + usersData.forEach((user)=>{ + users.push( + new User( + user.username, + user.firstname, + user.lastname, + user.email, + user.type, + user.password + ) + ) + }) + return users; + }), + tap((users) => { + this._users.next(users); + }) + ); + + } + + changeTypeKey(userInfo:any){ + for (const k in userInfo) { + if (k === "accountType") { + userInfo["type"] = userInfo[k]; + delete userInfo[k]; + } + } + userInfo.type=userInfo.type === 0 ? "user":"admin"; + } + + + changeAccountTypeKey(userInfo: any){ + let userInfoChanged = { ...userInfo } + for (const k in userInfoChanged) { + if (k === "type") { + userInfoChanged["accountType"] = userInfoChanged[k]; + delete userInfoChanged[k]; + } + } + userInfoChanged.accountType=userInfoChanged.accountType === "user" ? 0:1; + return userInfoChanged; + } + + addUser( + formDataUsers: FormGroup<any> + ) { + + let userInfo=formDataUsers.value; + userInfo.password = this.loginService.hashPassword(userInfo.password); + if(userInfo.accountType === "User") + userInfo.accountType = 0; + else + userInfo.accountType = 1; + userInfo.password=this.loginService.hashPassword(userInfo.password); + return this.httpClient.post<any>('http://localhost:30992/api/v1/admin/'+this.username+'/create-user-account', userInfo) + .pipe( + switchMap(() => { + return this.users; + }), + take(1), + tap((users) => { + this.changeTypeKey(userInfo); + this._users.next(users.concat(userInfo)); + }) + ); + } + + updateUser(username: string, new_username: string, firstname: string, lastname: string, email: string, type: string, password?: string) { + let editUsers: User[]; + return this.users.pipe( + take(1), + switchMap((users) => { + if (!users || users.length <= 0) { + return this.fetchUsers(); + } + else { + return of(users); + } + + }), + switchMap(users => { + const usernameSearch = users.findIndex( + (u) => u.username === username + ); + editUsers = [...users]; + const pastUser = editUsers[usernameSearch]; + console.log("type:", type); + editUsers[usernameSearch] = new User( + username, + firstname, + lastname, + email, + type==="User"?"user":"admin", + password?this.loginService.hashPassword(password):pastUser.password + ); + console.log(editUsers[usernameSearch]); + let userEdited=this.changeAccountTypeKey(editUsers[usernameSearch]); + console.log(userEdited); + return this.httpClient.put( + `http://localhost:30992/api/v1/admin/${this.username}/update-user-account`, + { ...userEdited } + ); + + }), + tap(() => { + this._users.next(editUsers); + }) + ); + } + + } diff --git a/Frontend/quizz-game/tsconfig.json b/Frontend/quizz-game/tsconfig.json index ed966d43afa55368b184ea967e1c1ef4df0b4caa..64a863ef28cb6dc452aa530249aa97f5f7457c37 100644 --- a/Frontend/quizz-game/tsconfig.json +++ b/Frontend/quizz-game/tsconfig.json @@ -19,6 +19,7 @@ "target": "ES2022", "module": "ES2022", "useDefineForClassFields": false, + "allowSyntheticDefaultImports": true, "lib": [ "ES2022", "dom"