Implémentation SkydiverId API
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
<div @flyInOut>
|
<div @flyInOut>
|
||||||
<div class="content">
|
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<div class="flex-fill">
|
<div class="flex-fill">
|
||||||
<h1 class="mb-1">{{title}}</h1>
|
<h1 class="mb-1">{{title}}</h1>
|
||||||
@@ -48,4 +47,3 @@
|
|||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="container content auth-page">
|
<div class="container auth-page">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6 offset-md-3 col-xs-12">
|
<div class="col-md-6 offset-md-3 col-xs-12">
|
||||||
<h1 class="text-xs-center">{{ title }}</h1>
|
<h1 class="text-xs-center">{{ title }}</h1>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<div @flyInOut>
|
<div @flyInOut>
|
||||||
<div class="calculator-page content">
|
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<div class="flex-fill">
|
<div class="flex-fill">
|
||||||
<h1 class="mb-1">{{title}}</h1>
|
<h1 class="mb-1">{{title}}</h1>
|
||||||
@@ -56,7 +55,7 @@
|
|||||||
<table class="table table-striped table-dark table-hover mat-elevation-z2">
|
<table class="table table-striped table-dark table-hover mat-elevation-z2">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="warn">
|
<tr class="warn">
|
||||||
<th class="first"></th>
|
<th class="text-nowrap pe-4"></th>
|
||||||
<th class="text-nowrap">Taille actuelle</th>
|
<th class="text-nowrap">Taille actuelle</th>
|
||||||
<th class="text-nowrap">Taille min</th>
|
<th class="text-nowrap">Taille min</th>
|
||||||
<th class="text-nowrap">Taille min -11%</th>
|
<th class="text-nowrap">Taille min -11%</th>
|
||||||
@@ -64,34 +63,34 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="warn">
|
<tr class="warn">
|
||||||
<th class="first">Taille de voile en ft<sup>2</sup></th>
|
<th class="text-nowrap pe-4">Taille de voile en ft<sup>2</sup></th>
|
||||||
<td class="font-monospace text-{{ info.state.color }}"> ●
|
<td class="font-monospace text-{{ info.state.color }}"> ●
|
||||||
{{ info.sizesFeet.current }} </td>
|
{{ info.sizesFeet.current }} </td>
|
||||||
<td class="font-monospace text-success"> ● {{ info.sizesFeet.min }} </td>
|
<td class="font-monospace text-success"> ● {{ info.sizesFeet.min }} </td>
|
||||||
<td class="font-monospace text-warning"> ● {{ info.sizesFeet.min11 }} </td>
|
<td class="font-monospace text-warning"> ● {{ info.sizesFeet.min11 }} </td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="warn">
|
<tr class="warn">
|
||||||
<th class="first">Charge alaire</th>
|
<th class="text-nowrap pe-4">Charge alaire</th>
|
||||||
<td class="font-monospace">{{ info.charges.current | number : '1.2-3' }}</td>
|
<td class="font-monospace">{{ info.charges.current | number : '1.2-3' }}</td>
|
||||||
<td class="font-monospace">{{ info.charges.min | number : '1.2-3' }}</td>
|
<td class="font-monospace">{{ info.charges.min | number : '1.2-3' }}</td>
|
||||||
<td class="font-monospace">{{ info.charges.min11 | number : '1.2-3' }}</td>
|
<td class="font-monospace">{{ info.charges.min11 | number : '1.2-3' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="warn">
|
<tr class="warn">
|
||||||
<th class="first">Taille de voile en m<sup>2</sup></th>
|
<th class="text-nowrap pe-4">Taille de voile en m<sup>2</sup></th>
|
||||||
<td class="font-monospace">{{ info.sizesMeter.current | number : '1.2-3' }}</td>
|
<td class="font-monospace">{{ info.sizesMeter.current | number : '1.2-3' }}</td>
|
||||||
<td class="font-monospace">{{ info.sizesMeter.min | number : '1.2-3' }}</td>
|
<td class="font-monospace">{{ info.sizesMeter.min | number : '1.2-3' }}</td>
|
||||||
<td class="font-monospace">{{ info.sizesMeter.min11 | number : '1.2-3' }}</td>
|
<td class="font-monospace">{{ info.sizesMeter.min11 | number : '1.2-3' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="warn">
|
<tr class="warn">
|
||||||
<th class="first">Coefficient kilo/livres</th>
|
<th class="text-nowrap pe-4">Coefficient kilo/livres</th>
|
||||||
<td colspan="3" class="font-monospace text-start">{{ coeffKgLbs }}</td>
|
<td colspan="3" class="font-monospace text-start">{{ coeffKgLbs }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="warn">
|
<tr class="warn">
|
||||||
<th class="first">Coefficient pied/mètre</th>
|
<th class="text-nowrap pe-4">Coefficient pied/mètre</th>
|
||||||
<td colspan="3" class="font-monospace text-start">{{ coeffFtM }}</td>
|
<td colspan="3" class="font-monospace text-start">{{ coeffFtM }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="warn">
|
<tr class="warn">
|
||||||
<th class="first">Formule charge alaire</th>
|
<th class="text-nowrap pe-4">Formule charge alaire</th>
|
||||||
<td colspan="3" class="font-monospace text-start">
|
<td colspan="3" class="font-monospace text-start">
|
||||||
( ( {{ inputs.weight }} + {{ inputs.gear }} ) * {{ coeffKgLbs }} ) /
|
( ( {{ inputs.weight }} + {{ inputs.gear }} ) * {{ coeffKgLbs }} ) /
|
||||||
{{ inputs.current }} = {{ info.charges.current | number : '1.5' }}<br />
|
{{ inputs.current }} = {{ info.charges.current | number : '1.5' }}<br />
|
||||||
@@ -129,7 +128,7 @@
|
|||||||
<table class="table table-striped table-dark table-hover mat-elevation-z2 mb-1">
|
<table class="table table-striped table-dark table-hover mat-elevation-z2 mb-1">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="warn">
|
<tr class="warn">
|
||||||
<th class="first"></th>
|
<th class="text-nowrap pe-4"></th>
|
||||||
@for (header of sizesHeader; track header; let index = $index) {
|
@for (header of sizesHeader; track header; let index = $index) {
|
||||||
<th class="pl-3 pr-3 {{ tableHeader[(index+1)].active }}">{{ header.name }}</th>
|
<th class="pl-3 pr-3 {{ tableHeader[(index+1)].active }}">{{ header.name }}</th>
|
||||||
}
|
}
|
||||||
@@ -137,26 +136,26 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="warn">
|
<tr class="warn">
|
||||||
<th class="first">Taille de voile en ft<sup>2</sup></th>
|
<th class="firtext-nowrap pe-4st">Taille de voile en ft<sup>2</sup></th>
|
||||||
@for (value of sizesValuesFeet; track value; let index = $index) {
|
@for (value of sizesValuesFeet; track value; let index = $index) {
|
||||||
<td class="pl-3 text-nowrap {{ tableHeader[(index+1)].active }}">{{ value }}</td>
|
<td class="pl-3 text-nowrap {{ tableHeader[(index+1)].active }}">{{ value }}</td>
|
||||||
}
|
}
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="warn">
|
<tr class="warn">
|
||||||
<th class="first">Abbattement 11%</th>
|
<th class="text-nowrap pe-4">Abbattement 11%</th>
|
||||||
@for (value of sizesMinValuesFeet; track value; let index = $index) {
|
@for (value of sizesMinValuesFeet; track value; let index = $index) {
|
||||||
<td class="pl-3 text-nowrap {{ tableHeader[(index+1)].active }}">{{ value }}</td>
|
<td class="pl-3 text-nowrap {{ tableHeader[(index+1)].active }}">{{ value }}</td>
|
||||||
}
|
}
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="warn">
|
<tr class="warn">
|
||||||
<th class="first">Charge alaire</th>
|
<th class="text-nowrap pe-4">Charge alaire</th>
|
||||||
@for (charge of sizesCharges; track charge; let index = $index) {
|
@for (charge of sizesCharges; track charge; let index = $index) {
|
||||||
<td class="pl-3 text-nowrap {{ tableHeader[(index+1)].active }}">
|
<td class="pl-3 text-nowrap {{ tableHeader[(index+1)].active }}">
|
||||||
{{ charge | number : '1.2-3' }}</td>
|
{{ charge | number : '1.2-3' }}</td>
|
||||||
}
|
}
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="warn">
|
<tr class="warn">
|
||||||
<th class="first">Taille de voile en m<sup>2</sup></th>
|
<th class="text-nowrap pe-4">Taille de voile en m<sup>2</sup></th>
|
||||||
@for (value of sizesValuesMeter; track value; let index = $index) {
|
@for (value of sizesValuesMeter; track value; let index = $index) {
|
||||||
<td class="pl-3 text-nowrap {{ tableHeader[(index+1)].active }}">
|
<td class="pl-3 text-nowrap {{ tableHeader[(index+1)].active }}">
|
||||||
{{ value | number : '1.2-2' }}</td>
|
{{ value | number : '1.2-2' }}</td>
|
||||||
@@ -175,7 +174,7 @@
|
|||||||
class="table table-striped table-dark table-hover mat-elevation-z2">
|
class="table table-striped table-dark table-hover mat-elevation-z2">
|
||||||
<!-- weight column -->
|
<!-- weight column -->
|
||||||
<ng-container matColumnDef="weight">
|
<ng-container matColumnDef="weight">
|
||||||
<th mat-header-cell *matHeaderCellDef mat-sort-header class="first {{tableHeader[0].active}}">
|
<th mat-header-cell *matHeaderCellDef mat-sort-header class="text-nowrap pe-4 {{tableHeader[0].active}}">
|
||||||
{{tableHeader[0].name}} </th>
|
{{tableHeader[0].name}} </th>
|
||||||
<th mat-cell *matCellDef="let element;" class="text-end ps-3 pe-4 fs-6" role="button"
|
<th mat-cell *matCellDef="let element;" class="text-end ps-3 pe-4 fs-6" role="button"
|
||||||
(click)="setCurrentWeight(element.weight)">
|
(click)="setCurrentWeight(element.weight)">
|
||||||
@@ -256,4 +255,3 @@
|
|||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<div @flyInOut>
|
<div @flyInOut>
|
||||||
<div class="content">
|
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<div class="flex-fill">
|
<div class="flex-fill">
|
||||||
<h1 class="mb-1">{{title}}</h1>
|
<h1 class="mb-1">{{title}}</h1>
|
||||||
@@ -55,4 +54,3 @@
|
|||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
<div class="content">
|
|
||||||
<h1 class="mb-1">{{title}}</h1>
|
<h1 class="mb-1">{{title}}</h1>
|
||||||
<span [hidden]="!lastJump.numero" class="me-2 fst-italic0 fs-6">
|
<span [hidden]="!lastJump.numero" class="me-2 fst-italic0 fs-6">
|
||||||
Dernier saut enregistré : <span class="fs-5 mx-1 text-primary">{{ lastJump.numero }}<sup>ème</sup></span> à <span class="fs-5 mx-1 text-primary">{{ lastJump.lieu }}</span> le <span class="fs-5 mx-1 text-primary">{{ lastJump.date | date: 'dd/MM/yyyy' }}</span>
|
Dernier saut enregistré : <span class="fs-5 mx-1 text-primary">{{ lastJump.numero }}<sup>ème</sup></span> à <span class="fs-5 mx-1 text-primary">{{ lastJump.lieu }}</span> le <span class="fs-5 mx-1 text-primary">{{ lastJump.date | date: 'dd/MM/yyyy' }}</span>
|
||||||
@@ -35,4 +34,3 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
<div @flyInOut>
|
<div @flyInOut>
|
||||||
<div class="content">
|
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<div class="flex-fill">
|
<div class="flex-fill">
|
||||||
<h1 class="mb-1">{{title}}</h1>
|
<h1 class="mb-1">{{title}}</h1>
|
||||||
@@ -54,4 +53,3 @@
|
|||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,17 @@
|
|||||||
|
/* Home */
|
||||||
|
//@use 'variable' as var;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
#FF41F8
|
||||||
|
#F0060B
|
||||||
|
#F0070C
|
||||||
|
#CC26D5
|
||||||
|
#7702FF
|
||||||
|
|
||||||
|
#35A2EB
|
||||||
|
#B7DDD0
|
||||||
|
#B0D9CB
|
||||||
|
#D9CAAE
|
||||||
|
#9788C7
|
||||||
|
*/
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ export class HomeComponent implements OnInit {
|
|||||||
public errors: Errors = { errors: {} };
|
public errors: Errors = { errors: {} };
|
||||||
public lastJump: Jump = {} as Jump;
|
public lastJump: Jump = {} as Jump;
|
||||||
public destroyRef = inject(DestroyRef);
|
public destroyRef = inject(DestroyRef);
|
||||||
|
public now = new Date();
|
||||||
|
public isJumpDay = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _jumpsService: JumpsService
|
private _jumpsService: JumpsService
|
||||||
@@ -50,6 +52,12 @@ export class HomeComponent implements OnInit {
|
|||||||
this._lastjump$ = this._jumpsService.getLastJump().pipe(takeUntilDestroyed(this.destroyRef));
|
this._lastjump$ = this._jumpsService.getLastJump().pipe(takeUntilDestroyed(this.destroyRef));
|
||||||
this._lastjump = this._lastjump$.subscribe((jump) => {
|
this._lastjump = this._lastjump$.subscribe((jump) => {
|
||||||
this.lastJump = jump;
|
this.lastJump = jump;
|
||||||
|
this.isJumpDay = this._isToday(new Date(this.lastJump.date));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
private _isToday(someDate: Date) {
|
||||||
|
return someDate.getDate() == this.now.getDate() &&
|
||||||
|
someDate.getMonth() == this.now.getMonth() &&
|
||||||
|
someDate.getFullYear() == this.now.getFullYear()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export * from './dashboard/dashboard.component';
|
|||||||
export * from './dropzone/dropzone.component';
|
export * from './dropzone/dropzone.component';
|
||||||
export * from './home/home.component';
|
export * from './home/home.component';
|
||||||
export * from './jump/jump.component';
|
export * from './jump/jump.component';
|
||||||
|
export * from './jumps/jumps.component';
|
||||||
export * from './logbook/logbook.component';
|
export * from './logbook/logbook.component';
|
||||||
export * from './profile/profile.component';
|
export * from './profile/profile.component';
|
||||||
export * from './qcm/qcm.component';
|
export * from './qcm/qcm.component';
|
||||||
|
|||||||
@@ -1,22 +1,46 @@
|
|||||||
<div @flyInOut>
|
|
||||||
<div class="content">
|
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<div class="flex-fill">
|
<div class="flex-fill">
|
||||||
<h1 class="mb-1">{{title}}</h1>
|
<h1 class="mb-1">
|
||||||
<span [hidden]="!lastJump.numero" class="me-2 fs-6">
|
{{title}}
|
||||||
Dernier saut enregistré : <span class="fs-5 mx-1 text-primary">{{ lastJump.numero }}<sup>ème</sup></span> à <span class="fs-5 mx-1 text-primary">{{ lastJump.lieu }}</span> le <span class="fs-5 mx-1 text-primary">{{ lastJump.date | date: 'dd/MM/yyyy' }}</span>
|
<span class="fs-3 text-accent ms-2">{{ jump.categorie }} {{ jump.module }}</span>
|
||||||
|
<span class="fs-3 text-muted ms-2">{{ jump.voile }} {{ jump.taille }}</span>
|
||||||
|
</h1>
|
||||||
|
<span class="me-2 fs-6">
|
||||||
|
Le <span class="fs-5 mx-1 text-primary">{{ jump.date | date: 'dd/MM/yyyy' }}</span>
|
||||||
|
à <span class="fs-5 mx-1 text-primary">{{ jump.lieu }} {{ jump.oaci }}</span>
|
||||||
|
@if (jump.x2data) {
|
||||||
|
depuis <span class="fs-5 mx-1 text-primary">{{ jump.aeronef }} {{ jump.imat }}</span>
|
||||||
|
}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="flex-spacer"></span>
|
<span class="flex-spacer"></span>
|
||||||
|
<div class="align-self-center me-4">
|
||||||
|
<button mat-button [routerLink]="['/jump', prevSlug]" aria-label="Saut précédent" color="accent">
|
||||||
|
<mat-icon fontIcon="navigate_before"></mat-icon> {{ jump.numero - 1}}
|
||||||
|
</button>
|
||||||
|
<div class="vr mx-2 fs-3 align-middle"></div>
|
||||||
|
<span class="mx-2 align-middle">{{ jump.numero }}</span>
|
||||||
|
<div class="vr mx-2 fs-3 align-middle"></div>
|
||||||
|
<button mat-button [routerLink]="['/jump', nextSlug]" aria-label="Saut suivant" color="accent">
|
||||||
|
<mat-icon fontIcon="navigate_next" iconPositionEnd></mat-icon> {{ jump.numero +1}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<div class="align-self-center me-2">
|
<div class="align-self-center me-2">
|
||||||
<button mat-icon-button [matMenuTriggerFor]="menuAeronef" aria-label="Menu Aeronef">
|
<button mat-icon-button [matMenuTriggerFor]="menuJump" aria-label="Menu saut">
|
||||||
<mat-icon fontIcon="more_vert"></mat-icon>
|
<mat-icon fontIcon="more_vert"></mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<mat-menu #menuAeronef="matMenu">
|
<mat-menu #menuJump="matMenu">
|
||||||
@for (menuitem of menuItems.getMenuPanel(); track menuitem) {
|
@if (jump.x2data) {
|
||||||
<button mat-menu-item>
|
<button mat-menu-item>
|
||||||
<mat-icon [fontIcon]="menuitem.icon"></mat-icon>
|
<mat-icon fontIcon="language" color="accent"></mat-icon>
|
||||||
<span>{{ menuitem.name }}</span>
|
<span class="text-accent fw-medium">Obtenir le KML</span>
|
||||||
|
</button>
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
}
|
||||||
|
@for (menuitem of menuItems.getMenuJump(); track menuitem) {
|
||||||
|
<button mat-menu-item>
|
||||||
|
<mat-icon [fontIcon]="menuitem.icon" [color]="menuitem.color"></mat-icon>
|
||||||
|
<span class="text-{{menuitem.color}} fw-medium">{{ menuitem.name }}</span>
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
@@ -24,109 +48,236 @@
|
|||||||
</div>
|
</div>
|
||||||
<mat-divider class="my-3"></mat-divider>
|
<mat-divider class="my-3"></mat-divider>
|
||||||
<mat-card>
|
<mat-card>
|
||||||
<mat-card-header>
|
<mat-card-content>
|
||||||
<mat-card-title>{{ subtitle }}</mat-card-title>
|
|
||||||
</mat-card-header>
|
|
||||||
<mat-card-content class="mt-2">
|
|
||||||
@if(displayCharts) {
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xxl-6 col-xs-12">
|
<div class="col-lg-6 col-md-12">
|
||||||
<app-linearea-chart [headers]="seriesHeader" [names]="seriesName" [values]="seriesRow" [colors]="seriesColor"></app-linearea-chart>
|
<dl class="dl-horizontal">
|
||||||
|
<dt class="text-light-info fw-normal">Aeronef:</dt>
|
||||||
|
<dd>{{ jump.aeronef }} {{ jump.imat }}</dd>
|
||||||
|
<dt class="text-light-info fw-normal">Voile:</dt>
|
||||||
|
<dd>{{ jump.voile }} {{ jump.taille }} ft<sup>2</sup></dd>
|
||||||
|
@if (jump.programme) {
|
||||||
|
<dt class="text-light-info fw-normal">Programme:</dt>
|
||||||
|
<dd>{{ jump.programme }}</dd>
|
||||||
|
}
|
||||||
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xxl-6 col-xs-12">
|
<div class="col-lg-6 col-md-12">
|
||||||
<app-bars-chart [headers]="seriesHeader" [names]="seriesName" [values]="seriesRow" [colors]="seriesColor" [legend]="true"></app-bars-chart>
|
<dl class="dl-horizontal">
|
||||||
|
@if (!jump.x2data) {
|
||||||
|
<dt class="text-light-info fw-normal">Hauteur:</dt>
|
||||||
|
<dd>{{ jump.hauteur }} m</dd>
|
||||||
|
<dt class="text-light-info fw-normal">Déploiement:</dt>
|
||||||
|
<dd>{{ jump.deploiement }} m</dd>
|
||||||
|
}
|
||||||
|
@for (file of jump.files; track file) {
|
||||||
|
<dt class="text-light-info fw-normal">Fichier {{ file.type }}</dt>
|
||||||
|
<dd>{{ file.name }}</dd>
|
||||||
|
}
|
||||||
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
@if (jump.x2data) {
|
||||||
|
<mat-card class="mt-3">
|
||||||
|
<mat-card-content>
|
||||||
|
<div class="row my-3">
|
||||||
|
<div class="col-sm-4 col-xs-12 text-center">
|
||||||
|
<h6>Hauteur</h6>
|
||||||
|
@if (jump.x2data.altitude.exit > 4200) {
|
||||||
|
<mat-icon class="align-middle fs-5 me-2" fontIcon="mood" color="primary"></mat-icon>
|
||||||
|
}
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ jump.x2data.altitude.exit }} m</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 col-xs-12 text-center">
|
||||||
|
<h6 class="d-flex justify-content-center"><mat-icon fontIcon="timer" class="me-1 fs-5"></mat-icon> Durée de la chute</h6>
|
||||||
|
<span class="text-primary fw-medium fs-4">{{ formatDuration(jump.x2data.duration.freeFall) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 col-xs-12 text-center">
|
||||||
|
<h6>Déploiement</h6>
|
||||||
|
@if (jump.x2data.altitude.deployment < 650) {
|
||||||
|
<mat-icon class="align-middle fs-5 me-2" fontIcon="warning" color="raspberry"></mat-icon>
|
||||||
|
<span class="text-raspberry fw-medium fs-5">{{ jump.x2data.altitude.deployment }} m</span>
|
||||||
|
}
|
||||||
|
@else if (jump.x2data.altitude.deployment < 750) {
|
||||||
|
<mat-icon class="align-middle fs-5 me-2" fontIcon="local_florist" color="warn"></mat-icon>
|
||||||
|
<span class="text-warn fw-medium fs-5">{{ jump.x2data.altitude.deployment }} m</span>
|
||||||
|
}
|
||||||
|
@else if (jump.x2data.altitude.deployment > 1000) {
|
||||||
|
<mat-icon class="align-middle fs-5 me-2" fontIcon="mood" color="primary"></mat-icon>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ jump.x2data.altitude.deployment }} m</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mt-4">
|
||||||
|
<div class="{{ jump.accessoires ? 'col-sm-6 ' : '' }}col-xs-12 text-center">
|
||||||
|
<h5 class="d-flex justify-content-center mb-4"><mat-icon fontIcon="people" class="me-2"></mat-icon> Participants ({{ jump.sautants.length + 1 }})</h5>
|
||||||
|
@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>
|
||||||
|
{{ jump.author.username }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
@if (jump.accessoires) {
|
||||||
|
<div class="col-sm-6 col-xs-12 text-center">
|
||||||
|
<h5 class="d-flex justify-content-center mb-4"><mat-icon fontIcon="auto_awesome" class="me-2"></mat-icon> Accessoires</h5>
|
||||||
|
<span class="badge rounded-pill bg-navy-light mb-2 me-1 pe-3 py-1 fw-normal">
|
||||||
|
<mat-icon class="align-middle me-1" fontIcon="auto_awesome"></mat-icon>
|
||||||
|
{{ jump.accessoires }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
<div class="row">
|
</div>
|
||||||
<div class="col-xs-12">
|
</mat-card-content>
|
||||||
<mat-divider class="mt-3 mb-0"></mat-divider>
|
</mat-card>
|
||||||
<table class="table table-striped table-dark table-hover">
|
<mat-card class="mt-3">
|
||||||
<thead>
|
<mat-card-content>
|
||||||
<tr>
|
<div class="row my-3">
|
||||||
<th></th>
|
<div class="col-xs-12 text-center">
|
||||||
<th *ngFor='let name of seriesHeader; let i=index' class="text-end"> {{ name }} </th>
|
<h5 class="d-flex justify-content-center mb-3"><mat-icon fontIcon="speed" class="me-1"></mat-icon> Vitesse en chute</h5>
|
||||||
<th class="text-end">Total</th>
|
</div>
|
||||||
</tr>
|
<div class="col-sm-6 hidden-xs text-center">
|
||||||
</thead>
|
<h6>Verticale</h6>
|
||||||
<tbody>
|
</div>
|
||||||
<tr *ngFor='let values of seriesRow; let i=index'>
|
<div class="col-sm-6 hidden-xs text-center">
|
||||||
<th class="{{seriesColorClass[i]}} text-end"> ● {{ seriesName[i] }} </th>
|
<h6>Horizontale</h6>
|
||||||
<td *ngFor='let value of values; let i=index' class="font-monospace text-end">
|
</div>
|
||||||
<span *ngIf="value; else elseBlock" class="pr-1">{{ value }}</span>
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
<ng-template #elseBlock><span class="text-empty pr-1">{{ value }}</span></ng-template>
|
<h6>Vitesse maximale</h6>
|
||||||
</td>
|
<span class="text-primary fw-medium fs-5">{{ (jump.x2data.speed.freeFall.vertical.max / 1000 * 60 * 60) | number : '1.0-0' }} km/h</span>
|
||||||
<th class="{{seriesColorClass[i]}} font-monospace text-end">{{ seriesRowTotal[i] }}</th>
|
</div>
|
||||||
</tr>
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
</tbody>
|
<h6>Vitesse moyenne</h6>
|
||||||
<tfoot>
|
<span class="text-primary fw-medium fs-5">{{ (jump.x2data.speed.freeFall.vertical.avg / 1000 * 60 * 60) | number : '1.0-0' }} km/h</span>
|
||||||
<tr>
|
</div>
|
||||||
<th class="text-end">Total</th>
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
<th *ngFor='let value of seriesColTotal; let i=index' class="font-monospace text-end">
|
<h6>Vitesse maximale</h6>
|
||||||
<span *ngIf="value; else elseBlock" class="pr-1">{{ value }}</span>
|
<span class="text-primary fw-medium fs-5">{{ (jump.x2data.speed.freeFall.horizontal.max / 1000 * 60 * 60) | number : '1.0-0' }} km/h</span>
|
||||||
<ng-template #elseBlock><span class="text-empty pr-1">{{ value }}</span></ng-template>
|
</div>
|
||||||
</th>
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
<th class="font-monospace text-end">{{ grandTotal }}</th>
|
<h6>Vitesse moyenne</h6>
|
||||||
</tr>
|
<span class="text-primary fw-medium fs-5">{{ (jump.x2data.speed.freeFall.horizontal.avg / 1000 * 60 * 60) | number : '1.0-0' }} km/h</span>
|
||||||
<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 | number : '1.0-1' }}</span>
|
|
||||||
<ng-template #elseBlock><span class="text-empty pr-1">{{ value | number : '1.0-1' }}</span></ng-template>
|
|
||||||
</th>
|
|
||||||
<th class="font-monospace text-end">{{ grandAvg | number : '1.0-1' }}</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th class="text-end">Moyenne <small>3 dernières années</small></th>
|
|
||||||
<th *ngFor='let value of seriesRowAvgLastYears; let i=index' class="font-monospace text-end">
|
|
||||||
<span *ngIf="value; else elseBlock" class="pr-1">{{ value | number : '1.0-1' }}</span>
|
|
||||||
<ng-template #elseBlock><span class="text-empty pr-1">{{ value | number : '1.0-1' }}</span></ng-template>
|
|
||||||
</th>
|
|
||||||
<th class="font-monospace text-end">{{ grandAvgLastYears | number : '1.0-1' }}</th>
|
|
||||||
</tr>
|
|
||||||
</tfoot>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
<mat-card class="mt-3">
|
<mat-card class="mt-3">
|
||||||
<mat-card-header>
|
<mat-card-content>
|
||||||
<mat-card-title>Types de sauts</mat-card-title>
|
<div class="row my-3">
|
||||||
</mat-card-header>
|
<div class="col-xs-12 text-center">
|
||||||
<mat-card-content class="mt-2">
|
<h5 class="d-flex justify-content-center mb-3"><mat-icon fontIcon="speed" class="me-1"></mat-icon> Vitesse sous voile</h5>
|
||||||
@if(displayCharts) {
|
</div>
|
||||||
<div class="row">
|
<div class="col-sm-6 hidden-xs text-center">
|
||||||
<div class="col-xs-12">
|
<h6>Verticale</h6>
|
||||||
<app-line-chart [headers]="seriesTypesHeader" [names]="seriesTypesName" [values]="seriesTypesRowCumulated" [colors]="seriesTypesColor" [legend]="true"></app-line-chart>
|
</div>
|
||||||
|
<div class="col-sm-6 hidden-xs text-center">
|
||||||
|
<h6>Horizontale</h6>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Vitesse maximale</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ (jump.x2data.speed.underCanopy.vertical.max / 1000 * 60 * 60) | number : '1.0-0' }} km/h</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Vitesse moyenne</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ (jump.x2data.speed.underCanopy.vertical.avg / 1000 * 60 * 60) | number : '1.0-0' }} km/h</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Vitesse maximale</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ (jump.x2data.speed.underCanopy.horizontal.max / 1000 * 60 * 60) | number : '1.0-0' }} km/h</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Vitesse moyenne</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ (jump.x2data.speed.underCanopy.horizontal.avg / 1000 * 60 * 60) | number : '1.0-0' }} km/h</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<mat-divider class="mt-2 mb-3"></mat-divider>
|
|
||||||
<div class="row">
|
|
||||||
@for (item of getCategories(); track $index) {
|
|
||||||
<div class="col-lg-2 col-sm-4 col-xs-6">
|
|
||||||
<app-circle-chart [headers]="seriesHeader" [names]="seriesName" [values]="[item.count, (lastJump.numero-item.count)]" [color]="$index" [label]="item.categorie"></app-circle-chart>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
@for (item of getModules(); track $index) {
|
|
||||||
<div class="col-lg-2 col-sm-4 col-xs-6">
|
|
||||||
<app-circle-chart [headers]="seriesHeader" [names]="seriesName" [values]="[item.count, (lastJump.numero-item.count)]" [color]="getModuleColor($index)" [label]="item.module"></app-circle-chart>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<mat-divider class="my-3"></mat-divider>
|
|
||||||
<!--
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-xxl-6 col-xs-12">
|
|
||||||
<app-line-chart [headers]="seriesTypesHeader" [names]="seriesTypesName" [values]="seriesTypesRow" [colors]="seriesTypesColor" [legend]="true"></app-line-chart>
|
|
||||||
</div>
|
|
||||||
<div class="col-xxl-6 col-xs-12">
|
|
||||||
<app-line-chart [headers]="seriesTypesHeader" [names]="seriesTypesName" [values]="seriesTypesRowCumulated" [colors]="seriesTypesColor" [legend]="true"></app-line-chart>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
-->
|
|
||||||
}
|
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
<mat-card class="mt-3">
|
||||||
|
<mat-card-content>
|
||||||
|
<div class="row my-3">
|
||||||
|
<div class="col-xs-12 text-center">
|
||||||
|
<h5 class="d-flex justify-content-center mb-3"><mat-icon fontIcon="square_foot" class="me-1"></mat-icon> Finesse</h5>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 hidden-xs text-center">
|
||||||
|
<h6>En chute</h6>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 hidden-xs text-center">
|
||||||
|
<h6>Sous voile</h6>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Finesse Max</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ jump.x2data.glideRatio.freeFall.max | number : '1.2-2' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Finesse Moyenne</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ jump.x2data.glideRatio.freeFall.avg | number : '1.2-2' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Finesse Max</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ jump.x2data.glideRatio.underCanopy.max | number : '1.2-2' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Finesse Moyenne</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ jump.x2data.glideRatio.underCanopy.avg | number : '1.2-2' }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
<mat-card class="mt-3">
|
||||||
|
<mat-card-content>
|
||||||
|
<div class="row my-3">
|
||||||
|
<div class="col-xs-12 text-center">
|
||||||
|
<h5 class="d-flex justify-content-center mb-3"><mat-icon fontIcon="straighten" class="me-1"></mat-icon> Distance</h5>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Distance au largage</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ jump.x2data.distance.exitFromLandingZone| number : '1.0-0' }} m</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Durée sous voile</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ formatDuration(jump.x2data.duration.underCanopy) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Distance totale</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ jump.x2data.distance.totalFlying | number : '1.0-0' }} m</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Distance horizontale</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ jump.x2data.distance.totalHorizontal | number : '1.0-0' }} m</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
}
|
||||||
|
@else {
|
||||||
|
<mat-card class="mt-3">
|
||||||
|
<mat-card-content>
|
||||||
|
<div class="row my-3">
|
||||||
|
<div class="col-xs-12 text-center">
|
||||||
|
<h5 class="d-flex justify-content-center mb-4"><mat-icon fontIcon="people" class="me-1"></mat-icon> Participants ({{ jump.sautants.length + 1 }})</h5>
|
||||||
|
@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>
|
||||||
|
{{ jump.author.username }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
<mat-card class="mt-3">
|
||||||
|
<mat-card-content>
|
||||||
|
<div class="d-flex justify-content-center my-3 fs-5"><mat-icon fontIcon="satellite_alt" class="me-2"></mat-icon> Aucune donnée GPS</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
}
|
||||||
@@ -6,10 +6,12 @@ describe('JumpComponent', () => {
|
|||||||
let component: JumpComponent;
|
let component: JumpComponent;
|
||||||
let fixture: ComponentFixture<JumpComponent>;
|
let fixture: ComponentFixture<JumpComponent>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [JumpComponent]
|
imports: [JumpComponent]
|
||||||
});
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(JumpComponent);
|
fixture = TestBed.createComponent(JumpComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|||||||
@@ -1,248 +1,71 @@
|
|||||||
import { trigger, state, style, animate, transition } from '@angular/animations';
|
|
||||||
import { Component, DestroyRef, inject, OnInit, OnDestroy } from '@angular/core';
|
import { Component, DestroyRef, inject, OnInit, OnDestroy } from '@angular/core';
|
||||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { DatePipe, DecimalPipe } from '@angular/common';
|
||||||
import { CommonModule } from '@angular/common';
|
import { ActivatedRoute, RouterLink } from '@angular/router';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import { MatCardModule } from '@angular/material/card';
|
||||||
import { MatDividerModule } from '@angular/material/divider';
|
import { MatDividerModule } from '@angular/material/divider';
|
||||||
import { MatExpansionModule } from '@angular/material/expansion';
|
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
|
|
||||||
import { Observable, Subscription } from 'rxjs';
|
import { Observable, Subscription } from 'rxjs';
|
||||||
|
|
||||||
import { MenuItems } from 'src/app/components/shared';
|
import { ListErrorsComponent, MenuItems } from 'src/app/components/shared';
|
||||||
import { BarsChartComponent, CircleChartComponent, LineChartComponent, LineAreaChartComponent } from 'src/app/components/shared/helpers-chart';
|
import { Errors, Jump, JumpPageData } from 'src/app/core/models';
|
||||||
import { UtilitiesService } from 'src/app/core/services';
|
|
||||||
import { Jump, JumpByCategorie, JumpByDate, JumpByDateByModule, JumpByModule, JumpsPageData, JumpYears } from 'src/app/core/models';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-jump',
|
selector: 'app-jump',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
DatePipe, DecimalPipe, RouterLink,
|
||||||
MatButtonModule, MatCardModule, MatDividerModule,
|
MatButtonModule, MatCardModule,
|
||||||
MatExpansionModule, MatIconModule, MatMenuModule,
|
MatDividerModule, MatIconModule, MatMenuModule,
|
||||||
BarsChartComponent, CircleChartComponent, LineChartComponent, LineAreaChartComponent
|
ListErrorsComponent
|
||||||
],
|
],
|
||||||
templateUrl: './jump.component.html',
|
templateUrl: './jump.component.html',
|
||||||
styleUrl: './jump.component.scss',
|
styleUrl: './jump.component.scss'
|
||||||
animations: [
|
|
||||||
trigger('flyInOut', [
|
|
||||||
state('in', style({ transform: 'translateX(0)' })),
|
|
||||||
transition('void => *', [
|
|
||||||
style({ transform: 'translateX(-100%)' }),
|
|
||||||
animate(200)
|
|
||||||
]),
|
|
||||||
transition('* => void', [
|
|
||||||
style({ transform: 'translateX(100%)' }),
|
|
||||||
animate(200)
|
|
||||||
])
|
|
||||||
])
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
export class JumpComponent implements OnInit, OnDestroy {
|
export class JumpComponent implements OnInit, OnDestroy {
|
||||||
private _data: Subscription = new Subscription();
|
private _data: Subscription = new Subscription();
|
||||||
private _jumpsByCategorie: Array<JumpByCategorie> = [];
|
public title: string = '';
|
||||||
private _jumpsByModule: Array<JumpByModule> = [];
|
public errors: Errors = { errors: {} };
|
||||||
private _jumpsByDate: Array<JumpByDate> = [];
|
|
||||||
public lastJump: Jump = {} as Jump;
|
|
||||||
public title: string = 'Sauts';
|
|
||||||
public subtitle: string = 'Nombre total de sauts par mois';
|
|
||||||
public displayCharts = false;
|
|
||||||
public destroyRef = inject(DestroyRef);
|
public destroyRef = inject(DestroyRef);
|
||||||
public min = 0;
|
public jump: Jump = {} as Jump;
|
||||||
public max = 0;
|
public prevSlug: string = '';
|
||||||
public grandAvg = 0;
|
public nextSlug: string = '';
|
||||||
public grandAvgLastYears = 0;
|
|
||||||
public grandTotal = 0;
|
|
||||||
public seriesHeader: string[] = [];
|
|
||||||
public seriesName: string[] = [];
|
|
||||||
public seriesRow: Array<Array<number>> = [];
|
|
||||||
public seriesColor: {
|
|
||||||
backgroundColor: string[],
|
|
||||||
borderColor: string[]
|
|
||||||
} = {
|
|
||||||
backgroundColor: this._utilitiesService.getSeriesColors(0.8, 'all'),
|
|
||||||
borderColor: this._utilitiesService.getSeriesColors(1, 'all')
|
|
||||||
};
|
|
||||||
public seriesTypesHeader: string[] = [];
|
|
||||||
public seriesTypesName: string[] = [];
|
|
||||||
public seriesTypesRow: Array<Array<number>> = [];
|
|
||||||
public seriesTypesRowCumulated: Array<Array<number>> = [];
|
|
||||||
public seriesTypesColor: {
|
|
||||||
backgroundColor: string[],
|
|
||||||
borderColor: string[]
|
|
||||||
} = {
|
|
||||||
backgroundColor: this._utilitiesService.getSeriesColors(0.8, 'pastels'),
|
|
||||||
borderColor: this._utilitiesService.getSeriesColors(1, 'pastels')
|
|
||||||
};
|
|
||||||
public seriesColorClass: string[] = this._utilitiesService.getChartColors();
|
|
||||||
public seriesRowTotal: number[] = [];
|
|
||||||
public seriesRowAvg: number[] = [];
|
|
||||||
public seriesRowAvgLastYears: number[] = [];
|
|
||||||
public seriesColTotal: number[] = [];
|
|
||||||
public seriesColTotalClosed: number[] = [];
|
|
||||||
public seriesColTotalLastYears: number[] = [];
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private _utilitiesService: UtilitiesService,
|
|
||||||
public menuItems: MenuItems
|
public menuItems: MenuItems
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
const data$: Observable<{ jumpsPageData: JumpsPageData }> = this.route.data as Observable<{ jumpsPageData: JumpsPageData }>;
|
const data$: Observable<{ pageData: JumpPageData }> = this.route.data as Observable<{ pageData: JumpPageData }>;
|
||||||
this._data = data$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data: { jumpsPageData: JumpsPageData }) => {
|
this._data = data$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data: { pageData: JumpPageData }) => {
|
||||||
const pageData: JumpsPageData = data.jumpsPageData;
|
this.jump = data.pageData.jump;
|
||||||
this.lastJump = pageData.lastjump;
|
this.prevSlug = data.pageData.prevJump?.slug;
|
||||||
const currentYear: number = new Date().getFullYear();
|
this.nextSlug = data.pageData.nextJump?.slug;
|
||||||
const types: Array<string> = ['FF', 'Solo', 'VR', 'Wingsuit'];
|
this.title = `Saut n° ${this.jump.numero} `;
|
||||||
const verticals: Array<string> = ['Chutas', 'Head Up', 'Head Down'];
|
|
||||||
const others: Array<string> = ['Track', 'Trace'];
|
|
||||||
const modules: Array<string> = [...verticals, ...others];
|
|
||||||
this.min = pageData.jumpsByYears[0].year;
|
|
||||||
this.max = pageData.jumpsByYears[(pageData.jumpsByYears.length-1)].year;
|
|
||||||
|
|
||||||
this.seriesHeader = this._utilitiesService.getMonthsList();
|
|
||||||
const values: Array<number> = this.seriesHeader.map(() => 0);
|
|
||||||
this.seriesColTotal = [...values];
|
|
||||||
this.seriesColTotalClosed = [...values];
|
|
||||||
this.seriesColTotalLastYears = [...values];
|
|
||||||
this.seriesName = pageData.jumpsByYears.map((row: JumpYears) => {
|
|
||||||
this.seriesRow.push([...values]);
|
|
||||||
return row.year.toString();
|
|
||||||
});
|
|
||||||
|
|
||||||
this._jumpsByDate = pageData.jumpsByDate.map((row: JumpByDate) => {
|
|
||||||
this.seriesRow[(row.year-this.min)][(row.month-1)] = row.count;
|
|
||||||
this.seriesColTotal[(row.month-1)] += row.count;
|
|
||||||
if (row.year < currentYear) {
|
|
||||||
this.seriesColTotalClosed[(row.month-1)] += row.count;
|
|
||||||
}
|
|
||||||
if (row.year >= (currentYear-3) && row.year < currentYear) {
|
|
||||||
this.seriesColTotalLastYears[(row.month-1)] += row.count;
|
|
||||||
}
|
|
||||||
return row;
|
|
||||||
});
|
|
||||||
this.seriesRow.forEach((row: number[]) => {
|
|
||||||
const total = row.reduce((partialSum, a) => partialSum + a, 0);
|
|
||||||
this.seriesRowTotal.push(total);
|
|
||||||
});
|
|
||||||
this.seriesColTotalClosed.forEach((row: number) => {
|
|
||||||
const value: number = (row/(this.seriesName.length-2)); // -2 pour ne pas compter la première année
|
|
||||||
this.seriesRowAvg.push(parseInt(value.toFixed(0)));
|
|
||||||
});
|
|
||||||
this.seriesColTotalLastYears.forEach((row: number) => {
|
|
||||||
const value: number = (row/3); // Les 3 dernières années
|
|
||||||
this.seriesRowAvgLastYears.push(parseInt(value.toFixed(0)));
|
|
||||||
});
|
|
||||||
this.grandAvg = this.seriesRowAvg.reduce((partialSum, accumulated) => partialSum + accumulated, 0);
|
|
||||||
this.grandAvgLastYears = this.seriesRowAvgLastYears.reduce((partialSum, accumulated) => partialSum + accumulated, 0);
|
|
||||||
this.grandTotal = this.seriesColTotal.reduce((partialSum, accumulated) => partialSum + accumulated, 0);
|
|
||||||
|
|
||||||
pageData.jumpsByCategory.forEach((row: JumpByCategorie) => {
|
|
||||||
if (types.indexOf(row.categorie) !== -1) {
|
|
||||||
this._jumpsByCategorie.push(row);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//const focus: Array<string> = ['FF', 'Solo']; // ['FF']
|
|
||||||
let verticalCount:number = 0;
|
|
||||||
let otherCount:number = 0;
|
|
||||||
pageData.jumpsByModule.forEach((row: JumpByModule) => {
|
|
||||||
//if (focus.indexOf(row.categorie) !== -1 && modules.indexOf(row.module) !== -1) {
|
|
||||||
if (modules.indexOf(row.module) !== -1) {
|
|
||||||
if (verticals.indexOf(row.module) !== -1) {
|
|
||||||
verticalCount += row.count;
|
|
||||||
} else {
|
|
||||||
otherCount += row.count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (verticalCount > 0) {
|
|
||||||
const row:JumpByModule = {
|
|
||||||
categorie: 'FF',
|
|
||||||
module: 'Vertical',
|
|
||||||
count: verticalCount
|
|
||||||
}
|
|
||||||
this._jumpsByModule.push(row);
|
|
||||||
}
|
|
||||||
if (otherCount > 0) {
|
|
||||||
const row:JumpByModule = {
|
|
||||||
categorie: 'FF',
|
|
||||||
module: 'Track/Trace',
|
|
||||||
count: otherCount
|
|
||||||
}
|
|
||||||
this._jumpsByModule.push(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let year = 0; year < pageData.jumpsByYears.length; year++) {
|
|
||||||
for (let index = 0; index < 12; index++) {
|
|
||||||
const month: string = ((index+1) < 10) ? `0${(index+1)}` : `${(index+1)}`;
|
|
||||||
this.seriesTypesHeader.push(`${month}-${pageData.jumpsByYears[year].year}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const emptyValues: Array<number> = this.seriesTypesHeader.map(() => 0);
|
|
||||||
this.seriesTypesName = types;
|
|
||||||
this.seriesTypesName.forEach(() => {
|
|
||||||
this.seriesTypesRow.push([...emptyValues]);
|
|
||||||
});
|
|
||||||
pageData.jumpsByDateByModule.forEach((row: JumpByDateByModule) => {
|
|
||||||
const indexOf: number = this.seriesTypesName.indexOf(row.categorie);
|
|
||||||
if (indexOf !== -1) {
|
|
||||||
this.seriesTypesRow[indexOf][(((row.year-this.min)*12)+row.month-1)] += row.count;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.seriesTypesRowCumulated = this.seriesTypesRow.map((row: Array<number>) => {
|
|
||||||
let accumulated: number = 0;
|
|
||||||
return row.map((value: number) => {
|
|
||||||
accumulated += value;
|
|
||||||
return accumulated;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
this.seriesTypesHeader = this.seriesTypesHeader.slice((pageData.jumpsByDateByModule[0].month+1), -(pageData.jumpsByDateByModule[(pageData.jumpsByDateByModule.length-1)].month));
|
|
||||||
this.seriesTypesRow = this.seriesTypesRow.map((row: Array<number>) => {
|
|
||||||
return row.slice((pageData.jumpsByDateByModule[0].month+1), -(pageData.jumpsByDateByModule[(pageData.jumpsByDateByModule.length-1)].month));
|
|
||||||
});
|
|
||||||
this.seriesTypesRowCumulated = this.seriesTypesRowCumulated.map((row: Array<number>) => {
|
|
||||||
return row.slice((pageData.jumpsByDateByModule[0].month+1), -(pageData.jumpsByDateByModule[(pageData.jumpsByDateByModule.length-1)].month));
|
|
||||||
});
|
});
|
||||||
/*
|
/*
|
||||||
console.log('this.min', this.min);
|
const data$: Observable<Jump> = this.route.data as Observable<Jump>;
|
||||||
console.log('this.max', this.max);
|
this._data = data$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data: Jump) => {
|
||||||
console.log('this.lastJump', this.lastJump);
|
this.jump = data;
|
||||||
console.log('this.seriesHeader', this.seriesHeader);
|
console.log('jump : ', this.jump);
|
||||||
console.log('this.seriesName', this.seriesName);
|
|
||||||
console.log('this.seriesRow', this.seriesRow);
|
|
||||||
console.log('this.seriesRowTotal', this.seriesRowTotal);
|
|
||||||
console.log('this.seriesRowAvg', this.seriesRowAvg);
|
|
||||||
console.log('this.seriesRowAvgLastYears', this.seriesRowAvgLastYears);
|
|
||||||
console.log('this._jumpsByCategorie', this._jumpsByCategorie);
|
|
||||||
console.log('this._jumpsByModule', this._jumpsByModule);
|
|
||||||
console.log('this.seriesTypesHeader', this.seriesTypesHeader);
|
|
||||||
console.log('this.seriesTypesName', this.seriesTypesName);
|
|
||||||
console.log('this.seriesTypesRow', this.seriesTypesRow);
|
|
||||||
console.log('this.seriesTypesRowCumulated', this.seriesTypesRowCumulated);
|
|
||||||
*/
|
|
||||||
this.displayCharts = true;
|
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this._data.unsubscribe();
|
this._data.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCategories(): Array<JumpByCategorie> {
|
formatDuration(duration: number): string {
|
||||||
return this._jumpsByCategorie;
|
const start = new Date(0);
|
||||||
|
start.setSeconds(duration);
|
||||||
|
return start.toISOString().substring(14, 19);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getModules(): Array<JumpByModule> {
|
private _resetErrors(): void {
|
||||||
return this._jumpsByModule;
|
this.errors = { errors: {} };
|
||||||
}
|
|
||||||
|
|
||||||
public getModuleColor(index: number): number {
|
|
||||||
return (this._jumpsByCategorie.length + index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
<div @flyInOut>
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="flex-fill">
|
||||||
|
<h1 class="mb-1">{{title}}</h1>
|
||||||
|
<span [hidden]="!lastJump.numero" class="me-2 fs-6">
|
||||||
|
Dernier saut enregistré : <span class="fs-5 mx-1 text-primary">{{ lastJump.numero }}<sup>ème</sup></span> à <span class="fs-5 mx-1 text-primary">{{ lastJump.lieu }}</span> le <span class="fs-5 mx-1 text-primary">{{ lastJump.date | date: 'dd/MM/yyyy' }}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span class="flex-spacer"></span>
|
||||||
|
<div class="align-self-center me-2">
|
||||||
|
<button mat-icon-button [matMenuTriggerFor]="menuJumps" aria-label="Menu sauts">
|
||||||
|
<mat-icon fontIcon="more_vert"></mat-icon>
|
||||||
|
</button>
|
||||||
|
<mat-menu #menuJumps="matMenu">
|
||||||
|
@for (menuitem of menuItems.getMenuPanel(); track menuitem) {
|
||||||
|
<button mat-menu-item>
|
||||||
|
<mat-icon [fontIcon]="menuitem.icon"></mat-icon>
|
||||||
|
<span>{{ menuitem.name }}</span>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</mat-menu>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<mat-divider class="my-3"></mat-divider>
|
||||||
|
<mat-card>
|
||||||
|
<mat-card-header>
|
||||||
|
<mat-card-title>{{ subtitle }}</mat-card-title>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content class="mt-2">
|
||||||
|
@if(displayCharts) {
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xxl-6 col-xs-12">
|
||||||
|
<app-linearea-chart [headers]="seriesHeader" [names]="seriesName" [values]="seriesRow" [colors]="seriesColor"></app-linearea-chart>
|
||||||
|
</div>
|
||||||
|
<div class="col-xxl-6 col-xs-12">
|
||||||
|
<app-bars-chart [headers]="seriesHeader" [names]="seriesName" [values]="seriesRow" [colors]="seriesColor" [legend]="true"></app-bars-chart>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<mat-divider class="mt-3 mb-0"></mat-divider>
|
||||||
|
<table class="table table-striped table-dark table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th *ngFor='let name of seriesHeader; let i=index' class="text-end"> {{ name }} </th>
|
||||||
|
<th class="text-end">Total</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor='let values of seriesRow; let i=index'>
|
||||||
|
<th class="{{seriesColorClass[i]}} text-end"> ● {{ seriesName[i] }} </th>
|
||||||
|
<td *ngFor='let value of values; 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>
|
||||||
|
</td>
|
||||||
|
<th class="{{seriesColorClass[i]}} font-monospace text-end">{{ seriesRowTotal[i] }}</th>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<th class="text-end">Total</th>
|
||||||
|
<th *ngFor='let value of seriesColTotal; 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">{{ grandTotal }}</th>
|
||||||
|
</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 | number : '1.0-1' }}</span>
|
||||||
|
<ng-template #elseBlock><span class="text-empty pr-1">{{ value | number : '1.0-1' }}</span></ng-template>
|
||||||
|
</th>
|
||||||
|
<th class="font-monospace text-end">{{ grandAvg | number : '1.0-1' }}</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="text-end">Moyenne <small>3 dernières années</small></th>
|
||||||
|
<th *ngFor='let value of seriesRowAvgLastYears; let i=index' class="font-monospace text-end">
|
||||||
|
<span *ngIf="value; else elseBlock" class="pr-1">{{ value | number : '1.0-1' }}</span>
|
||||||
|
<ng-template #elseBlock><span class="text-empty pr-1">{{ value | number : '1.0-1' }}</span></ng-template>
|
||||||
|
</th>
|
||||||
|
<th class="font-monospace text-end">{{ grandAvgLastYears | number : '1.0-1' }}</th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
<mat-card class="mt-3">
|
||||||
|
<mat-card-header>
|
||||||
|
<mat-card-title>Types de sauts</mat-card-title>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content class="mt-2">
|
||||||
|
@if(displayCharts) {
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<app-line-chart [headers]="seriesTypesHeader" [names]="seriesTypesName" [values]="seriesTypesRowCumulated" [colors]="seriesTypesColor" [legend]="true"></app-line-chart>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<mat-divider class="mt-2 mb-3"></mat-divider>
|
||||||
|
<div class="row">
|
||||||
|
@for (item of getCategories(); track $index) {
|
||||||
|
<div class="col-lg-2 col-sm-4 col-xs-6">
|
||||||
|
<app-circle-chart [headers]="seriesHeader" [names]="seriesName" [values]="[item.count, (lastJump.numero-item.count)]" [color]="$index" [label]="item.categorie"></app-circle-chart>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@for (item of getModules(); track $index) {
|
||||||
|
<div class="col-lg-2 col-sm-4 col-xs-6">
|
||||||
|
<app-circle-chart [headers]="seriesHeader" [names]="seriesName" [values]="[item.count, (lastJump.numero-item.count)]" [color]="getModuleColor($index)" [label]="item.module"></app-circle-chart>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<mat-divider class="my-3"></mat-divider>
|
||||||
|
<!--
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xxl-6 col-xs-12">
|
||||||
|
<app-line-chart [headers]="seriesTypesHeader" [names]="seriesTypesName" [values]="seriesTypesRow" [colors]="seriesTypesColor" [legend]="true"></app-line-chart>
|
||||||
|
</div>
|
||||||
|
<div class="col-xxl-6 col-xs-12">
|
||||||
|
<app-line-chart [headers]="seriesTypesHeader" [names]="seriesTypesName" [values]="seriesTypesRowCumulated" [colors]="seriesTypesColor" [legend]="true"></app-line-chart>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
}
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { JumpsComponent } from './jumps.component';
|
||||||
|
|
||||||
|
describe('JumpsComponent', () => {
|
||||||
|
let component: JumpsComponent;
|
||||||
|
let fixture: ComponentFixture<JumpsComponent>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [JumpsComponent]
|
||||||
|
});
|
||||||
|
fixture = TestBed.createComponent(JumpsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,249 @@
|
|||||||
|
import { trigger, state, style, animate, transition } from '@angular/animations';
|
||||||
|
import { Component, DestroyRef, inject, OnInit, OnDestroy } from '@angular/core';
|
||||||
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatCardModule } from '@angular/material/card';
|
||||||
|
import { MatDividerModule } from '@angular/material/divider';
|
||||||
|
import { MatExpansionModule } from '@angular/material/expansion';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
|
|
||||||
|
import { Observable, Subscription } from 'rxjs';
|
||||||
|
|
||||||
|
import { MenuItems } from 'src/app/components/shared';
|
||||||
|
import { BarsChartComponent, CircleChartComponent, LineChartComponent, LineAreaChartComponent } from 'src/app/components/shared/helpers-chart';
|
||||||
|
import { UtilitiesService } from 'src/app/core/services';
|
||||||
|
import { Jump, JumpByCategorie, JumpByDate, JumpByDateByModule, JumpByModule, JumpsPageData, JumpYears } from 'src/app/core/models';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-jumps',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
MatButtonModule, MatCardModule, MatDividerModule,
|
||||||
|
MatExpansionModule, MatIconModule, MatMenuModule,
|
||||||
|
BarsChartComponent, CircleChartComponent, LineChartComponent, LineAreaChartComponent
|
||||||
|
],
|
||||||
|
templateUrl: './jumps.component.html',
|
||||||
|
styleUrl: './jumps.component.scss',
|
||||||
|
animations: [
|
||||||
|
trigger('flyInOut', [
|
||||||
|
state('in', style({ transform: 'translateX(0)' })),
|
||||||
|
transition('void => *', [
|
||||||
|
style({ transform: 'translateX(-100%)' }),
|
||||||
|
animate(200)
|
||||||
|
]),
|
||||||
|
transition('* => void', [
|
||||||
|
style({ transform: 'translateX(100%)' }),
|
||||||
|
animate(200)
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class JumpsComponent implements OnInit, OnDestroy {
|
||||||
|
private _data: Subscription = new Subscription();
|
||||||
|
private _jumpsByCategorie: Array<JumpByCategorie> = [];
|
||||||
|
private _jumpsByModule: Array<JumpByModule> = [];
|
||||||
|
private _jumpsByDate: Array<JumpByDate> = [];
|
||||||
|
public lastJump: Jump = {} as Jump;
|
||||||
|
public title: string = 'Sauts';
|
||||||
|
public subtitle: string = 'Nombre total de sauts par mois';
|
||||||
|
public displayCharts = false;
|
||||||
|
public destroyRef = inject(DestroyRef);
|
||||||
|
public min = 0;
|
||||||
|
public max = 0;
|
||||||
|
public grandAvg = 0;
|
||||||
|
public grandAvgLastYears = 0;
|
||||||
|
public grandTotal = 0;
|
||||||
|
public seriesHeader: string[] = [];
|
||||||
|
public seriesName: string[] = [];
|
||||||
|
public seriesRow: Array<Array<number>> = [];
|
||||||
|
public seriesColor: {
|
||||||
|
backgroundColor: string[],
|
||||||
|
borderColor: string[]
|
||||||
|
} = {
|
||||||
|
backgroundColor: this._utilitiesService.getSeriesColors(0.8, 'all'),
|
||||||
|
borderColor: this._utilitiesService.getSeriesColors(1, 'all')
|
||||||
|
};
|
||||||
|
public seriesTypesHeader: string[] = [];
|
||||||
|
public seriesTypesName: string[] = [];
|
||||||
|
public seriesTypesRow: Array<Array<number>> = [];
|
||||||
|
public seriesTypesRowCumulated: Array<Array<number>> = [];
|
||||||
|
public seriesTypesColor: {
|
||||||
|
backgroundColor: string[],
|
||||||
|
borderColor: string[]
|
||||||
|
} = {
|
||||||
|
backgroundColor: this._utilitiesService.getSeriesColors(0.8, 'pastels'),
|
||||||
|
borderColor: this._utilitiesService.getSeriesColors(1, 'pastels')
|
||||||
|
};
|
||||||
|
public seriesColorClass: string[] = this._utilitiesService.getChartColors();
|
||||||
|
public seriesRowTotal: number[] = [];
|
||||||
|
public seriesRowAvg: number[] = [];
|
||||||
|
public seriesRowAvgLastYears: number[] = [];
|
||||||
|
public seriesColTotal: number[] = [];
|
||||||
|
public seriesColTotalClosed: number[] = [];
|
||||||
|
public seriesColTotalLastYears: number[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private _utilitiesService: UtilitiesService,
|
||||||
|
public menuItems: MenuItems
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const data$: Observable<{ pageData: JumpsPageData }> = this.route.data as Observable<{ pageData: JumpsPageData }>;
|
||||||
|
this._data = data$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data: { pageData: JumpsPageData }) => {
|
||||||
|
const pageData: JumpsPageData = data.pageData;
|
||||||
|
this.lastJump = pageData.lastjump;
|
||||||
|
const currentYear: number = new Date().getFullYear();
|
||||||
|
const types: Array<string> = ['FF', 'Solo', 'VR', 'Wingsuit'];
|
||||||
|
const verticals: Array<string> = ['Chutas', 'Head Up', 'Head Down'];
|
||||||
|
const others: Array<string> = ['Track', 'Trace'];
|
||||||
|
const modules: Array<string> = [...verticals, ...others];
|
||||||
|
const minoration = 2; // -2 pour ne pas compter la première année
|
||||||
|
this.min = pageData.jumpsByYears[0].year;
|
||||||
|
this.max = pageData.jumpsByYears[(pageData.jumpsByYears.length-1)].year;
|
||||||
|
|
||||||
|
this.seriesHeader = this._utilitiesService.getMonthsList();
|
||||||
|
const values: Array<number> = this.seriesHeader.map(() => 0);
|
||||||
|
this.seriesColTotal = [...values];
|
||||||
|
this.seriesColTotalClosed = [...values];
|
||||||
|
this.seriesColTotalLastYears = [...values];
|
||||||
|
this.seriesName = pageData.jumpsByYears.map((row: JumpYears) => {
|
||||||
|
this.seriesRow.push([...values]);
|
||||||
|
return row.year.toString();
|
||||||
|
});
|
||||||
|
|
||||||
|
this._jumpsByDate = pageData.jumpsByDate.map((row: JumpByDate) => {
|
||||||
|
this.seriesRow[(row.year-this.min)][(row.month-1)] = row.count;
|
||||||
|
this.seriesColTotal[(row.month-1)] += row.count;
|
||||||
|
if (row.year < currentYear) {
|
||||||
|
this.seriesColTotalClosed[(row.month-1)] += row.count;
|
||||||
|
}
|
||||||
|
if (row.year >= (currentYear-3) && row.year < currentYear) {
|
||||||
|
this.seriesColTotalLastYears[(row.month-1)] += row.count;
|
||||||
|
}
|
||||||
|
return row;
|
||||||
|
});
|
||||||
|
this.seriesRow.forEach((row: number[]) => {
|
||||||
|
const total = row.reduce((partialSum, a) => partialSum + a, 0);
|
||||||
|
this.seriesRowTotal.push(total);
|
||||||
|
});
|
||||||
|
this.seriesColTotalClosed.forEach((row: number) => {
|
||||||
|
const value: number = (row/(this.seriesName.length-minoration));
|
||||||
|
this.seriesRowAvg.push(parseInt(value.toFixed(0)));
|
||||||
|
});
|
||||||
|
this.seriesColTotalLastYears.forEach((row: number) => {
|
||||||
|
const value: number = (row/3); // Les 3 dernières années
|
||||||
|
this.seriesRowAvgLastYears.push(parseInt(value.toFixed(0)));
|
||||||
|
});
|
||||||
|
this.grandAvg = this.seriesRowAvg.reduce((partialSum, accumulated) => partialSum + accumulated, 0);
|
||||||
|
this.grandAvgLastYears = this.seriesRowAvgLastYears.reduce((partialSum, accumulated) => partialSum + accumulated, 0);
|
||||||
|
this.grandTotal = this.seriesColTotal.reduce((partialSum, accumulated) => partialSum + accumulated, 0);
|
||||||
|
|
||||||
|
pageData.jumpsByCategory.forEach((row: JumpByCategorie) => {
|
||||||
|
if (types.indexOf(row.categorie) !== -1) {
|
||||||
|
this._jumpsByCategorie.push(row);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//const focus: Array<string> = ['FF', 'Solo']; // ['FF']
|
||||||
|
let verticalCount:number = 0;
|
||||||
|
let otherCount:number = 0;
|
||||||
|
pageData.jumpsByModule.forEach((row: JumpByModule) => {
|
||||||
|
//if (focus.indexOf(row.categorie) !== -1 && modules.indexOf(row.module) !== -1) {
|
||||||
|
if (modules.indexOf(row.module) !== -1) {
|
||||||
|
if (verticals.indexOf(row.module) !== -1) {
|
||||||
|
verticalCount += row.count;
|
||||||
|
} else {
|
||||||
|
otherCount += row.count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (verticalCount > 0) {
|
||||||
|
const row:JumpByModule = {
|
||||||
|
categorie: 'FF',
|
||||||
|
module: 'Vertical',
|
||||||
|
count: verticalCount
|
||||||
|
}
|
||||||
|
this._jumpsByModule.push(row);
|
||||||
|
}
|
||||||
|
if (otherCount > 0) {
|
||||||
|
const row:JumpByModule = {
|
||||||
|
categorie: 'FF',
|
||||||
|
module: 'Track/Trace',
|
||||||
|
count: otherCount
|
||||||
|
}
|
||||||
|
this._jumpsByModule.push(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let year = 0; year < pageData.jumpsByYears.length; year++) {
|
||||||
|
for (let index = 0; index < 12; index++) {
|
||||||
|
const month: string = ((index+1) < 10) ? `0${(index+1)}` : `${(index+1)}`;
|
||||||
|
this.seriesTypesHeader.push(`${month}-${pageData.jumpsByYears[year].year}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const emptyValues: Array<number> = this.seriesTypesHeader.map(() => 0);
|
||||||
|
this.seriesTypesName = types;
|
||||||
|
this.seriesTypesName.forEach(() => {
|
||||||
|
this.seriesTypesRow.push([...emptyValues]);
|
||||||
|
});
|
||||||
|
pageData.jumpsByDateByModule.forEach((row: JumpByDateByModule) => {
|
||||||
|
const indexOf: number = this.seriesTypesName.indexOf(row.categorie);
|
||||||
|
if (indexOf !== -1) {
|
||||||
|
this.seriesTypesRow[indexOf][(((row.year-this.min)*12)+row.month-1)] += row.count;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.seriesTypesRowCumulated = this.seriesTypesRow.map((row: Array<number>) => {
|
||||||
|
let accumulated: number = 0;
|
||||||
|
return row.map((value: number) => {
|
||||||
|
accumulated += value;
|
||||||
|
return accumulated;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.seriesTypesHeader = this.seriesTypesHeader.slice((pageData.jumpsByDateByModule[0].month+1), -(pageData.jumpsByDateByModule[(pageData.jumpsByDateByModule.length-1)].month));
|
||||||
|
this.seriesTypesRow = this.seriesTypesRow.map((row: Array<number>) => {
|
||||||
|
return row.slice((pageData.jumpsByDateByModule[0].month+1), -(pageData.jumpsByDateByModule[(pageData.jumpsByDateByModule.length-1)].month));
|
||||||
|
});
|
||||||
|
this.seriesTypesRowCumulated = this.seriesTypesRowCumulated.map((row: Array<number>) => {
|
||||||
|
return row.slice((pageData.jumpsByDateByModule[0].month+1), -(pageData.jumpsByDateByModule[(pageData.jumpsByDateByModule.length-1)].month));
|
||||||
|
});
|
||||||
|
/*
|
||||||
|
console.log('this.min', this.min);
|
||||||
|
console.log('this.max', this.max);
|
||||||
|
console.log('this.lastJump', this.lastJump);
|
||||||
|
console.log('this.seriesHeader', this.seriesHeader);
|
||||||
|
console.log('this.seriesName', this.seriesName);
|
||||||
|
console.log('this.seriesRow', this.seriesRow);
|
||||||
|
console.log('this.seriesRowTotal', this.seriesRowTotal);
|
||||||
|
console.log('this.seriesRowAvg', this.seriesRowAvg);
|
||||||
|
console.log('this.seriesRowAvgLastYears', this.seriesRowAvgLastYears);
|
||||||
|
console.log('this._jumpsByCategorie', this._jumpsByCategorie);
|
||||||
|
console.log('this._jumpsByModule', this._jumpsByModule);
|
||||||
|
console.log('this.seriesTypesHeader', this.seriesTypesHeader);
|
||||||
|
console.log('this.seriesTypesName', this.seriesTypesName);
|
||||||
|
console.log('this.seriesTypesRow', this.seriesTypesRow);
|
||||||
|
console.log('this.seriesTypesRowCumulated', this.seriesTypesRowCumulated);
|
||||||
|
*/
|
||||||
|
this.displayCharts = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this._data.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCategories(): Array<JumpByCategorie> {
|
||||||
|
return this._jumpsByCategorie;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getModules(): Array<JumpByModule> {
|
||||||
|
return this._jumpsByModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getModuleColor(index: number): number {
|
||||||
|
return (this._jumpsByCategorie.length + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -245,7 +245,7 @@
|
|||||||
}
|
}
|
||||||
<span class="badge rounded-pill bg-accent mb-2 me-1 pe-3 py-1 fw-normal text-dark">
|
<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>
|
<mat-icon class="align-middle pointer me-1" fontIcon="person"></mat-icon>
|
||||||
ju_solide
|
{{ lastJump.author.username }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -180,7 +180,7 @@
|
|||||||
}
|
}
|
||||||
<span class="badge rounded-pill bg-accent mb-2 me-1 pe-3 py-1 fw-normal text-dark">
|
<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>
|
<mat-icon class="align-middle pointer me-1" fontIcon="person"></mat-icon>
|
||||||
ju_solide
|
{{ jump.author.username }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,29 +1,69 @@
|
|||||||
<h2 mat-dialog-title class="bg-cyan border-bottom border-light-subtle d-flex mb-3 pt-3 pb-2">
|
<h2 mat-dialog-title class="bg-navy-light border-bottom border-light-subtle d-flex mb-3 pt-3 pb-2">
|
||||||
Saut n° {{jump.numero}}<span class="flex-spacer"></span>
|
Saut n° {{jump.numero}}<span class="flex-spacer"></span>
|
||||||
<mat-icon fontIcon="close" class="pointer" (click)="closeDialog()"></mat-icon>
|
<mat-icon fontIcon="close" class="pointer" (click)="closeDialog()"></mat-icon>
|
||||||
</h2>
|
</h2>
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<div class="container">
|
<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="d-flex border-bottom border-light-subtle text-light-info pb-2 mb-3">
|
||||||
<div class="row mb-3">
|
<div class="flex-fill">
|
||||||
|
<h5>Le {{ jump.date | date: 'dd/MM/yyyy' }} à {{ jump.lieu }} {{ jump.zone ? jump.zone : jump.oaci }} :</h5>
|
||||||
|
</div>
|
||||||
|
<span class="flex-spacer"></span>
|
||||||
|
<div class="align-self-center me-2">
|
||||||
|
<span class="text-accent fs-5">{{ jump.categorie }}</span>
|
||||||
|
@if (jump.module) {
|
||||||
|
<span class="fs-5 mx-2">/</span>
|
||||||
|
<span class="text-muted fs-5">{{ jump.module }}</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
<div class="col-lg-6 col-md-12">
|
<div class="col-lg-6 col-md-12">
|
||||||
<dl class="dl-horizontal">
|
<dl class="dl-horizontal">
|
||||||
<dt class="text-cyan fw-normal">Lieu:</dt>
|
<dt class="text-light-info fw-normal">Aeronef:</dt>
|
||||||
<dd>{{jump.lieu}}</dd>
|
<dd>{{ jump.aeronef }} {{ jump.imat }}</dd>
|
||||||
<dt class="text-cyan fw-normal">Oaci:</dt>
|
<dt class="text-light-info fw-normal">Voile:</dt>
|
||||||
<dd>{{jump.oaci}}</dd>
|
<dd>{{ jump.voile }} {{ jump.taille }} ft<sup>2</sup></dd>
|
||||||
<dt class="text-cyan fw-normal">Aeronef:</dt>
|
@if (jump.programme) {
|
||||||
<dd>{{jump.aeronef}}</dd>
|
<dt class="text-light-info fw-normal">Programme:</dt>
|
||||||
<dt class="text-cyan fw-normal">Imat:</dt>
|
<dd>{{ jump.programme }}</dd>
|
||||||
<dd>{{jump.imat}}</dd>
|
}
|
||||||
<dt class="text-cyan fw-normal">Voile:</dt>
|
</dl>
|
||||||
<dd>{{jump.voile}}</dd>
|
</div>
|
||||||
<dt class="text-cyan fw-normal">Taille:</dt>
|
<div class="col-lg-6 col-md-12">
|
||||||
<dd>{{jump.taille}} ft<sup>2</sup></dd>
|
<dl class="dl-horizontal">
|
||||||
<dt class="text-cyan fw-normal">Participants:</dt>
|
@if (!jump.x2data) {
|
||||||
<dd>{{jump.participants}}</dd>
|
<dt class="text-light-info fw-normal">Hauteur:</dt>
|
||||||
<dt class="text-cyan fw-normal">Sautants:</dt>
|
<dd>{{ jump.hauteur }} m</dd>
|
||||||
<dd>
|
<dt class="text-light-info fw-normal">Déploiement:</dt>
|
||||||
|
<dd>{{ jump.deploiement }} m</dd>
|
||||||
|
}
|
||||||
|
@for (file of jump.files; track file) {
|
||||||
|
<dt class="text-light-info fw-normal">Fichier {{ file.type }}</dt>
|
||||||
|
<dd>{{ file.name }}</dd>
|
||||||
|
}
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
@if (jump.x2data) {
|
||||||
|
<div class="row my-3">
|
||||||
|
<div class="col-sm-4 col-xs-12 text-center">
|
||||||
|
<h6>Hauteur</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ jump.x2data.altitude.exit }} m</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 col-xs-12 text-center">
|
||||||
|
<h6 class="d-flex justify-content-center"><mat-icon fontIcon="timer" class="me-1 fs-5"></mat-icon> Durée de la chute</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{formatDuration(jump.x2data.duration.freeFall)}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 col-xs-12 text-center">
|
||||||
|
<h6>Déploiement</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ jump.x2data.altitude.deployment }} m</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row my-4">
|
||||||
|
<div class="{{ jump.accessoires ? 'col-sm-6 ' : '' }}col-xs-12 text-center">
|
||||||
|
<h5 class="d-flex justify-content-center mb-4"><mat-icon fontIcon="people" class="me-1"></mat-icon> Participants ({{ jump.sautants.length + 1 }})</h5>
|
||||||
@for (sautant of jump.sautants; track sautant) {
|
@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">
|
<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>
|
<mat-icon class="align-middle me-1" fontIcon="person"></mat-icon>
|
||||||
@@ -32,35 +72,140 @@
|
|||||||
}
|
}
|
||||||
<span class="badge rounded-pill bg-accent mb-2 me-1 pe-3 py-1 fw-normal text-dark">
|
<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>
|
<mat-icon class="align-middle me-1" fontIcon="person"></mat-icon>
|
||||||
ju_solide
|
{{ jump.author.username }}
|
||||||
</span>
|
</span>
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6 col-md-12">
|
@if (jump.accessoires) {
|
||||||
<dl class="dl-horizontal">
|
<div class="col-sm-6 col-xs-12 text-center">
|
||||||
<dt class="text-cyan fw-normal">Hauteur:</dt>
|
<h5 class="d-flex justify-content-center mb-4"><mat-icon fontIcon="auto_awesome" class="me-1"></mat-icon> Accessoires</h5>
|
||||||
<dd>{{jump.hauteur}} m</dd>
|
<span class="badge rounded-pill bg-navy-light mb-2 me-1 pe-3 py-1 fw-normal">
|
||||||
<dt class="text-cyan fw-normal">Deploiement:</dt>
|
<mat-icon class="align-middle me-1" fontIcon="auto_awesome"></mat-icon>
|
||||||
<dd>{{jump.deploiement}} m</dd>
|
{{ jump.accessoires }}
|
||||||
<dt class="text-cyan fw-normal">Categorie:</dt>
|
</span>
|
||||||
<dd>{{jump.categorie}}</dd>
|
</div>
|
||||||
<dt class="text-cyan fw-normal">Module:</dt>
|
}
|
||||||
<dd>{{jump.module}}</dd>
|
</div>
|
||||||
<dt class="text-cyan fw-normal">Accessoires:</dt>
|
|
||||||
<dd>{{jump.accessoires}}</dd>
|
<div class="row my-3">
|
||||||
<dt class="text-cyan fw-normal">Zone:</dt>
|
<div class="col-xs-12 text-center">
|
||||||
<dd>{{jump.zone}}</dd>
|
<h5 class="d-flex justify-content-center mb-3"><mat-icon fontIcon="speed" class="me-1"></mat-icon> Vitesse en chute</h5>
|
||||||
<dt class="text-cyan fw-normal">Dossier media:</dt>
|
</div>
|
||||||
<dd>{{jump.dossier}}</dd>
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
<dt class="text-cyan fw-normal">Video:</dt>
|
<h6>Max Verticale</h6>
|
||||||
<dd>{{jump.video}}</dd>
|
<span class="text-primary fw-medium fs-5">{{ (jump.x2data.speed.freeFall.vertical.max / 1000 * 60 * 60) | number : '1.0-0' }} km/h</span>
|
||||||
<dt class="text-cyan fw-normal">Programme:</dt>
|
</div>
|
||||||
<dd>{{jump.programme}}</dd>
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
</dl>
|
<h6>Max Horizontale</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ (jump.x2data.speed.freeFall.horizontal.max / 1000 * 60 * 60) | number : '1.0-0' }} km/h</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Moyenne Verticale</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ (jump.x2data.speed.freeFall.vertical.avg / 1000 * 60 * 60) | number : '1.0-0' }} km/h</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Moyenne Horizontale</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ (jump.x2data.speed.freeFall.horizontal.avg / 1000 * 60 * 60) | number : '1.0-0' }} km/h</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<mat-divider></mat-divider>
|
<mat-divider></mat-divider>
|
||||||
|
|
||||||
|
<div class="row mt-4 mb-3">
|
||||||
|
<div class="col-xs-12 text-center">
|
||||||
|
<h5 class="d-flex justify-content-center mb-3"><mat-icon fontIcon="speed" class="me-1"></mat-icon> Vitesse sous voile</h5>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Max Verticale</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ (jump.x2data.speed.underCanopy.vertical.max / 1000 * 60 * 60) | number : '1.0-0' }} km/h</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Max Horizontale</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ (jump.x2data.speed.underCanopy.horizontal.max / 1000 * 60 * 60) | number : '1.0-0' }} km/h</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Moyenne Verticale</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ (jump.x2data.speed.underCanopy.vertical.avg / 1000 * 60 * 60) | number : '1.0-0' }} km/h</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Moyenne Horizontale</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ (jump.x2data.speed.underCanopy.horizontal.avg / 1000 * 60 * 60) | number : '1.0-0' }} km/h</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
|
||||||
|
<div class="row mt-3">
|
||||||
|
<div class="col-xs-12 text-center">
|
||||||
|
<h5 class="d-flex justify-content-center mb-3"><mat-icon fontIcon="square_foot" class="me-1"></mat-icon> Finesse</h5>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-xs-12 text-center">
|
||||||
|
<h6>Finesse en chute</h6>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-xs-12 text-center">
|
||||||
|
<h6>Finesse sous voile</h6>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Finesse Max</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ jump.x2data.glideRatio.freeFall.max | number : '1.2-2' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Finesse Moyenne</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ jump.x2data.glideRatio.freeFall.avg | number : '1.2-2' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Finesse Max</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ jump.x2data.glideRatio.underCanopy.max | number : '1.2-2' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Finesse Moyenne</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ jump.x2data.glideRatio.underCanopy.avg | number : '1.2-2' }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
|
||||||
|
<div class="row my-3">
|
||||||
|
<div class="col-xs-12 text-center">
|
||||||
|
<h5 class="d-flex justify-content-center mb-3"><mat-icon fontIcon="straighten" class="me-1"></mat-icon> Distance</h5>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Distance au largage</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ jump.x2data.distance.exitFromLandingZone| number : '1.0-0' }} m</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6 class="d-flex justify-content-center"><mat-icon fontIcon="timer" class="me-1 fs-5"></mat-icon> Durée sous voile</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{formatDuration(jump.x2data.duration.underCanopy)}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Distance totale</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ jump.x2data.distance.totalFlying | number : '1.0-0' }} m</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-xs-12 text-center">
|
||||||
|
<h6>Distance horizontale</h6>
|
||||||
|
<span class="text-primary fw-medium fs-5">{{ jump.x2data.distance.totalHorizontal | number : '1.0-0' }} m</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
}
|
||||||
|
@else {
|
||||||
|
<div class="row my-4">
|
||||||
|
<div class="col-xs-12 text-center">
|
||||||
|
<h5 class="d-flex justify-content-center mb-4"><mat-icon fontIcon="people" class="me-1"></mat-icon> Participants ({{ jump.sautants.length + 1 }})</h5>
|
||||||
|
@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>
|
||||||
|
{{ jump.author.username }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
<div class="d-flex justify-content-center my-3 fs-5"><mat-icon fontIcon="satellite_alt" class="me-2"></mat-icon> Aucune donnée GPS</div>
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Component, Inject } from '@angular/core';
|
import { Component, Inject } from '@angular/core';
|
||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe, DecimalPipe } 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 { MatDividerModule } from '@angular/material/divider';
|
||||||
@@ -12,11 +12,9 @@ import { Jump } from 'src/app/core/models';
|
|||||||
templateUrl: 'jump-view.dialog.html',
|
templateUrl: 'jump-view.dialog.html',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [
|
imports: [
|
||||||
DatePipe,
|
DatePipe, DecimalPipe,
|
||||||
MatButtonModule,
|
MatButtonModule, MatDialogModule,
|
||||||
MatDialogModule,
|
MatDividerModule, MatIconModule
|
||||||
MatDividerModule,
|
|
||||||
MatIconModule
|
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class JumpViewDialogComponent {
|
export class JumpViewDialogComponent {
|
||||||
@@ -30,4 +28,10 @@ export class JumpViewDialogComponent {
|
|||||||
// close the dialog without result
|
// close the dialog without result
|
||||||
this.dialogRef.close();
|
this.dialogRef.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
formatDuration(duration: number): string {
|
||||||
|
const start = new Date(0);
|
||||||
|
start.setSeconds(duration);
|
||||||
|
return start.toISOString().substring(14, 19);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<div @flyInOut>
|
<div @flyInOut>
|
||||||
<div class="content">
|
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<div class="flex-fill">
|
<div class="flex-fill">
|
||||||
<h1 class="mb-1">{{title}}</h1>
|
<h1 class="mb-1">{{title}}</h1>
|
||||||
@@ -104,4 +103,3 @@
|
|||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
@@ -12,14 +12,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="profile-page content">
|
<div class="profile-page">
|
||||||
<h1>{{title}}</h1>
|
<div class="d-flex">
|
||||||
<mat-divider></mat-divider>
|
<div class="flex-fill">
|
||||||
|
<h1 class="mb-1">{{title}}</h1>
|
||||||
|
</div>
|
||||||
|
<span class="flex-spacer"></span>
|
||||||
|
<div class="align-self-center me-2 text-end"></div>
|
||||||
|
</div>
|
||||||
|
<mat-divider class="my-3"></mat-divider>
|
||||||
<app-list-errors [errors]="errors"></app-list-errors>
|
<app-list-errors [errors]="errors"></app-list-errors>
|
||||||
<mat-card class="mt-4 bg-light text-black scaled">
|
<mat-card class="mt-4 bg-light text-black scaled">
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<a href="index.html" class="d-block p-4"><img height="72" width="90" src="assets/images/vector/upt_logo.png" alt="Logo UPT"></a>
|
<a href="/" class="d-block p-4"><img height="72" width="90" src="assets/images/vector/upt_logo.png" alt="Logo UPT"></a>
|
||||||
<mat-divider class="border-primary w-50 mx-auto"></mat-divider>
|
<mat-divider class="border-primary w-50 mx-auto"></mat-divider>
|
||||||
<h1 class="mt-3 mb-4"><span class="pt-1 pb-2 px-2">Vector 3 - <small class="text-muted">V306 Micron</small></span></h1>
|
<h1 class="mt-3 mb-4"><span class="pt-1 pb-2 px-2">Vector 3 - <small class="text-muted">V306 Micron</small></span></h1>
|
||||||
<mat-divider class="border-primary w-50 mx-auto"></mat-divider>
|
<mat-divider class="border-primary w-50 mx-auto"></mat-divider>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
.banner {
|
.banner {
|
||||||
background-color: var.$sidebar-footer;
|
background-color: var.$sidebar-footer;
|
||||||
padding: 1.6rem 0 1.3rem 0;
|
padding: 1.6rem 0 1.3rem 0;
|
||||||
|
margin: -1.5rem -1.5rem 1.5rem -1.5rem;
|
||||||
.user-img {
|
.user-img {
|
||||||
width: var.$user-img-size;
|
width: var.$user-img-size;
|
||||||
height: var.$user-img-size;
|
height: var.$user-img-size;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
<div class="content">
|
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<div class="flex-fill">
|
<div class="flex-fill">
|
||||||
<h1 class="mb-1">
|
<h1 class="mb-1">
|
||||||
@@ -24,9 +23,21 @@
|
|||||||
</div>
|
</div>
|
||||||
<mat-divider class="my-3"></mat-divider>
|
<mat-divider class="my-3"></mat-divider>
|
||||||
<app-list-errors [errors]="errors"></app-list-errors>
|
<app-list-errors [errors]="errors"></app-list-errors>
|
||||||
<mat-card [hidden]="!questions.length">
|
@if (questions.controls.length) {
|
||||||
<mat-card-content class="mt-4">
|
<mat-card [hidden]="!questions.controls.length">
|
||||||
<form [formGroup]="qcmForm">
|
<div class="mx-3 my-5">
|
||||||
|
<mat-progress-bar [mode]="loading ? 'query' : 'determinate'" [value]="loading ? 0 : (totalAnswer/questionsCount*100)" color="accent"></mat-progress-bar>
|
||||||
|
<mat-progress-bar class="mt-0" [mode]="loading ? 'query' : 'determinate'" [value]="loading ? 0 : ((timeProgress/timeMax)*100)" [color]="timeProgressColor"></mat-progress-bar>
|
||||||
|
<ol class="squareItem clearfix">
|
||||||
|
@for (category of qcm.categories; track category.num) {
|
||||||
|
@for (question of category.questions; track question.num) {
|
||||||
|
<li class="rounded-0">{{ question.num }}</li>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
<mat-card-content>
|
||||||
|
<form [formGroup]="qcmForm" (ngSubmit)="onSubmit()">
|
||||||
@for (category of qcm.categories; track category; let index = $index) {
|
@for (category of qcm.categories; track category; let index = $index) {
|
||||||
<mat-accordion>
|
<mat-accordion>
|
||||||
<mat-expansion-panel class="mb-3" [expanded]="expandedIndex === index" (opened)="setExpandedIndex(index)">
|
<mat-expansion-panel class="mb-3" [expanded]="expandedIndex === index" (opened)="setExpandedIndex(index)">
|
||||||
@@ -43,9 +54,9 @@
|
|||||||
@for (question of category.questions; track question; let index = $index) {
|
@for (question of category.questions; track question; let index = $index) {
|
||||||
<div class="mb-3" [formGroupName]="index">
|
<div class="mb-3" [formGroupName]="index">
|
||||||
<label class="fs-5 fw-medium mb-2" for="radio-group-{{ category.num }}-{{ question.num }}">{{ question.num }} - {{ question.libelle }}</label>
|
<label class="fs-5 fw-medium mb-2" for="radio-group-{{ category.num }}-{{ question.num }}">{{ question.num }} - {{ question.libelle }}</label>
|
||||||
<mat-radio-group id="radio-group-{{ category.num }}-{{ question.num }}" class="d-flex flex-column" (change)="onChange()">
|
<mat-radio-group formControlName="choice" id="radio-group-{{ category.num }}-{{ question.num }}" class="d-flex flex-column" (change)="onChange(category, question, $event.value)">
|
||||||
@for (choice of question.choices; track choice) {
|
@for (choice of question.choices; track choice) {
|
||||||
<mat-radio-button class="example-radio-button" [value]="choice.index" [color]="choice.correct ? 'primary' : 'warn'">{{ choice.libelle }}</mat-radio-button>
|
<mat-radio-button [value]="choice.index" [color]="choice.correct ? 'primary' : 'warn'">{{ choice.libelle }}</mat-radio-button>
|
||||||
}
|
}
|
||||||
</mat-radio-group>
|
</mat-radio-group>
|
||||||
</div>
|
</div>
|
||||||
@@ -56,5 +67,17 @@
|
|||||||
}
|
}
|
||||||
</form>
|
</form>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
<!--
|
||||||
|
<form [formGroup]="qcmForm">
|
||||||
|
<div class="mb-3 ms-4" formArrayName="questions">
|
||||||
|
@for (question of questions.controls; track question; let index = $index) {
|
||||||
|
<div class="mb-3" [formGroupName]="index">
|
||||||
|
<label class="fs-5 fw-medium mb-2" for="radio-group-{{ index }}">{{ index }} - Libellé</label>
|
||||||
|
<input formControlName="choice" type="text"/>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
-->
|
||||||
|
</mat-card>
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/* QCM */
|
||||||
|
@use 'variable' as var;
|
||||||
|
|
||||||
|
ol.squareItem {
|
||||||
|
padding: 0;
|
||||||
|
margin: 1rem 0;
|
||||||
|
li {
|
||||||
|
color: var.$primary;
|
||||||
|
background-color: var.$sidenav-content; //var.$dark;
|
||||||
|
background-image: none;
|
||||||
|
border: 1px solid var.$dark; //var.$extra-muted;
|
||||||
|
cursor: pointer;
|
||||||
|
float: left;
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0.17em;
|
||||||
|
padding: 0.34em 0;
|
||||||
|
text-align: center;
|
||||||
|
width: 33px;
|
||||||
|
height: 33px;
|
||||||
|
&.active {
|
||||||
|
border-color: var.$info;
|
||||||
|
}
|
||||||
|
&.valid {
|
||||||
|
color: var.$sidenav-content;
|
||||||
|
border-color: var.$success;
|
||||||
|
background-color: var.$primary;
|
||||||
|
}
|
||||||
|
&.defer {
|
||||||
|
border-color: var.$info-dark;
|
||||||
|
background-color: var.$navy-light;
|
||||||
|
}
|
||||||
|
&.error {
|
||||||
|
border-color: var.$purple-light;
|
||||||
|
background-color: var.$secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,12 +8,15 @@ import { MatDividerModule } from '@angular/material/divider';
|
|||||||
import { MatExpansionModule } from '@angular/material/expansion';
|
import { MatExpansionModule } from '@angular/material/expansion';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
|
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||||
import { MatRadioModule } from '@angular/material/radio';
|
import { MatRadioModule } from '@angular/material/radio';
|
||||||
import { Observable, Subscription } from 'rxjs';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
|
import { interval, Observable, Subscription } from 'rxjs';
|
||||||
|
import { take } from 'rxjs/operators';
|
||||||
|
|
||||||
import { MenuItems } from 'src/app/components/shared';
|
import { MenuItems } from 'src/app/components/shared';
|
||||||
import { ListErrorsComponent, } from 'src/app/components/shared';
|
import { ListErrorsComponent } from 'src/app/components/shared';
|
||||||
import { Errors, Qcm, User } from 'src/app/core/models';
|
import { Errors, Qcm, QcmCategory, QcmQuestion, User } from 'src/app/core/models';
|
||||||
import { QcmService, UserService } from 'src/app/core/services';
|
import { QcmService, UserService } from 'src/app/core/services';
|
||||||
import data from 'src/qcm-bpa.json';
|
import data from 'src/qcm-bpa.json';
|
||||||
|
|
||||||
@@ -23,7 +26,8 @@ import data from 'src/qcm-bpa.json';
|
|||||||
imports: [
|
imports: [
|
||||||
FormsModule, ReactiveFormsModule,
|
FormsModule, ReactiveFormsModule,
|
||||||
MatButtonModule, MatCardModule, MatDividerModule, MatExpansionModule,
|
MatButtonModule, MatCardModule, MatDividerModule, MatExpansionModule,
|
||||||
MatIconModule, MatMenuModule, MatRadioModule,
|
MatIconModule, MatMenuModule, MatProgressBarModule, MatRadioModule,
|
||||||
|
MatSelectModule,
|
||||||
ListErrorsComponent
|
ListErrorsComponent
|
||||||
],
|
],
|
||||||
templateUrl: './qcm.component.html',
|
templateUrl: './qcm.component.html',
|
||||||
@@ -32,6 +36,8 @@ import data from 'src/qcm-bpa.json';
|
|||||||
export class QcmComponent implements OnInit, OnDestroy {
|
export class QcmComponent implements OnInit, OnDestroy {
|
||||||
private _currentUser: Subscription = new Subscription();
|
private _currentUser: Subscription = new Subscription();
|
||||||
private _data: Subscription = new Subscription();
|
private _data: Subscription = new Subscription();
|
||||||
|
private _timer: Subscription = new Subscription();
|
||||||
|
private _refresh = 1000;
|
||||||
public qcm: Qcm = {} as Qcm;
|
public qcm: Qcm = {} as Qcm;
|
||||||
public currentUser: User = {} as User;
|
public currentUser: User = {} as User;
|
||||||
public canModify = false;
|
public canModify = false;
|
||||||
@@ -42,6 +48,11 @@ export class QcmComponent implements OnInit, OnDestroy {
|
|||||||
public expandedIndex = 0;
|
public expandedIndex = 0;
|
||||||
public questionsCount = 0;
|
public questionsCount = 0;
|
||||||
public qcmForm!: FormGroup;
|
public qcmForm!: FormGroup;
|
||||||
|
public loading = true;
|
||||||
|
public totalAnswer = 0;
|
||||||
|
public timeProgress = 0;
|
||||||
|
public timeProgressColor = 'primary';
|
||||||
|
public timeMax = (60*45);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
@@ -56,15 +67,16 @@ export class QcmComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get questions(): FormArray {
|
get questions(): FormArray {
|
||||||
return <FormArray>this.qcmForm.controls['questions'];
|
return this.qcmForm.controls['questions'] as FormArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
//this.importQuestions();
|
//this._importQuestions();
|
||||||
//this.importChoices();
|
//this._importChoices();
|
||||||
// Retreive the prefetched QCM
|
// Retreive the prefetched QCM
|
||||||
const data$: Observable<{ qcm: Qcm }> = this.route.data as Observable<{ qcm: Qcm }>;
|
const data$: Observable<{ qcm: Qcm }> = this.route.data as Observable<{ qcm: Qcm }>;
|
||||||
this._data = data$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data: { qcm: Qcm }) => {
|
this._data = data$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data: { qcm: Qcm }) => {
|
||||||
|
this.questionsCount = 0;
|
||||||
this.qcm = data.qcm;
|
this.qcm = data.qcm;
|
||||||
if (this.qcm.name === 'bpa') {
|
if (this.qcm.name === 'bpa') {
|
||||||
this.title = 'QCM du BPA';
|
this.title = 'QCM du BPA';
|
||||||
@@ -77,13 +89,7 @@ export class QcmComponent implements OnInit, OnDestroy {
|
|||||||
this.qcm.categories.forEach(category => {
|
this.qcm.categories.forEach(category => {
|
||||||
this.questionsCount += category.questions.length;
|
this.questionsCount += category.questions.length;
|
||||||
category.questions.forEach(question => {
|
category.questions.forEach(question => {
|
||||||
this.questions.push(
|
this.addQuestion(question);
|
||||||
this.fb.group({
|
|
||||||
id: new FormControl({ value: question.num, disabled: false }),
|
|
||||||
choice: ['']
|
|
||||||
//choice: new FormControl({ value: '', disabled: false })
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -93,6 +99,7 @@ export class QcmComponent implements OnInit, OnDestroy {
|
|||||||
this.currentUser = userData;
|
this.currentUser = userData;
|
||||||
this.canModify = userData.role === 'Admin';
|
this.canModify = userData.role === 'Admin';
|
||||||
});
|
});
|
||||||
|
this.loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
@@ -100,15 +107,61 @@ export class QcmComponent implements OnInit, OnDestroy {
|
|||||||
this._currentUser.unsubscribe();
|
this._currentUser.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _starTimer(): void {
|
||||||
|
this._timer = interval(1000)
|
||||||
|
.pipe(take(this.timeMax))
|
||||||
|
.subscribe(() => {
|
||||||
|
this.timeProgress++;
|
||||||
|
if (this.timeProgress > (this.timeMax/100*70) && this.timeProgress <= (this.timeMax/100*90)) {
|
||||||
|
this.timeProgressColor = 'warning';
|
||||||
|
} else if (this.timeProgress > (this.timeMax/100*90) && this.timeProgress <= (this.timeMax/100*98)) {
|
||||||
|
this.timeProgressColor = 'danger';
|
||||||
|
} else if (this.timeProgress > (this.timeMax/100*98)) {
|
||||||
|
this.timeProgressColor = 'purple';
|
||||||
|
}
|
||||||
|
if (this.timeProgress >= this.timeMax) {
|
||||||
|
this.timeProgressColor = 'accent';
|
||||||
|
this._timer.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addQuestion(question: QcmQuestion) {
|
||||||
|
const item = this.fb.group({
|
||||||
|
id: [question.num],
|
||||||
|
choice: ['']
|
||||||
|
});
|
||||||
|
this.questions.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
setExpandedIndex(index: number) {
|
setExpandedIndex(index: number) {
|
||||||
this.expandedIndex = index;
|
this.expandedIndex = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange() {
|
onChange(category: QcmCategory, question: QcmQuestion, value: unknown) {
|
||||||
//this.isDisabled = true;
|
//console.log('onChange', category.num, question.num, value);
|
||||||
|
if (this.timeProgress === 0) {
|
||||||
|
this._starTimer();
|
||||||
|
}
|
||||||
|
this.qcm.categories[(category.num-1)].questions[(question.num-1)].choices.forEach(choice => {
|
||||||
|
if (choice.index === value) {
|
||||||
|
if (choice.correct) {
|
||||||
|
console.log(`Réponse à la question ${question.num} de la catégorie ${category.num} : correcte`);
|
||||||
|
} else {
|
||||||
|
console.log(`Réponse à la question ${question.num} de la catégorie ${category.num} : incorrecte`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.totalAnswer++;
|
||||||
|
this.questions.controls[(question.num-1)].disable();
|
||||||
|
//console.log(this.questions.controls[(question.num-1)].disabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
importChoices() {
|
onSubmit() {
|
||||||
|
console.log('onSubmit');
|
||||||
|
}
|
||||||
|
|
||||||
|
private _importChoices() {
|
||||||
try {
|
try {
|
||||||
data.categories.forEach((category) => {
|
data.categories.forEach((category) => {
|
||||||
category.questions.forEach(question => {
|
category.questions.forEach(question => {
|
||||||
@@ -132,7 +185,7 @@ export class QcmComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
importQuestions() {
|
private _importQuestions() {
|
||||||
try {
|
try {
|
||||||
data.categories.forEach((category) => {
|
data.categories.forEach((category) => {
|
||||||
//Object.assign(this.jump, category);
|
//Object.assign(this.jump, category);
|
||||||
@@ -154,4 +207,8 @@ export class QcmComponent implements OnInit, OnDestroy {
|
|||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _resetErrors(): void {
|
||||||
|
this.errors = { errors: {} };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="credentials-page content">
|
<div class="credentials-page">
|
||||||
<h1>{{title}}</h1>
|
<h1>{{title}}</h1>
|
||||||
<mat-divider></mat-divider>
|
<mat-divider></mat-divider>
|
||||||
<app-list-errors [errors]="errors"></app-list-errors>
|
<app-list-errors [errors]="errors"></app-list-errors>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
.banner {
|
.banner {
|
||||||
background-color: var.$sidebar-footer;
|
background-color: var.$sidebar-footer;
|
||||||
padding: 1.6rem 0 1.3rem 0;
|
padding: 1.6rem 0 1.3rem 0;
|
||||||
|
margin: -1.5rem -1.5rem 1.5rem -1.5rem;
|
||||||
.user-img {
|
.user-img {
|
||||||
width: var.$user-img-size;
|
width: var.$user-img-size;
|
||||||
height: var.$user-img-size;
|
height: var.$user-img-size;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settings-page content">
|
<div class="settings-page">
|
||||||
<h1>{{title}}</h1>
|
<h1>{{title}}</h1>
|
||||||
<mat-divider></mat-divider>
|
<mat-divider></mat-divider>
|
||||||
<app-list-errors [errors]="errors"></app-list-errors>
|
<app-list-errors [errors]="errors"></app-list-errors>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
.banner {
|
.banner {
|
||||||
background-color: var.$sidebar-footer;
|
background-color: var.$sidebar-footer;
|
||||||
padding: 1.6rem 0 1.3rem 0;
|
padding: 1.6rem 0 1.3rem 0;
|
||||||
|
margin: -1.5rem -1.5rem 1.5rem -1.5rem;
|
||||||
/*
|
/*
|
||||||
background-color: mat.get-color-from-palette(var.$md-custom-warn, 700);
|
background-color: mat.get-color-from-palette(var.$md-custom-warn, 700);
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
|
|||||||
+2
-1
@@ -74,6 +74,7 @@ export class JumpsByMonthComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _loadJumpByDate() {
|
private _loadJumpByDate() {
|
||||||
|
const minoration = 2; // -2 pour ne pas compter la première année
|
||||||
this.seriesHeader = this._utilitiesService.getMonthsList();
|
this.seriesHeader = this._utilitiesService.getMonthsList();
|
||||||
const values: Array<number> = this.seriesHeader.map(() => 0);
|
const values: Array<number> = this.seriesHeader.map(() => 0);
|
||||||
this.seriesColTotal = [...values];
|
this.seriesColTotal = [...values];
|
||||||
@@ -111,7 +112,7 @@ export class JumpsByMonthComponent implements OnInit, OnDestroy {
|
|||||||
this.seriesRowTotal.push(total);
|
this.seriesRowTotal.push(total);
|
||||||
});
|
});
|
||||||
this.seriesColTotalClosed.forEach((row: number) => {
|
this.seriesColTotalClosed.forEach((row: number) => {
|
||||||
const value: number = (row/(this.seriesName.length-2)); // -2 pour ne pas compter la première année
|
const value: number = (row/(this.seriesName.length-minoration));
|
||||||
this.seriesRowAvg.push(parseInt(value.toFixed(0)));
|
this.seriesRowAvg.push(parseInt(value.toFixed(0)));
|
||||||
});
|
});
|
||||||
this.seriesColTotalLastYears.forEach((row: number) => {
|
this.seriesColTotalLastYears.forEach((row: number) => {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<mat-spinner [diameter]="32" [hidden]="!loading" color="accent" class="align-middle ms-2"></mat-spinner>
|
<mat-spinner [diameter]="32" [hidden]="!loading" color="accent" class="align-middle ms-2"></mat-spinner>
|
||||||
<span [hidden]="jumpsCount || loading" class="ms-2 fst-italic">Aucun saut à afficher pour le moment.</span>
|
<span [hidden]="jumpsCount || loading" class="ms-2 fst-italic">Aucun saut à afficher pour le moment.</span>
|
||||||
<span [hidden]="!loading" class="ms-2 fst-italic">Actualisation des sauts en cours</span>
|
<span [hidden]="!loading" class="ms-2 fst-italic">Chargement des sauts en cours</span>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 col-xs-12 px-0">
|
<div class="col-md-6 col-xs-12 px-0">
|
||||||
@@ -224,7 +224,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</td>
|
</td>
|
||||||
</ng-container> -->
|
</ng-container> -->
|
||||||
<!-- Video Column -->
|
<!-- Video Column
|
||||||
<ng-container matColumnDef="video">
|
<ng-container matColumnDef="video">
|
||||||
<th class="pl-3" mat-header-cell *matHeaderCellDef> Video </th>
|
<th class="pl-3" mat-header-cell *matHeaderCellDef> Video </th>
|
||||||
<td class="pl-3 text-nowrap" mat-cell *matCellDef="let element">
|
<td class="pl-3 text-nowrap" mat-cell *matCellDef="let element">
|
||||||
@@ -236,6 +236,41 @@
|
|||||||
</ngx-skeleton-loader>
|
</ngx-skeleton-loader>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
|
</ng-container> -->
|
||||||
|
<!-- Files Column -->
|
||||||
|
<ng-container matColumnDef="files">
|
||||||
|
<th class="pl-3" mat-header-cell *matHeaderCellDef> Fichiers </th>
|
||||||
|
<td class="pl-3 text-nowrap" mat-cell *matCellDef="let element">
|
||||||
|
@if (element.files) {
|
||||||
|
@for (file of element.files; track $index) {
|
||||||
|
@switch (file.type) {
|
||||||
|
@case ('video') {
|
||||||
|
<button mat-button (click)="openViewDialog(element)" color="navy-light">
|
||||||
|
<mat-icon fontIcon="videocam me-2"></mat-icon> {{ file.type }}
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
@case ('image') {
|
||||||
|
<button mat-button (click)="openViewDialog(element)" color="navy-light">
|
||||||
|
<mat-icon fontIcon="image me-2"></mat-icon> {{ file.type }}
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
@case ('kml') {
|
||||||
|
<button mat-button (click)="openViewDialog(element)" color="navy-light">
|
||||||
|
<mat-icon fontIcon="language me-2"></mat-icon> {{ file.type }}
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
@default {
|
||||||
|
<button mat-button (click)="openViewDialog(element)" color="navy-light">
|
||||||
|
<mat-icon fontIcon="description me-2"></mat-icon> {{ file.type }}
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@if (!element.numero) {
|
||||||
|
<ngx-skeleton-loader [theme]="{width: '30px', height: '13px', marginBottom: '0px'}"></ngx-skeleton-loader>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<!-- Actions Column -->
|
<!-- Actions Column -->
|
||||||
<ng-container matColumnDef="actions">
|
<ng-container matColumnDef="actions">
|
||||||
@@ -247,13 +282,17 @@
|
|||||||
<mat-icon>more_vert</mat-icon>
|
<mat-icon>more_vert</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<mat-menu [hidden]="!showAdd" #actionMenu="matMenu">
|
<mat-menu [hidden]="!showAdd" #actionMenu="matMenu">
|
||||||
|
<button mat-menu-item [routerLink]="['/jump', element.slug]">
|
||||||
|
<mat-icon aria-label="Voir" fontIcon="visibility" color="info" class="mini"></mat-icon>
|
||||||
|
<span class="text-info">Détails</span>
|
||||||
|
</button>
|
||||||
<button mat-menu-item (click)="openEditDialog(element)">
|
<button mat-menu-item (click)="openEditDialog(element)">
|
||||||
<mat-icon aria-label="Modifier" fontIcon="edit" color="primary" class="mini"></mat-icon>
|
<mat-icon aria-label="Modifier" fontIcon="edit" color="primary" class="mini"></mat-icon>
|
||||||
<span class="text-primary">Modifier</span>
|
<span class="text-primary">Modifier</span>
|
||||||
</button>
|
</button>
|
||||||
<button mat-menu-item (click)="openDeleteDialog(element)">
|
<button mat-menu-item (click)="openDeleteDialog(element)">
|
||||||
<mat-icon aria-label="Supprimer" fontIcon="delete" color="danger" class="mini"></mat-icon>
|
<mat-icon aria-label="Supprimer" fontIcon="delete" color="raspberry" class="mini"></mat-icon>
|
||||||
<span class="text-danger">Supprimer</span>
|
<span class="text-raspberry">Supprimer</span>
|
||||||
</button>
|
</button>
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { take } from 'rxjs/operators';
|
|||||||
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
||||||
|
|
||||||
import { FrenchPaginator } from 'src/app/components/shared/french-paginator.component';
|
import { FrenchPaginator } from 'src/app/components/shared/french-paginator.component';
|
||||||
import { ColumnDefinition, Errors, Jump, JumpList, JumpListConfig, jumpColumns } from 'src/app/core/models';
|
import { ColumnDefinition, Errors, Jump, JumpByDay, JumpFile, JumpFileType, JumpList, JumpListConfig, jumpColumns } from 'src/app/core/models';
|
||||||
import { JumpsService, JumpTableService } from 'src/app/core/services';
|
import { JumpsService, JumpTableService } from 'src/app/core/services';
|
||||||
import { JumpAddDialogComponent, JumpDeleteDialogComponent, JumpEditDialogComponent, JumpViewDialogComponent } from 'src/app/components/logbook/dialogs'
|
import { JumpAddDialogComponent, JumpDeleteDialogComponent, JumpEditDialogComponent, JumpViewDialogComponent } from 'src/app/components/logbook/dialogs'
|
||||||
|
|
||||||
@@ -41,6 +41,7 @@ import { JumpAddDialogComponent, JumpDeleteDialogComponent, JumpEditDialogCompon
|
|||||||
})
|
})
|
||||||
export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChecked {
|
export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChecked {
|
||||||
private _jumps: Subscription = new Subscription();
|
private _jumps: Subscription = new Subscription();
|
||||||
|
private _subscriptions: Array<Subscription> = [];
|
||||||
//private _jump: Subscription = new Subscription();
|
//private _jump: Subscription = new Subscription();
|
||||||
private _query: JumpListConfig = { type: 'all', filters: {} };
|
private _query: JumpListConfig = { type: 'all', filters: {} };
|
||||||
//private _lastjump: Jump = {} as Jump;
|
//private _lastjump: Jump = {} as Jump;
|
||||||
@@ -53,13 +54,13 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
|||||||
'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', 'files', 'actions'
|
||||||
];*/
|
];*/
|
||||||
public displayedColumns: string[] = [
|
public displayedColumns: string[] = [
|
||||||
'numero', 'date', 'lieu', 'aeronef',
|
'numero', 'date', 'lieu', 'aeronef',
|
||||||
'hauteur', 'voile', 'categorie',
|
'hauteur', 'voile', 'categorie',
|
||||||
'participants', 'zone', 'accessoires',
|
'participants', 'zone', 'accessoires',
|
||||||
'video', 'actions'
|
'files', 'actions'
|
||||||
];
|
];
|
||||||
//public displayedColumns: string[] = jumpColumns.map((col) => col.key)
|
//public displayedColumns: string[] = jumpColumns.map((col) => col.key)
|
||||||
public columnsSchema: Array<ColumnDefinition> = jumpColumns;
|
public columnsSchema: Array<ColumnDefinition> = jumpColumns;
|
||||||
@@ -115,7 +116,9 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
|||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this._jumps.unsubscribe();
|
this._jumps.unsubscribe();
|
||||||
//this._jump.unsubscribe();
|
this._subscriptions.forEach(subscription => {
|
||||||
|
subscription.unsubscribe();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterContentChecked() {
|
ngAfterContentChecked() {
|
||||||
@@ -155,6 +158,9 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
|||||||
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.updateJumps(data.jumps);
|
||||||
|
//this.linkSkydiverIdJumps();
|
||||||
|
//this.getKmlJumpFiles(data.jumps);
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.jumps = new MatTableDataSource<Jump>(data.jumps);
|
this.jumps = new MatTableDataSource<Jump>(data.jumps);
|
||||||
this.jumpsCount = data.jumpsCount;
|
this.jumpsCount = data.jumpsCount;
|
||||||
@@ -170,12 +176,150 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
linkSkydiverIdJumps() {
|
||||||
|
const config: JumpListConfig = { type: 'all', filters: {} } as JumpListConfig;
|
||||||
|
config.filters.limit = 200;
|
||||||
|
config.filters.offset = 0;
|
||||||
|
config.filters.dateRangeStart = '2024-01-01 00:00:00';
|
||||||
|
//const year = new Date().getFullYear();
|
||||||
|
//config.filters.dateRangeEnd = `${year}-12-31 23:59:59`;
|
||||||
|
config.filters.dateRangeEnd = '2024-12-31 23:59:59';
|
||||||
|
//console.log(config.filters);
|
||||||
|
const subscription: Subscription = this._jumpsService.getAllByDay(config)
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe({
|
||||||
|
next: (days) => {
|
||||||
|
this._resetErrors();
|
||||||
|
//console.log('getAllByDay : ', days);
|
||||||
|
days.forEach(day => {
|
||||||
|
this.loadSkydiverIdJumps(day, config);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
this.errors = err;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this._subscriptions.push(subscription);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadSkydiverIdJumps(day: JumpByDay, config: JumpListConfig) {
|
||||||
|
config.filters.dateRangeStart = `${day.jumps[0].date!.substring(0, 10)} 00:00:00`;
|
||||||
|
config.filters.dateRangeEnd = `${day.jumps[0].date!.substring(0, 10)} 23:59:59`;
|
||||||
|
const subscription: Subscription = this._jumpsService.getAllFromSkydiverIdApi(config)
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe({
|
||||||
|
next: (data) => {
|
||||||
|
if (data.items.length) {
|
||||||
|
const diff = day.count - data.items.length;
|
||||||
|
if (diff < 0) {
|
||||||
|
console.error(`${diff} ${diff > 1 ? 'données' : 'donnée'} altimètre de trop le ${day.jumps[0].date!.substring(0, 10)}`);
|
||||||
|
} else {
|
||||||
|
if (diff > 0) {
|
||||||
|
console.error(`${diff}/${day.count} ${diff > 1 ? 'données altimètre manquantes' : 'donnée altimètre manquante'} le ${day.jumps[0].date!.substring(0, 10)}`, day.jumps, data.items);
|
||||||
|
}
|
||||||
|
console.log(`${day.count} ${day.count > 1 ? 'sauts' : 'saut'} le ${data.items[0].date!.substring(0, 10)}`, day.jumps.sort((a, b) => b.numero! - a.numero!), data.items);
|
||||||
|
data.items.map((jump, index) => {
|
||||||
|
const file: JumpFile = {
|
||||||
|
name: jump.name,
|
||||||
|
path: `/Volumes/Storage/Skydive/X2_Logs/${day.jumps[index].date!.substring(0, 4)}/`,
|
||||||
|
type: JumpFileType.CSV
|
||||||
|
} as JumpFile;
|
||||||
|
this._subscriptions.push(
|
||||||
|
this._jumpsService.saveX2Data(day.jumps[index].slug!, file, jump)
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe({
|
||||||
|
next: (jump) => {
|
||||||
|
this._resetErrors();
|
||||||
|
console.log(`Le fichier ${file.name} a été ajouté au saut n°${jump.numero} !`, 'OK');
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
this.errors = err;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return jump;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//console.log(`${day.count} ${day.count > 1 ? 'sauts' : 'saut'} le ${day.jumps[0].date!.substring(0, 10)}`);
|
||||||
|
//console.log(`${data.items.length} ${data.items.length > 1 ? 'sauts' : 'saut'} le ${data.items[0].date!.substring(0, 10)}`, data);
|
||||||
|
} else {
|
||||||
|
console.info('Aucune données altimètre pour le ', day.jumps[0].date!.substring(0, 10));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
console.error('getAllFromSkydiverIdApi error');
|
||||||
|
this.errors = err;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this._subscriptions.push(subscription);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateJumps(jumps: Array<Jump>) {
|
||||||
|
jumps.map(jump => {
|
||||||
|
jump.files = [];
|
||||||
|
if (jump.dossier !== "" && jump.video !== "") {
|
||||||
|
const file: JumpFile = {
|
||||||
|
name: jump.video!,
|
||||||
|
path: jump.dossier!,
|
||||||
|
type: JumpFileType.VIDEO
|
||||||
|
} as JumpFile;
|
||||||
|
this._subscriptions.push(
|
||||||
|
this._jumpsService.saveFile(jump.slug, file)
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe({
|
||||||
|
next: (file) => {
|
||||||
|
this._resetErrors();
|
||||||
|
jump.files.push(file);
|
||||||
|
console.log(`Le fichier ${file.name} a été ajouté au saut n°${jump.numero} !`, 'OK');
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
this.errors = err;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return jump;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getKmlJumpFiles(jumps: Array<Jump>) {
|
||||||
|
jumps.map(jump => {
|
||||||
|
if (jump.x2data !== null) {
|
||||||
|
//console.log(`Le fichier ${jump.x2data.name} existe pour le saut n°${jump.numero} !`, `https://skydiver.id/api/jump/${jump.x2data.id}/kml`);
|
||||||
|
const file: JumpFile = {
|
||||||
|
name: jump.x2data.name.substring(0, -4) + '.kml',
|
||||||
|
path: `/X2_Kmls/${jump.date.substring(0, 4)}/`,
|
||||||
|
type: JumpFileType.KML
|
||||||
|
} as JumpFile;
|
||||||
|
this._subscriptions.push(
|
||||||
|
this._jumpsService.saveKml(jump.slug, file)
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe({
|
||||||
|
next: (file) => {
|
||||||
|
this._resetErrors();
|
||||||
|
console.log(`Le fichier ${file.path}${file.name} a été ajouté au saut n°${jump.numero} !`, 'OK');
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
this.errors = err;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
return jump;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
deleteJump(slug: string) {
|
deleteJump(slug: string) {
|
||||||
this.isDeleting = true;
|
this.isDeleting = true;
|
||||||
this._jumpsService.destroy(slug).pipe(take(1))
|
this._subscriptions.push(
|
||||||
|
this._jumpsService.destroy(slug)
|
||||||
|
.pipe(take(1))
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.router.navigateByUrl('/');
|
this.router.navigateByUrl('/');
|
||||||
});
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
openDeleteDialog(jump: Jump): void {
|
openDeleteDialog(jump: Jump): void {
|
||||||
@@ -183,12 +327,15 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
|||||||
width: '60vw',
|
width: '60vw',
|
||||||
data: jump
|
data: jump
|
||||||
});
|
});
|
||||||
dialogRef.afterClosed().pipe(take(1))
|
this._subscriptions.push(
|
||||||
|
dialogRef.afterClosed()
|
||||||
|
.pipe(take(1))
|
||||||
.subscribe(result => {
|
.subscribe(result => {
|
||||||
if (result != undefined) {
|
if (result != undefined) {
|
||||||
this._onDelete(result.slug);
|
this._onDelete(result.slug);
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
openEditDialog(jump: Jump): void {
|
openEditDialog(jump: Jump): void {
|
||||||
@@ -196,12 +343,15 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
|||||||
width: '70vw',
|
width: '70vw',
|
||||||
data: jump
|
data: jump
|
||||||
});
|
});
|
||||||
dialogRef.afterClosed().pipe(take(1))
|
this._subscriptions.push(
|
||||||
|
dialogRef.afterClosed()
|
||||||
|
.pipe(take(1))
|
||||||
.subscribe(result => {
|
.subscribe(result => {
|
||||||
if (result != undefined) {
|
if (result != undefined) {
|
||||||
this._onEdit(result);
|
this._onEdit(result);
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
openViewDialog(jump: Jump): void {
|
openViewDialog(jump: Jump): void {
|
||||||
@@ -230,6 +380,7 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
|||||||
private _onDelete(slug: string): void {
|
private _onDelete(slug: string): void {
|
||||||
try {
|
try {
|
||||||
this.isDeleting = true;
|
this.isDeleting = true;
|
||||||
|
this._subscriptions.push(
|
||||||
this._jumpsService.destroy(slug)
|
this._jumpsService.destroy(slug)
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe({
|
.subscribe({
|
||||||
@@ -243,7 +394,8 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
|||||||
error: (err) => {
|
error: (err) => {
|
||||||
this.errors = err;
|
this.errors = err;
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
@@ -252,6 +404,7 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
|||||||
private _onEdit(jump: Jump): void {
|
private _onEdit(jump: Jump): void {
|
||||||
try {
|
try {
|
||||||
this.isSubmitting = true;
|
this.isSubmitting = true;
|
||||||
|
this._subscriptions.push(
|
||||||
this._jumpsService.update(jump)
|
this._jumpsService.update(jump)
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe({
|
.subscribe({
|
||||||
@@ -266,7 +419,8 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
|||||||
this.errors = err;
|
this.errors = err;
|
||||||
this.isSubmitting = false;
|
this.isSubmitting = false;
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<mat-toolbar class="topbar bg-primary">
|
<mat-toolbar class="topbar bg-primary">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<a class="navbar-brand" href="index.html">
|
<a class="navbar-brand" href="/">
|
||||||
<span class="logo">
|
<span class="logo">
|
||||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="190px" height="33px" viewBox="0 0 190 33" enable-background="new 0 0 190 33" xml:space="preserve">
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="190px" height="33px" viewBox="0 0 190 33" enable-background="new 0 0 190 33" xml:space="preserve">
|
||||||
<path id="Jumper_2" fill="#FFFFFF"
|
<path id="Jumper_2" fill="#FFFFFF"
|
||||||
@@ -281,8 +281,8 @@
|
|||||||
<app-layout-footer></app-layout-footer>
|
<app-layout-footer></app-layout-footer>
|
||||||
</mat-sidenav>
|
</mat-sidenav>
|
||||||
<mat-sidenav-content class="page-wrapper">
|
<mat-sidenav-content class="page-wrapper">
|
||||||
<div class="page-content">
|
<!--<div class="page-content">-->
|
||||||
<router-outlet><!--<app-spinner></app-spinner>--></router-outlet>
|
<router-outlet><!--<app-spinner></app-spinner>--></router-outlet>
|
||||||
</div>
|
<!--</div>-->
|
||||||
</mat-sidenav-content>
|
</mat-sidenav-content>
|
||||||
</mat-sidenav-container>
|
</mat-sidenav-container>
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
|
import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
|
||||||
|
|
||||||
import { Router, RouterOutlet, RouterModule } from '@angular/router';
|
import { Router, RouterOutlet, RouterModule } from '@angular/router';
|
||||||
import { MediaMatcher } from '@angular/cdk/layout';
|
import { MediaMatcher } from '@angular/cdk/layout';
|
||||||
import { MatBadgeModule } from '@angular/material/badge';
|
import { MatBadgeModule } from '@angular/material/badge';
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -13,12 +13,17 @@ const MENUITEMS: Menu[] = [
|
|||||||
{ state: 'logbook', type: 'link', name: 'Carnet de saut', icon: 'assignment_turned_in', desc: '' },
|
{ state: 'logbook', type: 'link', name: 'Carnet de saut', icon: 'assignment_turned_in', desc: '' },
|
||||||
{ state: 'aeronef', type: 'link', name: 'Aéronefs', icon: 'flight', desc: '' },
|
{ state: 'aeronef', type: 'link', name: 'Aéronefs', icon: 'flight', desc: '' },
|
||||||
{ state: 'canopy', type: 'link', name: 'Voiles', icon: 'paragliding', desc: '' },
|
{ state: 'canopy', type: 'link', name: 'Voiles', icon: 'paragliding', desc: '' },
|
||||||
{ state: 'dropzone', type: 'link', name: 'Dropzones', icon: 'adjust', desc: '' },
|
{ state: 'dropzone', type: 'link', name: 'Drop Zones', icon: 'flight_takeoff', desc: '' },
|
||||||
{ state: 'jump', type: 'link', name: 'Sauts', icon: 'cloud_download', desc: '' },
|
{ state: 'jumps', type: 'link', name: 'Sauts', icon: 'cloud', desc: '' },
|
||||||
{ state: 'calculator', type: 'link', name: 'Taille de voile', icon: 'calculate', desc: '' },
|
{ state: 'calculator', type: 'link', name: 'Taille de voile', icon: 'calculate', desc: '' },
|
||||||
{ state: 'qcm', type: 'menu', name: 'QCM Brevets', icon: 'rule_folder', desc: '' }
|
{ state: 'qcm', type: 'menu', name: 'QCM Brevets', icon: 'rule_folder', desc: '' }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const MENUPJUMP: Menu[] = [
|
||||||
|
{ state: '#', type: 'link', name: 'Modifier', icon: 'edit', desc: '', color: 'primary' },
|
||||||
|
{ state: '#', type: 'link', name: 'Supprimer', icon: 'delete', desc: '', color: 'raspberry' }
|
||||||
|
];
|
||||||
|
|
||||||
const MENUQCM: Menu[] = [
|
const MENUQCM: Menu[] = [
|
||||||
{ state: 'bpa', type: 'link', name: 'BPA', icon: 'rule' },
|
{ state: 'bpa', type: 'link', name: 'BPA', icon: 'rule' },
|
||||||
{ state: 'c', type: 'link', name: 'Brevet C', icon: 'rule' },
|
{ state: 'c', type: 'link', name: 'Brevet C', icon: 'rule' },
|
||||||
@@ -63,4 +68,7 @@ export class MenuItems {
|
|||||||
getMenuPanel(): Menu[] {
|
getMenuPanel(): Menu[] {
|
||||||
return MENUPANEL;
|
return MENUPANEL;
|
||||||
}
|
}
|
||||||
|
getMenuJump(): Menu[] {
|
||||||
|
return MENUPJUMP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ export * from './calculator.model';
|
|||||||
export * from './canopy.model';
|
export * from './canopy.model';
|
||||||
export * from './canopysize.model';
|
export * from './canopysize.model';
|
||||||
export * from './chart.model';
|
export * from './chart.model';
|
||||||
export * from './reducerow.model';
|
|
||||||
export * from './dropzone.model';
|
export * from './dropzone.model';
|
||||||
export * from './errors.model';
|
export * from './errors.model';
|
||||||
export * from './jump.model';
|
export * from './jump.model';
|
||||||
@@ -14,4 +13,5 @@ export * from './jump-list.model';
|
|||||||
export * from './jump-list-config.model';
|
export * from './jump-list-config.model';
|
||||||
export * from './profile.model';
|
export * from './profile.model';
|
||||||
export * from './qcm.model';
|
export * from './qcm.model';
|
||||||
|
export * from './shared.model';
|
||||||
export * from './user.model';
|
export * from './user.model';
|
||||||
|
|||||||
@@ -33,4 +33,6 @@ export interface JumpListFilters {
|
|||||||
hauteurRangeEnd?: number;
|
hauteurRangeEnd?: number;
|
||||||
yearRangeStart?: number;
|
yearRangeStart?: number;
|
||||||
yearRangeEnd?: number;
|
yearRangeEnd?: number;
|
||||||
|
dateRangeStart?: string;
|
||||||
|
dateRangeEnd?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { FormControl } from '@angular/forms';
|
import { FormControl } from '@angular/forms';
|
||||||
|
|
||||||
import { Profile } from './profile.model';
|
import { Profile } from './profile.model';
|
||||||
|
import { PageLinks, PageMeta } from './shared.model';
|
||||||
|
|
||||||
export interface Jump {
|
export interface Jump {
|
||||||
slug: string;
|
slug: string;
|
||||||
@@ -23,12 +24,26 @@ export interface Jump {
|
|||||||
zone?: string;
|
zone?: string;
|
||||||
dossier?: string;
|
dossier?: string;
|
||||||
video?: string;
|
video?: string;
|
||||||
|
files: Array<JumpFile>;
|
||||||
|
x2data: X2Data;
|
||||||
author: Profile;
|
author: Profile;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
//isEdit?: boolean;
|
//isEdit?: boolean;
|
||||||
isSelected?: boolean;
|
isSelected?: boolean;
|
||||||
}
|
}
|
||||||
|
export enum JumpFileType {
|
||||||
|
CSV = "csv",
|
||||||
|
IMAGE = "image",
|
||||||
|
KML = "kml",
|
||||||
|
VIDEO = "video",
|
||||||
|
}
|
||||||
|
export interface JumpFile {
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
path: string;
|
||||||
|
type: JumpFileType;
|
||||||
|
}
|
||||||
|
|
||||||
export interface JumpForm {
|
export interface JumpForm {
|
||||||
date: FormControl<string>;
|
date: FormControl<string>;
|
||||||
@@ -69,6 +84,11 @@ export interface JumpByCategorie {
|
|||||||
count: number;
|
count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface JumpByDay {
|
||||||
|
jumps: Array<Partial<Jump>>;
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface JumpByModule {
|
export interface JumpByModule {
|
||||||
categorie: string;
|
categorie: string;
|
||||||
module: string;
|
module: string;
|
||||||
@@ -88,12 +108,89 @@ export interface JumpYears {
|
|||||||
count: number;
|
count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SkydiverIdJumps {
|
||||||
|
items: Array<X2Data>;
|
||||||
|
_links: PageLinks;
|
||||||
|
_meta: PageMeta;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface X2Data {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
description: string;
|
||||||
|
landingZone: string;
|
||||||
|
speed: {
|
||||||
|
freeFall: {
|
||||||
|
vertical: {
|
||||||
|
max: number;
|
||||||
|
avg: number;
|
||||||
|
};
|
||||||
|
horizontal: {
|
||||||
|
max: number;
|
||||||
|
avg: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
underCanopy: {
|
||||||
|
vertical: {
|
||||||
|
max: number;
|
||||||
|
avg: number;
|
||||||
|
};
|
||||||
|
horizontal: {
|
||||||
|
max: number;
|
||||||
|
avg: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
glideRatio: {
|
||||||
|
freeFall: {
|
||||||
|
max: number;
|
||||||
|
avg: number;
|
||||||
|
};
|
||||||
|
underCanopy: {
|
||||||
|
max: number;
|
||||||
|
avg: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
duration: {
|
||||||
|
freeFall: number;
|
||||||
|
underCanopy: number;
|
||||||
|
};
|
||||||
|
distance: {
|
||||||
|
exitFromLandingZone: number;
|
||||||
|
totalFlying: number;
|
||||||
|
totalHorizontal: number;
|
||||||
|
};
|
||||||
|
altitude: {
|
||||||
|
exit: number;
|
||||||
|
deployment: number;
|
||||||
|
};
|
||||||
|
cutaway: string;
|
||||||
|
malfunctions:Array<
|
||||||
|
{
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
date: string;
|
||||||
|
createdOn: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface JumpPageData {
|
||||||
|
jump: Jump;
|
||||||
|
prevJump: Jump;
|
||||||
|
nextJump: Jump;
|
||||||
|
_links: PageLinks;
|
||||||
|
_meta: PageMeta;
|
||||||
|
}
|
||||||
|
|
||||||
export interface JumpsPageData {
|
export interface JumpsPageData {
|
||||||
jumpsByCategory: Array<JumpByCategorie>;
|
jumpsByCategory: Array<JumpByCategorie>;
|
||||||
jumpsByDate: Array<JumpByDate>;
|
jumpsByDate: Array<JumpByDate>;
|
||||||
jumpsByDateByModule: Array<JumpByDateByModule>;
|
jumpsByDateByModule: Array<JumpByDateByModule>;
|
||||||
jumpsByModule: Array<JumpByModule>;
|
jumpsByModule: Array<JumpByModule>;
|
||||||
jumpsByYears: Array<JumpYears>;
|
jumpsByYears: Array<JumpYears>;
|
||||||
|
//jumpsFromSkydiverIdApi: SkydiverIdJumps;
|
||||||
lastjump: Jump;
|
lastjump: Jump;
|
||||||
/*yearsCount: number;
|
/*yearsCount: number;
|
||||||
jumpsByCategoryCount: number;
|
jumpsByCategoryCount: number;
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ export interface Menu {
|
|||||||
icon: string;
|
icon: string;
|
||||||
desc?: string;
|
desc?: string;
|
||||||
badge?: Badge[];
|
badge?: Badge[];
|
||||||
|
color?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
export interface PageLinks {
|
||||||
|
self: {
|
||||||
|
href: string;
|
||||||
|
};
|
||||||
|
first: {
|
||||||
|
href: string;
|
||||||
|
};
|
||||||
|
last: {
|
||||||
|
href: string;
|
||||||
|
};
|
||||||
|
prev: {
|
||||||
|
href: string;
|
||||||
|
};
|
||||||
|
next: {
|
||||||
|
href: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PageMeta {
|
||||||
|
totalCount: number;
|
||||||
|
pageCount: number;
|
||||||
|
currentPage: number;
|
||||||
|
perPage: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ReduceRow {
|
||||||
|
key: string[];
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
@@ -2,10 +2,10 @@ import { inject } from '@angular/core';
|
|||||||
import { ActivatedRouteSnapshot, ResolveFn } from '@angular/router';
|
import { ActivatedRouteSnapshot, ResolveFn } from '@angular/router';
|
||||||
import { take } from 'rxjs/operators';
|
import { take } from 'rxjs/operators';
|
||||||
|
|
||||||
import { Jump } from 'src/app/core/models';
|
import { JumpPageData } from 'src/app/core/models';
|
||||||
import { JumpsService } from 'src/app/core/services';
|
import { JumpsService } from 'src/app/core/services';
|
||||||
|
|
||||||
export const jumpResolver: ResolveFn<Jump> = (
|
export const jumpResolver: ResolveFn<JumpPageData> = (
|
||||||
route: ActivatedRouteSnapshot
|
route: ActivatedRouteSnapshot
|
||||||
) => {
|
) => {
|
||||||
return inject(JumpsService).get(route.params['slug']).pipe(take(1));
|
return inject(JumpsService).get(route.params['slug']).pipe(take(1));
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ export class ApplicationsService {
|
|||||||
return this.apiService
|
return this.apiService
|
||||||
.get(
|
.get(
|
||||||
'/applications' + ((config.type === 'feed') ? '/feed' : ''),
|
'/applications' + ((config.type === 'feed') ? '/feed' : ''),
|
||||||
new HttpParams({ fromObject: <any>params })
|
new HttpParams({ fromObject: <{
|
||||||
|
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
|
||||||
|
}>params })
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ export class CalculatorService {
|
|||||||
|
|
||||||
private _getTableLine(weight: number): number {
|
private _getTableLine(weight: number): number {
|
||||||
let line: number;
|
let line: number;
|
||||||
let min = 60;
|
const min = 60;
|
||||||
let max = 110;
|
const max = 110;
|
||||||
if (weight < min) {
|
if (weight < min) {
|
||||||
line = min;
|
line = min;
|
||||||
} else if (weight > max) {
|
} else if (weight > max) {
|
||||||
@@ -52,14 +52,14 @@ export class CalculatorService {
|
|||||||
/* const maxRange = 2000; */
|
/* const maxRange = 2000; */
|
||||||
/* DT48 - 08 février 2024 */
|
/* DT48 - 08 février 2024 */
|
||||||
const maxRange = 1600;
|
const maxRange = 1600;
|
||||||
let result: CalculatorResult = {
|
const result: CalculatorResult = {
|
||||||
min: 59,
|
min: 59,
|
||||||
min11: 34
|
min11: 34
|
||||||
};
|
};
|
||||||
if (jumps > maxRange) {
|
if (jumps > maxRange) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
let index: number = (this._getTableLine(weight) - this._getTableLine(0));
|
const index: number = (this._getTableLine(weight) - this._getTableLine(0));
|
||||||
result.min = weightSizes[index].ranges[this._getTableColumn(jumps)].value!;
|
result.min = weightSizes[index].ranges[this._getTableColumn(jumps)].value!;
|
||||||
result.min11 = this._reduceLimit(result.min, 11);
|
result.min11 = this._reduceLimit(result.min, 11);
|
||||||
|
|
||||||
@@ -71,16 +71,14 @@ export class CalculatorService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getCanopySizes(weight: number, reduce = false): number[] {
|
public getCanopySizes(weight: number, reduce = false): number[] {
|
||||||
var data: number[] = [];
|
|
||||||
if (weight < 60) {
|
if (weight < 60) {
|
||||||
weight = 60;
|
weight = 60;
|
||||||
}
|
}
|
||||||
if (weight > 110) {
|
if (weight > 110) {
|
||||||
weight = 110;
|
weight = 110;
|
||||||
}
|
}
|
||||||
if (weight >= 60 && weight <= 110) {
|
|
||||||
const line = (weight - this._getTableLine(0));
|
const line = (weight - this._getTableLine(0));
|
||||||
let data = weightSizes[line];
|
const data = weightSizes[line];
|
||||||
if (reduce) {
|
if (reduce) {
|
||||||
return data.ranges.map((range: WeightSizeRange): number => {
|
return data.ranges.map((range: WeightSizeRange): number => {
|
||||||
return Math.ceil(range.value! * (100 - 11) / 100);
|
return Math.ceil(range.value! * (100 - 11) / 100);
|
||||||
@@ -91,15 +89,13 @@ export class CalculatorService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getCharge(canopySize: number, nakedWeight: number, equipementWeight: number): number {
|
public getCharge(canopySize: number, nakedWeight: number, equipementWeight: number): number {
|
||||||
return (((nakedWeight + equipementWeight) * this.coeffKgLbs) / canopySize);
|
return (((nakedWeight + equipementWeight) * this.coeffKgLbs) / canopySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getRangeNum(jumps: number): number {
|
public getRangeNum(jumps: number): number {
|
||||||
let data: WeightSizeRange[] = weightSizes[0].ranges;
|
const data: WeightSizeRange[] = weightSizes[0].ranges;
|
||||||
let num: number = 1;
|
let num: number = 1;
|
||||||
/* DT48 - 13 mars 2020 */
|
/* DT48 - 13 mars 2020 */
|
||||||
/* const maxRange = 2000; */
|
/* const maxRange = 2000; */
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ export class JumpTableService {
|
|||||||
_jumpRefreshBS = new BehaviorSubject<boolean>(false);
|
_jumpRefreshBS = new BehaviorSubject<boolean>(false);
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.tableRefresh = false;;
|
this.tableRefresh = false;
|
||||||
this.jumpRefresh = false;;
|
this.jumpRefresh = false;
|
||||||
|
|
||||||
//this._tableRefreshBS.next(this.tableRefresh);
|
//this._tableRefreshBS.next(this.tableRefresh);
|
||||||
//this._jumpRefreshBS.next(this.jumpRefresh);
|
//this._jumpRefreshBS.next(this.jumpRefresh);
|
||||||
|
|||||||
@@ -4,7 +4,11 @@ import { Observable } from 'rxjs';
|
|||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
import { ApiService } from './api.service';
|
import { ApiService } from './api.service';
|
||||||
import { Jump, JumpByCategorie, JumpByDate, JumpByModule, JumpList, JumpListConfig, JumpListFilters } from 'src/app/core/models';
|
import {
|
||||||
|
Jump, JumpByCategorie, JumpByDate, JumpByDay, JumpByModule, JumpFile,
|
||||||
|
JumpList, JumpListConfig, JumpListFilters, JumpPageData,
|
||||||
|
X2Data, SkydiverIdJumps
|
||||||
|
} from 'src/app/core/models';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class JumpsService {
|
export class JumpsService {
|
||||||
@@ -44,52 +48,67 @@ export class JumpsService {
|
|||||||
*/
|
*/
|
||||||
const params: JumpListFilters = {} as JumpListFilters;
|
const params: JumpListFilters = {} as JumpListFilters;
|
||||||
Object.assign(params, config.filters);
|
Object.assign(params, config.filters);
|
||||||
|
|
||||||
return this.apiService
|
return this.apiService
|
||||||
.get(
|
.get(
|
||||||
'/jumps' + ((config.type === 'feed') ? '/feed' : ''),
|
'/jumps' + ((config.type === 'feed') ? '/feed' : ''),
|
||||||
new HttpParams({ fromObject: <any>params })
|
new HttpParams({ fromObject: <{
|
||||||
|
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
|
||||||
|
}>params })
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get(slug: string): Observable<Jump> {
|
get(slug: string): Observable<JumpPageData> {
|
||||||
return this.apiService.get(`/jumps/${slug}`)
|
/* return this.apiService.get(`/jumps/${slug}`)
|
||||||
.pipe(map(data => data.jump));
|
.pipe(map(data => {
|
||||||
|
return { jump: data.jump, prevJump: data.prevJump, nextJump: data.nextJump };
|
||||||
|
})); */
|
||||||
|
return this.apiService.get(`/jumps/${slug}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
getAll(): Observable<[Jump]> {
|
getAll(): Observable<Array<Jump>> {
|
||||||
return this.apiService.get('/jumps')
|
return this.apiService.get('/jumps').pipe(map(data => data.jumps));
|
||||||
.pipe(map(data => data.jumps));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllByDate(): Observable<Array<JumpByDate>> {
|
getAllByDate(): Observable<Array<JumpByDate>> {
|
||||||
return this.apiService.get('/jumps/allByDate')
|
return this.apiService.get('/jumps/allByDate').pipe(map(data => data.jumps));
|
||||||
.pipe(map(data => data.jumps));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllByCategorie(): Observable<Array<JumpByCategorie>> {
|
getAllByCategorie(): Observable<Array<JumpByCategorie>> {
|
||||||
return this.apiService.get('/jumps/allByCategorie')
|
return this.apiService.get('/jumps/allByCategorie').pipe(map(data => data.jumps));
|
||||||
.pipe(map(data => data.jumps));
|
}
|
||||||
|
|
||||||
|
getAllByDay(config: JumpListConfig): Observable<Array<JumpByDay>> {
|
||||||
|
const params: JumpListFilters = {} as JumpListFilters;
|
||||||
|
Object.assign(params, config.filters);
|
||||||
|
return this.apiService.get('/jumps/allByDay', new HttpParams({ fromObject: <{
|
||||||
|
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
|
||||||
|
}>params }))
|
||||||
|
.pipe(map(data => data.days));
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllByModule(): Observable<Array<JumpByModule>> {
|
getAllByModule(): Observable<Array<JumpByModule>> {
|
||||||
return this.apiService.get('/jumps/allByModule')
|
return this.apiService.get('/jumps/allByModule').pipe(map(data => data.jumps));
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllFromSkydiverIdApi(config: JumpListConfig): Observable<SkydiverIdJumps> {
|
||||||
|
const params: JumpListFilters = {} as JumpListFilters;
|
||||||
|
Object.assign(params, config.filters);
|
||||||
|
return this.apiService.get('/jumps/allFromSkydiverIdApi', new HttpParams({ fromObject: <{
|
||||||
|
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
|
||||||
|
}>params }))
|
||||||
.pipe(map(data => data.jumps));
|
.pipe(map(data => data.jumps));
|
||||||
}
|
}
|
||||||
|
|
||||||
getLastJump(): Observable<Jump> {
|
getLastJump(): Observable<Jump> {
|
||||||
return this.apiService.get('/jumps/last')
|
return this.apiService.get('/jumps/last').pipe(map(data => data.jump));
|
||||||
.pipe(map(data => data.jump));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
create(jump: Jump): Observable<Jump> {
|
create(jump: Jump): Observable<Jump> {
|
||||||
return this.apiService.post('/jumps/', { jump: jump })
|
return this.apiService.post('/jumps/', { jump: jump }).pipe(map(data => data.jump));
|
||||||
.pipe(map(data => data.jump));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update(jump: Jump): Observable<Jump> {
|
update(jump: Jump): Observable<Jump> {
|
||||||
return this.apiService.put(`/jumps/${jump.slug}`, { jump: jump })
|
return this.apiService.put(`/jumps/${jump.slug}`, { jump: jump }).pipe(map(data => data.jump));
|
||||||
.pipe(map(data => data.jump));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy(slug: string) {
|
destroy(slug: string) {
|
||||||
@@ -99,14 +118,27 @@ export class JumpsService {
|
|||||||
save(jump: Jump): Observable<Jump> {
|
save(jump: Jump): Observable<Jump> {
|
||||||
// If we're updating an existing jump
|
// If we're updating an existing jump
|
||||||
if (jump.slug) {
|
if (jump.slug) {
|
||||||
return this.apiService.put('/jumps/' + jump.slug, { jump: jump })
|
return this.apiService.put(`/jumps/${jump.slug}`, { jump: jump }).pipe(map(data => data.jump));
|
||||||
.pipe(map(data => data.jump));
|
|
||||||
|
|
||||||
// Otherwise, create a new jump
|
// Otherwise, create a new jump
|
||||||
} else {
|
} else {
|
||||||
return this.apiService.post('/jumps/', { jump: jump })
|
return this.apiService.post('/jumps/', { jump: jump }).pipe(map(data => data.jump));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveX2Data(slug: string, file: JumpFile, data: X2Data): Observable<Jump> {
|
||||||
|
return this.apiService.post(`/jumps/data/${slug}`, { file: file, data: data })
|
||||||
.pipe(map(data => data.jump));
|
.pipe(map(data => data.jump));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
saveFile(slug: string, file: JumpFile): Observable<JumpFile> {
|
||||||
|
return this.apiService.post(`/jumps/file/${slug}`, { file: file })
|
||||||
|
.pipe(map(data => data.file));
|
||||||
|
}
|
||||||
|
|
||||||
|
saveKml(slug: string, file: JumpFile): Observable<JumpFile> {
|
||||||
|
return this.apiService.post(`/jumps/kml/${slug}`, { file: file })
|
||||||
|
.pipe(map(data => data.file));
|
||||||
}
|
}
|
||||||
|
|
||||||
getAeronefs() {
|
getAeronefs() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { BubbleDataPoint, Chart, ChartTypeRegistry, Point } from 'chart.js';
|
import { Chart } from 'chart.js';
|
||||||
import { Configuration } from 'ng-chartist';
|
import { Configuration } from 'ng-chartist';
|
||||||
|
|
||||||
import { BarConfig, CircleConfig, DoughnutConfig, LineConfig } from 'src/app/core/models';
|
import { BarConfig, CircleConfig, DoughnutConfig, LineConfig } from 'src/app/core/models';
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ import { Routes } from '@angular/router';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
AeronefComponent, CalculatorComponent, CanopyComponent, CredentialsComponent,
|
AeronefComponent, CalculatorComponent, CanopyComponent, CredentialsComponent,
|
||||||
DashboardComponent, DropzoneComponent, JumpComponent, LogbookComponent,
|
DashboardComponent, DropzoneComponent, JumpComponent, JumpsComponent,
|
||||||
ProfileComponent, QcmComponent, SettingsComponent
|
LogbookComponent, ProfileComponent, QcmComponent, SettingsComponent
|
||||||
} from 'src/app/components';
|
} from 'src/app/components';
|
||||||
import { authGuard } from 'src/app/core/guards';
|
import { authGuard } from 'src/app/core/guards';
|
||||||
import {
|
import {
|
||||||
aeronefsPageResolver, authResolver, canopiesPageResolver, dropZonesPageResolver,
|
aeronefsPageResolver, authResolver, canopiesPageResolver, dropZonesPageResolver,
|
||||||
jumpsPageResolver, lastjumpResolver, profileResolver, qcmResolver
|
jumpResolver, jumpsPageResolver, lastjumpResolver, profileResolver, qcmResolver
|
||||||
} from 'src/app/core/resolvers';
|
} from 'src/app/core/resolvers';
|
||||||
|
|
||||||
export const AUTH_ROUTES: Routes = [
|
export const AUTH_ROUTES: Routes = [
|
||||||
@@ -53,19 +53,20 @@ export const AUTH_ROUTES: Routes = [
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'jump',
|
path: 'jumps',
|
||||||
|
component: JumpsComponent,
|
||||||
|
canActivate: [ authGuard ],
|
||||||
|
resolve: {
|
||||||
|
pageData: jumpsPageResolver
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'jump/:slug',
|
||||||
component: JumpComponent,
|
component: JumpComponent,
|
||||||
canActivate: [ authGuard ],
|
canActivate: [ authGuard ],
|
||||||
resolve: {
|
resolve: {
|
||||||
jumpsPageData: jumpsPageResolver
|
pageData: jumpResolver
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: ':slug',
|
|
||||||
component: JumpComponent,
|
|
||||||
canActivate: [ authGuard ]
|
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'logbook',
|
path: 'logbook',
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 982 241" style="width: max(calc(700 * min(100vw, 2560px) / 1470), 350px); height: auto;">
|
||||||
|
<g clip-path="url(#wordmark_a)">
|
||||||
|
<path fill="url(#wordmark_b)" d="M388.676 191.625h30.849L363.31 31.828h-35.758l-56.215 159.797h30.848l13.174-39.356h60.061l13.256 39.356Zm-65.461-62.675 21.602-64.311h1.227l21.603 64.311h-44.432Zm126.831-7.527v70.202h-28.23V71.839h27.002v20.374h1.392c2.782-6.71 7.2-12.028 13.255-15.956 6.056-3.927 13.584-5.89 22.503-5.89 8.264 0 15.465 1.8 21.684 5.318 6.137 3.518 10.964 8.673 14.319 15.382 3.437 6.71 5.074 14.81 4.992 24.383v76.175h-28.23v-71.92c0-8.019-2.046-14.237-6.219-18.819-4.173-4.5-9.819-6.791-17.102-6.791-4.91 0-9.328 1.063-13.174 3.272-3.846 2.128-6.792 5.237-9.001 9.328-2.046 4.009-3.191 8.918-3.191 14.728ZM589.233 239c-10.147 0-18.82-1.391-26.103-4.091-7.282-2.7-13.092-6.382-17.511-10.964-4.418-4.582-7.528-9.655-9.164-15.219l25.448-6.136c1.145 2.372 2.782 4.663 4.991 6.954 2.209 2.291 5.155 4.255 8.837 5.81 3.683 1.554 8.428 2.291 14.074 2.291 8.019 0 14.647-1.964 19.884-5.81 5.237-3.845 7.856-10.227 7.856-19.064v-22.665h-1.391c-1.473 2.946-3.601 5.892-6.383 9.001-2.782 3.109-6.464 5.645-10.965 7.691-4.582 2.046-10.228 3.109-17.101 3.109-9.165 0-17.511-2.209-25.039-6.545-7.446-4.337-13.42-10.883-17.757-19.474-4.418-8.673-6.628-19.473-6.628-32.565 0-13.091 2.21-24.301 6.628-33.383 4.419-9.082 10.311-15.955 17.839-20.7 7.528-4.746 15.874-7.037 25.038-7.037 7.038 0 12.847 1.145 17.348 3.518 4.582 2.373 8.182 5.236 10.883 8.51 2.7 3.272 4.746 6.382 6.137 9.327h1.554v-19.8h27.821v121.749c0 10.228-2.454 18.737-7.364 25.447-4.91 6.709-11.538 11.7-20.048 15.055-8.509 3.355-18.165 4.991-28.884 4.991Zm.245-71.266c5.974 0 11.047-1.473 15.302-4.337 4.173-2.945 7.446-7.118 9.573-12.519 2.21-5.482 3.274-12.027 3.274-19.637 0-7.609-1.064-14.155-3.274-19.8-2.127-5.646-5.318-10.064-9.491-13.255-4.174-3.11-9.329-4.746-15.384-4.746s-11.537 1.636-15.792 4.91c-4.173 3.272-7.365 7.772-9.492 13.418-2.128 5.727-3.191 12.191-3.191 19.392 0 7.2 1.063 13.746 3.273 19.228 2.127 5.482 5.318 9.736 9.573 12.764 4.174 3.027 9.41 4.582 15.629 4.582Zm141.56-26.51V71.839h28.23v119.786h-27.412v-21.273h-1.227c-2.7 6.709-7.119 12.191-13.338 16.446-6.137 4.255-13.747 6.382-22.748 6.382-7.855 0-14.81-1.718-20.783-5.237-5.974-3.518-10.72-8.591-14.075-15.382-3.355-6.709-5.073-14.891-5.073-24.464V71.839h28.312v71.921c0 7.609 2.046 13.664 6.219 18.083 4.173 4.5 9.655 6.709 16.365 6.709 4.173 0 8.183-.982 12.111-3.028 3.927-2.045 7.118-5.072 9.655-9.082 2.537-4.091 3.764-9.164 3.764-15.218Zm65.707-109.395v159.796h-28.23V31.828h28.23Zm44.841 162.169c-7.61 0-14.402-1.391-20.457-4.091-6.055-2.7-10.883-6.791-14.32-12.109-3.518-5.319-5.237-11.946-5.237-19.801 0-6.791 1.228-12.355 3.765-16.773 2.536-4.419 5.891-7.937 10.228-10.637 4.337-2.619 9.164-4.664 14.647-6.055 5.4-1.391 11.046-2.373 16.856-3.027 7.037-.737 12.683-1.391 17.102-1.964 4.337-.573 7.528-1.555 9.574-2.782 1.963-1.309 3.027-3.273 3.027-5.973v-.491c0-5.891-1.718-10.391-5.237-13.664-3.518-3.191-8.51-4.828-15.056-4.828-6.955 0-12.356 1.473-16.447 4.5-4.01 3.028-6.71 6.546-8.183 10.719l-26.348-3.764c2.046-7.282 5.483-13.336 10.31-18.328 4.746-4.909 10.638-8.59 17.511-11.045 6.955-2.455 14.565-3.682 22.912-3.682 5.809 0 11.537.654 17.265 2.045s10.965 3.6 15.711 6.71c4.746 3.109 8.51 7.282 11.455 12.6 2.864 5.318 4.337 11.946 4.337 19.883v80.184h-27.166v-16.446h-.9c-1.719 3.355-4.091 6.464-7.201 9.328-3.109 2.864-6.955 5.237-11.619 6.955-4.828 1.718-10.229 2.536-16.529 2.536Zm7.364-20.701c5.646 0 10.556-1.145 14.729-3.354 4.173-2.291 7.364-5.237 9.655-9.001 2.292-3.763 3.355-7.854 3.355-12.273v-14.155c-.9.737-2.373 1.391-4.5 2.046-2.128.654-4.419 1.145-7.037 1.636-2.619.491-5.155.9-7.692 1.227-2.537.328-4.746.655-6.628.901-4.173.572-8.019 1.472-11.292 2.781-3.355 1.31-5.973 3.11-7.855 5.401-1.964 2.291-2.864 5.318-2.864 8.918 0 5.237 1.882 9.164 5.728 11.782 3.682 2.782 8.51 4.091 14.401 4.091Zm64.643 18.328V71.839h27.412v19.965h1.227c2.21-6.955 5.974-12.274 11.292-16.038 5.319-3.763 11.456-5.645 18.329-5.645 1.555 0 3.355.082 5.237.163 1.964.164 3.601.328 4.91.573v25.938c-1.227-.41-3.109-.819-5.646-1.146a58.815 58.815 0 0 0-7.446-.49c-5.155 0-9.738 1.145-13.829 3.354-4.091 2.209-7.282 5.236-9.655 9.164-2.373 3.927-3.519 8.427-3.519 13.5v70.448h-28.312ZM222.077 39.192l-8.019 125.923L137.387 0l84.69 39.192Zm-53.105 162.825-57.933 33.056-57.934-33.056 11.783-28.556h92.301l11.783 28.556ZM111.039 62.675l30.357 73.803H80.681l30.358-73.803ZM7.937 165.115 0 39.192 84.69 0 7.937 165.115Z"></path>
|
||||||
|
<path fill="url(#wordmark_c)" d="M388.676 191.625h30.849L363.31 31.828h-35.758l-56.215 159.797h30.848l13.174-39.356h60.061l13.256 39.356Zm-65.461-62.675 21.602-64.311h1.227l21.603 64.311h-44.432Zm126.831-7.527v70.202h-28.23V71.839h27.002v20.374h1.392c2.782-6.71 7.2-12.028 13.255-15.956 6.056-3.927 13.584-5.89 22.503-5.89 8.264 0 15.465 1.8 21.684 5.318 6.137 3.518 10.964 8.673 14.319 15.382 3.437 6.71 5.074 14.81 4.992 24.383v76.175h-28.23v-71.92c0-8.019-2.046-14.237-6.219-18.819-4.173-4.5-9.819-6.791-17.102-6.791-4.91 0-9.328 1.063-13.174 3.272-3.846 2.128-6.792 5.237-9.001 9.328-2.046 4.009-3.191 8.918-3.191 14.728ZM589.233 239c-10.147 0-18.82-1.391-26.103-4.091-7.282-2.7-13.092-6.382-17.511-10.964-4.418-4.582-7.528-9.655-9.164-15.219l25.448-6.136c1.145 2.372 2.782 4.663 4.991 6.954 2.209 2.291 5.155 4.255 8.837 5.81 3.683 1.554 8.428 2.291 14.074 2.291 8.019 0 14.647-1.964 19.884-5.81 5.237-3.845 7.856-10.227 7.856-19.064v-22.665h-1.391c-1.473 2.946-3.601 5.892-6.383 9.001-2.782 3.109-6.464 5.645-10.965 7.691-4.582 2.046-10.228 3.109-17.101 3.109-9.165 0-17.511-2.209-25.039-6.545-7.446-4.337-13.42-10.883-17.757-19.474-4.418-8.673-6.628-19.473-6.628-32.565 0-13.091 2.21-24.301 6.628-33.383 4.419-9.082 10.311-15.955 17.839-20.7 7.528-4.746 15.874-7.037 25.038-7.037 7.038 0 12.847 1.145 17.348 3.518 4.582 2.373 8.182 5.236 10.883 8.51 2.7 3.272 4.746 6.382 6.137 9.327h1.554v-19.8h27.821v121.749c0 10.228-2.454 18.737-7.364 25.447-4.91 6.709-11.538 11.7-20.048 15.055-8.509 3.355-18.165 4.991-28.884 4.991Zm.245-71.266c5.974 0 11.047-1.473 15.302-4.337 4.173-2.945 7.446-7.118 9.573-12.519 2.21-5.482 3.274-12.027 3.274-19.637 0-7.609-1.064-14.155-3.274-19.8-2.127-5.646-5.318-10.064-9.491-13.255-4.174-3.11-9.329-4.746-15.384-4.746s-11.537 1.636-15.792 4.91c-4.173 3.272-7.365 7.772-9.492 13.418-2.128 5.727-3.191 12.191-3.191 19.392 0 7.2 1.063 13.746 3.273 19.228 2.127 5.482 5.318 9.736 9.573 12.764 4.174 3.027 9.41 4.582 15.629 4.582Zm141.56-26.51V71.839h28.23v119.786h-27.412v-21.273h-1.227c-2.7 6.709-7.119 12.191-13.338 16.446-6.137 4.255-13.747 6.382-22.748 6.382-7.855 0-14.81-1.718-20.783-5.237-5.974-3.518-10.72-8.591-14.075-15.382-3.355-6.709-5.073-14.891-5.073-24.464V71.839h28.312v71.921c0 7.609 2.046 13.664 6.219 18.083 4.173 4.5 9.655 6.709 16.365 6.709 4.173 0 8.183-.982 12.111-3.028 3.927-2.045 7.118-5.072 9.655-9.082 2.537-4.091 3.764-9.164 3.764-15.218Zm65.707-109.395v159.796h-28.23V31.828h28.23Zm44.841 162.169c-7.61 0-14.402-1.391-20.457-4.091-6.055-2.7-10.883-6.791-14.32-12.109-3.518-5.319-5.237-11.946-5.237-19.801 0-6.791 1.228-12.355 3.765-16.773 2.536-4.419 5.891-7.937 10.228-10.637 4.337-2.619 9.164-4.664 14.647-6.055 5.4-1.391 11.046-2.373 16.856-3.027 7.037-.737 12.683-1.391 17.102-1.964 4.337-.573 7.528-1.555 9.574-2.782 1.963-1.309 3.027-3.273 3.027-5.973v-.491c0-5.891-1.718-10.391-5.237-13.664-3.518-3.191-8.51-4.828-15.056-4.828-6.955 0-12.356 1.473-16.447 4.5-4.01 3.028-6.71 6.546-8.183 10.719l-26.348-3.764c2.046-7.282 5.483-13.336 10.31-18.328 4.746-4.909 10.638-8.59 17.511-11.045 6.955-2.455 14.565-3.682 22.912-3.682 5.809 0 11.537.654 17.265 2.045s10.965 3.6 15.711 6.71c4.746 3.109 8.51 7.282 11.455 12.6 2.864 5.318 4.337 11.946 4.337 19.883v80.184h-27.166v-16.446h-.9c-1.719 3.355-4.091 6.464-7.201 9.328-3.109 2.864-6.955 5.237-11.619 6.955-4.828 1.718-10.229 2.536-16.529 2.536Zm7.364-20.701c5.646 0 10.556-1.145 14.729-3.354 4.173-2.291 7.364-5.237 9.655-9.001 2.292-3.763 3.355-7.854 3.355-12.273v-14.155c-.9.737-2.373 1.391-4.5 2.046-2.128.654-4.419 1.145-7.037 1.636-2.619.491-5.155.9-7.692 1.227-2.537.328-4.746.655-6.628.901-4.173.572-8.019 1.472-11.292 2.781-3.355 1.31-5.973 3.11-7.855 5.401-1.964 2.291-2.864 5.318-2.864 8.918 0 5.237 1.882 9.164 5.728 11.782 3.682 2.782 8.51 4.091 14.401 4.091Zm64.643 18.328V71.839h27.412v19.965h1.227c2.21-6.955 5.974-12.274 11.292-16.038 5.319-3.763 11.456-5.645 18.329-5.645 1.555 0 3.355.082 5.237.163 1.964.164 3.601.328 4.91.573v25.938c-1.227-.41-3.109-.819-5.646-1.146a58.815 58.815 0 0 0-7.446-.49c-5.155 0-9.738 1.145-13.829 3.354-4.091 2.209-7.282 5.236-9.655 9.164-2.373 3.927-3.519 8.427-3.519 13.5v70.448h-28.312ZM222.077 39.192l-8.019 125.923L137.387 0l84.69 39.192Zm-53.105 162.825-57.933 33.056-57.934-33.056 11.783-28.556h92.301l11.783 28.556ZM111.039 62.675l30.357 73.803H80.681l30.358-73.803ZM7.937 165.115 0 39.192 84.69 0 7.937 165.115Z"></path>
|
||||||
|
</g>
|
||||||
|
<defs _ngcontent-ng-c433524483="">
|
||||||
|
<radialGradient id="wordmark_c" cx="0" cy="0" r="1" gradientTransform="rotate(118.122 171.182 60.81) scale(205.794)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#FF41F8"></stop>
|
||||||
|
<stop offset=".707" stop-color="#FF41F8" stop-opacity=".5"></stop>
|
||||||
|
<stop offset="1" stop-color="#FF41F8" stop-opacity="0"></stop>
|
||||||
|
</radialGradient>
|
||||||
|
<linearGradient id="wordmark_b" x1="0" x2="982" y1="192" y2="192" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#F0060B"></stop>
|
||||||
|
<stop offset="0" stop-color="#F0070C"></stop>
|
||||||
|
<stop offset=".526" stop-color="#CC26D5"></stop>
|
||||||
|
<stop offset="1" stop-color="#7702FF"></stop>
|
||||||
|
</linearGradient>
|
||||||
|
<clipPath id="wordmark_a">
|
||||||
|
<path fill="#fff" d="M0 0h982v239H0z"></path>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 9.7 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 13 KiB |
@@ -13,14 +13,9 @@ html {
|
|||||||
background: $white;
|
background: $white;
|
||||||
.page-wrapper{
|
.page-wrapper{
|
||||||
height:calc(100vh - 64px);
|
height:calc(100vh - 64px);
|
||||||
.page-content{
|
|
||||||
padding-bottom: 30px;
|
|
||||||
.content {
|
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
body {
|
body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user