rajah 10 сар өмнө
parent
commit
f5c3987773

+ 1 - 1
src/app/composants/poll-booth/poll-booth.component.css

@@ -1,3 +1,3 @@
-#selectionChosen, #selectionDiscarded { width: 360px; min-height: 400px; overflow-x: auto; padding: 0px; }
+#selectionChosen, #selectionDiscarded { width: 400px; min-height: 400px; overflow-x: auto; padding: 0px; }
 
 .boutons { width: 90px; }

+ 1 - 1
src/app/composants/poll-booth/poll-booth.component.html

@@ -84,7 +84,7 @@
 	<div class="modal-dialog modal-dialog-centered" role="document">
 		<div class="modal-content">
 			<div class="modal-header">
-        <h5 class="modal-title text-danger" id="modalEffacerTitre"><span i18n>Valider</span></h5>
+        <h5 class="modal-title text-danger" id="modalValiderTitre"><span i18n>Valider</span></h5>
 			</div>
       <div class="modal-body">
         <span i18n>

+ 20 - 0
src/app/composants/poll-list/poll-list.component.html

@@ -6,6 +6,7 @@
   		<div class="row">
   			<div class="form-group col-sm-4 label-nobr">
   				<button type="button" (click)="goToRefreshListCategorie()" class="btn bg-gradient btn-primary btn-sm" style="margin-right: 5px;"><i class="fa-solid fa-rotate"></i>&nbsp;<span i18n>Actualiser</span></button>
+          @if (this.logged && (this.role === "ADMIN")) { <button type="button" #boutonCloturer class="btn bg-gradient btn-danger btn-sm disabled" style="margin-right: 5px;" data-bs-toggle="modal" data-bs-target="#modalFermerVotes"><i class="fa-solid fa-lock"></i>&nbsp;<span i18n>Clôturer les votes</span></button> }
   			</div>
   		</div>
   	</div>
@@ -26,4 +27,23 @@
   		</table>
   	</div>
   </div>
+
+  <div class="modal fade" id="modalFermerVotes" tabindex="-1" aria-labelledby="modalFermerVotesTitre" aria-hidden="true">
+    <div class="modal-dialog modal-dialog-centered" role="document">
+      <div class="modal-content">
+        <div class="modal-header">
+          <h5 class="modal-title text-danger" id="modalFermerVotesTitre"><span i18n>Clôturer tous les scrutins</span></h5>
+        </div>
+        <div class="modal-body">
+          <span i18n>
+            Les participants ne pourront plus voter pour l'ensemble des catégories. Les choix en cours seront validés automatiquement. Les résultats seront calculés et en attente pour une prochaine publication.
+          </span>
+        </div>
+        <div class="modal-footer">
+          <button type="button" class="btn bg-gradient btn-secondary btn-sm" data-bs-dismiss="modal"><span i18n>Annuler</span></button>
+          <button type="button" class="btn bg-gradient btn-danger btn-sm" (click)="fermerVotes()" data-bs-dismiss="modal"><span i18n>Confirmer</span></button>
+        </div>
+      </div>
+    </div>
+  </div>
 </div>

+ 36 - 5
src/app/composants/poll-list/poll-list.component.ts

@@ -1,29 +1,60 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, OnInit, ViewChild, ElementRef, Renderer2 } from '@angular/core';
 import { Router, ActivatedRoute } from '@angular/router';
 
 import { MenuComponent } from '../menu/menu.component';
 import { Categorie } from '../../interfaces/categorie';
 import { CategorieService } from '../../services/categorie.service';
+import { AccountService } from '../../services/account.service';
 
 @Component({ selector: 'app-poll-list', imports: [MenuComponent], templateUrl: './poll-list.component.html', styleUrl: './poll-list.component.css' })
 
 export class PollListComponent implements OnInit
 {
 
+  @ViewChild('boutonCloturer', {static: false}) boutonCloturer!: ElementRef;
+
+  logged: boolean = false;
+  role: string = "";
+
   categories: Categorie[] = [];
+  affiches: number = 0;
 
   constructor(
     private categorieService: CategorieService,
     private router: Router,
-    private route: ActivatedRoute
+    private route: ActivatedRoute,
+    private accountService: AccountService,
+    private renderer: Renderer2
   ) { }
 
-  ngOnInit() { this.goToRefreshListCategorie(); }
-
-  private retreiveDatas() { this.categorieService.getListCategorie(false).subscribe(data => { this.categories = data; }); }
+  ngOnInit()
+  {
+    this.logged = this.accountService.isLogged();
+    this.role = this.accountService.getRole();
+
+    this.goToRefreshListCategorie();
+  }
+
+  private retreiveDatas()
+  {
+    this.categorieService.getListCategorie(false).subscribe(data => {
+      this.affiches = 0;
+      this.categories = data;
+      if (this.categories)
+      {
+        if (this.categories.length > 0)
+        {
+          for (let i = 0; i < this.categories.length; i++) { if (this.categories[i].pollable) { this.affiches++; } }
+        }
+      }
+      if (this.affiches > 0) { this.renderer.removeClass(this.boutonCloturer.nativeElement, 'disabled'); }
+    });
+  }
 
   goToRefreshListCategorie() { this.retreiveDatas(); }
 
   voteCategorie(id: number) { this.router.navigate(['/poll-booth', id]); }
 
+  fermerVotes() { if (this.logged && (this.role === "ADMIN")) { this.categorieService.cloreScrutins().subscribe(() => { this.goToRefreshListCategorie(); }); } }
+
 }

+ 1 - 1
src/app/composants/show-links/show-links.component.css

@@ -1,3 +1,3 @@
-#selectionLinked, #selectionUnlinked { width: 360px; min-height: 400px; overflow-x: auto; padding: 0px; }
+#selectionLinked, #selectionUnlinked { width: 400px; min-height: 400px; overflow-x: auto; padding: 0px; }
 
 .boutons { width: 90px; }

+ 1 - 1
src/app/composants/show-links/show-links.component.html

@@ -34,7 +34,7 @@
     </div>
 
     <div class="col">
-      <select class="form-select-sm" size="16" id="selectionUnlinked" #selecteurUnlinked (change)="changeEtatBoutonsUnlinked($event)">
+      <select class="form-select-sm" size="16" id="selectionUnlinked" #selecteurUnlinked (change)="changeEtatBoutonsUnlinked($event)" [class.disabled]="categorie.pollable">
       @for (prod of unlinkedProductions; track prod.numeroProduction) {
         <option [value]="prod.numeroProduction"> {{ prod.titre }} - {{ prod.auteurs }} / {{ prod.groupes }}</option>
       }

+ 2 - 2
src/app/composants/show-links/show-links.component.ts

@@ -66,7 +66,7 @@ export class ShowLinksComponent implements OnInit
   {
     this.numeroProduction = event.target.value;
 
-    var b: boolean = (this.numeroProduction == 0);
+    var b: boolean = (this.numeroProduction == 0) || (this.categorie.pollable);
 
     if (this.boutonLier) { if (b) { this.renderer.addClass(this.boutonLier.nativeElement, 'disabled'); } else { this.renderer.removeClass(this.boutonLier.nativeElement, 'disabled'); } }
   }
@@ -79,7 +79,7 @@ export class ShowLinksComponent implements OnInit
   {
     this.numeroProduction = -event.target.value;
 
-    var b: boolean = (this.numeroProduction == 0);
+    var b: boolean = (this.numeroProduction == 0) || (this.categorie.pollable);
 
     if (this.boutonRetirer) { if (b) { this.renderer.addClass(this.boutonRetirer.nativeElement, 'disabled'); } else { this.renderer.removeClass(this.boutonRetirer.nativeElement, 'disabled'); } }
     if (this.boutonAvancer) { if (b) { this.renderer.addClass(this.boutonAvancer.nativeElement, 'disabled'); } else { this.renderer.removeClass(this.boutonAvancer.nativeElement, 'disabled'); } }

+ 25 - 6
src/app/composants/show-list/show-list.component.html

@@ -15,15 +15,16 @@
 @for (categorie of categories; track categorie.numeroCategorie) { @if (categorie.available) {
 <div class="card shadow">
   <div class="card-header shadow-sm">
-    {{ categorie.libelle }}&nbsp;&nbsp;&nbsp;&nbsp;
-    @if (!categorie.pollable) {
+    {{ categorie.libelle }}
+    @if (!categorie.pollable) { &nbsp;&nbsp;&nbsp;&nbsp;
       <button type="button" (click)="lierProductions(categorie.numeroCategorie)" class="btn bg-gradient btn-primary btn-sm" style="margin-right: 5px;" i18n-tootip tooltip="Rattacher des productions à cette catégorie et les ordonner" placement="right" container="body"><i class="fa-solid fa-link"></i>&nbsp;<span i18n>Rattacher</span></button>
       <button type="button" (click)="getDiaporama(categorie.numeroCategorie, categorie.libelle)" class="btn bg-gradient btn-primary btn-sm" style="margin-right: 5px;" i18n-tootip tooltip="Télécharger le fichier de présentations de cette catégorie" placement="right" container="body"><i class="fa-solid fa-file-code"></i>&nbsp;<span i18n>Diaporama</span></button>
+      <button type="button" [disabled]="productions.length == 0" class="btn bg-gradient btn-danger btn-sm" style="margin-right: 5px;" i18n-tootip tooltip="Ouvrir le scrutin, après que le présentateur a utilisé le diaporama publiquement" placement="right" container="body" data-bs-toggle="modal" [attr.data-bs-target]="'#modalOuvrirVotes' + categorie.numeroCategorie"><i class="fa-solid fa-check-to-slot"></i>&nbsp;<span i18n>Ouvrir les votes</span></button>
     }
     @if (categorie.uploadable) { }
-    @if (categorie.pollable) { }
-    @if (categorie.computed) { }
-    @if (categorie.displayable) { }
+    @if (categorie.pollable) { <span i18n> : le scrutin est ouvert. </span> }
+    @if (categorie.computed) {  <span i18n> : le scrutin est fermé, les résultats sont calculés. </span> }
+    @if (categorie.displayable) { <span i18n> : les résultats sont publiés. </span> }
   </div>
   <div class="card-body hstack align-items-baseline show_row">
 {{ resetLettre() }} @for (production of productions; track production.numeroProduction) { @if (categorie.numeroCategorie == production.numeroCategorie) {
@@ -55,6 +56,24 @@
 } }
   </div>
 </div>
-} }
 
+<div class="modal fade" [attr.id]="'modalOuvrirVotes' + categorie.numeroCategorie" tabindex="-1" aria-labelledby="modalOuvrirVotesTitre" aria-hidden="true">
+	<div class="modal-dialog modal-dialog-centered" role="document">
+		<div class="modal-content">
+			<div class="modal-header">
+        <h5 class="modal-title text-danger" id="modalOuvrirVotesTitre"><span i18n>Ouvrir les votes pour {{ categorie.libelle }}</span></h5>
+			</div>
+      <div class="modal-body">
+        <span i18n>
+          A enclencher une fois que le diaporama ait été affiché publiquement, et les productions de cette catégorie présentées par la régie.
+        </span>
+      </div>
+			<div class="modal-footer">
+				<button type="button" class="btn bg-gradient btn-secondary btn-sm" data-bs-dismiss="modal"><span i18n>Annuler</span></button>
+        <button type="button" class="btn bg-gradient btn-danger btn-sm" (click)="ouvrirScrutin(categorie.numeroCategorie)" data-bs-dismiss="modal"><span i18n>Confirmer</span></button>
+			</div>
+		</div>
+	</div>
+</div>
+} }
 </div>

+ 2 - 0
src/app/composants/show-list/show-list.component.ts

@@ -58,4 +58,6 @@ export class ShowListComponent implements OnInit
   getFile(id: number, nom: string) { this.productionService.getProductionFile(id).subscribe(response => { this.saveFile(response.body, nom); }); }
   saveFile(data: any, filename?: string) { const blob = new Blob([data], {type: 'application/zip'}); saveAs(blob, filename); }
 
+  ouvrirScrutin(id: number) { this.categorieService.ouvrirScrutin(id).subscribe(() => { this.goToRefreshListCategorie(); }); }
+
 }

+ 4 - 0
src/app/services/categorie.service.ts

@@ -30,4 +30,8 @@ export class CategorieService
 
   deleteCategorie(id: number): Observable<Object>{ return this.httpClient.delete(`${this.baseURL}/delete/${id}`); }
 
+  ouvrirScrutin(id: number): Observable<Object>{ return this.httpClient.get(`${this.baseURL}/open-poll/${id}`); }
+
+  cloreScrutins(): Observable<Object>{ return this.httpClient.get(`${this.baseURL}/close-polls`); }
+
 }