Mise à jour de composant partagés

This commit is contained in:
Julien Gautier
2023-10-03 13:47:48 +02:00
parent d0039dc275
commit 6d3e79aac5
40 changed files with 1327 additions and 345 deletions
@@ -63,6 +63,14 @@
</th> </th>
<th class="font-monospace text-end">{{ grandTotal }}</th> <th class="font-monospace text-end">{{ grandTotal }}</th>
</tr> </tr>
<tr>
<th class="text-end">Moyenne</th>
<th *ngFor='let value of seriesRowAvg; let i=index' class="font-monospace text-end">
<span *ngIf="value; else elseBlock" class="pr-1">{{ value }}</span>
<ng-template #elseBlock><span class="text-empty pr-1">{{ value }}</span></ng-template>
</th>
<th class="font-monospace text-end">{{ grandAvg }}</th>
</tr>
</tfoot> </tfoot>
</table> </table>
</mat-expansion-panel> </mat-expansion-panel>
@@ -31,12 +31,14 @@ export class JumpsByMonthComponent implements OnInit, OnDestroy {
public subtitle: string = 'Nombre total de sauts par mois'; public subtitle: string = 'Nombre total de sauts par mois';
public min = 0; public min = 0;
public max = 0; public max = 0;
public grandAvg = 0;
public grandTotal = 0; public grandTotal = 0;
public seriesHeader: string[] = []; public seriesHeader: string[] = [];
public seriesName: String[] = []; public seriesName: String[] = [];
public seriesRow: any[] = []; public seriesRow: any[] = [];
public seriesColor: String[] = this._utilitiesService.getChartColors(); public seriesColor: String[] = this._utilitiesService.getChartColors();
public seriesRowTotal: number[] = []; public seriesRowTotal: number[] = [];
public seriesRowAvg: number[] = [];
public seriesColTotal: number[] = []; public seriesColTotal: number[] = [];
public displayCharts = false; public displayCharts = false;
public barChartJumps: Configuration = this._utilitiesService.getBarConfig(); public barChartJumps: Configuration = this._utilitiesService.getBarConfig();
@@ -83,7 +85,12 @@ export class JumpsByMonthComponent implements OnInit, OnDestroy {
const total = row.reduce((partialSum, a) => partialSum + a, 0); const total = row.reduce((partialSum, a) => partialSum + a, 0);
this.seriesRowTotal.push(total); this.seriesRowTotal.push(total);
}); });
this.grandTotal = this.seriesColTotal.reduce((partialSum, a) => partialSum + a, 0); this.seriesRowTotal.forEach((row: number) => {
let value: number = (row/this.seriesName.length);
this.seriesRowAvg.push(value);
});
this.grandAvg = this.seriesRowAvg.reduce((partialSum, accumulated) => partialSum + accumulated, 0);
this.grandTotal = this.seriesColTotal.reduce((partialSum, accumulated) => partialSum + accumulated, 0);
this.barChartJumps = { this.barChartJumps = {
type: 'Bar', type: 'Bar',
data: { data: {
@@ -1,64 +1,294 @@
<h2 mat-dialog-title>Ajouter un saut</h2> <h2 mat-dialog-title class="bg-warn border-bottom border-light-subtle d-flex mb-3 pt-3 pb-2">
<mat-divider class="mt-2 mb-1 border-light-subtle"></mat-divider> Ajouter un saut<span class="flex-spacer"></span>
<mat-icon fontIcon="close" class="pointer" (click)="closeDialog()"></mat-icon>
</h2>
<mat-dialog-content> <mat-dialog-content>
<div fxLayout="row wrap"> <div class="container">
<!-- column --> <!--
<div fxFlex.gt-lg="25" fxFlex.gt-md="50" fxFlex.gt-xs="100" fxFlex="100" class="px-2"> <div class="row">
<mat-form-field appearance="fill" class="me-2"> <div class="col-xs-12 border-bottom border-dark pb-2 mb-2">
<mat-label>Numéro</mat-label> <mat-form-field appearance="outline" class="mt-2 me-2" color="warn">
<input matInput [(ngModel)]="jump.numero"> <mat-label>Numéro ou plage de saut à ajouter</mat-label>
<input matInput [(ngModel)]="params.numeros" required />
<mat-hint>645 / +5 / 650-660</mat-hint>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="me-2"> <mat-form-field appearance="outline" class="mt-2 me-3" color="warn">
<mat-label>Date</mat-label> <mat-label>Choisissez une date</mat-label>
<input matInput [(ngModel)]="jump.date"> <input matInput [matDatepicker]="datepicker" [(ngModel)]="params.date" (dateChange)="onDateChange()" required />
<mat-hint>MM/DD/YYYY</mat-hint>
<mat-datepicker-toggle matIconSuffix [for]="datepicker"></mat-datepicker-toggle>
<mat-datepicker #datepicker>
<mat-datepicker-actions>
<button mat-button matDatepickerCancel>Annuler</button>
<button mat-raised-button color="warn" matDatepickerApply>Appliquer</button>
</mat-datepicker-actions>
</mat-datepicker>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="me-2"> <mat-checkbox (change)="setLastJump($event.checked)" [checked]="useLast.all">
<mat-icon fontIcon="history" class="align-middle me-2"></mat-icon> <span class="d-inline-block align-middle">Utiliser les valeurs du dernier saut</span>
</mat-checkbox>
</div>
</div>
-->
<form class="row" [formGroup]="jumpForm" (ngSubmit)="submitForm()">
<div class="col-xs-12 border-bottom border-dark pb-2 mb-2">
<mat-form-field appearance="outline" class="mt-2 me-2" color="warn">
<mat-label>Numéro ou plage de saut à ajouter</mat-label>
<input matInput formControlName="numero" required />
<mat-hint>645 / +5 / 650-660</mat-hint>
</mat-form-field>
<mat-form-field appearance="outline" class="mt-2 me-3" color="warn">
<mat-label>Choisissez une date</mat-label>
<input matInput [matDatepicker]="datepicker" formControlName="date" (dateChange)="onDateChange()" required />
<mat-hint>MM/DD/YYYY</mat-hint>
<mat-datepicker-toggle matIconSuffix [for]="datepicker"></mat-datepicker-toggle>
<mat-datepicker #datepicker>
<mat-datepicker-actions>
<button mat-button matDatepickerCancel>Annuler</button>
<button mat-raised-button color="warn" matDatepickerApply>Appliquer</button>
</mat-datepicker-actions>
</mat-datepicker>
</mat-form-field>
<mat-checkbox (change)="setLastJump($event.checked)" [checked]="useLast.all">
<mat-icon fontIcon="history" class="align-middle me-2"></mat-icon> <span class="d-inline-block align-middle">Utiliser les valeurs du dernier saut</span>
</mat-checkbox>
</div>
<div class="col-lg-6 col-md-12">
<h4 class="border-bottom border-secondary mb-3 lh-lg">
Dropzone
<mat-checkbox class="float-end" (change)="setLastDropzone($event.checked)" [checked]="useLast.dropzone">
<mat-icon fontIcon="history" class="align-middle"></mat-icon>
</mat-checkbox>
</h4>
<mat-form-field appearance="fill" class="me-2" color="warn">
<mat-label>Lieu</mat-label>
<input matInput formControlName="lieu">
<mat-error *ngIf="this.jumpForm.controls['lieu'].status === 'INVALID'">{{getErrorMessage('lieu')}}</mat-error>
</mat-form-field>
<mat-form-field appearance="fill" class="me-2" color="warn">
<mat-label>Oaci</mat-label>
<input matInput formControlName="oaci">
<mat-error *ngIf="this.jumpForm.controls['oaci'].status === 'INVALID'">{{getErrorMessage('oaci')}}</mat-error>
</mat-form-field>
<h4 class="border-bottom border-secondary mb-3 lh-lg">
Aéronef
<mat-checkbox class="float-end" (change)="setLastAeronef($event.checked)" [checked]="useLast.aeronef">
<mat-icon fontIcon="history" class="align-middle"></mat-icon>
</mat-checkbox>
</h4>
<mat-form-field appearance="fill" class="me-2" color="warn">
<mat-label>Aéronef</mat-label>
<input matInput formControlName="aeronef">
<mat-error *ngIf="this.jumpForm.controls['aeronef'].status === 'INVALID'">{{getErrorMessage('aeronef')}}</mat-error>
</mat-form-field>
<mat-form-field appearance="fill" class="me-2" color="warn">
<mat-label>Imatriculation</mat-label>
<input matInput formControlName="imat">
<mat-error *ngIf="this.jumpForm.controls['imat'].status === 'INVALID'">{{getErrorMessage('imat')}}</mat-error>
</mat-form-field>
<h4 class="border-bottom border-secondary mb-3 lh-lg">
Voile
<mat-checkbox class="float-end" (change)="setLastVoile($event.checked)" [checked]="useLast.voile">
<mat-icon fontIcon="history" class="align-middle"></mat-icon>
</mat-checkbox>
</h4>
<mat-form-field appearance="fill" class="me-2" color="warn">
<mat-label>Modèle</mat-label>
<input matInput formControlName="voile">
<mat-error *ngIf="this.jumpForm.controls['voile'].status === 'INVALID'">{{getErrorMessage('voile')}}</mat-error>
</mat-form-field>
<mat-form-field appearance="fill" class="me-2" color="warn">
<mat-label>Taille en ft<sup>2</sup></mat-label>
<input matInput formControlName="taille" type="number" min="0" step="1">
<span matTextSuffix>ft<sup>2</sup></span>
<mat-error *ngIf="this.jumpForm.controls['taille'].status === 'INVALID'">{{getErrorMessage('taille')}}</mat-error>
</mat-form-field>
</div>
<div class="col-lg-6 col-md-12">
<h4 class="border-bottom border-secondary mb-3 lh-lg">
Altitude
<mat-checkbox class="float-end" (change)="setLastAltitude($event.checked)" [checked]="useLast.altitude">
<mat-icon fontIcon="history" class="align-middle"></mat-icon>
</mat-checkbox>
</h4>
<mat-form-field appearance="fill" class="me-2" color="warn">
<mat-label>Hauteur de largage</mat-label>
<input matInput formControlName="hauteur" type="number" min="0" step="1">
<mat-error *ngIf="this.jumpForm.controls['hauteur'].status === 'INVALID'">{{getErrorMessage('hauteur')}}</mat-error>
</mat-form-field>
<mat-form-field appearance="fill" class="me-2" color="warn">
<mat-label>Hauteur de déploiement</mat-label>
<input matInput formControlName="deploiement" type="number" min="0" step="1">
<mat-error *ngIf="this.jumpForm.controls['deploiement'].status === 'INVALID'">{{getErrorMessage('deploiement')}}</mat-error>
</mat-form-field>
<h4 class="border-bottom border-secondary mb-3 lh-lg">
Discipline
<mat-checkbox class="float-end" (change)="setLastDiscipline($event.checked)" [checked]="useLast.discipline">
<mat-icon fontIcon="history" class="align-middle"></mat-icon>
</mat-checkbox>
</h4>
<mat-form-field appearance="fill" class="me-2" color="warn">
<mat-label>Categorie</mat-label>
<input matInput formControlName="categorie">
<mat-error *ngIf="this.jumpForm.controls['categorie'].status === 'INVALID'">{{getErrorMessage('categorie')}}</mat-error>
</mat-form-field>
<mat-form-field appearance="fill" class="me-2" color="warn">
<mat-label>Module</mat-label>
<input matInput formControlName="module">
<mat-error *ngIf="this.jumpForm.controls['module'].status === 'INVALID'">{{getErrorMessage('module')}}</mat-error>
</mat-form-field>
<h4 class="border-bottom border-secondary mb-3 lh-lg">
Divers
<mat-checkbox class="float-end" (change)="setLastDivers($event.checked)" [checked]="useLast.divers">
<mat-icon fontIcon="history" class="align-middle"></mat-icon>
</mat-checkbox>
</h4>
<mat-form-field appearance="fill" class="me-2" color="warn">
<mat-label>Accessoires</mat-label>
<input matInput formControlName="accessoires">
<mat-error *ngIf="this.jumpForm.controls['accessoires'].status === 'INVALID'">{{getErrorMessage('accessoires')}}</mat-error>
</mat-form-field>
<mat-form-field appearance="fill" class="me-2" color="warn">
<mat-label>Zone</mat-label>
<input matInput formControlName="zone">
<mat-error *ngIf="this.jumpForm.controls['zone'].status === 'INVALID'">{{getErrorMessage('zone')}}</mat-error>
</mat-form-field>
</div>
<div class="col-lg-6 col-md-12">
<h4 class="border-bottom border-secondary mb-3 lh-lg">
Groupe
<mat-checkbox class="float-end" (change)="setLastGroupe($event.checked)" [checked]="useLast.groupe">
<mat-icon fontIcon="history" class="align-middle"></mat-icon>
</mat-checkbox>
</h4>
<mat-form-field appearance="fill" class="me-2" color="warn">
<mat-label>Sautants</mat-label>
<input matInput placeholder="Ajouter un sautant" [formControl]="tagField" (keyup.enter)="addSautant()">
</mat-form-field>
<mat-form-field appearance="fill" class="me-2" color="warn">
<mat-label>Nombre de participants</mat-label>
<input matInput formControlName="participants" type="number" min="0" step="1">
<mat-error *ngIf="this.jumpForm.controls['participants'].status === 'INVALID'">{{getErrorMessage('participants')}}</mat-error>
</mat-form-field>
<div class="mb-2">
<span *ngFor="let sautant of jump.sautants" class="badge rounded-pill bg-primary mb-2 me-1 pe-3 py-1 fw-normal text-dark">
<mat-icon class="align-middle pointer me-1" fontIcon="close" (click)="removeSautant(sautant)"></mat-icon>
{{ sautant }}
</span>
<span class="badge rounded-pill bg-accent mb-2 me-1 pe-3 py-1 fw-normal text-dark">
<mat-icon class="align-middle pointer me-1" fontIcon="person"></mat-icon>
ju_solide
</span>
</div>
</div>
<div class="col-lg-6 col-md-12">
<h4 class="border-bottom border-secondary mb-3 lh-lg">
Programme
<mat-checkbox class="float-end" (change)="setLastProgramme($event.checked)" [checked]="useLast.programme">
<mat-icon fontIcon="history" class="align-middle"></mat-icon>
</mat-checkbox>
</h4>
<mat-form-field appearance="fill" class="me-2 w-100" color="warn">
<mat-label>Programme</mat-label>
<textarea matInput formControlName="programme"></textarea>
<mat-error *ngIf="this.jumpForm.controls['programme'].status === 'INVALID'">{{getErrorMessage('programme')}}</mat-error>
</mat-form-field>
<h4 class="border-bottom border-secondary mb-3 lh-lg">Vidéo</h4>
<mat-form-field appearance="fill" class="me-2" color="warn">
<mat-label>Dossier</mat-label>
<input matInput formControlName="dossier">
<mat-error *ngIf="this.jumpForm.controls['dossier'].status === 'INVALID'">{{getErrorMessage('dossier')}}</mat-error>
</mat-form-field>
<mat-form-field appearance="fill" class="me-2" color="warn">
<mat-label>Video</mat-label>
<input matInput formControlName="video">
<mat-error *ngIf="this.jumpForm.controls['video'].status === 'INVALID'">{{getErrorMessage('video')}}</mat-error>
</mat-form-field>
<span class="d-inline-block align-middle ms-1">{{ filepath }}{{ filename }}</span>
</div>
</form>
<div class="row" [hidden]="true">
<div class="col-lg-6 col-md-12">
<h4 class="border-bottom border-secondary mb-3 lh-lg">
Dropzone
<mat-checkbox class="float-end" (change)="setLastDropzone($event.checked)" [(ngModel)]="useLast.dropzone">
<mat-icon fontIcon="history" class="align-middle"></mat-icon>
</mat-checkbox>
</h4>
<mat-form-field appearance="fill" class="me-2" color="warn">
<mat-label>Lieu</mat-label> <mat-label>Lieu</mat-label>
<input matInput [(ngModel)]="jump.lieu"> <input matInput [(ngModel)]="jump.lieu">
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="me-2" color="warn">
<mat-label>Oaci</mat-label>
<input matInput [(ngModel)]="jump.oaci">
</mat-form-field>
<h4 class="border-bottom border-secondary mb-3 lh-lg">
Aéronef
<mat-checkbox class="float-end" (change)="setLastAeronef($event.checked)" [(ngModel)]="useLast.aeronef">
<mat-icon fontIcon="history" class="align-middle"></mat-icon>
</mat-checkbox>
</h4>
<mat-form-field appearance="fill" class="me-2"> <mat-form-field appearance="fill" class="me-2">
<mat-label>Aeronef</mat-label> <mat-label>Aéronef</mat-label>
<input matInput [(ngModel)]="jump.aeronef"> <input matInput [(ngModel)]="jump.aeronef">
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="me-2"> <mat-form-field appearance="fill" class="me-2">
<mat-label>Hauteur</mat-label> <mat-label>Imatriculation</mat-label>
<input matInput [(ngModel)]="jump.hauteur"> <input matInput [(ngModel)]="jump.imat">
</mat-form-field> </mat-form-field>
<h4 class="border-bottom border-secondary mb-3 lh-lg">
Voile
<mat-checkbox class="float-end" (change)="setLastVoile($event.checked)" [(ngModel)]="useLast.voile">
<mat-icon fontIcon="history" class="align-middle"></mat-icon>
</mat-checkbox>
</h4>
<mat-form-field appearance="fill" class="me-2"> <mat-form-field appearance="fill" class="me-2">
<mat-label>Voile</mat-label> <mat-label>Modèle</mat-label>
<input matInput [(ngModel)]="jump.voile"> <input matInput [(ngModel)]="jump.voile">
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="me-2"> <mat-form-field appearance="fill" class="me-2">
<mat-label>Taille</mat-label> <mat-label>Taille</mat-label>
<input matInput [(ngModel)]="jump.taille"> <input matInput [(ngModel)]="jump.taille" type="number" min="0" step="1">
</mat-form-field> </mat-form-field>
</div>
<div class="col-lg-6 col-md-12">
<h4 class="border-bottom border-secondary mb-3 lh-lg">
Altitude
<mat-checkbox class="float-end" (change)="setLastAltitude($event.checked)" [(ngModel)]="useLast.altitude">
<mat-icon fontIcon="history" class="align-middle"></mat-icon>
</mat-checkbox>
</h4>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Hauteur</mat-label>
<input matInput [(ngModel)]="jump.hauteur" type="number" min="0" step="1">
</mat-form-field>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Hauteur de déploiement</mat-label>
<input matInput [(ngModel)]="jump.deploiement" type="number" min="0" step="1">
</mat-form-field>
<h4 class="border-bottom border-secondary mb-3 lh-lg">
Discipline
<mat-checkbox class="float-end" (change)="setLastDiscipline($event.checked)" [(ngModel)]="useLast.discipline">
<mat-icon fontIcon="history" class="align-middle"></mat-icon>
</mat-checkbox>
</h4>
<mat-form-field appearance="fill" class="me-2"> <mat-form-field appearance="fill" class="me-2">
<mat-label>Categorie</mat-label> <mat-label>Categorie</mat-label>
<input matInput [(ngModel)]="jump.categorie"> <input matInput [(ngModel)]="jump.categorie">
<mat-hint>FF / Solo / VR / Wingsuit</mat-hint>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="me-2"> <mat-form-field appearance="fill" class="me-2">
<mat-label>Module</mat-label> <mat-label>Module</mat-label>
<input matInput [(ngModel)]="jump.module"> <input matInput [(ngModel)]="jump.module">
<mat-hint>Chutas / Track / Trace</mat-hint>
</mat-form-field> </mat-form-field>
</div> <h4 class="border-bottom border-secondary mb-3 lh-lg">
<!-- column --> Divers
<div fxFlex.gt-lg="25" fxFlex.gt-md="50" fxFlex.gt-xs="100" fxFlex="100" class="px-2"> <mat-checkbox class="float-end" (change)="setLastDivers($event.checked)" [(ngModel)]="useLast.divers">
<mat-form-field appearance="fill" class="me-2"> <mat-icon fontIcon="history" class="align-middle"></mat-icon>
<mat-label>Participants</mat-label> </mat-checkbox>
<input matInput [(ngModel)]="jump.participants"> </h4>
</mat-form-field>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Programme</mat-label>
<input matInput [(ngModel)]="jump.programme">
</mat-form-field>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Oaci</mat-label>
<input matInput [(ngModel)]="jump.oaci">
</mat-form-field>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Imat</mat-label>
<input matInput [(ngModel)]="jump.imat">
</mat-form-field>
<mat-form-field appearance="fill" class="me-2"> <mat-form-field appearance="fill" class="me-2">
<mat-label>Accessoires</mat-label> <mat-label>Accessoires</mat-label>
<input matInput [(ngModel)]="jump.accessoires"> <input matInput [(ngModel)]="jump.accessoires">
@@ -67,25 +297,53 @@
<mat-label>Zone</mat-label> <mat-label>Zone</mat-label>
<input matInput [(ngModel)]="jump.zone"> <input matInput [(ngModel)]="jump.zone">
</mat-form-field> </mat-form-field>
</div>
<div class="col-lg-6 col-md-12">
<h4 class="border-bottom border-secondary mb-3 lh-lg">
Groupe
<mat-checkbox class="float-end" (change)="setLastGroupe($event.checked)" [(ngModel)]="useLast.groupe">
<mat-icon fontIcon="history" class="align-middle"></mat-icon>
</mat-checkbox>
</h4>
<mat-form-field appearance="fill" class="me-2"> <mat-form-field appearance="fill" class="me-2">
<mat-label>Dossier</mat-label> <mat-label>Sautants</mat-label>
<input matInput [(ngModel)]="jump.dossier"> <input matInput type="text" placehomder="Ajouter un sautant" [formControl]="tagField" (keyup.enter)="addSautant()">
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="me-2"> <mat-form-field appearance="fill" class="me-2">
<mat-label>Video</mat-label> <mat-label>Nombre de participants</mat-label>
<input matInput [(ngModel)]="jump.video"> <input matInput [(ngModel)]="jump.participants" type="number" min="0" step="1" [value]="jump.sautants.length+1">
</mat-form-field> </mat-form-field>
<div class="mb-2">
<span *ngFor="let sautant of jump.sautants" class="badge rounded-pill bg-primary mb-2 me-1 pe-3 py-1 fw-normal text-dark">
<mat-icon class="align-middle pointer me-1" fontIcon="close" (click)="removeSautant(sautant)"></mat-icon>
{{ sautant }}
</span>
<span class="badge rounded-pill bg-accent mb-2 me-1 pe-3 py-1 fw-normal text-dark">
<mat-icon class="align-middle pointer me-1" fontIcon="person"></mat-icon>
ju_solide
</span>
</div> </div>
<!-- column -->
<div fxFlex.gt-lg="25" fxFlex.gt-md="50" fxFlex.gt-xs="100" fxFlex="100" class="px-2">
</div> </div>
<!-- column --> <div class="col-lg-6 col-md-12">
<div fxFlex.gt-lg="25" fxFlex.gt-md="50" fxFlex.gt-xs="100" fxFlex="100" class="px-2"> <h4 class="border-bottom border-secondary mb-3 lh-lg">
Programme
<mat-checkbox class="float-end" [(ngModel)]="params.video">
<mat-icon fontIcon="videocam" class="align-middle"></mat-icon>
</mat-checkbox>
</h4>
<mat-form-field appearance="fill" class="me-2 w-100">
<mat-label>Programme</mat-label>
<textarea matInput [(ngModel)]="jump.programme"></textarea>
</mat-form-field>
<span class="d-inline-block align-middle ms-1">{{ filepath }}{{ this.jumpForm.controls['date'].value | date: 'yyyy-MM-dd' }}_S00{{ nextJump }}.mp4</span>
<span class="d-inline-block align-middle ms-1">{{ jump.dossier }}{{ jump.video }}</span>
</div>
</div> </div>
</div> </div>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions> <mat-dialog-actions>
<span class="flex-spacer"></span> <span class="flex-spacer"></span>
<button mat-button (click)="onCloseDialog()" class="me-1">Annuler</button> <button mat-button (click)="closeDialog()" class="me-1">Annuler</button>
<button mat-button color="primary" [mat-dialog-close]="jump" cdkFocusInitial>Enregistrer</button> <!--<button mat-button color="warn" [disabled]="!jumpForm.valid" [mat-dialog-close]="{jump: jump, params: params}" cdkFocusInitial>Enregistrer</button>-->
<button mat-button color="warn" [disabled]="!jumpForm.valid" (click)="submitForm()" cdkFocusInitial>Enregistrer</button>
</mat-dialog-actions> </mat-dialog-actions>
@@ -1,32 +1,486 @@
import { Component, Inject } from '@angular/core'; import { Component, Inject, OnDestroy } from '@angular/core';
import { FormsModule } from '@angular/forms'; import { DatePipe, NgFor, NgIf } from '@angular/common';
import { FormBuilder, FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatOptionModule } from '@angular/material/core'; import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { MatDividerModule } from '@angular/material/divider'; import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatOptionModule } from '@angular/material/core';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { Subscription } from 'rxjs';
import { Jump } from 'src/app/core/models'; import { Jump, JumpAddParams } from 'src/app/core/models';
@Component({ @Component({
selector: 'huapp-jump-add-dialog', selector: 'huapp-jump-add-dialog',
templateUrl: 'jump-add.dialog.html', templateUrl: 'jump-add.dialog.html',
standalone: true, standalone: true,
imports: [ imports: [
FormsModule, DatePipe, NgFor, NgIf, FormsModule, ReactiveFormsModule,
MatDialogModule, MatFormFieldModule, MatInputModule, MatDividerModule, MatButtonModule, MatCheckboxModule, MatDatepickerModule,
MatSelectModule, MatOptionModule, MatButtonModule MatDialogModule, MatFormFieldModule, MatIconModule,
MatInputModule, MatSelectModule, MatOptionModule
] ]
}) })
export class JumpAddDialogComponent { export class JumpAddDialogComponent implements OnDestroy {
private _formChanges: Array<Subscription> = [];
public tagField = new FormControl<string>('', { nonNullable: true});
public jumpForm: FormGroup;
public jump: Jump;
public lastJump: Jump;
public nextJump: number;
public params: JumpAddParams;
public filename: string;
public filepath: string;
public useLast: {
all: boolean;
aeronef: boolean;
altitude: boolean;
discipline: boolean;
divers: boolean;
dropzone: boolean;
groupe: boolean;
programme: boolean;
voile: boolean;
} = {
all: false,
aeronef: false,
altitude: false,
discipline: false,
divers: false,
dropzone: false,
groupe: false,
programme: false,
voile: false
};
constructor( constructor(
public dialogRef: MatDialogRef<JumpAddDialogComponent>, public dialogRef: MatDialogRef<JumpAddDialogComponent>,
@Inject(MAT_DIALOG_DATA) public jump: Jump private fb: FormBuilder,
) { } @Inject(MAT_DIALOG_DATA) public data: {jump: Jump, lastJump: Jump}
) {
this.jump = data.jump;
this.lastJump = data.lastJump;
this.nextJump = (this.lastJump.numero + 1);
this.params = {
numeros: this.nextJump.toString(),
date: '',
video: true
};
this.jump.numero = this.nextJump;
let controlsConfig = {
date: ['', Validators.required],
numero: [this.nextJump, Validators.required],
lieu: ['', Validators.required],
oaci: '',
aeronef: ['', Validators.required],
imat: '',
hauteur: ['', Validators.required],
deploiement: '',
voile: '',
taille: ['', Validators.required],
categorie: '',
module: '',
participants: [1, Validators.required],
sautants: [[]],
programme: '',
accessoires: '',
zone: '',
dossier: '',
video: ''
};
this.jumpForm = this.fb.group(controlsConfig);
this.filename = this._computeFilename();
this.filepath = this._computeFilepath();
this._formChanges.push(
this.jumpForm.controls['module'].valueChanges.subscribe(() => {
this.filepath = this._computeFilepath();
}),
this.jumpForm.controls['numero'].valueChanges.subscribe(() => {
this.filename = this._computeFilename();
})
);
}
onCloseDialog(): void { ngOnDestroy() {
this._formChanges.forEach((sub: Subscription) => {
sub.unsubscribe();
});
}
public onDateChange(): void {
this.filename = this._computeFilename();
}
private _computeFilename(numero?: string): string {
let file: string = '';
let timestamp: number = Date.parse(this.jumpForm.controls['date'].value);
if (isNaN(timestamp) == false) {
let date: Date = new Date(timestamp);
file += `${(date.getFullYear() + '').padStart(2, '0')}-${((date.getMonth() + 1) + '').padStart(2, '0')}-${(date.getDate() + '').padStart(2, '0')}_`;
}
if (numero !== undefined) {
numero = (numero + '').padStart(5, '0');
} else {
numero = (this.jumpForm.controls['numero'].value + '').padStart(5, '0');
}
file += `S${numero}.mp4`;
this.jumpForm.controls['video'].setValue(file);
return file;
}
private _computeFilepath(): string {
let path: string = '/Volumes/Storage/Skydive/Videos/';
if (this.jumpForm.controls['module'].value != '') {
path += `${this.jumpForm.controls['module'].value}/`;
}
this.jumpForm.controls['dossier'].setValue(path);
return path;
}
private _isLastForAllSections() {
return (
this.useLast.aeronef
&& this.useLast.altitude
&& this.useLast.discipline
&& this.useLast.divers
&& this.useLast.dropzone
&& this.useLast.groupe
&& this.useLast.programme
&& this.useLast.voile
);
}
private _setAllLast(checked: boolean) {
this.useLast.all = checked;
this.useLast.aeronef = checked;
this.useLast.altitude = checked;
this.useLast.discipline = checked;
this.useLast.divers = checked;
this.useLast.dropzone = checked;
this.useLast.groupe = checked;
this.useLast.programme = checked;
this.useLast.voile = checked;
}
addSautant(): void {
this.useLast.groupe = false;
this.useLast.all = this._isLastForAllSections();
const tag = this.tagField.value;
if (tag != null && tag.trim() !== '' && this.jump.sautants.indexOf(tag) < 0) {
this.jump.sautants.push(tag);
}
this.tagField.reset('');
const participants = (this.jump.sautants.length + 1);
this.jumpForm.controls['participants'].setValue(participants);
}
closeDialog(): void {
this._setAllLast(false);
//this.jump = <Jump>{};
//this.jump.numero = this.nextJump;
this.dialogRef.close(); this.dialogRef.close();
} }
getErrorMessage(name: string): string {
if (this.jumpForm.controls[name].errors !== null) {
return 'Ce champ est requis.';
}
return '';
}
removeSautant(index: string): void {
this.useLast.groupe = false;
this.useLast.all = this._isLastForAllSections();
this.jump.sautants = this.jump.sautants.filter((sautant) => sautant !== index);
const participants = (this.jump.sautants.length + 1);
this.jumpForm.controls['participants'].setValue(participants);
}
setLastJump(checked: boolean) {
if (checked) {
this._setAllLast(true);
this.jumpForm.controls['lieu'].setValue(this.lastJump.lieu);
this.jumpForm.controls['oaci'].setValue(this.lastJump.oaci);
this.jumpForm.controls['aeronef'].setValue(this.lastJump.aeronef);
this.jumpForm.controls['imat'].setValue(this.lastJump.imat);
this.jumpForm.controls['hauteur'].setValue(this.lastJump.hauteur);
this.jumpForm.controls['deploiement'].setValue(this.lastJump.deploiement);
this.jumpForm.controls['voile'].setValue(this.lastJump.voile);
this.jumpForm.controls['taille'].setValue(this.lastJump.taille);
this.jumpForm.controls['categorie'].setValue(this.lastJump.categorie);
this.jumpForm.controls['module'].setValue(this.lastJump.module);
this.jumpForm.controls['participants'].setValue(this.lastJump.participants);
//this.jumpForm.controls['sautants'].setValue(this.lastJump.sautants);
this.jumpForm.controls['programme'].setValue(this.lastJump.programme);
this.jumpForm.controls['accessoires'].setValue(this.lastJump.accessoires);
this.jumpForm.controls['zone'].setValue(this.lastJump.zone);
this.jump.sautants = this.lastJump.sautants;
/*
Object.assign(
this.jump,
{
date: this.lastJump.date,
numero: this.lastJump.numero,
lieu: this.lastJump.lieu,
oaci: this.lastJump.oaci,
aeronef: this.lastJump.aeronef,
imat: this.lastJump.imat,
hauteur: this.lastJump.hauteur,
deploiement: this.lastJump.deploiement,
voile: this.lastJump.voile,
taille: this.lastJump.taille,
categorie: this.lastJump.categorie,
module: this.lastJump.module,
participants: this.lastJump.participants,
sautants: this.lastJump.sautants,
programme: this.lastJump.programme,
accessoires: this.lastJump.accessoires,
zone: this.lastJump.zone,
}
);
*/
this.jump.date = '';
} else {
this._setAllLast(false);
this.jumpForm.controls['lieu'].setValue('');
this.jumpForm.controls['oaci'].setValue('');
this.jumpForm.controls['aeronef'].setValue('');
this.jumpForm.controls['imat'].setValue('');
this.jumpForm.controls['hauteur'].setValue('');
this.jumpForm.controls['deploiement'].setValue('');
this.jumpForm.controls['voile'].setValue('');
this.jumpForm.controls['taille'].setValue('');
this.jumpForm.controls['categorie'].setValue('');
this.jumpForm.controls['module'].setValue('');
this.jumpForm.controls['participants'].setValue(1);
//this.jumpForm.controls['sautants'].setValue('');
this.jumpForm.controls['programme'].setValue('');
this.jumpForm.controls['accessoires'].setValue('');
this.jumpForm.controls['zone'].setValue('');
this.jump.sautants = [];
}
this.jump.numero = this.nextJump;
};
setLastAeronef(checked: boolean = false) {
if (checked) {
this.useLast.aeronef = true;
this.jumpForm.controls['aeronef'].setValue(this.lastJump.aeronef);
this.jumpForm.controls['imat'].setValue(this.lastJump.imat);
} else {
this.useLast.aeronef = false;
this.jumpForm.controls['aeronef'].setValue('');
this.jumpForm.controls['imat'].setValue('');
}
this.useLast.all = this._isLastForAllSections();
}
setLastAltitude(checked: boolean = false) {
if (checked) {
this.useLast.altitude = true;
this.jumpForm.controls['hauteur'].setValue(this.lastJump.hauteur);
this.jumpForm.controls['deploiement'].setValue(this.lastJump.deploiement);
} else {
this.useLast.altitude = false;
this.jumpForm.controls['hauteur'].setValue('');
this.jumpForm.controls['deploiement'].setValue('');
}
this.useLast.all = this._isLastForAllSections();
}
setLastDiscipline(checked: boolean = false) {
if (checked) {
this.useLast.discipline = true;
this.jumpForm.controls['categorie'].setValue(this.lastJump.categorie);
this.jumpForm.controls['module'].setValue(this.lastJump.module);
} else {
this.useLast.discipline = false;
this.jumpForm.controls['categorie'].setValue('');
this.jumpForm.controls['module'].setValue('');
}
this.useLast.all = this._isLastForAllSections();
}
setLastDivers(checked: boolean = false) {
if (checked) {
this.useLast.divers = true;
this.jumpForm.controls['accessoires'].setValue(this.lastJump.accessoires);
this.jumpForm.controls['zone'].setValue(this.lastJump.zone);
} else {
this.useLast.divers = false;
this.jumpForm.controls['accessoires'].setValue('');
this.jumpForm.controls['zone'].setValue('');
}
this.useLast.all = this._isLastForAllSections();
}
setLastDropzone(checked: boolean = false) {
if (checked) {
this.useLast.dropzone = true;
this.jumpForm.controls['lieu'].setValue(this.lastJump.lieu);
this.jumpForm.controls['oaci'].setValue(this.lastJump.oaci);
} else {
this.useLast.dropzone = false;
this.jumpForm.controls['lieu'].setValue('');
this.jumpForm.controls['oaci'].setValue('');
}
this.useLast.all = this._isLastForAllSections();
}
setLastGroupe(checked: boolean = false) {
if (checked) {
this.useLast.groupe = true;
this.jumpForm.controls['participants'].setValue(this.lastJump.participants);
//this.jumpForm.controls['sautants'].setValue(this.lastJump.sautants);
this.jump.sautants = this.lastJump.sautants;
} else {
this.useLast.groupe = false;
this.jumpForm.controls['participants'].setValue(1);
//this.jumpForm.controls['sautants'].setValue('');
this.jump.sautants = [];
}
this.useLast.all = this._isLastForAllSections();
}
setLastProgramme(checked: boolean = false) {
if (checked) {
this.useLast.programme = true;
this.jumpForm.controls['programme'].setValue(this.lastJump.participants);
} else {
this.useLast.programme = false;
this.jumpForm.controls['programme'].setValue('');
}
this.useLast.all = this._isLastForAllSections();
}
setLastVoile(checked: boolean = false) {
if (checked) {
this.useLast.voile = true;
this.jumpForm.controls['voile'].setValue(this.lastJump.voile);
this.jumpForm.controls['taille'].setValue(this.lastJump.taille);
} else {
this.useLast.voile = false;
this.jumpForm.controls['voile'].setValue('');
this.jumpForm.controls['taille'].setValue('');
}
this.useLast.all = this._isLastForAllSections();
}
submitForm(): void {
/*
* Création d'un tableau de saut contenant de 1 à n saut en fonction
* de la valeur du champ numero du formulaire jumpForm
*/
let jumps: Array<Jump> = [];
let jump: Jump = {} as Jump;
let numeros: Array<number> = [];
let date: Date;
/* Controle de la validité du champ date et conversion au format ISO */
let timestamp: number = Date.parse(this.jumpForm.controls['date'].value);
if (isNaN(timestamp) == false) {
date = new Date(timestamp);
} else {
date = new Date();
}
if (isNaN(+this.jumpForm.controls['numero'].value)) {
/*
* 'numero' n'est pas un entier , il s'agit donc d'une plage, d'une quantité ou de plusieurs valeur
* decomposer la valeur 'numero' et ajouter chaque sauts au tableau retourné par la fenêtre dialog
*/
let jumpNum: number = this.lastJump.numero;
const elements: string[] = this.jumpForm.controls['numero'].value.split(';');
elements.forEach((element: string) => {
if (element == '') {
jumpNum ++;
element = jumpNum.toString();
}
const values: string[] = element.split('-');
if (values.length == 2) {
const start: number = parseInt(values[0]);
const stop: number = parseInt(values[1]);
const diff: number = (stop - start);
/* Ajout de saut par plage */
for (let index = 0; index <= diff; index++) {
jumpNum = (start + index);
numeros.push(jumpNum);
}
} else {
const quantity: string[] = values[0].split('+');
if (quantity.length == 2) {
/* Ajout de sauts par quantité */
const start: number = jumpNum;
for (let index = 1; index <= parseInt(quantity[1]); index++) {
jumpNum ++;
numeros.push(jumpNum);
}
} else {
/* Ajout de sauts par numero */
jumpNum = parseInt(quantity[0]);
numeros.push(jumpNum);
}
}
});
} else {
/* 'numero' est un entier */
numeros.push(this.jumpForm.controls['numero'].value);
}
/* Valeurs communes aux 1 à n saut(s) à ajouter */
jump.date = date.toISOString();
jump.lieu = this.jumpForm.controls['lieu'].value;
jump.oaci = this.jumpForm.controls['oaci'].value;
jump.aeronef = this.jumpForm.controls['aeronef'].value;
jump.imat = this.jumpForm.controls['imat'].value;
jump.hauteur = this.jumpForm.controls['hauteur'].value;
jump.deploiement = this.jumpForm.controls['deploiement'].value;
jump.voile = this.jumpForm.controls['voile'].value;
jump.taille = this.jumpForm.controls['taille'].value;
jump.categorie = this.jumpForm.controls['categorie'].value;
jump.module = this.jumpForm.controls['module'].value;
jump.participants = this.jumpForm.controls['participants'].value;
jump.sautants = this.jump.sautants;
//jump.sautants = this.jumpForm.controls['sautants'].value;
jump.programme = this.jumpForm.controls['programme'].value;
jump.accessoires = this.jumpForm.controls['accessoires'].value;
jump.zone = this.jumpForm.controls['zone'].value;
//jump.dossier = this.jumpForm.controls['dossier'].value;
//jump.video = this.jumpForm.controls['video'].value;
//console.log(numeros);
/* Ajout du saut au tableau à retourner */
numeros.forEach((numero: number) => {
let item: Jump = {} as Jump;
Object.assign(item, jump);
item.numero = numero;
item.dossier = this._computeFilepath();
item.video = this._computeFilename(numero.toString());
jumps.push(item);
//console.log(item);
});
//console.log(jumps);
/* Reset all 'last jump values' booleans */
this._setAllLast(false);
/* close the dialog with result */
this.dialogRef.close(jumps);
/*
// Reset all 'last jump values' booleans
this._setAllLast(false);
// update the model
this.updateJump(this.jumpForm.value);
// close the dialog with result
this.dialogRef.close(this.jump);
*/
}
updateJump(values: NonNullable<unknown>): void {
Object.assign(this.jump, values);
}
} }
@@ -1,50 +1,64 @@
<h2 mat-dialog-title>Supprimer le saut n°{{jump.numero}}</h2> <h2 mat-dialog-title class="bg-accent border-bottom border-light-subtle d-flex mb-3 pt-3 pb-2">
<mat-divider class="mt-2 mb-1 border-light-subtle"></mat-divider> Supprimer le saut n°{{jump.numero}}<span class="flex-spacer"></span>
<mat-icon fontIcon="close" class="pointer" (click)="closeDialog()"></mat-icon>
</h2>
<mat-dialog-content> <mat-dialog-content>
<p class="mt-2 mb-3 text-accent">Veuillez confirmer la suppression de ce saut. Attention, cette action est irréversible.</p> <div class="container">
<h3>Données du saut :</h3> <div class="mt-2 mb-4 text-center text-danger border-warning alert alert-danger">
<div class="mb-3 clearfix"> <p class="fs-6 m-0">
Veuillez confirmer la suppression de ce saut.<br />
<span class="fw-semibold">Attention</span>, cette <span class="fw-semibold">action</span> est <span class="fw-semibold">irréversible</span>.
</p>
</div>
<h3 class="border-bottom border-light-subtle pb-2 mb-3">Données du saut :</h3>
<div class="row mb-3">
<div class="col-lg-6 col-md-12">
<dl class="dl-horizontal"> <dl class="dl-horizontal">
<dt class="text-lowercase text-bold">numero:</dt> <dt class="text-accent fw-normal">numero:</dt>
<dd>{{jump.numero}}</dd> <dd>{{jump.numero}}</dd>
<dt class="text-lowercase text-bold">date:</dt> <dt class="text-accent fw-normal">lieu:</dt>
<dd>{{jump.date}}</dd>
<dt class="text-lowercase text-bold">lieu:</dt>
<dd>{{jump.lieu}}</dd> <dd>{{jump.lieu}}</dd>
<dt class="text-lowercase text-bold">oaci:</dt> <dt class="text-accent fw-normal">aeronef:</dt>
<dd>{{jump.oaci}}</dd>
<dt class="text-lowercase text-bold">aeronef:</dt>
<dd>{{jump.aeronef}}</dd> <dd>{{jump.aeronef}}</dd>
<dt class="text-lowercase text-bold">imat:</dt> <dt class="text-accent fw-normal">voile:</dt>
<dd>{{jump.imat}}</dd>
<dt class="text-lowercase text-bold">hauteur:</dt>
<dd>{{jump.hauteur}}</dd>
<dt class="text-lowercase text-bold">voile:</dt>
<dd>{{jump.voile}}</dd> <dd>{{jump.voile}}</dd>
<dt class="text-lowercase text-bold">taille:</dt> <dt class="text-accent fw-normal">hauteur:</dt>
<dd>{{jump.taille}}</dd> <dd>{{jump.hauteur}} m</dd>
<dt class="text-lowercase text-bold">categorie:</dt> <dt class="text-accent fw-normal">categorie:</dt>
<dd>{{jump.categorie}}</dd> <dd>{{jump.categorie}}</dd>
<dt class="text-lowercase text-bold">module:</dt> <dt class="text-accent fw-normal">accessoires:</dt>
<dd>{{jump.module}}</dd>
<dt class="text-lowercase text-bold">participants:</dt>
<dd>{{jump.participants}}</dd>
<dt class="text-lowercase text-bold">programme:</dt>
<dd>{{jump.programme}}</dd>
<dt class="text-lowercase text-bold">accessoires:</dt>
<dd>{{jump.accessoires}}</dd> <dd>{{jump.accessoires}}</dd>
<dt class="text-lowercase text-bold">zone:</dt> <dt class="text-accent fw-normal">dossier:</dt>
<dd>{{jump.zone}}</dd>
<dt class="text-lowercase text-bold">dossier:</dt>
<dd>{{jump.dossier}}</dd> <dd>{{jump.dossier}}</dd>
<dt class="text-lowercase text-bold">video:</dt> <dt class="text-accent fw-normal">programme:</dt>
<dd>{{jump.programme}}</dd>
</dl>
</div>
<div class="col-lg-6 col-md-12">
<dl class="dl-horizontal">
<dt class="text-accent fw-normal">date:</dt>
<dd>{{jump.date | date: 'mediumDate'}}</dd>
<dt class="text-accent fw-normal">oaci:</dt>
<dd>{{jump.oaci}}</dd>
<dt class="text-accent fw-normal">imat:</dt>
<dd>{{jump.imat}}</dd>
<dt class="text-accent fw-normal">taille:</dt>
<dd>{{jump.taille}} ft<sup>2</sup></dd>
<dt class="text-accent fw-normal">participants:</dt>
<dd>{{jump.participants}}</dd>
<dt class="text-accent fw-normal">module:</dt>
<dd>{{jump.module}}</dd>
<dt class="text-accent fw-normal">zone:</dt>
<dd>{{jump.zone}}</dd>
<dt class="text-accent fw-normal">video:</dt>
<dd>{{jump.video}}</dd> <dd>{{jump.video}}</dd>
</dl> </dl>
</div> </div>
<hr /> </div>
</div>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions> <mat-dialog-actions>
<span class="flex-spacer"></span> <span class="flex-spacer"></span>
<button mat-button (click)="onCloseDialog()" class="me-1">Annuler</button> <button mat-button (click)="closeDialog()" class="me-1">Annuler</button>
<button mat-button color="accent" [mat-dialog-close]="jump" cdkFocusInitial>Supprimer</button> <button mat-button color="accent" [mat-dialog-close]="jump" cdkFocusInitial>Supprimer</button>
</mat-dialog-actions> </mat-dialog-actions>
@@ -1,7 +1,8 @@
import { Component, Inject } from '@angular/core'; import { Component, Inject } from '@angular/core';
import { DatePipe } from '@angular/common';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { MatDividerModule } from '@angular/material/divider'; import { MatIconModule } from '@angular/material/icon';
import { Jump } from 'src/app/core/models'; import { Jump } from 'src/app/core/models';
@@ -9,7 +10,10 @@ import { Jump } from 'src/app/core/models';
selector: 'huapp-jump-delete-dialog', selector: 'huapp-jump-delete-dialog',
templateUrl: 'jump-delete.dialog.html', templateUrl: 'jump-delete.dialog.html',
standalone: true, standalone: true,
imports: [MatDialogModule, MatButtonModule, MatDividerModule] imports: [
DatePipe,
MatDialogModule, MatButtonModule, MatIconModule
]
}) })
export class JumpDeleteDialogComponent { export class JumpDeleteDialogComponent {
constructor( constructor(
@@ -17,7 +21,7 @@ export class JumpDeleteDialogComponent {
@Inject(MAT_DIALOG_DATA) public jump: Jump @Inject(MAT_DIALOG_DATA) public jump: Jump
) { } ) { }
onCloseDialog(): void { closeDialog(): void {
this.dialogRef.close(); this.dialogRef.close();
} }
} }
@@ -1,85 +1,145 @@
<h2 mat-dialog-title>Editer un saut</h2> <h2 mat-dialog-title class="bg-primary border-bottom border-light-subtle d-flex mb-3 pt-3 pb-2">
<mat-divider class="mt-2 mb-1 border-light-subtle"></mat-divider> Modifier un saut<span class="flex-spacer"></span>
<mat-icon fontIcon="close" class="pointer" (click)="closeDialog()"></mat-icon>
</h2>
<mat-dialog-content> <mat-dialog-content>
<div fxLayout="row wrap"> <div class="container">
<!-- column --> <form class="row" [formGroup]="jumpForm" (ngSubmit)="submitForm()">
<div fxFlex.gt-lg="50" fxFlex.gt-md="50" fxFlex.gt-xs="100" fxFlex="100" class="px-2"> <div class="col-xs-12">
<mat-form-field appearance="fill"> <mat-form-field appearance="outline" class="mt-2 me-2" color="primary">
<mat-label>Numéro</mat-label> <mat-label>Numéro du saut</mat-label>
<input matInput [(ngModel)]="jump.numero"> <input matInput formControlName="numero">
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill"> <mat-form-field appearance="outline" class="mt-2 me-3" color="primary">
<mat-label>Date</mat-label> <mat-label>Choisissez une date</mat-label>
<input matInput [(ngModel)]="jump.date"> <input matInput [matDatepicker]="datepicker" formControlName="date" />
<mat-hint>MM/DD/YYYY</mat-hint>
<mat-datepicker-toggle matIconSuffix [for]="datepicker"></mat-datepicker-toggle>
<mat-datepicker #datepicker>
<mat-datepicker-actions>
<button mat-button matDatepickerCancel>Annuler</button>
<button mat-raised-button color="primary" matDatepickerApply>Appliquer</button>
</mat-datepicker-actions>
</mat-datepicker>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill"> </div>
<div class="col-lg-6 col-md-12">
<h4 class="border-bottom border-primary pb-1 mb-3">Dropzone</h4>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Lieu</mat-label> <mat-label>Lieu</mat-label>
<input matInput [(ngModel)]="jump.lieu"> <input matInput formControlName="lieu">
<mat-error *ngIf="this.jumpForm.controls['lieu'].status === 'INVALID'">{{getErrorMessage('lieu')}}</mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill"> <mat-form-field appearance="fill" class="me-2">
<mat-label>Aeronef</mat-label>
<input matInput [(ngModel)]="jump.aeronef">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Hauteur</mat-label>
<input matInput [(ngModel)]="jump.hauteur">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Voile</mat-label>
<input matInput [(ngModel)]="jump.voile">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Taille</mat-label>
<input matInput [(ngModel)]="jump.taille">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Categorie</mat-label>
<input matInput [(ngModel)]="jump.categorie">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Module</mat-label>
<input matInput [(ngModel)]="jump.module">
</mat-form-field>
</div>
<!-- column -->
<div fxFlex.gt-lg="50" fxFlex.gt-md="50" fxFlex.gt-xs="100" fxFlex="100" class="px-2">
<mat-form-field appearance="fill">
<mat-label>Participants</mat-label>
<input matInput [(ngModel)]="jump.participants">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Programme</mat-label>
<input matInput [(ngModel)]="jump.programme">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Oaci</mat-label> <mat-label>Oaci</mat-label>
<input matInput [(ngModel)]="jump.oaci"> <input matInput formControlName="oaci">
<mat-error *ngIf="this.jumpForm.controls['oaci'].status === 'INVALID'">{{getErrorMessage('oaci')}}</mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill"> <h4 class="border-bottom border-primary pb-1 mb-3">Aéronef</h4>
<mat-label>Imat</mat-label> <mat-form-field appearance="fill" class="me-2">
<input matInput [(ngModel)]="jump.imat"> <mat-label>Aéronef</mat-label>
<input matInput formControlName="aeronef">
<mat-error *ngIf="this.jumpForm.controls['aeronef'].status === 'INVALID'">{{getErrorMessage('aeronef')}}</mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill"> <mat-form-field appearance="fill" class="me-2">
<mat-label>Accessoires</mat-label> <mat-label>Imatriculation</mat-label>
<input matInput [(ngModel)]="jump.accessoires"> <input matInput formControlName="imat">
<mat-error *ngIf="this.jumpForm.controls['imat'].status === 'INVALID'">{{getErrorMessage('imat')}}</mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill"> <h4 class="border-bottom border-primary pb-1 mb-3">Voile</h4>
<mat-label>Zone</mat-label> <mat-form-field appearance="fill" class="me-2">
<input matInput [(ngModel)]="jump.zone"> <mat-label>Modèle</mat-label>
<input matInput formControlName="voile">
<mat-error *ngIf="this.jumpForm.controls['voile'].status === 'INVALID'">{{getErrorMessage('voile')}}</mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill"> <mat-form-field appearance="fill" class="me-2">
<mat-label>Dossier</mat-label> <mat-label>Taille en ft<sup>2</sup></mat-label>
<input matInput [(ngModel)]="jump.dossier"> <input matInput formControlName="taille" type="number" min="0" step="1">
</mat-form-field> <span matTextSuffix>ft<sup>2</sup></span>
<mat-form-field appearance="fill"> <mat-error *ngIf="this.jumpForm.controls['taille'].status === 'INVALID'">{{getErrorMessage('taille')}}</mat-error>
<mat-label>Video</mat-label>
<input matInput [(ngModel)]="jump.video">
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-lg-6 col-md-12">
<h4 class="border-bottom border-primary pb-1 mb-3">Altitude</h4>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Hauteur de largage</mat-label>
<input matInput formControlName="hauteur" type="number" min="0" step="1">
<mat-error *ngIf="this.jumpForm.controls['hauteur'].status === 'INVALID'">{{getErrorMessage('hauteur')}}</mat-error>
</mat-form-field>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Hauteur de déploiement</mat-label>
<input matInput formControlName="deploiement" type="number" min="0" step="1">
<mat-error *ngIf="this.jumpForm.controls['deploiement'].status === 'INVALID'">{{getErrorMessage('deploiement')}}</mat-error>
</mat-form-field>
<h4 class="border-bottom border-primary pb-1 mb-3">Discipline</h4>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Categorie</mat-label>
<input matInput formControlName="categorie">
<mat-error *ngIf="this.jumpForm.controls['categorie'].status === 'INVALID'">{{getErrorMessage('categorie')}}</mat-error>
</mat-form-field>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Module</mat-label>
<input matInput formControlName="module">
<mat-error *ngIf="this.jumpForm.controls['module'].status === 'INVALID'">{{getErrorMessage('module')}}</mat-error>
</mat-form-field>
<h4 class="border-bottom border-primary pb-1 mb-3">Divers</h4>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Accessoires</mat-label>
<input matInput formControlName="accessoires">
<mat-error *ngIf="this.jumpForm.controls['accessoires'].status === 'INVALID'">{{getErrorMessage('accessoires')}}</mat-error>
</mat-form-field>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Zone</mat-label>
<input matInput formControlName="zone">
<mat-error *ngIf="this.jumpForm.controls['zone'].status === 'INVALID'">{{getErrorMessage('zone')}}</mat-error>
</mat-form-field>
</div>
<div class="col-lg-6 col-md-12">
<h4 class="border-bottom border-primary pb-1 mb-3">Groupe</h4>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Sautants</mat-label>
<input matInput placeholder="Ajouter un sautant" [formControl]="tagField" (keyup.enter)="addSautant()">
</mat-form-field>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Nombre de participants</mat-label>
<input matInput formControlName="participants" type="number" min="0" step="1">
<mat-error *ngIf="this.jumpForm.controls['participants'].status === 'INVALID'">{{getErrorMessage('participants')}}</mat-error>
</mat-form-field>
<div class="mb-2">
<span *ngFor="let sautant of jump.sautants" class="badge rounded-pill bg-primary mb-2 me-1 pe-3 py-1 fw-normal text-dark">
<mat-icon class="align-middle pointer me-1" fontIcon="close" (click)="removeSautant(sautant)"></mat-icon>
{{ sautant }}
</span>
<span class="badge rounded-pill bg-accent mb-2 me-1 pe-3 py-1 fw-normal text-dark">
<mat-icon class="align-middle pointer me-1" fontIcon="person"></mat-icon>
ju_solide
</span>
</div>
</div>
<div class="col-lg-6 col-md-12">
<h4 class="border-bottom border-primary pb-1 mb-3">Programme</h4>
<mat-form-field appearance="fill" class="me-2 w-100">
<mat-label>Programme</mat-label>
<textarea matInput formControlName="programme"></textarea>
<mat-error *ngIf="this.jumpForm.controls['programme'].status === 'INVALID'">{{getErrorMessage('programme')}}</mat-error>
</mat-form-field>
<h4 class="border-bottom border-primary pb-1 mb-3">Vidéo</h4>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Dossier</mat-label>
<input matInput formControlName="dossier">
<mat-error *ngIf="this.jumpForm.controls['dossier'].status === 'INVALID'">{{getErrorMessage('dossier')}}</mat-error>
</mat-form-field>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Video</mat-label>
<input matInput formControlName="video">
<mat-error *ngIf="this.jumpForm.controls['video'].status === 'INVALID'">{{getErrorMessage('video')}}</mat-error>
</mat-form-field>
</div>
</form>
</div> </div>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions> <mat-dialog-actions>
<span class="flex-spacer"></span> <span class="flex-spacer"></span>
<button mat-button (click)="onCloseDialog()" class="me-1">Annuler</button> <button mat-button (click)="closeDialog()" class="me-1">Annuler</button>
<button mat-button color="primary" [mat-dialog-close]="jump" cdkFocusInitial>Enregistrer</button> <button mat-button color="primary" [disabled]="!jumpForm.valid" (click)="submitForm()" cdkFocusInitial>Enregistrer</button>
</mat-dialog-actions> </mat-dialog-actions>
@@ -1,33 +1,98 @@
import { Component, Inject } from '@angular/core'; import { Component, Inject } from '@angular/core';
import { FormsModule } from '@angular/forms'; import { NgFor, NgIf } from '@angular/common';
import { FormBuilder, FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatOptionModule } from '@angular/material/core'; import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { MatDividerModule } from '@angular/material/divider';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatOptionModule } from '@angular/material/core';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { Jump } from 'src/app/core/models'; import { Jump, JumpForm } from 'src/app/core/models';
@Component({ @Component({
selector: 'huapp-jump-edit-dialog', selector: 'huapp-jump-edit-dialog',
templateUrl: 'jump-edit.dialog.html', templateUrl: 'jump-edit.dialog.html',
standalone: true, standalone: true,
imports: [ imports: [
FormsModule, NgFor, NgIf, FormsModule, ReactiveFormsModule,
MatDialogModule, MatFormFieldModule, MatInputModule, MatDividerModule, MatButtonModule, MatCheckboxModule, MatDatepickerModule,
MatSelectModule, MatOptionModule, MatIconModule, MatButtonModule MatDialogModule, MatFormFieldModule, MatIconModule,
MatInputModule, MatSelectModule, MatOptionModule
] ]
}) })
export class JumpEditDialogComponent { export class JumpEditDialogComponent {
public tagField = new FormControl<string>('', { nonNullable: true});
public jumpForm: FormGroup;
constructor( constructor(
public dialogRef: MatDialogRef<JumpEditDialogComponent>, public dialogRef: MatDialogRef<JumpEditDialogComponent>,
private fb: FormBuilder,
@Inject(MAT_DIALOG_DATA) public jump: Jump @Inject(MAT_DIALOG_DATA) public jump: Jump
) { } ) {
let controlsConfig = {
slug: [this.jump.slug, Validators.required],
date: [this.jump.date, Validators.required],
numero: [this.jump.numero, Validators.required],
lieu: [this.jump.lieu, Validators.required],
oaci: this.jump.oaci,
aeronef: [this.jump.aeronef, Validators.required],
imat: this.jump.imat,
hauteur: [this.jump.hauteur, Validators.required],
deploiement: this.jump.deploiement,
voile: this.jump.voile,
taille: [this.jump.taille, Validators.required],
categorie: this.jump.categorie,
module: this.jump.module,
participants: [this.jump.participants, Validators.required],
programme: this.jump.programme,
accessoires: this.jump.accessoires,
zone: this.jump.zone,
dossier: this.jump.dossier,
video: this.jump.video
};
this.jumpForm = this.fb.group(controlsConfig);
}
onCloseDialog(): void { addSautant(): void {
const tag = this.tagField.value;
if (tag != null && tag.trim() !== '' && this.jump.sautants.indexOf(tag) < 0) {
this.jump.sautants.push(tag);
}
const participants = (this.jump.sautants.length + 1);
this.jumpForm.controls['participants'].setValue(participants);
this.tagField.reset('');
}
closeDialog(): void {
// close the dialog without result
this.dialogRef.close(); this.dialogRef.close();
} }
getErrorMessage(name: string): string {
if (this.jumpForm.controls[name].errors !== null) {
return `Ce champ est requis.`;
}
return '';
}
removeSautant(index: string): void {
this.jump.sautants = this.jump.sautants.filter((sautant) => sautant !== index);
const participants = (this.jump.sautants.length + 1);
this.jumpForm.controls['participants'].setValue(participants);
}
submitForm(): void {
// update the model
this.updateJump(this.jumpForm.value);
// close the dialog with result
this.dialogRef.close(this.jump);
}
updateJump(values: NonNullable<unknown>): void {
Object.assign(this.jump, values);
}
} }
@@ -19,8 +19,7 @@
</mat-paginator> </mat-paginator>
</div> </div>
</div> </div>
<table mat-table [dataSource]="jumps" matSort <table mat-table [dataSource]="jumps" matSort class="table table-dark table-striped table-hover table-condensed mat-elevation-z2">
class="table table-dark table-striped table-hover table-condensed mat-elevation-z2">
<caption [hidden]="jumpsCount || loading">Aucun saut à afficher pour le moment.</caption> <caption [hidden]="jumpsCount || loading">Aucun saut à afficher pour le moment.</caption>
<!-- Numero Column --> <!-- Numero Column -->
<ng-container matColumnDef="numero"> <ng-container matColumnDef="numero">
@@ -38,7 +37,7 @@
<ng-container matColumnDef="date"> <ng-container matColumnDef="date">
<th class="pl-3" mat-header-cell *matHeaderCellDef> Date </th> <th class="pl-3" mat-header-cell *matHeaderCellDef> Date </th>
<td class="pl-3 text-nowrap" mat-cell *matCellDef="let element"> <td class="pl-3 text-nowrap" mat-cell *matCellDef="let element">
<ng-container *ngIf="element.date">{{element.date}}</ng-container> <ng-container *ngIf="element.date">{{element.date | date: 'mediumDate'}}</ng-container>
<ng-container *ngIf="!element.numero"> <ng-container *ngIf="!element.numero">
<ngx-skeleton-loader [theme]="{width: '30px', height: '13px', marginBottom: '0px'}"> <ngx-skeleton-loader [theme]="{width: '30px', height: '13px', marginBottom: '0px'}">
</ngx-skeleton-loader> </ngx-skeleton-loader>
@@ -238,3 +237,57 @@
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true" class="accent"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true" class="accent"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" class="text-middle accent"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;" class="text-middle accent"></tr>
</table> </table>
<!--
<table mat-table [dataSource]="jumps">
<ng-container [matColumnDef]="col.key" *ngFor="let col of columnsSchema">
<th mat-header-cell *matHeaderCellDef [ngSwitch]="col.key">
<span *ngSwitchCase="'isSelected'">
<mat-checkbox (change)="selectAll($event)" [checked]="isAllSelected()" [indeterminate]="!isAllSelected() && isAnySelected()"></mat-checkbox>
</span>
<span *ngSwitchDefault>{{ col.label }}</span>
</th>
<td mat-cell *matCellDef="let element">
<div [ngSwitch]="col.type" *ngIf="!element.isEdit">
<ng-container *ngSwitchCase="'isSelected'">
<mat-checkbox (change)="element.isSelected = $event.checked" [checked]="element.isSelected">
</mat-checkbox>
</ng-container>
<div class="btn-edit" *ngSwitchCase="'isEdit'">
<button mat-button (click)="element.isEdit = !element.isEdit">
Modifier
</button>
<button mat-button class="button-remove" (click)="openDeleteDialog(element)">
Supprimer
</button>
</div>
<span *ngSwitchCase="'date'">
{{ element[col.key] | date: 'mediumDate' }}
</span>
<span *ngSwitchDefault>
{{ element[col.key] }}
</span>
</div>
<div [ngSwitch]="col.type" *ngIf="element.isEdit">
<div *ngSwitchCase="'isSelected'"></div>
<div class="btn-edit" *ngSwitchCase="'isEdit'">
<button mat-icon-button color="primary" [hidden]="!showAdd" (click)="openEditDialog(element)" [disabled]="disableSubmit(element.id)">
<mat-icon aria-label="Modifier" fontIcon="edit"></mat-icon>
</button>
</div>
<mat-form-field class="form-input" *ngSwitchCase="'date'" appearance="fill">
<mat-label>Choose a date</mat-label>
<input matInput [matDatepicker]="picker" [(ngModel)]="element[col.key]" />
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
<mat-form-field class="form-input" *ngSwitchDefault>
<input matInput [required]="col.required!" [pattern]="col.pattern!" [type]="col.type"
[(ngModel)]="element[col.key]" (change)="inputHandler($event, element.id, col.key)" />
</mat-form-field>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
-->
@@ -1,5 +1,5 @@
import { Component, Input, ViewChild, OnChanges, OnDestroy, computed, Signal, WritableSignal } from '@angular/core'; import { Component, AfterContentChecked, Input, ViewChild, OnChanges, OnDestroy, computed, Signal, WritableSignal } from '@angular/core';
import { NgIf, DecimalPipe, DatePipe } from '@angular/common'; import { CommonModule, DecimalPipe, DatePipe } from '@angular/common';
import { UntypedFormBuilder, UntypedFormGroup, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { Router, RouterLink } from '@angular/router'; import { Router, RouterLink } from '@angular/router';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
@@ -9,61 +9,67 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatMenuModule } from '@angular/material/menu'; import { MatMenuModule } from '@angular/material/menu';
import { MatNativeDateModule } from '@angular/material/core';
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator'; import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSort, MatSortModule } from '@angular/material/sort'; import { MatSort, MatSortModule } from '@angular/material/sort';
import { MatTableDataSource, MatTableModule } from '@angular/material/table'; import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import { MatSnackBar, MatSnackBarHorizontalPosition, MatSnackBarModule, MatSnackBarVerticalPosition } from '@angular/material/snack-bar'; import { MatSnackBar, MatSnackBarHorizontalPosition, MatSnackBarModule, MatSnackBarVerticalPosition } from '@angular/material/snack-bar';
import { Observable, Subscription } from 'rxjs'; import { Observable, Subject, Subscription } from 'rxjs';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { Errors, Jump, JumpList, JumpListConfig } from 'src/app/core/models'; import { ColumnDefinition, Errors, Jump, JumpList, JumpListConfig, jumpColumns } from 'src/app/core/models';
import { JumpsService, BackendService } from 'src/app/core/services'; import { JumpsService, JumpTableService } from 'src/app/core/services';
import { JumpAddDialogComponent, JumpDeleteDialogComponent, JumpEditDialogComponent } from 'src/app/components/shared/dialogs' import { JumpAddDialogComponent, JumpDeleteDialogComponent, JumpEditDialogComponent } from 'src/app/components/shared/dialogs'
@Component({ @Component({
standalone: true, standalone: true,
imports: [ imports: [
NgIf, DecimalPipe, DatePipe, RouterLink, FormsModule, ReactiveFormsModule, NgxSkeletonLoaderModule, CommonModule, DecimalPipe, DatePipe, RouterLink, FormsModule, ReactiveFormsModule, NgxSkeletonLoaderModule,
MatFormFieldModule, MatInputModule, MatButtonModule, MatCardModule, MatDialogModule,
MatProgressSpinnerModule, MatButtonModule, MatCardModule, MatIconModule, MatMenuModule, MatFormFieldModule, MatIconModule, MatInputModule, MatNativeDateModule, MatMenuModule,
MatPaginatorModule, MatTableModule, MatSortModule, MatSnackBarModule, MatDialogModule, MatPaginatorModule, MatProgressSpinnerModule, MatSnackBarModule, MatSortModule, MatTableModule,
JumpAddDialogComponent, JumpDeleteDialogComponent, JumpEditDialogComponent JumpAddDialogComponent, JumpDeleteDialogComponent, JumpEditDialogComponent
], ],
selector: 'huapp-jump-table', selector: 'huapp-jump-table',
styleUrls: ['./jump-table.component.scss'], styleUrls: ['./jump-table.component.scss'],
templateUrl: './jump-table.component.html' templateUrl: './jump-table.component.html'
}) })
export class JumpTableComponent implements OnChanges, OnDestroy { export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChecked {
private _subject: Subject<void> = new Subject<void>();
private _jumps: Subscription = new Subscription(); private _jumps: Subscription = new Subscription();
private _lastjump: Subscription = new Subscription(); private _jump: Subscription = new Subscription();
errors!: Errors; private _query: JumpListConfig = { type: 'all', filters: {} };
query: JumpListConfig = { type: 'all', filters: {} }; private _lastjump: Jump = {} as Jump;
jump: Jump = {} as Jump; private _currentPage = 1;
jumps!: MatTableDataSource<Jump>; public errors!: Errors;
lastjump: Jump = {} as Jump; public jump: Jump = {} as Jump;
jumpsCount = 0; public jumps!: MatTableDataSource<Jump>;
currentPage = 1; public jumpsCount = 0;
displayedColumns: string[] = [ public displayedColumns: string[] = [
'numero', 'date', 'lieu', 'oaci', 'aeronef', 'numero', 'date', 'lieu', 'oaci', 'aeronef',
'imat', 'hauteur', 'voile', 'taille', 'categorie', 'imat', 'hauteur', 'voile', 'taille', 'categorie',
'module', 'participants', 'programme', 'accessoires', 'module', 'participants', 'programme', 'accessoires',
'zone', 'video', 'actions' 'zone', 'video', 'actions'
]; ];
lastUpdate: Date = new Date(); //public displayedColumns: string[] = jumpColumns.map((col) => col.key)
loading = false; public columnsSchema: Array<ColumnDefinition> = jumpColumns;
isSubmitting = false; public loading = false;
isDeleting = false; public isSubmitting = false;
searchForm: UntypedFormGroup; public isDeleting = false;
public searchForm: UntypedFormGroup;
public valid: any = {};
public tableRefresh = false;
public jumpRefresh = false;
@ViewChild(MatSort) sort!: MatSort; @ViewChild(MatSort) sort!: MatSort;
@ViewChild(MatPaginator) paginator!: MatPaginator; @ViewChild(MatPaginator) paginator!: MatPaginator;
constructor( constructor(
private router: Router, private router: Router,
private jumpsService: JumpsService, private _jumpsService: JumpsService,
private _dataService: BackendService, private _jumpTableService: JumpTableService,
private dialog: MatDialog, private dialog: MatDialog,
private fb: UntypedFormBuilder, private fb: UntypedFormBuilder,
private snackBar: MatSnackBar private snackBar: MatSnackBar
@@ -75,49 +81,64 @@ export class JumpTableComponent implements OnChanges, OnDestroy {
}); });
} }
@Input() limit = 0;
@Input() refresh = 30000;
@Input() title = ''; @Input() title = '';
@Input() limit = 0;
@Input() refresh = false;
@Input() showAdd = false; @Input() showAdd = false;
@Input() isUser = false; @Input() isUser = false;
@Input() @Input()
set config(config: JumpListConfig) { set config(config: JumpListConfig) {
if (config) { if (config) {
this.query = config; this._query = config;
this.currentPage = 1; this._currentPage = 1;
} }
} }
get config(): JumpListConfig { get config(): JumpListConfig {
return this.query; return this._query;
} }
ngOnChanges() { ngOnChanges() {
this.loading = true; this.loading = true;
this.query = this.config; this._query = this.config;
this.runQuery(); this.runQuery();
//this.refresh = false;
console.log('ngOnChanges event in jump-table component');
} }
ngOnDestroy() { ngOnDestroy() {
this._jumps.unsubscribe(); this._jumps.unsubscribe();
this._lastjump.unsubscribe(); this._jump.unsubscribe();
}
ngAfterContentChecked() {
//console.log('jump-table ngAfterContentChecked', this.tableRefresh, this._jumpTableService.tableRefresh);
/*if (this.tableRefresh != this._jumpTableService.tableRefresh) {
this.tableRefresh = this._jumpTableService.tableRefresh;
console.log('refresh table', this.tableRefresh, this._jumpTableService.tableRefresh);
}*/
if (this.jumpRefresh != this._jumpTableService.jumpRefresh) {
this.jumpRefresh = this._jumpTableService.jumpRefresh;
this.runQuery();
console.log('table has been refreshed in jump-table component');
}
} }
runQuery() { runQuery() {
const lastjump$: Observable<Jump> = this.jumpsService.getLastJump(); const jump$: Observable<Jump> = this._jumpsService.getLastJump();
this._lastjump = lastjump$.subscribe((jump) => { this._jump = jump$.subscribe((jump) => {
this.lastjump = jump; this._lastjump = jump;
}); });
if (this.limit) { if (this.limit) {
this.query.filters.limit = this.limit; this._query.filters.limit = this.limit;
this.query.filters.offset = (this.limit * (this.currentPage - 1)); this._query.filters.offset = (this.limit * (this._currentPage - 1));
} else { } else {
this.query.filters.limit = 0; this._query.filters.limit = 0;
this.query.filters.offset = 0; this._query.filters.offset = 0;
} }
const jumps$: Observable<JumpList> = this.jumpsService.query(this.query); const jumps$: Observable<JumpList> = this._jumpsService.query(this._query);
this._jumps = jumps$.subscribe({ this._jumps = jumps$.subscribe({
next: (data: JumpList) => { next: (data: JumpList) => {
this.loading = false; this.loading = false;
@@ -127,6 +148,8 @@ export class JumpTableComponent implements OnChanges, OnDestroy {
this.jumps.paginator = this.paginator; this.jumps.paginator = this.paginator;
this.jumps.sort = this.sort; this.jumps.sort = this.sort;
this._resetErrors(); this._resetErrors();
//this.tableRefresh = !this.tableRefresh;
//this._jumpTableService.updateJumpRefresh(this.tableRefresh);
}, },
error: (err) => { error: (err) => {
this.errors = err; this.errors = err;
@@ -136,7 +159,7 @@ export class JumpTableComponent implements OnChanges, OnDestroy {
deleteJump(slug: string) { deleteJump(slug: string) {
this.isDeleting = true; this.isDeleting = true;
this.jumpsService.destroy(slug).pipe(take(1)) this._jumpsService.destroy(slug).pipe(take(1))
.subscribe(() => { .subscribe(() => {
this.router.navigateByUrl('/'); this.router.navigateByUrl('/');
}); });
@@ -144,7 +167,7 @@ export class JumpTableComponent implements OnChanges, OnDestroy {
openAddDialog(): void { openAddDialog(): void {
const dialogRef = this.dialog.open(JumpAddDialogComponent, { const dialogRef = this.dialog.open(JumpAddDialogComponent, {
width: '60vw', width: '70vw',
data: this.jump data: this.jump
}); });
dialogRef.afterClosed().pipe(take(1)) dialogRef.afterClosed().pipe(take(1))
@@ -157,7 +180,7 @@ export class JumpTableComponent implements OnChanges, OnDestroy {
openDeleteDialog(jump: Jump): void { openDeleteDialog(jump: Jump): void {
const dialogRef = this.dialog.open(JumpDeleteDialogComponent, { const dialogRef = this.dialog.open(JumpDeleteDialogComponent, {
width: '40vw', width: '60vw',
data: jump data: jump
}); });
dialogRef.afterClosed().pipe(take(1)) dialogRef.afterClosed().pipe(take(1))
@@ -170,7 +193,7 @@ export class JumpTableComponent implements OnChanges, OnDestroy {
openEditDialog(jump: Jump): void { openEditDialog(jump: Jump): void {
const dialogRef = this.dialog.open(JumpEditDialogComponent, { const dialogRef = this.dialog.open(JumpEditDialogComponent, {
width: '50vw', width: '70vw',
data: jump data: jump
}); });
dialogRef.afterClosed().pipe(take(1)) dialogRef.afterClosed().pipe(take(1))
@@ -190,7 +213,7 @@ export class JumpTableComponent implements OnChanges, OnDestroy {
submitForm() { submitForm() {
if (this.searchForm.valid) { if (this.searchForm.valid) {
this.query.filters.numero = this.searchForm.value.numero; this._query.filters.numero = this.searchForm.value.numero;
this._resetErrors(); this._resetErrors();
this.runQuery(); this.runQuery();
} }
@@ -199,13 +222,15 @@ export class JumpTableComponent implements OnChanges, OnDestroy {
private _onDelete(slug: string): void { private _onDelete(slug: string): void {
try { try {
this.isDeleting = true; this.isDeleting = true;
this.jumpsService.destroy(slug) this._jumpsService.destroy(slug)
.pipe(take(1)) .pipe(take(1))
.subscribe({ .subscribe({
next: () => { next: () => {
this._resetErrors(); this._resetErrors();
this._openSnackBar(`Le saut a été supprimé !`, 'OK'); this._openSnackBar(`Le saut a été supprimé !`, 'OK');
this.runQuery(); this.runQuery();
this.tableRefresh = !this.tableRefresh;
this._jumpTableService.updateTableRefresh(this.tableRefresh);
}, },
error: (err) => { error: (err) => {
this.errors = err; this.errors = err;
@@ -219,13 +244,16 @@ export class JumpTableComponent implements OnChanges, OnDestroy {
private _onEdit(jump: Jump): void { private _onEdit(jump: Jump): void {
try { try {
this.isSubmitting = true; this.isSubmitting = true;
this.jumpsService.update(jump) console.log(jump);
this._jumpsService.update(jump)
.pipe(take(1)) .pipe(take(1))
.subscribe({ .subscribe({
next: (jump) => { next: (jump) => {
this._resetErrors(); this._resetErrors();
this._openSnackBar(`Le saut n°${jump.numero} a été mis à jour !`, 'OK'); this._openSnackBar(`Le saut n°${jump.numero} a été mis à jour !`, 'OK');
this.runQuery(); this.runQuery();
this.tableRefresh = !this.tableRefresh;
this._jumpTableService.updateTableRefresh(this.tableRefresh);
}, },
error: (err) => { error: (err) => {
this.errors = err; this.errors = err;
@@ -241,7 +269,7 @@ export class JumpTableComponent implements OnChanges, OnDestroy {
try { try {
this.isSubmitting = true; this.isSubmitting = true;
Object.assign(this.jump, entry); Object.assign(this.jump, entry);
this.jumpsService.save(this.jump) this._jumpsService.save(this.jump)
.pipe(take(1)) .pipe(take(1))
.subscribe({ .subscribe({
next: (jump) => { next: (jump) => {
@@ -271,4 +299,35 @@ export class JumpTableComponent implements OnChanges, OnDestroy {
this.errors = { errors: {} }; this.errors = { errors: {} };
} }
inputHandler(e: any, id: number, key: string) {
if (!this.valid[id]) {
this.valid[id] = {}
}
this.valid[id][key] = e.target.validity.valid
}
disableSubmit(id: number) {
if (this.valid[id]) {
return Object.values(this.valid[id]).some((item) => item === false)
}
return false
}
/*
isAllSelected() {
return this.jumps.data.every((item) => item.isSelected)
}
isAnySelected() {
return this.jumps.data.some((item) => item.isSelected)
}
selectAll(event: any) {
this.jumps.data = this.jumps.data.map((item) => ({
...item,
isSelected: event.checked,
}))
}
*/
} }