---|qcm| Mise à jour V17 et QCM

This commit is contained in:
Rampeur
2024-05-04 02:08:04 +02:00
parent fa93c0c8f2
commit 6dece821a8
241 changed files with 27526 additions and 6520 deletions
@@ -0,0 +1,4 @@
export * from './jump-add.dialog';
export * from './jump-delete.dialog';
export * from './jump-edit.dialog';
export * from './jump-view.dialog';
@@ -0,0 +1,291 @@
<h2 mat-dialog-title class="bg-warn border-bottom border-light-subtle d-flex mb-3 pt-3 pb-2">
Ajouter un saut<span class="flex-spacer"></span>
<mat-icon fontIcon="close" class="pointer" (click)="closeDialog()"></mat-icon>
</h2>
<mat-dialog-content>
<div class="container">
<!--
<div class="row">
<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 [(ngModel)]="params.numeros" 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" [(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-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 cdkFocusInitial />
<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" [matAutocomplete]="autoDropzone">
<mat-autocomplete #autoDropzone="matAutocomplete" [displayWith]="displayLieuFn">
@for (option of filteredOptions.dropzones | async; track option) {
<mat-option [value]="option" (onSelectionChange)="onSelLieu(option)">{{option.lieu}} - {{option.oaci}}</mat-option>
}
</mat-autocomplete>
@if (this.jumpForm.controls['lieu'].status === 'INVALID') {
<mat-error>{{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" [matAutocomplete]="autoOaci">
<mat-autocomplete #autoOaci="matAutocomplete" [displayWith]="displayOaciFn">
@for (option of filteredOptions.oaci | async; track option) {
<mat-option [value]="option" (onSelectionChange)="onSelOaci(option)">{{option.lieu}} - {{option.oaci}}</mat-option>
}
</mat-autocomplete>
@if (this.jumpForm.controls['oaci'].status === 'INVALID') {
<mat-error>{{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" [matAutocomplete]="autoAeronef">
<mat-autocomplete #autoAeronef="matAutocomplete" [displayWith]="displayAeronefFn">
@for (option of filteredOptions.aeronefs | async; track option) {
<mat-option [value]="option" (onSelectionChange)="onSelAeronef(option)">{{option.aeronef}} - {{option.imat}}</mat-option>
}
</mat-autocomplete>
@if (this.jumpForm.controls['aeronef'].status === 'INVALID') {
<mat-error>{{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" [matAutocomplete]="autoImat">
<mat-autocomplete #autoImat="matAutocomplete" [displayWith]="displayImatFn">
@for (option of filteredOptions.imats | async; track option) {
<mat-option [value]="option" (onSelectionChange)="onSelImat(option)">{{option.aeronef}} - {{option.imat}}</mat-option>
}
</mat-autocomplete>
@if (this.jumpForm.controls['imat'].status === 'INVALID') {
<mat-error>{{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" [matAutocomplete]="autoCanopy">
<mat-autocomplete #autoCanopy="matAutocomplete" [displayWith]="displayVoileFn">
@for (option of filteredOptions.canopies | async; track option) {
<mat-option [value]="option" (onSelectionChange)="onSelVoile(option)">{{option.voile}} - {{option.taille}}</mat-option>
}
</mat-autocomplete>
@if (this.jumpForm.controls['voile'].status === 'INVALID') {
<mat-error>{{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" [matAutocomplete]="autoTaille">
<mat-autocomplete #autoTaille="matAutocomplete" [displayWith]="displayTailleFn">
@for (option of filteredOptions.tailles | async; track option) {
<mat-option [value]="option" (onSelectionChange)="onSelTaille(option)">{{option.voile}} - {{option.taille}}</mat-option>
}
</mat-autocomplete>
<span matTextSuffix>ft<sup>2</sup></span>
@if (this.jumpForm.controls['taille'].status === 'INVALID') {
<mat-error>{{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">
@if (this.jumpForm.controls['hauteur'].status === 'INVALID') {
<mat-error>{{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">
@if (this.jumpForm.controls['deploiement'].status === 'INVALID') {
<mat-error>{{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" [matAutocomplete]="autoCategorie">
<mat-autocomplete #autoCategorie="matAutocomplete" [displayWith]="displayCategorieFn">
@for (option of filteredOptions.categories | async; track option) {
<mat-option [value]="option" (onSelectionChange)="onSelCategorie(option)">{{option.categorie}}{{option.categorie && option.module ? ' - ' : ''}}{{option.module}}</mat-option>
}
</mat-autocomplete>
@if (this.jumpForm.controls['categorie'].status === 'INVALID') {
<mat-error>{{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" [matAutocomplete]="autoModule">
<mat-autocomplete #autoModule="matAutocomplete" [displayWith]="displayModuleFn">
@for (option of filteredOptions.modules | async; track option) {
<mat-option [value]="option" (onSelectionChange)="onSelModule(option)">{{option.categorie}}{{option.categorie && option.module ? ' - ' : ''}}{{option.module}}</mat-option>
}
</mat-autocomplete>
@if (this.jumpForm.controls['module'].status === 'INVALID') {
<mat-error>{{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">
@if (this.jumpForm.controls['accessoires'].status === 'INVALID') {
<mat-error>{{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">
@if (this.jumpForm.controls['zone'].status === 'INVALID') {
<mat-error>{{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">
@if (this.jumpForm.controls['participants'].status === 'INVALID') {
<mat-error>{{getErrorMessage('participants')}}</mat-error>
}
</mat-form-field>
<div class="mb-2">
@for (sautant of jump.sautants; track sautant) {
<span 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>
@if (this.jumpForm.controls['programme'].status === 'INVALID') {
<mat-error>{{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">
@if (this.jumpForm.controls['dossier'].status === 'INVALID') {
<mat-error>{{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">
@if (this.jumpForm.controls['video'].status === 'INVALID') {
<mat-error>{{getErrorMessage('video')}}</mat-error>
}
</mat-form-field>
<span class="d-inline-block align-middle ms-1">{{ filepath }}{{ filename }}</span>
</div>
</form>
</div>
</mat-dialog-content>
<mat-dialog-actions>
<span class="flex-spacer"></span>
<button mat-button (click)="closeDialog()" class="me-1">Annuler</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()">Enregistrer</button>
</mat-dialog-actions>
@@ -0,0 +1,837 @@
import { Component, Inject, OnDestroy } from '@angular/core';
import { AsyncPipe, DatePipe } from '@angular/common';
import { FormBuilder, FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatOptionModule } from '@angular/material/core';
import { MatSelectModule } from '@angular/material/select';
import { Observable, Subscription } from 'rxjs';
import { map, startWith } from 'rxjs/operators';
import { AeronefByImat, CanopyModelBySize, DropZoneByOaci, Jump, JumpAddParams, JumpByModule } from 'src/app/core/models';
import { AeronefsService, CanopiesService, DropZonesService, JumpsService } from 'src/app/core/services';
@Component({
selector: 'app-jump-add-dialog',
templateUrl: 'jump-add.dialog.html',
standalone: true,
imports: [
AsyncPipe,
DatePipe,
FormsModule,
ReactiveFormsModule,
MatAutocompleteModule,
MatButtonModule,
MatCheckboxModule,
MatDatepickerModule,
MatDialogModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
MatSelectModule,
MatOptionModule
]
})
export class JumpAddDialogComponent implements OnDestroy {
private _formChanges: Array<Subscription> = [];
private _aeronefByImat: Subscription = new Subscription();
private _canopyModelBySize: Subscription = new Subscription();
private _dropZoneByOaci: Subscription = new Subscription();
private _jumpByModule: Subscription = new 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
};
public inputOptions: {
aeronefs: Array<AeronefByImat>;
canopies: Array<CanopyModelBySize>;
dropzones: Array<DropZoneByOaci>;
categories: Array<JumpByModule>;
};
public filteredOptions: {
aeronefs: Observable<Array<AeronefByImat>>;
imats: Observable<Array<AeronefByImat>>;
canopies: Observable<Array<CanopyModelBySize>>;
tailles: Observable<Array<CanopyModelBySize>>;
dropzones: Observable<Array<DropZoneByOaci>>;
oaci: Observable<Array<DropZoneByOaci>>;
categories: Observable<Array<JumpByModule>>;
modules: Observable<Array<JumpByModule>>;
};
constructor(
public dialogRef: MatDialogRef<JumpAddDialogComponent>,
private fb: FormBuilder,
private _aeronefsService: AeronefsService,
private _canopiesService: CanopiesService,
private _dropZonesService: DropZonesService,
private _jumpsService: JumpsService,
@Inject(MAT_DIALOG_DATA) public data: {jump: Jump, lastJump: Jump}
) {
this.inputOptions = { aeronefs: [], canopies: [], dropzones: [], categories: [] };
//this.filteredOptions.aeronefs = this._aeronefsService.getAllByImat();
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;
const 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();
})
);
/*
this.filteredAeronefOptions = this.jumpForm.controls['aeronef'].valueChanges.pipe(
startWith(''),
map(value => {
const aeronef = typeof value === 'string' ? value : '';
return aeronef ? this._filterString(aeronef as string, this.aeronefOptions) : this.aeronefOptions.slice();
}),
);
this.filteredImatOptions = this.jumpForm.controls['imat'].valueChanges.pipe(
startWith(''),
map(value => {
const imat = typeof value === 'string' ? value : value?.imat;
return imat ? this._filterImat(imat as string) : this.imatOptions.slice();
}),
);
//this.filteredAeronefOptions = this._aeronefsService.getAllByImat();
*/
this.filteredOptions = {
aeronefs: this.jumpForm.controls['aeronef'].valueChanges.pipe(
startWith(''),
map(value => {
const aeronef = typeof value === 'string' ? value : value?.aeronef;
return aeronef ? this._filterImat(aeronef as string) : this.inputOptions.aeronefs.slice();
}),
),
imats: this.jumpForm.controls['imat'].valueChanges.pipe(
startWith(''),
map(value => {
const imat = typeof value === 'string' ? value : value?.imat;
return imat ? this._filterImat(imat as string) : this.inputOptions.aeronefs.slice();
}),
),
canopies: this.jumpForm.controls['voile'].valueChanges.pipe(
startWith(''),
map(value => {
const voile = typeof value === 'string' ? value : value?.voile;
return voile ? this._filterTaille(voile as string) : this.inputOptions.canopies.slice();
}),
),
tailles: this.jumpForm.controls['taille'].valueChanges.pipe(
startWith(''),
map(value => {
const taille = typeof value === 'string' ? value : value?.taille.toString();
return taille ? this._filterTaille(taille as string) : this.inputOptions.canopies.slice();
}),
),
dropzones: this.jumpForm.controls['lieu'].valueChanges.pipe(
startWith(''),
map(value => {
const lieu = typeof value === 'string' ? value : value?.lieu;
return lieu ? this._filterOaci(lieu as string) : this.inputOptions.dropzones.slice();
}),
),
oaci: this.jumpForm.controls['oaci'].valueChanges.pipe(
startWith(''),
map(value => {
const oaci = typeof value === 'string' ? value : value?.oaci;
return oaci ? this._filterOaci(oaci as string) : this.inputOptions.dropzones.slice();
}),
),
categories: this.jumpForm.controls['categorie'].valueChanges.pipe(
startWith(''),
map(value => {
const category = typeof value === 'string' ? value : value?.categorie;
return category ? this._filterModule(category as string) : this.inputOptions.categories.slice();
}),
),
modules: this.jumpForm.controls['module'].valueChanges.pipe(
startWith(''),
map(value => {
const module = typeof value === 'string' ? value : value?.module;
return module ? this._filterModule(module as string) : this.inputOptions.categories.slice();
}),
)
};
this._loadAeronefByImat();
this._loadCanopyModelBySize();
this._loadDropZoneByOaci();
this._loadJumpByModule();
}
ngOnDestroy() {
this._formChanges.forEach((sub: Subscription) => {
sub.unsubscribe();
});
this._aeronefByImat.unsubscribe();
this._canopyModelBySize.unsubscribe();
this._dropZoneByOaci.unsubscribe();
this._jumpByModule.unsubscribe();
}
public onDateChange(): void {
this.filename = this._computeFilename();
}
private _computeFilename(numero?: string): string {
let file: string = '';
const timestamp: number = Date.parse(this.jumpForm.controls['date'].value);
if (isNaN(timestamp) == false) {
const 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 _filterImat(imat: string): Array<AeronefByImat> {
const filterValue = imat.toLowerCase();
return this.inputOptions.aeronefs.filter(option => (option.aeronef.toLowerCase().includes(filterValue) || option.imat.toLowerCase().includes(filterValue)));
}
private _filterModule(module: string): Array<JumpByModule> {
const filterValue = module.toLowerCase();
return this.inputOptions.categories.filter(option => (option.categorie.toLowerCase().includes(filterValue) || option.module.toLowerCase().includes(filterValue)));
}
private _filterOaci(oaci: string): Array<DropZoneByOaci> {
const filterValue = oaci.toLowerCase();
return this.inputOptions.dropzones.filter(option => (option.lieu.toLowerCase().includes(filterValue) || option.oaci.toLowerCase().includes(filterValue)));
}
private _filterTaille(taille: string): Array<CanopyModelBySize> {
const filterValue = taille.toLowerCase();
return this.inputOptions.canopies.filter(option => (option.voile.toLowerCase().includes(filterValue) || option.taille.toString().includes(filterValue)));
}
private _loadAeronefByImat(): void {
const aeronefs$ = this._aeronefsService.getAllByImat();
this._aeronefByImat = aeronefs$.subscribe((aggregate: Array<AeronefByImat>) => {
/*
this.inputOptions.imats = aggregate.map((row: AeronefByImat) => {
if (this.inputOptions.aeronefs.indexOf(row.aeronef) === -1) {
this.inputOptions.aeronefs.push(row.aeronef);
}
return row;
});
*/
this.inputOptions.aeronefs = aggregate;
});
}
private _loadCanopyModelBySize(): void {
const canopies$ = this._canopiesService.getAllBySizeByModel();
this._canopyModelBySize = canopies$.subscribe((aggregate: Array<CanopyModelBySize>) => {
/*
this.inputOptions.tailles = aggregate.map((row: CanopyModelBySize) => {
if (this.inputOptions.canopies.indexOf(row.voile) === -1) {
this.inputOptions.canopies.push(row.voile);
}
return row;
});
*/
this.inputOptions.canopies = aggregate;
});
}
private _loadDropZoneByOaci(): void {
const dropzones$ = this._dropZonesService.getAllByOaci();
this._dropZoneByOaci = dropzones$.subscribe((aggregate: Array<DropZoneByOaci>) => {
/*
this.inputOptions.oaci = aggregate.map((row: DropZoneByOaci) => {
if (this.inputOptions.dropzones.indexOf(row.lieu) === -1) {
this.inputOptions.dropzones.push(row.lieu);
}
return row;
});
*/
this.inputOptions.dropzones = aggregate;
});
}
private _loadJumpByModule(): void {
const jumps$ = this._jumpsService.getAllByModule();
this._jumpByModule = jumps$.subscribe((aggregate: Array<JumpByModule>) => {
this.inputOptions.categories = aggregate;
});
}
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();
}
displayAeronefFn(aeronef: AeronefByImat): string {
let res = '';
if (aeronef) {
if (typeof aeronef === 'string') {
res = aeronef;
} else {
res = aeronef.aeronef ? aeronef.aeronef : '';
}
}
return res;
}
displayImatFn(aeronef: AeronefByImat): string {
let res = '';
if (aeronef) {
if (typeof aeronef === 'string') {
res = aeronef;
} else {
res = aeronef.imat ? aeronef.imat : '';
}
}
return res;
}
displayLieuFn(dropzone: DropZoneByOaci): string {
//return dropzone && dropzone.oaci ? `${dropzone.lieu} - ${dropzone.oaci}` : '';
let res = '';
if (dropzone) {
if (typeof dropzone === 'string') {
res = dropzone;
} else {
res = dropzone.lieu ? dropzone.lieu : '';
}
}
//return dropzone && dropzone.lieu ? dropzone.lieu : '';
return res;
}
displayOaciFn(dropzone: DropZoneByOaci): string {
//return dropzone && dropzone.oaci ? `${dropzone.lieu} - ${dropzone.oaci}` : '';
let res = '';
if (dropzone) {
if (typeof dropzone === 'string') {
res = dropzone;
} else {
res = dropzone.oaci ? dropzone.oaci : '';
}
}
//return dropzone && dropzone.oaci ? dropzone.oaci : '';
return res;
}
displayTailleFn(canopy: CanopyModelBySize): string {
let res = '';
if (canopy) {
if (typeof canopy === 'string') {
res = canopy;
} else {
res = canopy.taille ? canopy.taille.toString() : '';
}
}
return res;
}
displayVoileFn(canopy: CanopyModelBySize): string {
let res = '';
if (canopy) {
if (typeof canopy === 'string') {
res = canopy;
} else {
res = canopy.voile ? canopy.voile : '';
}
}
return res;
}
displayCategorieFn(jump: JumpByModule): string {
let res = '';
if (jump) {
if (typeof jump === 'string') {
res = jump;
} else {
res = jump.categorie ? jump.categorie : '';
}
}
return res;
}
displayModuleFn(jump: JumpByModule): string {
let res = '';
if (jump) {
if (typeof jump === 'string') {
res = jump;
} else {
res = jump.module ? jump.module : '';
}
}
return res;
}
getErrorMessage(name: string): string {
if (this.jumpForm.controls[name].errors !== null) {
return 'Ce champ est requis.';
}
return '';
}
onSelAeronef(aeronef: AeronefByImat) {
if (aeronef && aeronef.aeronef) {
//this.jumpForm.controls['imat'].setValue(aeronef.imat);
this.jumpForm.controls['imat'].setValue(aeronef);
}
}
onSelImat(aeronef: AeronefByImat) {
if (aeronef && aeronef.imat) {
//this.jumpForm.controls['aeronef'].setValue(aeronef.aeronef);
this.jumpForm.controls['aeronef'].setValue(aeronef);
}
}
onSelLieu(dropzone: DropZoneByOaci) {
if (dropzone && dropzone.oaci) {
//this.jumpForm.controls['oaci'].setValue(dropzone.oaci);
this.jumpForm.controls['oaci'].setValue(dropzone);
}
}
onSelOaci(dropzone: DropZoneByOaci) {
if (dropzone && dropzone.lieu) {
//this.jumpForm.controls['lieu'].setValue(dropzone.lieu);
this.jumpForm.controls['lieu'].setValue(dropzone);
}
}
onSelTaille(canopy: CanopyModelBySize) {
if (canopy && canopy.voile) {
//this.jumpForm.controls['voile'].setValue(canopy.voile);
this.jumpForm.controls['voile'].setValue(canopy);
}
}
onSelVoile(canopy: CanopyModelBySize) {
if (canopy && canopy.taille) {
//this.jumpForm.controls['taille'].setValue(canopy.taille.toString());
this.jumpForm.controls['taille'].setValue(canopy);
}
}
onSelCategorie(jump: JumpByModule) {
if (jump && jump.categorie) {
this.jumpForm.controls['module'].setValue(jump);
}
}
onSelModule(jump: JumpByModule) {
if (jump && jump.module) {
this.jumpForm.controls['categorie'].setValue(jump);
}
}
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?.toString());
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?.toString());
} 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
*/
const jumps: Array<Jump> = [];
const jump: Jump = {} as Jump;
const numeros: Array<number> = [];
let date: Date;
/* Controle de la validité du champ date et conversion au format ISO */
const timestamp: number = Date.parse(this.jumpForm.controls['date'].value);
if (isNaN(timestamp) == false) {
date = new Date(timestamp);
} else {
date = new Date();
}
let value = this.jumpForm.controls['numero'].value;
if (typeof value !== 'string') {
value = value.toString();
}
if (isNaN(+value) || value.split('+').length == 2) {
/*
* '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 = typeof this.jumpForm.controls['lieu'].value === 'string' ? this.jumpForm.controls['lieu'].value : this.jumpForm.controls['lieu'].value.lieu;
jump.oaci = typeof this.jumpForm.controls['oaci'].value === 'string' ? this.jumpForm.controls['oaci'].value : this.jumpForm.controls['oaci'].value.oaci;
jump.aeronef = typeof this.jumpForm.controls['aeronef'].value === 'string' ? this.jumpForm.controls['aeronef'].value : this.jumpForm.controls['aeronef'].value.aeronef;
jump.imat = typeof this.jumpForm.controls['imat'].value === 'string' ? this.jumpForm.controls['imat'].value : this.jumpForm.controls['imat'].value.imat;
jump.voile = typeof this.jumpForm.controls['voile'].value === 'string' ? this.jumpForm.controls['voile'].value : this.jumpForm.controls['voile'].value.voile;
jump.taille = typeof this.jumpForm.controls['taille'].value === 'string' ? this.jumpForm.controls['taille'].value : this.jumpForm.controls['taille'].value.taille;
jump.categorie = typeof this.jumpForm.controls['categorie'].value === 'string' ? this.jumpForm.controls['categorie'].value : this.jumpForm.controls['categorie'].value.categorie;
jump.module = typeof this.jumpForm.controls['module'].value === 'string' ? this.jumpForm.controls['module'].value : this.jumpForm.controls['module'].value.module;
jump.hauteur = this.jumpForm.controls['hauteur'].value;
jump.deploiement = this.jumpForm.controls['deploiement'].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;
/* Ajout du saut au tableau à retourner */
numeros.forEach((numero: number) => {
const 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);
}
}
@@ -0,0 +1,64 @@
<h2 mat-dialog-title class="bg-danger border-bottom border-light-subtle d-flex mb-3 pt-3 pb-2">
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>
<div class="container">
<div class="mt-2 mb-4 text-center text-danger border-danger alert alert-danger">
<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">
<dt class="text-accent fw-normal">numero:</dt>
<dd>{{jump.numero}}</dd>
<dt class="text-accent fw-normal">lieu:</dt>
<dd>{{jump.lieu}}</dd>
<dt class="text-accent fw-normal">aeronef:</dt>
<dd>{{jump.aeronef}}</dd>
<dt class="text-accent fw-normal">voile:</dt>
<dd>{{jump.voile}}</dd>
<dt class="text-accent fw-normal">hauteur:</dt>
<dd>{{jump.hauteur}} m</dd>
<dt class="text-accent fw-normal">categorie:</dt>
<dd>{{jump.categorie}}</dd>
<dt class="text-accent fw-normal">accessoires:</dt>
<dd>{{jump.accessoires}}</dd>
<dt class="text-accent fw-normal">dossier:</dt>
<dd>{{jump.dossier}}</dd>
<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>
</dl>
</div>
</div>
</div>
</mat-dialog-content>
<mat-dialog-actions>
<span class="flex-spacer"></span>
<button mat-button (click)="closeDialog()" class="me-1">Annuler</button>
<button mat-button color="accent" [mat-dialog-close]="jump" cdkFocusInitial>Supprimer</button>
</mat-dialog-actions>
@@ -0,0 +1,27 @@
import { Component, Inject } from '@angular/core';
import { DatePipe } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { Jump } from 'src/app/core/models';
@Component({
selector: 'app-jump-delete-dialog',
templateUrl: 'jump-delete.dialog.html',
standalone: true,
imports: [
DatePipe,
MatDialogModule, MatButtonModule, MatIconModule
]
})
export class JumpDeleteDialogComponent {
constructor(
public dialogRef: MatDialogRef<JumpDeleteDialogComponent>,
@Inject(MAT_DIALOG_DATA) public jump: Jump
) { }
closeDialog(): void {
this.dialogRef.close();
}
}
@@ -0,0 +1,219 @@
<h2 mat-dialog-title class="bg-primary border-bottom border-light-subtle d-flex mb-3 pt-3 pb-2">
Modifier un saut<span class="flex-spacer"></span>
<mat-icon fontIcon="close" class="pointer" (click)="closeDialog()"></mat-icon>
</h2>
<mat-dialog-content>
<div class="container">
<form class="row" [formGroup]="jumpForm" (ngSubmit)="submitForm()">
<div class="col-xs-12">
<mat-form-field appearance="outline" class="mt-2 me-2" color="primary">
<mat-label>Numéro du saut</mat-label>
<input matInput formControlName="numero">
</mat-form-field>
<mat-form-field appearance="outline" class="mt-2 me-3" color="primary">
<mat-label>Choisissez une date</mat-label>
<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>
</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>
<input matInput formControlName="lieu" [matAutocomplete]="autoDropzone">
<mat-autocomplete #autoDropzone="matAutocomplete" [displayWith]="displayLieuFn">
@for (option of filteredOptions.dropzones | async; track option) {
<mat-option [value]="option" (onSelectionChange)="onSelLieu(option)">{{option.lieu}} - {{option.oaci}}</mat-option>
}
</mat-autocomplete>
@if (this.jumpForm.controls['lieu'].status === 'INVALID') {
<mat-error>{{getErrorMessage('lieu')}}</mat-error>
}
</mat-form-field>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Oaci</mat-label>
<input matInput formControlName="oaci" [matAutocomplete]="autoOaci">
<mat-autocomplete #autoOaci="matAutocomplete" [displayWith]="displayOaciFn">
@for (option of filteredOptions.oaci | async; track option) {
<mat-option [value]="option" (onSelectionChange)="onSelOaci(option)">{{option.lieu}} - {{option.oaci}}</mat-option>
}
</mat-autocomplete>
@if (this.jumpForm.controls['oaci'].status === 'INVALID') {
<mat-error>{{getErrorMessage('oaci')}}</mat-error>
}
</mat-form-field>
<h4 class="border-bottom border-primary pb-1 mb-3">Aéronef</h4>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Aéronef</mat-label>
<input matInput formControlName="aeronef" [matAutocomplete]="autoAeronef">
<mat-autocomplete #autoAeronef="matAutocomplete" [displayWith]="displayAeronefFn">
@for (option of filteredOptions.aeronefs | async; track option) {
<mat-option [value]="option" (onSelectionChange)="onSelAeronef(option)">{{option.aeronef}} - {{option.imat}}</mat-option>
}
</mat-autocomplete>
@if (this.jumpForm.controls['aeronef'].status === 'INVALID') {
<mat-error>{{getErrorMessage('aeronef')}}</mat-error>
}
</mat-form-field>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Imatriculation</mat-label>
<input matInput formControlName="imat" [matAutocomplete]="autoImat">
<mat-autocomplete #autoImat="matAutocomplete" [displayWith]="displayImatFn">
@for (option of filteredOptions.imats | async; track option) {
<mat-option [value]="option" (onSelectionChange)="onSelImat(option)">{{option.aeronef}} - {{option.imat}}</mat-option>
}
</mat-autocomplete>
@if (this.jumpForm.controls['imat'].status === 'INVALID') {
<mat-error>{{getErrorMessage('imat')}}</mat-error>
}
</mat-form-field>
<h4 class="border-bottom border-primary pb-1 mb-3">Voile</h4>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Modèle</mat-label>
<input matInput formControlName="voile" [matAutocomplete]="autoCanopy">
<mat-autocomplete #autoCanopy="matAutocomplete" [displayWith]="displayVoileFn">
@for (option of filteredOptions.canopies | async; track option) {
<mat-option [value]="option" (onSelectionChange)="onSelVoile(option)">{{option.voile}} - {{option.taille}}</mat-option>
}
</mat-autocomplete>
@if (this.jumpForm.controls['voile'].status === 'INVALID') {
<mat-error>{{getErrorMessage('voile')}}</mat-error>
}
</mat-form-field>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Taille en ft<sup>2</sup></mat-label>
<input matInput formControlName="taille" [matAutocomplete]="autoTaille">
<mat-autocomplete #autoTaille="matAutocomplete" [displayWith]="displayTailleFn">
@for (option of filteredOptions.tailles | async; track option) {
<mat-option [value]="option" (onSelectionChange)="onSelTaille(option)">{{option.voile}} - {{option.taille}}</mat-option>
}
</mat-autocomplete>
<span matTextSuffix>ft<sup>2</sup></span>
@if (this.jumpForm.controls['taille'].status === 'INVALID') {
<mat-error>{{getErrorMessage('taille')}}</mat-error>
}
</mat-form-field>
</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">
@if (this.jumpForm.controls['hauteur'].status === 'INVALID') {
<mat-error>{{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">
@if (this.jumpForm.controls['deploiement'].status === 'INVALID') {
<mat-error>{{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" [matAutocomplete]="autoCategorie">
<mat-autocomplete #autoCategorie="matAutocomplete" [displayWith]="displayCategorieFn">
@for (option of filteredOptions.categories | async; track option) {
<mat-option [value]="option" (onSelectionChange)="onSelCategorie(option)">{{option.categorie}}{{option.categorie && option.module ? ' - ' : ''}}{{option.module}}</mat-option>
}
</mat-autocomplete>
@if (this.jumpForm.controls['categorie'].status === 'INVALID') {
<mat-error>{{getErrorMessage('categorie')}}</mat-error>
}
</mat-form-field>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Module</mat-label>
<input matInput formControlName="module" [matAutocomplete]="autoModule">
<mat-autocomplete #autoModule="matAutocomplete" [displayWith]="displayModuleFn">
@for (option of filteredOptions.modules | async; track option) {
<mat-option [value]="option" (onSelectionChange)="onSelModule(option)">{{option.categorie}}{{option.categorie && option.module ? ' - ' : ''}}{{option.module}}</mat-option>
}
</mat-autocomplete>
@if (this.jumpForm.controls['module'].status === 'INVALID') {
<mat-error>{{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">
@if (this.jumpForm.controls['accessoires'].status === 'INVALID') {
<mat-error>{{getErrorMessage('accessoires')}}</mat-error>
}
</mat-form-field>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Zone</mat-label>
<input matInput formControlName="zone">
@if (this.jumpForm.controls['zone'].status === 'INVALID') {
<mat-error>{{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">
@if (this.jumpForm.controls['participants'].status === 'INVALID') {
<mat-error>{{getErrorMessage('participants')}}</mat-error>
}
</mat-form-field>
<div class="mb-2">
@for (sautant of jump.sautants; track sautant) {
<span 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>
@if (this.jumpForm.controls['programme'].status === 'INVALID') {
<mat-error>{{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">
@if (this.jumpForm.controls['dossier'].status === 'INVALID') {
<mat-error>{{getErrorMessage('dossier')}}</mat-error>
}
</mat-form-field>
<mat-form-field appearance="fill" class="me-2">
<mat-label>Video</mat-label>
<input matInput formControlName="video">
@if (this.jumpForm.controls['video'].status === 'INVALID') {
<mat-error>{{getErrorMessage('video')}}</mat-error>
}
</mat-form-field>
</div>
</form>
</div>
</mat-dialog-content>
<mat-dialog-actions>
<span class="flex-spacer"></span>
<button mat-button (click)="closeDialog()" class="me-1">Annuler</button>
<button mat-button color="primary" [disabled]="!jumpForm.valid" (click)="submitForm()" cdkFocusInitial>Enregistrer</button>
</mat-dialog-actions>
@@ -0,0 +1,407 @@
import { Component, Inject, OnDestroy } from '@angular/core';
import { AsyncPipe, DatePipe } from '@angular/common';
import { FormBuilder, FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatOptionModule } from '@angular/material/core';
import { MatSelectModule } from '@angular/material/select';
import { Observable, Subscription } from 'rxjs';
import { map, startWith } from 'rxjs/operators';
import { AeronefByImat, CanopyModelBySize, DropZoneByOaci, Jump, JumpByModule } from 'src/app/core/models';
import { AeronefsService, CanopiesService, DropZonesService, JumpsService } from 'src/app/core/services';
@Component({
selector: 'app-jump-edit-dialog',
templateUrl: 'jump-edit.dialog.html',
standalone: true,
imports: [
AsyncPipe,
DatePipe,
FormsModule,
ReactiveFormsModule,
MatAutocompleteModule,
MatButtonModule,
MatCheckboxModule,
MatDatepickerModule,
MatDialogModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
MatSelectModule,
MatOptionModule
]
})
export class JumpEditDialogComponent implements OnDestroy {
private _aeronefByImat: Subscription = new Subscription();
private _canopyModelBySize: Subscription = new Subscription();
private _dropZoneByOaci: Subscription = new Subscription();
private _jumpByModule: Subscription = new Subscription();
public tagField = new FormControl<string>('', { nonNullable: true});
public jumpForm: FormGroup;
public inputOptions: {
aeronefs: Array<AeronefByImat>;
canopies: Array<CanopyModelBySize>;
dropzones: Array<DropZoneByOaci>;
categories: Array<JumpByModule>;
};
public filteredOptions: {
aeronefs: Observable<Array<AeronefByImat>>;
imats: Observable<Array<AeronefByImat>>;
canopies: Observable<Array<CanopyModelBySize>>;
tailles: Observable<Array<CanopyModelBySize>>;
dropzones: Observable<Array<DropZoneByOaci>>;
oaci: Observable<Array<DropZoneByOaci>>;
categories: Observable<Array<JumpByModule>>;
modules: Observable<Array<JumpByModule>>;
};
constructor(
public dialogRef: MatDialogRef<JumpEditDialogComponent>,
private fb: FormBuilder,
private _aeronefsService: AeronefsService,
private _canopiesService: CanopiesService,
private _dropZonesService: DropZonesService,
private _jumpsService: JumpsService,
@Inject(MAT_DIALOG_DATA) public jump: Jump
) {
this.inputOptions = { aeronefs: [], canopies: [], dropzones: [], categories: [] };
const 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?.toString(), 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);
this.filteredOptions = {
aeronefs: this.jumpForm.controls['aeronef'].valueChanges.pipe(
startWith(''),
map(value => {
const aeronef = typeof value === 'string' ? value : value?.aeronef;
return aeronef ? this._filterImat(aeronef as string) : this.inputOptions.aeronefs.slice();
}),
),
imats: this.jumpForm.controls['imat'].valueChanges.pipe(
startWith(''),
map(value => {
const imat = typeof value === 'string' ? value : value?.imat;
return imat ? this._filterImat(imat as string) : this.inputOptions.aeronefs.slice();
}),
),
canopies: this.jumpForm.controls['voile'].valueChanges.pipe(
startWith(''),
map(value => {
const voile = typeof value === 'string' ? value : value?.voile;
return voile ? this._filterTaille(voile as string) : this.inputOptions.canopies.slice();
}),
),
tailles: this.jumpForm.controls['taille'].valueChanges.pipe(
startWith(''),
map(value => {
const taille = typeof value === 'string' ? value : value?.taille.toString();
return taille ? this._filterTaille(taille as string) : this.inputOptions.canopies.slice();
}),
),
dropzones: this.jumpForm.controls['lieu'].valueChanges.pipe(
startWith(''),
map(value => {
const lieu = typeof value === 'string' ? value : value?.lieu;
return lieu ? this._filterOaci(lieu as string) : this.inputOptions.dropzones.slice();
}),
),
oaci: this.jumpForm.controls['oaci'].valueChanges.pipe(
startWith(''),
map(value => {
const oaci = typeof value === 'string' ? value : value?.oaci;
return oaci ? this._filterOaci(oaci as string) : this.inputOptions.dropzones.slice();
}),
),
categories: this.jumpForm.controls['categorie'].valueChanges.pipe(
startWith(''),
map(value => {
const category = typeof value === 'string' ? value : value?.categorie;
return category ? this._filterModule(category as string) : this.inputOptions.categories.slice();
}),
),
modules: this.jumpForm.controls['module'].valueChanges.pipe(
startWith(''),
map(value => {
const module = typeof value === 'string' ? value : value?.module;
return module ? this._filterModule(module as string) : this.inputOptions.categories.slice();
}),
)
};
this._loadAeronefByImat();
this._loadCanopyModelBySize();
this._loadDropZoneByOaci();
this._loadJumpByModule();
}
ngOnDestroy() {
this._aeronefByImat.unsubscribe();
this._canopyModelBySize.unsubscribe();
this._dropZoneByOaci.unsubscribe();
this._jumpByModule.unsubscribe();
}
private _filterImat(imat: string): Array<AeronefByImat> {
const filterValue = imat.toLowerCase();
return this.inputOptions.aeronefs.filter(option => (option.aeronef.toLowerCase().includes(filterValue) || option.imat.toLowerCase().includes(filterValue)));
}
private _filterModule(module: string): Array<JumpByModule> {
const filterValue = module.toLowerCase();
return this.inputOptions.categories.filter(option => (option.categorie.toLowerCase().includes(filterValue) || option.module.toLowerCase().includes(filterValue)));
}
private _filterOaci(oaci: string): Array<DropZoneByOaci> {
const filterValue = oaci.toLowerCase();
return this.inputOptions.dropzones.filter(option => (option.lieu.toLowerCase().includes(filterValue) || option.oaci.toLowerCase().includes(filterValue)));
}
private _filterTaille(taille: string): Array<CanopyModelBySize> {
const filterValue = taille.toLowerCase();
return this.inputOptions.canopies.filter(option => (option.voile.toLowerCase().includes(filterValue) || option.taille.toString().includes(filterValue)));
}
private _loadAeronefByImat(): void {
const aeronefs$ = this._aeronefsService.getAllByImat();
this._aeronefByImat = aeronefs$.subscribe((aggregate: Array<AeronefByImat>) => {
this.inputOptions.aeronefs = aggregate;
});
}
private _loadCanopyModelBySize(): void {
const canopies$ = this._canopiesService.getAllBySizeByModel();
this._canopyModelBySize = canopies$.subscribe((aggregate: Array<CanopyModelBySize>) => {
this.inputOptions.canopies = aggregate;
});
}
private _loadDropZoneByOaci(): void {
const dropzones$ = this._dropZonesService.getAllByOaci();
this._dropZoneByOaci = dropzones$.subscribe((aggregate: Array<DropZoneByOaci>) => {
this.inputOptions.dropzones = aggregate;
});
}
private _loadJumpByModule(): void {
const jumps$ = this._jumpsService.getAllByModule();
this._jumpByModule = jumps$.subscribe((aggregate: Array<JumpByModule>) => {
this.inputOptions.categories = aggregate;
});
}
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();
}
displayAeronefFn(aeronef: AeronefByImat): string {
let res = '';
if (aeronef) {
if (typeof aeronef === 'string') {
res = aeronef;
} else {
res = aeronef.aeronef ? aeronef.aeronef : '';
}
}
return res;
}
displayImatFn(aeronef: AeronefByImat): string {
let res = '';
if (aeronef) {
if (typeof aeronef === 'string') {
res = aeronef;
} else {
res = aeronef.imat ? aeronef.imat : '';
}
}
return res;
}
displayLieuFn(dropzone: DropZoneByOaci): string {
let res = '';
if (dropzone) {
if (typeof dropzone === 'string') {
res = dropzone;
} else {
res = dropzone.lieu ? dropzone.lieu : '';
}
}
return res;
}
displayOaciFn(dropzone: DropZoneByOaci): string {
let res = '';
if (dropzone) {
if (typeof dropzone === 'string') {
res = dropzone;
} else {
res = dropzone.oaci ? dropzone.oaci : '';
}
}
return res;
}
displayTailleFn(canopy: CanopyModelBySize): string {
let res = '';
if (canopy) {
if (typeof canopy === 'string') {
res = canopy;
} else {
res = canopy.taille ? canopy.taille.toString() : '';
}
}
return res;
}
displayVoileFn(canopy: CanopyModelBySize): string {
let res = '';
if (canopy) {
if (typeof canopy === 'string') {
res = canopy;
} else {
res = canopy.voile ? canopy.voile : '';
}
}
return res;
}
displayCategorieFn(jump: JumpByModule): string {
let res = '';
if (jump) {
if (typeof jump === 'string') {
res = jump;
} else {
res = jump.categorie ? jump.categorie : '';
}
}
return res;
}
displayModuleFn(jump: JumpByModule): string {
let res = '';
if (jump) {
if (typeof jump === 'string') {
res = jump;
} else {
res = jump.module ? jump.module : '';
}
}
return res;
}
getErrorMessage(name: string): string {
if (this.jumpForm.controls[name].errors !== null) {
return `Ce champ est requis.`;
}
return '';
}
onSelAeronef(aeronef: AeronefByImat) {
if (aeronef && aeronef.aeronef) {
this.jumpForm.controls['imat'].setValue(aeronef);
}
}
onSelImat(aeronef: AeronefByImat) {
if (aeronef && aeronef.imat) {
this.jumpForm.controls['aeronef'].setValue(aeronef);
}
}
onSelLieu(dropzone: DropZoneByOaci) {
if (dropzone && dropzone.oaci) {
this.jumpForm.controls['oaci'].setValue(dropzone);
}
}
onSelOaci(dropzone: DropZoneByOaci) {
if (dropzone && dropzone.lieu) {
this.jumpForm.controls['lieu'].setValue(dropzone);
}
}
onSelTaille(canopy: CanopyModelBySize) {
if (canopy && canopy.voile) {
this.jumpForm.controls['voile'].setValue(canopy);
}
}
onSelVoile(canopy: CanopyModelBySize) {
if (canopy && canopy.taille) {
this.jumpForm.controls['taille'].setValue(canopy);
}
}
onSelCategorie(jump: JumpByModule) {
if (jump && jump.categorie) {
this.jumpForm.controls['module'].setValue(jump);
}
}
onSelModule(jump: JumpByModule) {
if (jump && jump.module) {
this.jumpForm.controls['categorie'].setValue(jump);
}
}
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);
this.jump.lieu = typeof this.jumpForm.controls['lieu'].value === 'string' ? this.jumpForm.controls['lieu'].value : this.jumpForm.controls['lieu'].value.lieu;
this.jump.oaci = typeof this.jumpForm.controls['oaci'].value === 'string' ? this.jumpForm.controls['oaci'].value : this.jumpForm.controls['oaci'].value.oaci;
this.jump.aeronef = typeof this.jumpForm.controls['aeronef'].value === 'string' ? this.jumpForm.controls['aeronef'].value : this.jumpForm.controls['aeronef'].value.aeronef;
this.jump.imat = typeof this.jumpForm.controls['imat'].value === 'string' ? this.jumpForm.controls['imat'].value : this.jumpForm.controls['imat'].value.imat;
this.jump.voile = typeof this.jumpForm.controls['voile'].value === 'string' ? this.jumpForm.controls['voile'].value : this.jumpForm.controls['voile'].value.voile;
this.jump.taille = typeof this.jumpForm.controls['taille'].value === 'string' ? this.jumpForm.controls['taille'].value : this.jumpForm.controls['taille'].value.taille;
this.jump.categorie = typeof this.jumpForm.controls['categorie'].value === 'string' ? this.jumpForm.controls['categorie'].value : this.jumpForm.controls['categorie'].value.categorie;
this.jump.module = typeof this.jumpForm.controls['module'].value === 'string' ? this.jumpForm.controls['module'].value : this.jumpForm.controls['module'].value.module;
// close the dialog with result
this.dialogRef.close(this.jump);
}
updateJump(values: NonNullable<unknown>): void {
Object.assign(this.jump, values);
}
}
@@ -0,0 +1,69 @@
<h2 mat-dialog-title class="bg-cyan border-bottom border-light-subtle d-flex mb-3 pt-3 pb-2">
Saut n°{{jump.numero}}<span class="flex-spacer"></span>
<mat-icon fontIcon="close" class="pointer" (click)="closeDialog()"></mat-icon>
</h2>
<mat-dialog-content>
<div class="container">
<h5 class="border-bottom text-light-info border-light-subtle pb-2 mb-3">Le {{ jump.date | date: 'dd/MM/yyyy' }} à {{ jump.lieu }} :</h5>
<div class="row mb-3">
<div class="col-lg-6 col-md-12">
<dl class="dl-horizontal">
<dt class="text-cyan fw-normal">Lieu:</dt>
<dd>{{jump.lieu}}</dd>
<dt class="text-cyan fw-normal">Oaci:</dt>
<dd>{{jump.oaci}}</dd>
<dt class="text-cyan fw-normal">Aeronef:</dt>
<dd>{{jump.aeronef}}</dd>
<dt class="text-cyan fw-normal">Imat:</dt>
<dd>{{jump.imat}}</dd>
<dt class="text-cyan fw-normal">Voile:</dt>
<dd>{{jump.voile}}</dd>
<dt class="text-cyan fw-normal">Taille:</dt>
<dd>{{jump.taille}} ft<sup>2</sup></dd>
<dt class="text-cyan fw-normal">Participants:</dt>
<dd>{{jump.participants}}</dd>
<dt class="text-cyan fw-normal">Sautants:</dt>
<dd>
@for (sautant of jump.sautants; track sautant) {
<span class="badge rounded-pill bg-primary mb-2 me-1 pe-3 py-1 fw-normal text-dark">
<mat-icon class="align-middle me-1" fontIcon="person"></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 me-1" fontIcon="person"></mat-icon>
ju_solide
</span>
</dd>
</dl>
</div>
<div class="col-lg-6 col-md-12">
<dl class="dl-horizontal">
<dt class="text-cyan fw-normal">Hauteur:</dt>
<dd>{{jump.hauteur}} m</dd>
<dt class="text-cyan fw-normal">Deploiement:</dt>
<dd>{{jump.deploiement}} m</dd>
<dt class="text-cyan fw-normal">Categorie:</dt>
<dd>{{jump.categorie}}</dd>
<dt class="text-cyan fw-normal">Module:</dt>
<dd>{{jump.module}}</dd>
<dt class="text-cyan fw-normal">Accessoires:</dt>
<dd>{{jump.accessoires}}</dd>
<dt class="text-cyan fw-normal">Zone:</dt>
<dd>{{jump.zone}}</dd>
<dt class="text-cyan fw-normal">Dossier media:</dt>
<dd>{{jump.dossier}}</dd>
<dt class="text-cyan fw-normal">Video:</dt>
<dd>{{jump.video}}</dd>
<dt class="text-cyan fw-normal">Programme:</dt>
<dd>{{jump.programme}}</dd>
</dl>
</div>
</div>
<mat-divider></mat-divider>
</div>
</mat-dialog-content>
<mat-dialog-actions>
<span class="flex-spacer"></span>
<button mat-button (click)="closeDialog()" class="me-1">Fermer</button>
</mat-dialog-actions>
@@ -0,0 +1,33 @@
import { Component, Inject } from '@angular/core';
import { DatePipe } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
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';
@Component({
selector: 'app-jump-view-dialog',
templateUrl: 'jump-view.dialog.html',
standalone: true,
imports: [
DatePipe,
MatButtonModule,
MatDialogModule,
MatDividerModule,
MatIconModule
]
})
export class JumpViewDialogComponent {
constructor(
public dialogRef: MatDialogRef<JumpViewDialogComponent>,
@Inject(MAT_DIALOG_DATA) public jump: Jump
) { }
closeDialog(): void {
// close the dialog without result
this.dialogRef.close();
}
}