浏览代码

dev en cours

rajah 11 月之前
父节点
当前提交
40a79a3f55

+ 3 - 1
src/app/app.config.ts

@@ -4,6 +4,7 @@ import { routes } from './app.routes';
 import { provideClientHydration } from '@angular/platform-browser';
 import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
 import { provideHttpClient, withInterceptorsFromDi, HTTP_INTERCEPTORS, withXsrfConfiguration } from '@angular/common/http';
+import { provideNgIdle } from '@ng-idle/core';
 
 import { AuthInterceptor } from './services/auth.interceptor';
 
@@ -19,6 +20,7 @@ export const appConfig: ApplicationConfig =
       provide: HTTP_INTERCEPTORS,
       useClass: AuthInterceptor,
       multi: true
-    }
+    },
+    provideNgIdle(),
   ]
 };

+ 11 - 11
src/app/composants/home/home.component.ts

@@ -1,29 +1,29 @@
 import { Component, OnInit, AfterViewInit } from '@angular/core';
 import { MenuComponent } from '../menu/menu.component';
 import { Message } from '../../interfaces/divers';
-import { AccountService } from '../../services/account.service' 
-import { DiversService } from '../../services/divers.service' 
+import { AccountService } from '../../services/account.service'
+import { DiversService } from '../../services/divers.service'
 
 @Component({ selector: 'app-home', imports: [MenuComponent], templateUrl: './home.component.html', styleUrl: './home.component.css' })
 
-export class HomeComponent implements OnInit, AfterViewInit 
+export class HomeComponent implements OnInit, AfterViewInit
 {
 
   logged: boolean = false;
   pseudonyme: string = "";
   message: Message = new Message();
-  
+
   constructor(private diversService: DiversService, private accountService: AccountService) { }
-  
-  ngOnInit() 
-  { 
+
+  ngOnInit()
+  {
     this.logged = this.accountService.isLogged();
-    
+
     if (this.logged) { this.pseudonyme = this.accountService.getUsername(); }
-    
+
     this.diversService.getMessage().subscribe(data => { this.message = data; });
-  } 
-  
+  }
+
   ngAfterViewInit() { }
 
 }

+ 4 - 4
src/app/composants/menu/menu.component.html

@@ -7,7 +7,7 @@
 		<li><a routerLink="/event-list" routerLinkActive="active" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Planning" placement="right" container="body"><i class="fa-solid fa-clock"></i></a></li>
 		<li><a routerLink="/webcam-list" routerLinkActive="active" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Caméras" placement="right" container="body"><i class="fa-solid fa-eye"></i></a></li>
 	</ul>
-</div>
+</div><div #signouticon class="d-none"></div>
 
 } @else if (this.logged && (this.role === "USER")) {
 
@@ -15,7 +15,7 @@
   <ul class="nav nav-pills nav-flush flex-column text-center">
 	 	<li><a routerLink="/home" routerLinkActive="active" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Accueil" placement="right" container="body"><i class="fa-solid fa-home"></i></a></li>
 		<li><a routerLink="/account-details" routerLinkActive="active" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Compte" placement="right" container="body"><i class="fa-solid fa-user"></i></a></li>
-		<li><a routerLinkActive="active" data-bs-toggle="modal" data-bs-target="#modalDeconnecter" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Logout" placement="right" container="body"><i class="fa-solid fa-right-from-bracket"></i></a></li>
+    <li><a routerLinkActive="active" data-bs-toggle="modal" data-bs-target="#modalDeconnecter" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Logout" placement="right" container="body"><i #signouticon class="fa-solid fa-right-from-bracket"></i></a></li>
 		<li><a routerLink="/event-list" routerLinkActive="active" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Planning" placement="right" container="body"><i class="fa-solid fa-clock"></i></a></li>
 		<li><a routerLink="/webcam-list" routerLinkActive="active" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Caméras" placement="right" container="body"><i class="fa-solid fa-eye"></i></a></li>
 
@@ -35,7 +35,7 @@
   <ul class="nav nav-pills nav-flush flex-column text-center">
 	 	<li><a routerLink="/home" routerLinkActive="active" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Accueil" placement="right" container="body"><i class="fa-solid fa-home"></i></a></li>
 		<li><a routerLink="/account-details" routerLinkActive="active" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Compte" placement="right" container="body"><i class="fa-solid fa-user"></i></a></li>
-		<li><a routerLinkActive="active" data-bs-toggle="modal" data-bs-target="#modalDeconnecter" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Logout" placement="right" container="body"><i class="fa-solid fa-right-from-bracket"></i></a></li>
+		<li><a routerLinkActive="active" data-bs-toggle="modal" data-bs-target="#modalDeconnecter" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Logout" placement="right" container="body"><i #signouticon class="fa-solid fa-right-from-bracket"></i></a></li>
 		<li><a routerLink="/event-list" routerLinkActive="active" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Planning" placement="right" container="body"><i class="fa-solid fa-clock"></i></a></li>
 		<li><a routerLink="/webcam-list" routerLinkActive="active" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Caméras" placement="right" container="body"><i class="fa-solid fa-eye"></i></a></li>
 
@@ -55,7 +55,7 @@
   <ul class="nav nav-pills nav-flush flex-column text-center">
 	 	<li><a routerLink="/home" routerLinkActive="active" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Accueil" placement="right" container="body"><i class="fa-solid fa-home"></i></a></li>
 		<li><a routerLink="/account-details" routerLinkActive="active" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Compte" placement="right" container="body"><i class="fa-solid fa-user"></i></a></li>
-		<li><a routerLinkActive="active" data-bs-toggle="modal" data-bs-target="#modalDeconnecter" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Logout" placement="right" container="body"><i class="fa-solid fa-right-from-bracket"></i></a></li>
+		<li><a routerLinkActive="active" data-bs-toggle="modal" data-bs-target="#modalDeconnecter" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Logout" placement="right" container="body"><i #signouticon class="fa-solid fa-right-from-bracket"></i></a></li>
 		<li><a routerLink="/event-list" routerLinkActive="active" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Planning" placement="right" container="body"><i class="fa-solid fa-clock"></i></a></li>
 		<li><a routerLink="/webcam-list" routerLinkActive="active" class="nav-link rounded-0 bg-gradient" i18n-tooltip tooltip="Caméras" placement="right" container="body"><i class="fa-solid fa-eye"></i></a></li>
 

+ 30 - 5
src/app/composants/menu/menu.component.ts

@@ -1,8 +1,10 @@
-import { Injectable, Component, OnInit, AfterViewInit } from '@angular/core';
+import { Injectable, Component, OnInit, AfterViewInit, ViewChild, ElementRef, Renderer2 } from '@angular/core';
 import { Router, RouterLink, RouterLinkActive } from '@angular/router';
-import { AccountService } from '../../services/account.service';
+import { DEFAULT_INTERRUPTSOURCES, Idle } from '@ng-idle/core';
 import { TooltipModule } from 'ngx-bootstrap/tooltip';
 
+import { AccountService } from '../../services/account.service';
+
 @Component({ selector: 'app-menu', imports: [TooltipModule, RouterLink, RouterLinkActive], templateUrl: './menu.component.html', styleUrl: './menu.component.css' })
 
 @Injectable({ providedIn: 'root' })
@@ -11,21 +13,44 @@ export class MenuComponent implements OnInit, AfterViewInit
 {
 
   logged: boolean = false;
-
   role: string = "";
 
-  constructor(private router: Router, private accountService: AccountService) {  }
+  private idleState: String = 'NOT_STARTED';
+  private countdown: number = 0;
+  private timedOut: boolean = false;
+  @ViewChild('signouticon', {static: false}) signOutIcon!: ElementRef;
+
+  constructor(private idle: Idle, private router: Router, private accountService: AccountService, private el: ElementRef, private renderer: Renderer2)
+  {
+    this.idle.setIdle(900);
+    this.idle.setTimeout(15);
+    this.idle.setInterrupts(DEFAULT_INTERRUPTSOURCES);
+
+    this.idle.onIdleStart.subscribe(() => { this.idleState = 'IDLE'; this.showPendingLogout(); });
+    this.idle.onIdleEnd.subscribe(() => { this.resetIdle(); });
+    this.idle.onTimeout.subscribe(() => { if (this.logged) { this.idleState = 'TIMED_OUT'; this.timedOut = true; this.deconnexion(); } else { this.resetIdle(); } });
+    this.idle.onTimeoutWarning.subscribe((countdown) => { this.countdown = countdown; });
+  }
 
   ngOnInit()
   {
     this.logged = this.accountService.isLogged();
     this.role = this.accountService.getRole();
+
+    this.idle.setIdle(Math.max(15, this.accountService.getDelaiAvantDeconnexion()) * 60);
+    this.resetIdle();
+    this.idle.watch();
   }
 
   ngAfterViewInit() { }
 
-  deconnexion() { this.accountService.signOut(); if ((this.router.url === '/') || (this.router.url === '/home')) { window.location.reload(); } else { this.router.navigate(['/']); }  }
+  deconnexion() { this.accountService.signOut(); this.logged = false; if ((this.router.url === '/') || (this.router.url === '/home')) { window.location.reload(); } else { this.router.navigate(['/']); }  }
 
   getRandomInteger(min: number, max: number) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min)) + min; }
 
+  resetIdle() { this.hidePendingLogout(); this.idleState = "NOT_IDLE"; this.timedOut = false; this.countdown = 0; }
+
+  showPendingLogout() { if (this.logged) { if (this.signOutIcon) { this.renderer.addClass(this.signOutIcon.nativeElement, 'fa-beat-fade'); this.renderer.addClass(this.signOutIcon.nativeElement, 'text-danger'); } } }
+  hidePendingLogout() { if (this.logged) { if (this.signOutIcon) { this.renderer.removeClass(this.signOutIcon.nativeElement, 'fa-beat-fade'); this.renderer.removeClass(this.signOutIcon.nativeElement, 'text-danger'); } } }
+
 }

+ 26 - 0
src/app/composants/participant-create/participant-create.component.html

@@ -8,6 +8,32 @@
 		</div>
 		<div class="card-body scrollable">
 
+@if (this.profil === "ADMIN") {
+			<div class="form-group row">
+				<label class="col-sm-4 col-form-label col-form-label-sm label-nobr"><span i18n>Profil</span></label>
+				<div class="col-sm-8">
+					<div class="form-group field-separate">
+						<select class="form-select form-select-sm" id="status" name="status" [(ngModel)]="participant.role" required #statusRef="ngModel">
+							<option [value]="this.profils[0].key">{{ this.profils[0].value }}</option>
+							<option [value]="this.profils[1].key">{{ this.profils[1].value }}</option>
+							<option [value]="this.profils[2].key" selected>{{ this.profils[2].value }}</option>
+						</select>
+					</div>
+				</div>
+			</div>
+} @else if (this.profil === "ORGA") {
+			<div class="form-group row">
+				<label class="col-sm-4 col-form-label col-form-label-sm label-nobr"><span i18n>Profil</span></label>
+				<div class="col-sm-8">
+					<div class="form-group field-separate">
+						<select class="form-select form-select-sm" id="status" name="status" [(ngModel)]="participant.role" required #statusRef="ngModel">
+							<option [value]="this.profils[1].key">{{ this.profils[1].value }}</option>
+							<option [value]="this.profils[2].key">{{ this.profils[2].value }}</option>
+						</select>
+					</div>
+				</div>
+			</div>
+}
 			<div class="form-group row">
 				<label class="col-sm-4 col-form-label col-form-label-sm label-nobr"><span i18n>Nom</span>&nbsp;<sup><span class="text-danger">*</span></sup></label>
 				<div class="col-sm-8">

+ 15 - 3
src/app/composants/participant-create/participant-create.component.ts

@@ -3,16 +3,20 @@ import { Router } from '@angular/router';
 import { FormsModule, NgForm } from '@angular/forms';
 
 import { MenuComponent } from '../menu/menu.component';
-import { Participant, ParticipantEnum, ParticipantStatutList, ParticipantModePaiementList } from '../../interfaces/participant';
-import { ParticipantService } from '../../services/participant.service';
+import { Participant, ParticipantEnum, ProfilList, ParticipantStatutList, ParticipantModePaiementList } from '../../interfaces/participant';
 import { Journees } from '../../interfaces/divers';
+import { ParticipantService } from '../../services/participant.service';
 import { DiversService } from '../../services/divers.service'
+import { AccountService } from '../../services/account.service';
 
 @Component({ selector: 'app-participant-create', imports: [FormsModule, MenuComponent], templateUrl: './participant-create.component.html', styleUrl: './participant-create.component.css' })
 
 export class ParticipantCreateComponent implements OnInit, AfterViewInit
 {
 
+  profil: string = "";
+  profils: ParticipantEnum[] = ProfilList;
+
   journees: Journees = new Journees();
 
   PS: ParticipantEnum[] = ParticipantStatutList;
@@ -22,10 +26,18 @@ export class ParticipantCreateComponent implements OnInit, AfterViewInit
 
   participant: Participant = new Participant();
 
-  constructor(private diversService: DiversService, private participantService: ParticipantService, private router: Router, private menu: MenuComponent) { }
+  constructor(
+    private diversService: DiversService,
+    private participantService: ParticipantService,
+    private router: Router,
+    private menu: MenuComponent,
+    private accountService: AccountService
+  ) { }
 
   ngOnInit()
   {
+    this.profil = this.accountService.getRole();
+
     this.journees = new Journees();
     this.diversService.getJournees().subscribe(data => { this.journees = data; });
   }

+ 16 - 3
src/app/composants/participant-update/participant-update.component.ts

@@ -3,16 +3,20 @@ import { ActivatedRoute, Router } from '@angular/router';
 import { FormsModule, NgForm } from '@angular/forms';
 
 import { MenuComponent } from '../menu/menu.component';
-import { Participant, ParticipantEnum, ParticipantStatutList, ParticipantModePaiementList } from '../../interfaces/participant';
-import { ParticipantService } from '../../services/participant.service';
+import { Participant, ParticipantEnum, ProfilList, ParticipantStatutList, ParticipantModePaiementList } from '../../interfaces/participant';
 import { Journees } from '../../interfaces/divers';
+import { ParticipantService } from '../../services/participant.service';
 import { DiversService } from '../../services/divers.service'
+import { AccountService } from '../../services/account.service';
 
 @Component({ selector: 'app-participant-update', imports: [FormsModule, MenuComponent], templateUrl: './participant-update.component.html', styleUrl: './participant-update.component.css' })
 
 export class ParticipantUpdateComponent implements OnInit, AfterViewInit
 {
 
+  private profil: string = "";
+  profils: ParticipantEnum[] = ProfilList;
+
   journees: Journees = new Journees();
 
   PS: ParticipantEnum[] = ParticipantStatutList;
@@ -23,10 +27,19 @@ export class ParticipantUpdateComponent implements OnInit, AfterViewInit
   numeroParticipant: number = 0;
   participant: Participant = new Participant();
 
-  constructor(private diversService: DiversService, private participantService: ParticipantService, private route: ActivatedRoute, private router: Router, private menu: MenuComponent) { }
+  constructor(
+    private diversService: DiversService,
+    private participantService: ParticipantService,
+    private route: ActivatedRoute,
+    private router: Router,
+    private menu: MenuComponent,
+    private accountService: AccountService
+  ) { }
 
   ngOnInit()
   {
+    this.profil = this.accountService.getRole();
+
     this.journees = new Journees();
     this.diversService.getJournees().subscribe(data => { this.journees = data; });
 

+ 8 - 0
src/app/interfaces/participant.ts

@@ -1,5 +1,12 @@
 export class ParticipantEnum { key!: string; value!: string; }
 
+export const ProfilList: ParticipantEnum[] =
+[
+  { key: "ADMIN", value: $localize`Administrateur`},
+  { key: "ORGA", value: $localize`Organisateur`},
+  { key: "USER", value: $localize`Participant`},
+];
+
 export const ParticipantStatutList: ParticipantEnum[] =
 [
   { key: "EN_ATTENTE", value: $localize`En attente`},
@@ -25,6 +32,7 @@ export class Participant
   dateCreation: string = "";
   dateModification: string = "";
   numeroParticipant: number = 0;
+  role: string = "USER";
   nom: string = "";
   prenom: string = "";
   pseudonyme: string = "";

+ 1 - 0
src/app/services/account.service.ts

@@ -33,6 +33,7 @@ export class AccountService
   public isLogged() { if (this.userSubject.value) { return true; } return false; }
   public getUsername() { if (this.userSubject.value) { return this.userSubject.value.username; } return ""; }
   public getRole() { if (this.userSubject.value) { return this.userSubject.value.role; } return ""; }
+  public getDelaiAvantDeconnexion() { if (this.userSubject.value) { return this.userSubject.value.delaiAvantDeconnexion; } return 15; }
   public getAccessToken() { if (this.userSubject.value) { return this.userSubject.value.accessToken; } return ""; }
   private getRefreshToken() { if (this.userSubject.value) { return this.userSubject.value.refreshToken; } return ""; }