Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 25d47bc3be | |||
| 276da97003 | |||
| d1870adff6 | |||
| 7c3f0c9648 |
Generated
+543
-463
File diff suppressed because it is too large
Load Diff
+10
-9
@@ -25,30 +25,31 @@
|
||||
"@angular/common": "^17.3.5",
|
||||
"@angular/compiler": "^17.3.5",
|
||||
"@angular/core": "^17.3.5",
|
||||
"@angular/forms": "^17.3.5",
|
||||
"@angular/localize": "^17.3.5",
|
||||
"@angular/material": "^17.3.6",
|
||||
"@angular/forms": "^17.3.8",
|
||||
"@angular/google-maps": "^17.3.8",
|
||||
"@angular/localize": "^17.3.8",
|
||||
"@angular/material": "^17.3.8",
|
||||
"@angular/platform-browser": "^17.3.5",
|
||||
"@angular/platform-browser-dynamic": "^17.3.5",
|
||||
"@angular/router": "^17.3.5",
|
||||
"@angular/platform-browser-dynamic": "^17.3.8",
|
||||
"@angular/router": "^17.3.8",
|
||||
"bootstrap": "^5.3.3",
|
||||
"chart.js": "^4.4.2",
|
||||
"chartist": "^1.3.0",
|
||||
"ng-chartist": "^8.2.0",
|
||||
"ng2-charts": "^6.0.0",
|
||||
"ng2-charts": "^6.0.1",
|
||||
"ngx-skeleton-loader": "^9.0.0",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "^0.14.4"
|
||||
"zone.js": "^0.14.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^17.3.5",
|
||||
"@angular-devkit/build-angular": "^17.3.7",
|
||||
"@angular-eslint/builder": "17.3.0",
|
||||
"@angular-eslint/eslint-plugin": "17.3.0",
|
||||
"@angular-eslint/eslint-plugin-template": "17.3.0",
|
||||
"@angular-eslint/schematics": "17.3.0",
|
||||
"@angular-eslint/template-parser": "17.3.0",
|
||||
"@angular/cli": "^17.3.5",
|
||||
"@angular/cli": "^17.3.7",
|
||||
"@angular/compiler-cli": "^17.3.5",
|
||||
"@types/jasmine": "~5.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "7.2.0",
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
<div @flyInOut>
|
||||
<div class="content">
|
||||
<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]="menuAeronef" aria-label="Menu Aeronef">
|
||||
<mat-icon fontIcon="more_vert"></mat-icon>
|
||||
</button>
|
||||
<mat-menu #menuAeronef="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-4">
|
||||
@if (displayCharts) {
|
||||
<div class="row">
|
||||
<div class="col-xl-4 col-lg-5 col-md-6 col-sm-12">
|
||||
<app-pie-chart [headers]="seriesHeader" [names]="seriesName" [values]="seriesValue" [colors]="seriesColor"></app-pie-chart>
|
||||
</div>
|
||||
<div class="col-xl-8 col-lg-7 col-md-6 col-sm-12">
|
||||
<!--<app-bar-chart [headers]="seriesHeader" [names]="seriesName" [values]="seriesValue" [colors]="seriesColor" label="Nombre total de sauts" [legend]="false"></app-bar-chart>-->
|
||||
<app-bars-chart [headers]="seriesHeader" [names]="seriesName" [values]="seriesRow" [colors]="seriesColor" [legend]="false"></app-bars-chart>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="d-flex">
|
||||
<div class="flex-fill py-2">
|
||||
<mat-divider class="mt-3 mb-0"></mat-divider>
|
||||
<app-history-table [headers]="seriesHeader" [names]="seriesName" [values]="seriesValue" [rows]="seriesRow" [colors]="seriesColorClass"></app-history-table>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,23 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AeronefComponent } from './aeronef.component';
|
||||
|
||||
describe('AeronefComponent', () => {
|
||||
let component: AeronefComponent;
|
||||
let fixture: ComponentFixture<AeronefComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [AeronefComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(AeronefComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
<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]="menuAeronef" aria-label="Menu Aeronef">
|
||||
<mat-icon fontIcon="more_vert"></mat-icon>
|
||||
</button>
|
||||
<mat-menu #menuAeronef="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-4">
|
||||
@if (displayCharts) {
|
||||
<div class="row">
|
||||
<div class="col-xl-4 col-lg-5 col-md-6 col-sm-12">
|
||||
<app-pie-chart [headers]="seriesHeader" [names]="seriesName" [values]="seriesValue" [colors]="seriesColor"></app-pie-chart>
|
||||
</div>
|
||||
<div class="col-xl-8 col-lg-7 col-md-6 col-sm-12">
|
||||
<!--<app-bar-chart [headers]="seriesHeader" [names]="seriesName" [values]="seriesValue" [colors]="seriesColor" label="Nombre total de sauts" [legend]="false"></app-bar-chart>-->
|
||||
<app-bars-chart [headers]="seriesHeader" [names]="seriesName" [values]="seriesRow" [colors]="seriesColor" [legend]="false"></app-bars-chart>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="d-flex">
|
||||
<div class="flex-fill py-2">
|
||||
<mat-divider class="mt-3 mb-0"></mat-divider>
|
||||
<app-history-table [headers]="seriesHeader" [names]="seriesName" [values]="seriesValue" [rows]="seriesRow" [colors]="seriesColorClass"></app-history-table>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
Executable → Regular
Executable → Regular
+4
-6
@@ -1,4 +1,4 @@
|
||||
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AeronefsComponent } from './aeronefs.component';
|
||||
|
||||
@@ -6,14 +6,12 @@ describe('AeronefsComponent', () => {
|
||||
let component: AeronefsComponent;
|
||||
let fixture: ComponentFixture<AeronefsComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [AeronefsComponent]
|
||||
})
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AeronefsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
+4
-4
@@ -21,7 +21,7 @@ import { UtilitiesService } from 'src/app/core/services';
|
||||
import { AeronefByImat, AeronefByYear } from 'src/app/core/models';
|
||||
|
||||
@Component({
|
||||
selector: 'app-aeronef',
|
||||
selector: 'app-aeronefs',
|
||||
standalone: true,
|
||||
imports: [
|
||||
DatePipe,
|
||||
@@ -29,8 +29,8 @@ import { AeronefByImat, AeronefByYear } from 'src/app/core/models';
|
||||
MatExpansionModule, MatGridListModule, MatIconModule, MatMenuModule,
|
||||
BarsChartComponent, HistoryTableComponent, PieChartComponent
|
||||
],
|
||||
templateUrl: './aeronef.component.html',
|
||||
styleUrl: './aeronef.component.scss',
|
||||
templateUrl: './aeronefs.component.html',
|
||||
styleUrl: './aeronefs.component.scss',
|
||||
animations: [
|
||||
trigger('flyInOut', [
|
||||
state('in', style({ transform: 'translateX(0)' })),
|
||||
@@ -45,7 +45,7 @@ import { AeronefByImat, AeronefByYear } from 'src/app/core/models';
|
||||
])
|
||||
]
|
||||
})
|
||||
export class AeronefComponent implements OnInit, OnDestroy {
|
||||
export class AeronefsComponent implements OnInit, OnDestroy {
|
||||
private _data: Subscription = new Subscription();
|
||||
private _aeronefsByImat!: Array<AeronefByImat>;
|
||||
private _aeronefsByYear!: Array<AeronefByYear>;
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="container content auth-page">
|
||||
<div class="container auth-page">
|
||||
<div class="row">
|
||||
<div class="col-md-6 offset-md-3 col-xs-12">
|
||||
<h1 class="text-xs-center">{{ title }}</h1>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<div @flyInOut>
|
||||
<div class="calculator-page content">
|
||||
<div class="d-flex">
|
||||
<div class="flex-fill">
|
||||
<h1 class="mb-1">{{title}}</h1>
|
||||
@@ -56,7 +55,7 @@
|
||||
<table class="table table-striped table-dark table-hover mat-elevation-z2">
|
||||
<thead>
|
||||
<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 min</th>
|
||||
<th class="text-nowrap">Taille min -11%</th>
|
||||
@@ -64,34 +63,34 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<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 }}"> ●
|
||||
{{ info.sizesFeet.current }} </td>
|
||||
<td class="font-monospace text-success"> ● {{ info.sizesFeet.min }} </td>
|
||||
<td class="font-monospace text-warning"> ● {{ info.sizesFeet.min11 }} </td>
|
||||
</tr>
|
||||
<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.min | number : '1.2-3' }}</td>
|
||||
<td class="font-monospace">{{ info.charges.min11 | number : '1.2-3' }}</td>
|
||||
</tr>
|
||||
<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.min | number : '1.2-3' }}</td>
|
||||
<td class="font-monospace">{{ info.sizesMeter.min11 | number : '1.2-3' }}</td>
|
||||
</tr>
|
||||
<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>
|
||||
</tr>
|
||||
<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>
|
||||
</tr>
|
||||
<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">
|
||||
( ( {{ inputs.weight }} + {{ inputs.gear }} ) * {{ coeffKgLbs }} ) /
|
||||
{{ 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">
|
||||
<thead>
|
||||
<tr class="warn">
|
||||
<th class="first"></th>
|
||||
<th class="text-nowrap pe-4"></th>
|
||||
@for (header of sizesHeader; track header; let index = $index) {
|
||||
<th class="pl-3 pr-3 {{ tableHeader[(index+1)].active }}">{{ header.name }}</th>
|
||||
}
|
||||
@@ -137,26 +136,26 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<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) {
|
||||
<td class="pl-3 text-nowrap {{ tableHeader[(index+1)].active }}">{{ value }}</td>
|
||||
}
|
||||
</tr>
|
||||
<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) {
|
||||
<td class="pl-3 text-nowrap {{ tableHeader[(index+1)].active }}">{{ value }}</td>
|
||||
}
|
||||
</tr>
|
||||
<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) {
|
||||
<td class="pl-3 text-nowrap {{ tableHeader[(index+1)].active }}">
|
||||
{{ charge | number : '1.2-3' }}</td>
|
||||
}
|
||||
</tr>
|
||||
<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) {
|
||||
<td class="pl-3 text-nowrap {{ tableHeader[(index+1)].active }}">
|
||||
{{ value | number : '1.2-2' }}</td>
|
||||
@@ -175,7 +174,7 @@
|
||||
class="table table-striped table-dark table-hover mat-elevation-z2">
|
||||
<!-- weight column -->
|
||||
<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>
|
||||
<th mat-cell *matCellDef="let element;" class="text-end ps-3 pe-4 fs-6" role="button"
|
||||
(click)="setCurrentWeight(element.weight)">
|
||||
@@ -255,5 +254,4 @@
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,56 @@
|
||||
<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]="menuCanopyModel" aria-label="Menu Canopy Model">
|
||||
<mat-icon fontIcon="more_vert"></mat-icon>
|
||||
</button>
|
||||
<mat-menu #menuCanopyModel="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-4">
|
||||
@if (displayCharts) {
|
||||
<div class="row">
|
||||
<div class="col-xl-3 col-lg-6 col-md-6 col-sm-12">
|
||||
<app-pie-chart [headers]="seriesModelHeader" [names]="seriesModelName" [values]="seriesModelValue" [colors]="seriesColor"></app-pie-chart>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-6 col-md-6 col-sm-12">
|
||||
<app-pie-chart [headers]="seriesSizeHeader" [names]="seriesSizeName" [values]="seriesSizeValue" [colors]="seriesColor"></app-pie-chart>
|
||||
</div>
|
||||
<div class="col-xl-6 col-lg-12 col-md-12">
|
||||
<!--<app-pie-chart [headers]="seriesSizeHeader" [names]="seriesSizeName" [values]="seriesSizeValue" [colors]="seriesColor"></app-pie-chart>-->
|
||||
<app-bars-chart [headers]="seriesSizeHeader" [names]="seriesSizeName" [values]="seriesSizeRow" [colors]="seriesColor" [legend]="false"></app-bars-chart>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row">
|
||||
<div class="col-xl-6 col-lg-12">
|
||||
<mat-divider class="mt-3 mb-0"></mat-divider>
|
||||
<app-history-table [headers]="seriesModelHeader" [names]="seriesModelName" [values]="seriesModelValue" [rows]="seriesModelRow" [colors]="seriesColorClass"></app-history-table>
|
||||
</div>
|
||||
<div class="col-xl-6 col-lg-12">
|
||||
<mat-divider class="mt-3 mb-0"></mat-divider>
|
||||
<app-history-table [headers]="seriesSizeHeader" [names]="seriesSizeName" [values]="seriesSizeValue" [rows]="seriesSizeRow" [colors]="seriesColorClass"></app-history-table>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
+6
-6
@@ -1,18 +1,18 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CanopyComponent } from './canopy.component';
|
||||
import { CanopiesComponent } from './canopies.component';
|
||||
|
||||
describe('CanopyComponent', () => {
|
||||
let component: CanopyComponent;
|
||||
let fixture: ComponentFixture<CanopyComponent>;
|
||||
describe('CanopiesComponent', () => {
|
||||
let component: CanopiesComponent;
|
||||
let fixture: ComponentFixture<CanopiesComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [CanopyComponent]
|
||||
imports: [CanopiesComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(CanopyComponent);
|
||||
fixture = TestBed.createComponent(CanopiesComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
+4
-4
@@ -20,7 +20,7 @@ import { UtilitiesService } from 'src/app/core/services';
|
||||
import { CanopyBySize, CanopyByYear, CanopyModelBySize, CanopyModelByYear } from 'src/app/core/models';
|
||||
|
||||
@Component({
|
||||
selector: 'app-canopy',
|
||||
selector: 'app-canopies',
|
||||
standalone: true,
|
||||
imports: [
|
||||
DatePipe,
|
||||
@@ -28,8 +28,8 @@ import { CanopyBySize, CanopyByYear, CanopyModelBySize, CanopyModelByYear } from
|
||||
MatGridListModule, MatIconModule, MatMenuModule,
|
||||
HistoryTableComponent, BarsChartComponent, PieChartComponent
|
||||
],
|
||||
templateUrl: './canopy.component.html',
|
||||
styleUrl: './canopy.component.scss',
|
||||
templateUrl: './canopies.component.html',
|
||||
styleUrl: './canopies.component.scss',
|
||||
animations: [
|
||||
trigger('flyInOut', [
|
||||
state('in', style({ transform: 'translateX(0)' })),
|
||||
@@ -44,7 +44,7 @@ import { CanopyBySize, CanopyByYear, CanopyModelBySize, CanopyModelByYear } from
|
||||
])
|
||||
]
|
||||
})
|
||||
export class CanopyComponent implements OnInit, OnDestroy {
|
||||
export class CanopiesComponent implements OnInit, OnDestroy {
|
||||
private _data: Subscription = new Subscription();
|
||||
private _canopiesModelBySize!: Array<CanopyModelBySize>;
|
||||
private _canopiesModelByYear!: Array<CanopyModelByYear>;
|
||||
@@ -1,58 +0,0 @@
|
||||
<div @flyInOut>
|
||||
<div class="content">
|
||||
<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]="menuCanopyModel" aria-label="Menu Canopy Model">
|
||||
<mat-icon fontIcon="more_vert"></mat-icon>
|
||||
</button>
|
||||
<mat-menu #menuCanopyModel="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-4">
|
||||
@if (displayCharts) {
|
||||
<div class="row">
|
||||
<div class="col-xl-3 col-lg-6 col-md-6 col-sm-12">
|
||||
<app-pie-chart [headers]="seriesModelHeader" [names]="seriesModelName" [values]="seriesModelValue" [colors]="seriesColor"></app-pie-chart>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-6 col-md-6 col-sm-12">
|
||||
<app-pie-chart [headers]="seriesSizeHeader" [names]="seriesSizeName" [values]="seriesSizeValue" [colors]="seriesColor"></app-pie-chart>
|
||||
</div>
|
||||
<div class="col-xl-6 col-lg-12 col-md-12">
|
||||
<!--<app-pie-chart [headers]="seriesSizeHeader" [names]="seriesSizeName" [values]="seriesSizeValue" [colors]="seriesColor"></app-pie-chart>-->
|
||||
<app-bars-chart [headers]="seriesSizeHeader" [names]="seriesSizeName" [values]="seriesSizeRow" [colors]="seriesColor" [legend]="false"></app-bars-chart>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row">
|
||||
<div class="col-xl-6 col-lg-12">
|
||||
<mat-divider class="mt-3 mb-0"></mat-divider>
|
||||
<app-history-table [headers]="seriesModelHeader" [names]="seriesModelName" [values]="seriesModelValue" [rows]="seriesModelRow" [colors]="seriesColorClass"></app-history-table>
|
||||
</div>
|
||||
<div class="col-xl-6 col-lg-12">
|
||||
<mat-divider class="mt-3 mb-0"></mat-divider>
|
||||
<app-history-table [headers]="seriesSizeHeader" [names]="seriesSizeName" [values]="seriesSizeValue" [rows]="seriesSizeRow" [colors]="seriesColorClass"></app-history-table>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,10 +1,9 @@
|
||||
<div class="content">
|
||||
<h1 class="mb-1">{{title}}</h1>
|
||||
<span [hidden]="!lastJump.numero" class="me-2 fst-italic0 fs-6">
|
||||
<h1 class="mb-1">{{title}}</h1>
|
||||
<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>
|
||||
</span>
|
||||
<mat-divider class="my-3"></mat-divider>
|
||||
<ng-container *appShowAuthed="true">
|
||||
</span>
|
||||
<mat-divider class="my-3"></mat-divider>
|
||||
<ng-container *appShowAuthed="true">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<app-jumps-by-month></app-jumps-by-month>
|
||||
@@ -12,15 +11,15 @@
|
||||
</div>
|
||||
<div class="row mt-sm-2 mt-lg-3">
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<app-drop-zones></app-drop-zones>
|
||||
<app-dropzones-pie></app-dropzones-pie>
|
||||
</div>
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<app-drop-zones-bar></app-drop-zones-bar>
|
||||
<app-dropzones-bar></app-dropzones-bar>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-sm-2 mt-lg-3">
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<app-aeronefs></app-aeronefs>
|
||||
<app-aeronefs-pie></app-aeronefs-pie>
|
||||
</div>
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<app-aeronefs-bar></app-aeronefs-bar>
|
||||
@@ -28,11 +27,10 @@
|
||||
</div>
|
||||
<div class="row mt-sm-2 mt-lg-3">
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<app-canopy-models></app-canopy-models>
|
||||
<app-canopies-models></app-canopies-models>
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<app-canopy-sizes></app-canopy-sizes>
|
||||
<app-canopies-sizes></app-canopies-sizes>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
@@ -12,9 +12,9 @@ import { Aeronef, AeronefByImat, Canopy, CanopyModelBySize, DropZone, DropZoneBy
|
||||
import { JumpsService, UserService } from 'src/app/core/services';
|
||||
import { ShowAuthedDirective } from 'src/app/components/shared/show-authed.directive';
|
||||
import {
|
||||
AeronefsComponent, AeronefsBarComponent,
|
||||
CanopyModelsComponent, CanopySizesComponent,
|
||||
DropZonesComponent, DropZonesBarComponent,
|
||||
AeronefsPieComponent, AeronefsBarComponent,
|
||||
CanopiesModelsComponent, CanopiesSizesComponent,
|
||||
DropzonesPieComponent, DropzonesBarComponent,
|
||||
JumpsByMonthComponent
|
||||
} from 'src/app/components/shared/dashboard-components';
|
||||
|
||||
@@ -22,9 +22,9 @@ import {
|
||||
standalone: true,
|
||||
imports: [
|
||||
DatePipe, ShowAuthedDirective, MatDividerModule,
|
||||
AeronefsComponent, AeronefsBarComponent,
|
||||
CanopyModelsComponent, CanopySizesComponent,
|
||||
DropZonesComponent, DropZonesBarComponent,
|
||||
AeronefsPieComponent, AeronefsBarComponent,
|
||||
CanopiesModelsComponent, CanopiesSizesComponent,
|
||||
DropzonesPieComponent, DropzonesBarComponent,
|
||||
JumpsByMonthComponent
|
||||
],
|
||||
selector: 'app-dashboard',
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
<div @flyInOut>
|
||||
<div class="content">
|
||||
<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]="menuDropzone" aria-label="Menu Dropzone">
|
||||
<mat-icon fontIcon="more_vert"></mat-icon>
|
||||
</button>
|
||||
<mat-menu #menuDropzone="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-4">
|
||||
@if (displayCharts) {
|
||||
<div class="row">
|
||||
<div class="col-xl-4 col-lg-5 col-md-6 col-sm-12">
|
||||
<app-pie-chart [headers]="seriesHeader" [names]="seriesName" [values]="seriesValue" [colors]="seriesColor"></app-pie-chart>
|
||||
</div>
|
||||
<div class="col-xl-8 col-lg-7 col-md-6 col-sm-12">
|
||||
<app-bars-chart [headers]="seriesHeader" [names]="seriesName" [values]="seriesRow" [colors]="seriesColor" [legend]="false"></app-bars-chart>
|
||||
<!--
|
||||
@if (displayCharts) {
|
||||
<div class="barchart position-relative w-100 my-1">
|
||||
<x-chartist [configuration]="chartBarConfig"></x-chartist>
|
||||
</div>
|
||||
}
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="d-flex">
|
||||
<div class="flex-fill py-2">
|
||||
<mat-divider class="mt-3 mb-0"></mat-divider>
|
||||
<app-history-table [headers]="seriesHeader" [names]="seriesName" [values]="seriesValue" [rows]="seriesRow" [colors]="seriesColorClass"></app-history-table>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,55 @@
|
||||
<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]="menuDropzone" aria-label="Menu Dropzone">
|
||||
<mat-icon fontIcon="more_vert"></mat-icon>
|
||||
</button>
|
||||
<mat-menu #menuDropzone="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-4">
|
||||
@if (displayCharts) {
|
||||
<div class="row">
|
||||
<div class="col-xl-4 col-lg-5 col-md-6 col-sm-12">
|
||||
<app-pie-chart [headers]="seriesHeader" [names]="seriesName" [values]="seriesValue" [colors]="seriesColor"></app-pie-chart>
|
||||
</div>
|
||||
<div class="col-xl-8 col-lg-7 col-md-6 col-sm-12">
|
||||
<app-bars-chart [headers]="seriesHeader" [names]="seriesName" [values]="seriesRow" [colors]="seriesColor" [legend]="false"></app-bars-chart>
|
||||
<!--
|
||||
@if (displayCharts) {
|
||||
<div class="barchart position-relative w-100 my-1">
|
||||
<x-chartist [configuration]="chartBarConfig"></x-chartist>
|
||||
</div>
|
||||
}
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="d-flex">
|
||||
<div class="flex-fill py-2">
|
||||
<mat-divider class="mt-3 mb-0"></mat-divider>
|
||||
<app-history-table [headers]="seriesHeader" [names]="seriesName" [values]="seriesValue" [rows]="seriesRow" [colors]="seriesColorClass"></app-history-table>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
+6
-6
@@ -1,18 +1,18 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DropzoneComponent } from './dropzone.component';
|
||||
import { DropzonesComponent } from './dropzones.component';
|
||||
|
||||
describe('DropzoneComponent', () => {
|
||||
let component: DropzoneComponent;
|
||||
let fixture: ComponentFixture<DropzoneComponent>;
|
||||
describe('DropzonesComponent', () => {
|
||||
let component: DropzonesComponent;
|
||||
let fixture: ComponentFixture<DropzonesComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [DropzoneComponent]
|
||||
imports: [DropzonesComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(DropzoneComponent);
|
||||
fixture = TestBed.createComponent(DropzonesComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
+4
-4
@@ -21,7 +21,7 @@ import { DropZoneByOaci, DropZoneByYear, DropZonesPageData, Jump } from 'src/app
|
||||
import { UtilitiesService } from 'src/app/core/services';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dropzone',
|
||||
selector: 'app-dropzones',
|
||||
standalone: true,
|
||||
imports: [
|
||||
DatePipe,
|
||||
@@ -30,8 +30,8 @@ import { UtilitiesService } from 'src/app/core/services';
|
||||
//ChartistModule,
|
||||
HistoryTableComponent, BarsChartComponent, PieChartComponent
|
||||
],
|
||||
templateUrl: './dropzone.component.html',
|
||||
styleUrl: './dropzone.component.scss',
|
||||
templateUrl: './dropzones.component.html',
|
||||
styleUrl: './dropzones.component.scss',
|
||||
animations: [
|
||||
trigger('flyInOut', [
|
||||
state('in', style({ transform: 'translateX(0)' })),
|
||||
@@ -46,7 +46,7 @@ import { UtilitiesService } from 'src/app/core/services';
|
||||
])
|
||||
]
|
||||
})
|
||||
export class DropzoneComponent implements OnInit, OnDestroy {
|
||||
export class DropzonesComponent implements OnInit, OnDestroy {
|
||||
private _data: Subscription = new Subscription();
|
||||
private _lastjump: Subscription = new Subscription();
|
||||
private _dropzonesByOaci!: Array<DropZoneByOaci>;
|
||||
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 lastJump: Jump = {} as Jump;
|
||||
public destroyRef = inject(DestroyRef);
|
||||
public now = new Date();
|
||||
public isJumpDay = false;
|
||||
|
||||
constructor(
|
||||
private _jumpsService: JumpsService
|
||||
@@ -50,6 +52,12 @@ export class HomeComponent implements OnInit {
|
||||
this._lastjump$ = this._jumpsService.getLastJump().pipe(takeUntilDestroyed(this.destroyRef));
|
||||
this._lastjump = this._lastjump$.subscribe((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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
export * from './auth/auth.component';
|
||||
export * from './aeronef/aeronef.component';
|
||||
export * from './aeronefs/aeronefs.component';
|
||||
export * from './calculator/calculator.component';
|
||||
export * from './canopy/canopy.component';
|
||||
export * from './canopies/canopies.component';
|
||||
export * from './dashboard/dashboard.component';
|
||||
export * from './dropzone/dropzone.component';
|
||||
export * from './dropzones/dropzones.component';
|
||||
export * from './home/home.component';
|
||||
export * from './jump/jump.component';
|
||||
export * from './jumps/jumps.component';
|
||||
export * from './logbook/logbook.component';
|
||||
export * from './profile/profile.component';
|
||||
export * from './qcm/qcm.component';
|
||||
|
||||
@@ -1,132 +1,283 @@
|
||||
<div @flyInOut>
|
||||
<div class="content">
|
||||
<div class="d-flex">
|
||||
<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>
|
||||
<h1 class="mb-1">
|
||||
{{title}}
|
||||
<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>
|
||||
</div>
|
||||
<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">
|
||||
<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>
|
||||
</button>
|
||||
<mat-menu #menuAeronef="matMenu">
|
||||
@for (menuitem of menuItems.getMenuPanel(); track menuitem) {
|
||||
<mat-menu #menuJump="matMenu">
|
||||
@if (jump.x2data) {
|
||||
<button mat-menu-item>
|
||||
<mat-icon [fontIcon]="menuitem.icon"></mat-icon>
|
||||
<span>{{ menuitem.name }}</span>
|
||||
<mat-icon fontIcon="language" color="accent"></mat-icon>
|
||||
<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>
|
||||
}
|
||||
</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>
|
||||
<mat-divider class="my-3"></mat-divider>
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<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 class="col-lg-6 col-md-12">
|
||||
<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 class="col-xxl-6 col-xs-12">
|
||||
<app-bars-chart [headers]="seriesHeader" [names]="seriesName" [values]="seriesRow" [colors]="seriesColor" [legend]="true"></app-bars-chart>
|
||||
<div class="col-lg-6 col-md-12">
|
||||
<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>
|
||||
</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 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>
|
||||
</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="speed" class="me-1"></mat-icon> Vitesse en chute</h5>
|
||||
</div>
|
||||
<div class="col-sm-6 hidden-xs text-center">
|
||||
<h6>Verticale</h6>
|
||||
</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.freeFall.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.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>Vitesse maximale</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>Vitesse moyenne</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>
|
||||
</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>
|
||||
<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="speed" class="me-1"></mat-icon> Vitesse sous voile</h5>
|
||||
</div>
|
||||
<div class="col-sm-6 hidden-xs text-center">
|
||||
<h6>Verticale</h6>
|
||||
</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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
</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 fixture: ComponentFixture<JumpComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [JumpComponent]
|
||||
});
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(JumpComponent);
|
||||
component = fixture.componentInstance;
|
||||
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 { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { DatePipe, DecimalPipe } from '@angular/common';
|
||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
||||
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';
|
||||
import { ListErrorsComponent, MenuItems } from 'src/app/components/shared';
|
||||
import { Errors, Jump, JumpPageData } from 'src/app/core/models';
|
||||
|
||||
@Component({
|
||||
selector: 'app-jump',
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatButtonModule, MatCardModule, MatDividerModule,
|
||||
MatExpansionModule, MatIconModule, MatMenuModule,
|
||||
BarsChartComponent, CircleChartComponent, LineChartComponent, LineAreaChartComponent
|
||||
DatePipe, DecimalPipe, RouterLink,
|
||||
MatButtonModule, MatCardModule,
|
||||
MatDividerModule, MatIconModule, MatMenuModule,
|
||||
ListErrorsComponent
|
||||
],
|
||||
templateUrl: './jump.component.html',
|
||||
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)
|
||||
])
|
||||
])
|
||||
]
|
||||
styleUrl: './jump.component.scss'
|
||||
})
|
||||
export class JumpComponent 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 title: string = '';
|
||||
public errors: Errors = { errors: {} };
|
||||
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[] = [];
|
||||
public jump: Jump = {} as Jump;
|
||||
public prevSlug: string = '';
|
||||
public nextSlug: string = '';
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private _utilitiesService: UtilitiesService,
|
||||
public menuItems: MenuItems
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
const data$: Observable<{ jumpsPageData: JumpsPageData }> = this.route.data as Observable<{ jumpsPageData: JumpsPageData }>;
|
||||
this._data = data$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data: { jumpsPageData: JumpsPageData }) => {
|
||||
const pageData: JumpsPageData = data.jumpsPageData;
|
||||
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];
|
||||
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));
|
||||
const data$: Observable<{ pageData: JumpPageData }> = this.route.data as Observable<{ pageData: JumpPageData }>;
|
||||
this._data = data$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data: { pageData: JumpPageData }) => {
|
||||
this.jump = data.pageData.jump;
|
||||
this.prevSlug = data.pageData.prevJump?.slug;
|
||||
this.nextSlug = data.pageData.nextJump?.slug;
|
||||
this.title = `Saut n° ${this.jump.numero} `;
|
||||
});
|
||||
/*
|
||||
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;
|
||||
const data$: Observable<Jump> = this.route.data as Observable<Jump>;
|
||||
this._data = data$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data: Jump) => {
|
||||
this.jump = data;
|
||||
console.log('jump : ', this.jump);
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this._data.unsubscribe();
|
||||
}
|
||||
|
||||
public getCategories(): Array<JumpByCategorie> {
|
||||
return this._jumpsByCategorie;
|
||||
formatDuration(duration: number): string {
|
||||
const start = new Date(0);
|
||||
start.setSeconds(duration);
|
||||
return start.toISOString().substring(14, 19);
|
||||
}
|
||||
|
||||
public getModules(): Array<JumpByModule> {
|
||||
return this._jumpsByModule;
|
||||
}
|
||||
|
||||
public getModuleColor(index: number): number {
|
||||
return (this._jumpsByCategorie.length + index);
|
||||
private _resetErrors(): void {
|
||||
this.errors = { errors: {} };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>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" [hideZero]="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>
|
||||
<mat-card class="mt-3">
|
||||
<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>
|
||||
</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">
|
||||
<mat-icon class="align-middle pointer me-1" fontIcon="person"></mat-icon>
|
||||
ju_solide
|
||||
{{ lastJump.author.username }}
|
||||
</span>
|
||||
</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">
|
||||
<mat-icon class="align-middle pointer me-1" fontIcon="person"></mat-icon>
|
||||
ju_solide
|
||||
{{ jump.author.username }}
|
||||
</span>
|
||||
</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">
|
||||
Saut n°{{jump.numero}}<span class="flex-spacer"></span>
|
||||
<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>
|
||||
<mat-icon fontIcon="close" class="pointer" (click)="closeDialog()"></mat-icon>
|
||||
</h2>
|
||||
<mat-dialog-content>
|
||||
<div class="container">
|
||||
<h5 class="border-bottom text-light-info border-light-subtle pb-2 mb-3">Le {{ jump.date | date: 'dd/MM/yyyy' }} à {{ jump.lieu }} :</h5>
|
||||
<div class="row mb-3">
|
||||
<div class="d-flex border-bottom border-light-subtle text-light-info pb-2 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">
|
||||
<dl class="dl-horizontal">
|
||||
<dt class="text-cyan fw-normal">Lieu:</dt>
|
||||
<dd>{{jump.lieu}}</dd>
|
||||
<dt class="text-cyan fw-normal">Oaci:</dt>
|
||||
<dd>{{jump.oaci}}</dd>
|
||||
<dt class="text-cyan fw-normal">Aeronef:</dt>
|
||||
<dd>{{jump.aeronef}}</dd>
|
||||
<dt class="text-cyan fw-normal">Imat:</dt>
|
||||
<dd>{{jump.imat}}</dd>
|
||||
<dt class="text-cyan fw-normal">Voile:</dt>
|
||||
<dd>{{jump.voile}}</dd>
|
||||
<dt class="text-cyan fw-normal">Taille:</dt>
|
||||
<dd>{{jump.taille}} ft<sup>2</sup></dd>
|
||||
<dt class="text-cyan fw-normal">Participants:</dt>
|
||||
<dd>{{jump.participants}}</dd>
|
||||
<dt class="text-cyan fw-normal">Sautants:</dt>
|
||||
<dd>
|
||||
<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 class="col-lg-6 col-md-12">
|
||||
<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>
|
||||
<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) {
|
||||
<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>
|
||||
@@ -32,35 +72,140 @@
|
||||
}
|
||||
<span class="badge rounded-pill bg-accent mb-2 me-1 pe-3 py-1 fw-normal text-dark">
|
||||
<mat-icon class="align-middle me-1" fontIcon="person"></mat-icon>
|
||||
ju_solide
|
||||
{{ jump.author.username }}
|
||||
</span>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-12">
|
||||
<dl class="dl-horizontal">
|
||||
<dt class="text-cyan fw-normal">Hauteur:</dt>
|
||||
<dd>{{jump.hauteur}} m</dd>
|
||||
<dt class="text-cyan fw-normal">Deploiement:</dt>
|
||||
<dd>{{jump.deploiement}} m</dd>
|
||||
<dt class="text-cyan fw-normal">Categorie:</dt>
|
||||
<dd>{{jump.categorie}}</dd>
|
||||
<dt class="text-cyan fw-normal">Module:</dt>
|
||||
<dd>{{jump.module}}</dd>
|
||||
<dt class="text-cyan fw-normal">Accessoires:</dt>
|
||||
<dd>{{jump.accessoires}}</dd>
|
||||
<dt class="text-cyan fw-normal">Zone:</dt>
|
||||
<dd>{{jump.zone}}</dd>
|
||||
<dt class="text-cyan fw-normal">Dossier media:</dt>
|
||||
<dd>{{jump.dossier}}</dd>
|
||||
<dt class="text-cyan fw-normal">Video:</dt>
|
||||
<dd>{{jump.video}}</dd>
|
||||
<dt class="text-cyan fw-normal">Programme:</dt>
|
||||
<dd>{{jump.programme}}</dd>
|
||||
</dl>
|
||||
@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-1"></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>
|
||||
|
||||
<div class="row my-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 en chute</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.freeFall.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.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>
|
||||
<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>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { DatePipe, DecimalPipe } from '@angular/common';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
@@ -12,11 +12,9 @@ import { Jump } from 'src/app/core/models';
|
||||
templateUrl: 'jump-view.dialog.html',
|
||||
standalone: true,
|
||||
imports: [
|
||||
DatePipe,
|
||||
MatButtonModule,
|
||||
MatDialogModule,
|
||||
MatDividerModule,
|
||||
MatIconModule
|
||||
DatePipe, DecimalPipe,
|
||||
MatButtonModule, MatDialogModule,
|
||||
MatDividerModule, MatIconModule
|
||||
]
|
||||
})
|
||||
export class JumpViewDialogComponent {
|
||||
@@ -30,4 +28,10 @@ export class JumpViewDialogComponent {
|
||||
// close the dialog without result
|
||||
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 class="content">
|
||||
<div class="d-flex">
|
||||
<div class="flex-fill">
|
||||
<h1 class="mb-1">{{title}}</h1>
|
||||
@@ -103,5 +102,4 @@
|
||||
</app-jump-table>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
@@ -12,14 +12,20 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="profile-page content">
|
||||
<h1>{{title}}</h1>
|
||||
<mat-divider></mat-divider>
|
||||
<div class="profile-page">
|
||||
<div class="d-flex">
|
||||
<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>
|
||||
<mat-card class="mt-4 bg-light text-black scaled">
|
||||
<mat-card-content>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
.banner {
|
||||
background-color: var.$sidebar-footer;
|
||||
padding: 1.6rem 0 1.3rem 0;
|
||||
margin: -1.5rem -1.5rem 1.5rem -1.5rem;
|
||||
.user-img {
|
||||
width: var.$user-img-size;
|
||||
height: var.$user-img-size;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<div class="content">
|
||||
<div class="d-flex">
|
||||
<div class="d-flex">
|
||||
<div class="flex-fill">
|
||||
<h1 class="mb-1">
|
||||
{{ title }}
|
||||
@@ -21,12 +20,22 @@
|
||||
}
|
||||
</mat-menu>
|
||||
</div>
|
||||
</div>
|
||||
<mat-divider class="my-3"></mat-divider>
|
||||
<app-list-errors [errors]="errors"></app-list-errors>
|
||||
@if (questions.controls.length) {
|
||||
<mat-card [hidden]="!questions.controls.length">
|
||||
<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="squareItems clearfix">
|
||||
@for (answer of answers; track $index) {
|
||||
<li [class]="answer">{{ ($index + 1) }}</li>
|
||||
}
|
||||
</ol>
|
||||
</div>
|
||||
<mat-divider class="my-3"></mat-divider>
|
||||
<app-list-errors [errors]="errors"></app-list-errors>
|
||||
<mat-card [hidden]="!questions.length">
|
||||
<mat-card-content class="mt-4">
|
||||
<form [formGroup]="qcmForm">
|
||||
<mat-card-content>
|
||||
<form [formGroup]="qcmForm" (ngSubmit)="onSubmit()">
|
||||
@for (category of qcm.categories; track category; let index = $index) {
|
||||
<mat-accordion>
|
||||
<mat-expansion-panel class="mb-3" [expanded]="expandedIndex === index" (opened)="setExpandedIndex(index)">
|
||||
@@ -43,9 +52,9 @@
|
||||
@for (question of category.questions; track question; let index = $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>
|
||||
<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) {
|
||||
<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>
|
||||
</div>
|
||||
@@ -56,5 +65,17 @@
|
||||
}
|
||||
</form>
|
||||
</mat-card-content>
|
||||
<!--
|
||||
<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>
|
||||
</form>
|
||||
-->
|
||||
</mat-card>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/* QCM */
|
||||
@use 'variable' as var;
|
||||
|
||||
ol.squareItems {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component, DestroyRef, inject, OnInit, OnDestroy } from '@angular/core';
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { FormControl, FormGroup, FormBuilder, FormArray, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { /*FormControl,*/ FormGroup, FormBuilder, FormArray, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
@@ -8,12 +8,15 @@ 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 { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
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 { ListErrorsComponent, } from 'src/app/components/shared';
|
||||
import { Errors, Qcm, User } from 'src/app/core/models';
|
||||
import { ListErrorsComponent } from 'src/app/components/shared';
|
||||
import { Errors, Qcm, QcmCategory, QcmQuestion, QcmQuestionState, User } from 'src/app/core/models';
|
||||
import { QcmService, UserService } from 'src/app/core/services';
|
||||
import data from 'src/qcm-bpa.json';
|
||||
|
||||
@@ -23,7 +26,8 @@ import data from 'src/qcm-bpa.json';
|
||||
imports: [
|
||||
FormsModule, ReactiveFormsModule,
|
||||
MatButtonModule, MatCardModule, MatDividerModule, MatExpansionModule,
|
||||
MatIconModule, MatMenuModule, MatRadioModule,
|
||||
MatIconModule, MatMenuModule, MatProgressBarModule, MatRadioModule,
|
||||
MatSelectModule,
|
||||
ListErrorsComponent
|
||||
],
|
||||
templateUrl: './qcm.component.html',
|
||||
@@ -32,6 +36,8 @@ import data from 'src/qcm-bpa.json';
|
||||
export class QcmComponent implements OnInit, OnDestroy {
|
||||
private _currentUser: Subscription = new Subscription();
|
||||
private _data: Subscription = new Subscription();
|
||||
private _timer: Subscription = new Subscription();
|
||||
private _refresh = 1000;
|
||||
public qcm: Qcm = {} as Qcm;
|
||||
public currentUser: User = {} as User;
|
||||
public canModify = false;
|
||||
@@ -41,7 +47,13 @@ export class QcmComponent implements OnInit, OnDestroy {
|
||||
public destroyRef = inject(DestroyRef);
|
||||
public expandedIndex = 0;
|
||||
public questionsCount = 0;
|
||||
public answers: Array<QcmQuestionState> = [];
|
||||
public qcmForm!: FormGroup;
|
||||
public loading = true;
|
||||
public totalAnswer = 0;
|
||||
public timeProgress = 0;
|
||||
public timeProgressColor = 'primary';
|
||||
public timeMax = (60*45);
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
@@ -56,15 +68,16 @@ export class QcmComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
get questions(): FormArray {
|
||||
return <FormArray>this.qcmForm.controls['questions'];
|
||||
return this.qcmForm.controls['questions'] as FormArray;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
//this.importQuestions();
|
||||
//this.importChoices();
|
||||
//this._importQuestions();
|
||||
//this._importChoices();
|
||||
// Retreive the prefetched 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.questionsCount = 0;
|
||||
this.qcm = data.qcm;
|
||||
if (this.qcm.name === 'bpa') {
|
||||
this.title = 'QCM du BPA';
|
||||
@@ -77,13 +90,7 @@ export class QcmComponent implements OnInit, OnDestroy {
|
||||
this.qcm.categories.forEach(category => {
|
||||
this.questionsCount += category.questions.length;
|
||||
category.questions.forEach(question => {
|
||||
this.questions.push(
|
||||
this.fb.group({
|
||||
id: new FormControl({ value: question.num, disabled: false }),
|
||||
choice: ['']
|
||||
//choice: new FormControl({ value: '', disabled: false })
|
||||
})
|
||||
);
|
||||
this.addQuestion(question);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -93,6 +100,7 @@ export class QcmComponent implements OnInit, OnDestroy {
|
||||
this.currentUser = userData;
|
||||
this.canModify = userData.role === 'Admin';
|
||||
});
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
@@ -100,15 +108,64 @@ export class QcmComponent implements OnInit, OnDestroy {
|
||||
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.answers.push(QcmQuestionState.UNANSWERED);
|
||||
this.questions.push(item);
|
||||
}
|
||||
|
||||
setExpandedIndex(index: number) {
|
||||
this.expandedIndex = index;
|
||||
}
|
||||
|
||||
onChange() {
|
||||
//this.isDisabled = true;
|
||||
onChange(category: QcmCategory, question: QcmQuestion, value: unknown) {
|
||||
//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) {
|
||||
this.answers[(question.num-1)] = QcmQuestionState.VALID;
|
||||
console.log(`Réponse à la question ${question.num} de la catégorie ${category.num} : correcte`);
|
||||
} else {
|
||||
this.answers[(question.num-1)] = QcmQuestionState.ERROR;
|
||||
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 {
|
||||
data.categories.forEach((category) => {
|
||||
category.questions.forEach(question => {
|
||||
@@ -132,7 +189,7 @@ export class QcmComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
importQuestions() {
|
||||
private _importQuestions() {
|
||||
try {
|
||||
data.categories.forEach((category) => {
|
||||
//Object.assign(this.jump, category);
|
||||
@@ -154,4 +211,8 @@ export class QcmComponent implements OnInit, OnDestroy {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
private _resetErrors(): void {
|
||||
this.errors = { errors: {} };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="credentials-page content">
|
||||
<div class="credentials-page">
|
||||
<h1>{{title}}</h1>
|
||||
<mat-divider></mat-divider>
|
||||
<app-list-errors [errors]="errors"></app-list-errors>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
.banner {
|
||||
background-color: var.$sidebar-footer;
|
||||
padding: 1.6rem 0 1.3rem 0;
|
||||
margin: -1.5rem -1.5rem 1.5rem -1.5rem;
|
||||
.user-img {
|
||||
width: var.$user-img-size;
|
||||
height: var.$user-img-size;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-page content">
|
||||
<div class="settings-page">
|
||||
<h1>{{title}}</h1>
|
||||
<mat-divider></mat-divider>
|
||||
<app-list-errors [errors]="errors"></app-list-errors>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
.banner {
|
||||
background-color: var.$sidebar-footer;
|
||||
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);
|
||||
margin-bottom: 1rem;
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
Directive,
|
||||
OnInit,
|
||||
AfterViewInit,
|
||||
AfterContentChecked
|
||||
} from '@angular/core';
|
||||
import { Directive, AfterContentChecked } from '@angular/core';
|
||||
import { Router, NavigationEnd } from '@angular/router';
|
||||
|
||||
import { AccordionLinkDirective } from './accordionlink.directive';
|
||||
@@ -51,7 +46,7 @@ export class AccordionDirective implements AfterContentChecked {
|
||||
ngAfterContentChecked(): void {
|
||||
this.router.events
|
||||
.pipe(filter(event => event instanceof NavigationEnd))
|
||||
.subscribe(e => this.checkOpenLinks());
|
||||
.subscribe(() => this.checkOpenLinks());
|
||||
}
|
||||
|
||||
constructor(private router: Router) {
|
||||
|
||||
@@ -14,7 +14,7 @@ export class AccordionAnchorDirective {
|
||||
}
|
||||
|
||||
@HostListener('click', ['$event'])
|
||||
onClick(e: any) {
|
||||
onClick() {
|
||||
this.navlink.toggle();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import { AccordionDirective } from './accordion.directive';
|
||||
})
|
||||
export class AccordionLinkDirective implements OnInit, OnDestroy {
|
||||
@Input()
|
||||
public group: any;
|
||||
public group!: string;
|
||||
|
||||
@HostBinding('class.selected')
|
||||
@Input()
|
||||
@@ -37,15 +37,15 @@ export class AccordionLinkDirective implements OnInit, OnDestroy {
|
||||
this.nav = nav;
|
||||
}
|
||||
|
||||
ngOnInit(): any {
|
||||
ngOnInit() {
|
||||
this.nav.addLink(this);
|
||||
}
|
||||
|
||||
ngOnDestroy(): any {
|
||||
ngOnDestroy(){
|
||||
this.nav.removeGroup(this);
|
||||
}
|
||||
|
||||
toggle(): any {
|
||||
toggle() {
|
||||
this.selected = !this.selected;
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AeronefsPieComponent } from './aeronefs-pie.component';
|
||||
|
||||
describe('AeronefsPieComponent', () => {
|
||||
let component: AeronefsPieComponent;
|
||||
let fixture: ComponentFixture<AeronefsPieComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [AeronefsPieComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AeronefsPieComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+3
-3
@@ -16,16 +16,16 @@ import { UtilitiesService, AeronefsService } from 'src/app/core/services';
|
||||
import { AeronefByImat, AeronefByYear } from 'src/app/core/models';
|
||||
|
||||
@Component({
|
||||
selector: 'app-aeronefs',
|
||||
selector: 'app-aeronefs-pie',
|
||||
standalone: true,
|
||||
imports: [
|
||||
MatBadgeModule, MatButtonModule, MatCardModule, MatDividerModule,
|
||||
MatExpansionModule, MatIconModule, MatMenuModule,
|
||||
HistoryTableComponent, PieChartComponent
|
||||
],
|
||||
templateUrl: './aeronefs.component.html'
|
||||
templateUrl: './aeronefs-pie.component.html'
|
||||
})
|
||||
export class AeronefsComponent implements OnInit, OnDestroy {
|
||||
export class AeronefsPieComponent implements OnInit, OnDestroy {
|
||||
private _aeronefByImat: Subscription = new Subscription();
|
||||
private _aeronefByYear: Subscription = new Subscription();
|
||||
private _aeronefsByImat!: Array<AeronefByImat>;
|
||||
+6
-6
@@ -1,20 +1,20 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DropZonesComponent } from './drop-zones.component';
|
||||
import { CanopiesModelsComponent } from './canopies-models.component';
|
||||
|
||||
describe('DropZonesComponent', () => {
|
||||
let component: DropZonesComponent;
|
||||
let fixture: ComponentFixture<DropZonesComponent>;
|
||||
describe('CanopiesModelsComponent', () => {
|
||||
let component: CanopiesModelsComponent;
|
||||
let fixture: ComponentFixture<CanopiesModelsComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [DropZonesComponent]
|
||||
imports: [CanopiesModelsComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DropZonesComponent);
|
||||
fixture = TestBed.createComponent(CanopiesModelsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
+3
-3
@@ -15,16 +15,16 @@ import { UtilitiesService, CanopiesService } from 'src/app/core/services';
|
||||
import { CanopyModelBySize, CanopyModelByYear } from 'src/app/core/models';
|
||||
|
||||
@Component({
|
||||
selector: 'app-canopy-models',
|
||||
selector: 'app-canopies-models',
|
||||
standalone: true,
|
||||
imports: [
|
||||
MatButtonModule, MatCardModule, MatDividerModule,
|
||||
MatExpansionModule, MatIconModule, MatMenuModule,
|
||||
PieChartComponent, HistoryTableComponent
|
||||
],
|
||||
templateUrl: './canopy-models.component.html'
|
||||
templateUrl: './canopies-models.component.html'
|
||||
})
|
||||
export class CanopyModelsComponent implements OnInit, OnDestroy {
|
||||
export class CanopiesModelsComponent implements OnInit, OnDestroy {
|
||||
private _canopyBySize: Subscription = new Subscription();
|
||||
private _canopyByYear: Subscription = new Subscription();
|
||||
private _canopiesBySize!: Array<CanopyModelBySize>;
|
||||
+6
-6
@@ -1,20 +1,20 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DropZonesBarComponent } from './drop-zones-bar.component';
|
||||
import { CanopiesSizesComponent } from './canopies-sizes.component';
|
||||
|
||||
describe('DropZonesBarComponent', () => {
|
||||
let component: DropZonesBarComponent;
|
||||
let fixture: ComponentFixture<DropZonesBarComponent>;
|
||||
describe('CanopiesSizesComponent', () => {
|
||||
let component: CanopiesSizesComponent;
|
||||
let fixture: ComponentFixture<CanopiesSizesComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [DropZonesBarComponent]
|
||||
imports: [CanopiesSizesComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DropZonesBarComponent);
|
||||
fixture = TestBed.createComponent(CanopiesSizesComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
+3
-3
@@ -16,16 +16,16 @@ import { UtilitiesService, CanopiesService } from 'src/app/core/services';
|
||||
import { CanopyBySize, CanopyByYear } from 'src/app/core/models';
|
||||
|
||||
@Component({
|
||||
selector: 'app-canopy-sizes',
|
||||
selector: 'app-canopies-sizes',
|
||||
standalone: true,
|
||||
imports: [
|
||||
MatButtonModule, MatCardModule, MatDividerModule,
|
||||
MatExpansionModule, MatIconModule, MatMenuModule,
|
||||
PieChartComponent, HistoryTableComponent
|
||||
],
|
||||
templateUrl: './canopy-sizes.component.html'
|
||||
templateUrl: './canopies-sizes.component.html'
|
||||
})
|
||||
export class CanopySizesComponent implements OnInit, OnDestroy {
|
||||
export class CanopiesSizesComponent implements OnInit, OnDestroy {
|
||||
private _canopyBySize: Subscription = new Subscription();
|
||||
private _canopyByYear: Subscription = new Subscription();
|
||||
private _canopiesBySize!: Array<CanopyBySize>;
|
||||
+6
-6
@@ -1,20 +1,20 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CanopyModelsComponent } from './canopy-models.component';
|
||||
import { DropzonesBarComponent } from './dropzones-bar.component';
|
||||
|
||||
describe('CanopyModelsComponent', () => {
|
||||
let component: CanopyModelsComponent;
|
||||
let fixture: ComponentFixture<CanopyModelsComponent>;
|
||||
describe('DropzonesBarComponent', () => {
|
||||
let component: DropzonesBarComponent;
|
||||
let fixture: ComponentFixture<DropzonesBarComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CanopyModelsComponent]
|
||||
imports: [DropzonesBarComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CanopyModelsComponent);
|
||||
fixture = TestBed.createComponent(DropzonesBarComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
+3
-3
@@ -17,7 +17,7 @@ import { UtilitiesService, DropZonesService } from 'src/app/core/services';
|
||||
import { DropZoneByOaci, DropZoneByYear } from 'src/app/core/models';
|
||||
|
||||
@Component({
|
||||
selector: 'app-drop-zones-bar',
|
||||
selector: 'app-dropzones-bar',
|
||||
standalone: true,
|
||||
imports: [
|
||||
MatButtonModule, MatCardModule, MatDividerModule,
|
||||
@@ -25,9 +25,9 @@ import { DropZoneByOaci, DropZoneByYear } from 'src/app/core/models';
|
||||
BaseChartDirective, ChartistModule,
|
||||
HistoryTableComponent
|
||||
],
|
||||
templateUrl: './drop-zones-bar.component.html'
|
||||
templateUrl: './dropzones-bar.component.html'
|
||||
})
|
||||
export class DropZonesBarComponent implements OnInit, OnDestroy {
|
||||
export class DropzonesBarComponent implements OnInit, OnDestroy {
|
||||
private _dropzoneByOaci: Subscription = new Subscription();
|
||||
private _dropzoneByYear: Subscription = new Subscription();
|
||||
private _dropzonesByOaci!: Array<DropZoneByOaci>;
|
||||
Executable
+6
-6
@@ -1,20 +1,20 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CanopySizesComponent } from './canopy-sizes.component';
|
||||
import { DropzonesPieComponent } from './dropzones-pie.component';
|
||||
|
||||
describe('CanopySizesComponent', () => {
|
||||
let component: CanopySizesComponent;
|
||||
let fixture: ComponentFixture<CanopySizesComponent>;
|
||||
describe('DropzonesPieComponent', () => {
|
||||
let component: DropzonesPieComponent;
|
||||
let fixture: ComponentFixture<DropzonesPieComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CanopySizesComponent]
|
||||
imports: [DropzonesPieComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CanopySizesComponent);
|
||||
fixture = TestBed.createComponent(DropzonesPieComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
+3
-3
@@ -16,16 +16,16 @@ import { UtilitiesService, DropZonesService } from 'src/app/core/services';
|
||||
import { DropZoneByOaci, DropZoneByYear } from 'src/app/core/models';
|
||||
|
||||
@Component({
|
||||
selector: 'app-drop-zones',
|
||||
selector: 'app-dropzones-pie',
|
||||
standalone: true,
|
||||
imports: [
|
||||
MatButtonModule, MatCardModule, MatDividerModule,
|
||||
MatExpansionModule, MatIconModule, MatMenuModule,
|
||||
PieChartComponent, HistoryTableComponent
|
||||
],
|
||||
templateUrl: './drop-zones.component.html'
|
||||
templateUrl: './dropzones-pie.component.html'
|
||||
})
|
||||
export class DropZonesComponent implements OnInit, OnDestroy {
|
||||
export class DropzonesPieComponent implements OnInit, OnDestroy {
|
||||
private _dropzoneByOaci: Subscription = new Subscription();
|
||||
private _dropzoneByYear: Subscription = new Subscription();
|
||||
private _dropzonesByOaci!: Array<DropZoneByOaci>;
|
||||
@@ -1,7 +1,7 @@
|
||||
export * from './aeronefs/aeronefs.component';
|
||||
export * from './aeronefs-pie/aeronefs-pie.component';
|
||||
export * from './aeronefs-bar/aeronefs-bar.component';
|
||||
export * from './canopy-models/canopy-models.component';
|
||||
export * from './canopy-sizes/canopy-sizes.component';
|
||||
export * from './drop-zones/drop-zones.component';
|
||||
export * from './drop-zones-bar/drop-zones-bar.component';
|
||||
export * from './canopies-models/canopies-models.component';
|
||||
export * from './canopies-sizes/canopies-sizes.component';
|
||||
export * from './dropzones-pie/dropzones-pie.component';
|
||||
export * from './dropzones-bar/dropzones-bar.component';
|
||||
export * from './jumps-by-month/jumps-by-month.component';
|
||||
+2
-1
@@ -74,6 +74,7 @@ export class JumpsByMonthComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
private _loadJumpByDate() {
|
||||
const minoration = 2; // -2 pour ne pas compter la première année
|
||||
this.seriesHeader = this._utilitiesService.getMonthsList();
|
||||
const values: Array<number> = this.seriesHeader.map(() => 0);
|
||||
this.seriesColTotal = [...values];
|
||||
@@ -111,7 +112,7 @@ export class JumpsByMonthComponent implements OnInit, OnDestroy {
|
||||
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
|
||||
const value: number = (row/(this.seriesName.length-minoration));
|
||||
this.seriesRowAvg.push(parseInt(value.toFixed(0)));
|
||||
});
|
||||
this.seriesColTotalLastYears.forEach((row: number) => {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<canvas baseChart class="w-100 h-auto"
|
||||
[data]="chartConfig.barChartData"
|
||||
[options]="chartConfig.barChartOptions"
|
||||
[plugins]="chartConfig.barChartPlugins"
|
||||
[plugins]="chartConfig.barChartPlugins!"
|
||||
[legend]="chartConfig.barChartLegend"
|
||||
[type]="'bar'">
|
||||
</canvas>
|
||||
|
||||
@@ -39,7 +39,7 @@ export class BarChartComponent implements OnChanges {
|
||||
}
|
||||
|
||||
private _loadBarChart(): void {
|
||||
const data: ChartDataset<'bar'> = {
|
||||
const dataset: ChartDataset<'bar'> = {
|
||||
data: [...this.values],
|
||||
label: this.label,
|
||||
backgroundColor: this.colors.backgroundColor,
|
||||
@@ -47,7 +47,7 @@ export class BarChartComponent implements OnChanges {
|
||||
borderWidth: 1
|
||||
};
|
||||
this.chartConfig.barChartData.labels = [...this.names];
|
||||
this.chartConfig.barChartData.datasets!.push(data);
|
||||
this.chartConfig.barChartData.datasets!.push(dataset);
|
||||
/*this.chartConfig.barChartOptions!.scales = {
|
||||
x: {display: false},
|
||||
y: {display: true}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<canvas baseChart
|
||||
[data]="chartConfig.barChartData"
|
||||
[options]="chartConfig.barChartOptions"
|
||||
[plugins]="chartConfig.barChartPlugins"
|
||||
[plugins]="chartConfig.barChartPlugins!"
|
||||
[legend]="chartConfig.barChartLegend"
|
||||
[type]="'bar'">
|
||||
</canvas>
|
||||
|
||||
@@ -39,7 +39,7 @@ export class BarHorizontalChartComponent implements OnChanges {
|
||||
}
|
||||
|
||||
private _loadBarChart(): void {
|
||||
const data: ChartDataset<'bar'> = {
|
||||
const dataset: ChartDataset<'bar'> = {
|
||||
data: [...this.values],
|
||||
label: this.label,
|
||||
backgroundColor: this.colors.backgroundColor,
|
||||
@@ -47,7 +47,7 @@ export class BarHorizontalChartComponent implements OnChanges {
|
||||
borderWidth: 1
|
||||
};
|
||||
this.chartConfig.barChartData.labels = [...this.names];
|
||||
this.chartConfig.barChartData.datasets!.push(data);
|
||||
this.chartConfig.barChartData.datasets!.push(dataset);
|
||||
this.chartConfig.barChartLegend = this.legend;
|
||||
this.displayCharts = true;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<canvas baseChart class="w-100 h-auto"
|
||||
[data]="chartConfig.barChartData"
|
||||
[options]="chartConfig.barChartOptions"
|
||||
[plugins]="chartConfig.barChartPlugins"
|
||||
[plugins]="chartConfig.barChartPlugins!"
|
||||
[legend]="chartConfig.barChartLegend"
|
||||
[type]="'bar'">
|
||||
</canvas>
|
||||
|
||||
@@ -34,7 +34,7 @@ export class BarsChartComponent implements OnChanges, AfterContentChecked {
|
||||
@Input() legend: boolean = false;
|
||||
|
||||
ngOnChanges() {
|
||||
//this._loadBarChart();
|
||||
this._loadBarChart();
|
||||
}
|
||||
|
||||
ngAfterContentChecked() {
|
||||
@@ -63,7 +63,7 @@ export class BarsChartComponent implements OnChanges, AfterContentChecked {
|
||||
}
|
||||
};
|
||||
this.names.forEach((label: string, index: number) => {
|
||||
const data: ChartDataset<'bar'> = {
|
||||
const dataset: ChartDataset<'bar'> = {
|
||||
data: [...this.values[index]],
|
||||
label: label,
|
||||
backgroundColor: this.colors.backgroundColor[index],
|
||||
@@ -71,7 +71,7 @@ export class BarsChartComponent implements OnChanges, AfterContentChecked {
|
||||
borderWidth: 1,
|
||||
//stack: 'Stack 0'
|
||||
};
|
||||
this.chartConfig.barChartData.datasets!.push(data);
|
||||
this.chartConfig.barChartData.datasets!.push(dataset);
|
||||
});
|
||||
this.chartConfig.barChartLegend = this.legend;
|
||||
this.displayCharts = true;
|
||||
|
||||
@@ -50,7 +50,7 @@ export class CircleChartComponent implements OnChanges {
|
||||
}
|
||||
|
||||
/*private _loadCircleChart(): void {
|
||||
const data: ChartDataset<'circle'> = {
|
||||
const dataset: ChartDataset<'circle'> = {
|
||||
data: [...this.values],
|
||||
label: 'Nombre total de sauts',
|
||||
backgroundColor: this._utilitiesService.getSeriesColors(0.8),
|
||||
@@ -58,7 +58,7 @@ export class CircleChartComponent implements OnChanges {
|
||||
borderWidth: 1
|
||||
};
|
||||
this.chartConfig.circleChartLabels = [...this.names];
|
||||
this.chartConfig.circleChartDatasets!.push(data);
|
||||
this.chartConfig.circleChartDatasets!.push(dataset);
|
||||
this.displayCharts = true;
|
||||
}*/
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, Input, OnChanges } from '@angular/core';
|
||||
import { ChartDataset } from 'chart.js';
|
||||
import { ChartDataset, Point } from 'chart.js';
|
||||
import { BaseChartDirective } from 'ng2-charts';
|
||||
|
||||
import { UtilitiesService } from 'src/app/core/services';
|
||||
@@ -32,6 +32,7 @@ export class LineChartComponent implements OnChanges {
|
||||
borderColor: this._utilitiesService.getSeriesColors(1)
|
||||
};
|
||||
@Input() legend: boolean = false;
|
||||
@Input() hideZero: boolean = false;
|
||||
|
||||
ngOnChanges() {
|
||||
this._loadLineChart();
|
||||
@@ -40,8 +41,14 @@ export class LineChartComponent implements OnChanges {
|
||||
private _loadLineChart(): void {
|
||||
this.chartConfig.lineChartData.labels = [...this.headers];
|
||||
this.names.forEach((label: string, index: number) => {
|
||||
const data: ChartDataset<'line'> = {
|
||||
data: [...this.values[index]],
|
||||
let data: Array<(number | Point | null)> = [];
|
||||
if (this.hideZero) {
|
||||
data = [...this.values[index].map(value => value === 0 ? null : value)];
|
||||
} else {
|
||||
data = [...this.values[index]];
|
||||
}
|
||||
const dataset: ChartDataset<'line'> = {
|
||||
data: data,
|
||||
label: label,
|
||||
backgroundColor: this.colors.backgroundColor[index],
|
||||
borderColor: this.colors.borderColor[index],
|
||||
@@ -49,7 +56,7 @@ export class LineChartComponent implements OnChanges {
|
||||
cubicInterpolationMode: 'monotone',
|
||||
tension: 0
|
||||
};
|
||||
this.chartConfig.lineChartData.datasets!.push(data);
|
||||
this.chartConfig.lineChartData.datasets!.push(dataset);
|
||||
});
|
||||
this.chartConfig.lineChartLegend = this.legend;
|
||||
this.displayCharts = true;
|
||||
|
||||
@@ -44,7 +44,7 @@ export class LineAreaChartComponent implements OnChanges {
|
||||
if (index === 0) {
|
||||
fill = true;
|
||||
}
|
||||
const data: ChartDataset<'line'> = {
|
||||
const dataset: ChartDataset<'line'> = {
|
||||
data: [...this.values[index]],
|
||||
label: label,
|
||||
backgroundColor: this.colors.backgroundColor[index],
|
||||
@@ -55,7 +55,7 @@ export class LineAreaChartComponent implements OnChanges {
|
||||
cubicInterpolationMode: 'monotone',
|
||||
tension: 0
|
||||
};
|
||||
this.chartConfig.lineChartData.datasets!.push(data);
|
||||
this.chartConfig.lineChartData.datasets!.push(dataset);
|
||||
});
|
||||
this.chartConfig.lineChartLegend = this.legend;
|
||||
this.displayCharts = true;
|
||||
|
||||
@@ -49,7 +49,7 @@ export class PieChartComponent implements OnChanges {
|
||||
}
|
||||
|
||||
/*private _loadDoughnutChart(): void {
|
||||
const data: ChartDataset<'doughnut'> = {
|
||||
const dataset: ChartDataset<'doughnut'> = {
|
||||
data: [...this.values],
|
||||
label: 'Nombre total de sauts',
|
||||
backgroundColor: this._utilitiesService.getSeriesColors(0.8),
|
||||
@@ -57,7 +57,7 @@ export class PieChartComponent implements OnChanges {
|
||||
borderWidth: 1
|
||||
};
|
||||
this.chartConfig.doughnutChartLabels = [...this.names];
|
||||
this.chartConfig.doughnutChartDatasets!.push(data);
|
||||
this.chartConfig.doughnutChartDatasets!.push(dataset);
|
||||
this.displayCharts = true;
|
||||
}*/
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, Input, OnChanges, AfterContentChecked } from '@angular/core';
|
||||
import { Component, Input, AfterContentChecked } from '@angular/core';
|
||||
import { NgIf, NgFor } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@@ -10,7 +10,7 @@ import { NgIf, NgFor } from '@angular/common';
|
||||
templateUrl: './history-table.component.html',
|
||||
styleUrls: []
|
||||
})
|
||||
export class HistoryTableComponent implements OnChanges, AfterContentChecked {
|
||||
export class HistoryTableComponent implements AfterContentChecked {
|
||||
public seriesColTotal: number[] = [];
|
||||
public grandTotal: number = 0;
|
||||
|
||||
@@ -22,10 +22,10 @@ export class HistoryTableComponent implements OnChanges, AfterContentChecked {
|
||||
@Input() rows: Array<Array<number>> = [];
|
||||
@Input() colors: string[] = [];
|
||||
|
||||
ngOnChanges() {
|
||||
/*ngOnChanges() {
|
||||
//this._loadHistoryTable();
|
||||
//console.log('onChanges');
|
||||
}
|
||||
}*/
|
||||
|
||||
ngAfterContentChecked() {
|
||||
if (this.rows !== undefined && this.rows.length) {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { Component, OnInit, OnDestroy, Input, computed, Signal, WritableSignal } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy, Input } from '@angular/core';
|
||||
import { NgClass, DatePipe } from '@angular/common';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { take } from 'rxjs/operators';
|
||||
|
||||
import { Errors, Jump, JumpList, JumpListConfig } from 'src/app/core/models';
|
||||
import { JumpsService } from 'src/app/core/services';
|
||||
|
||||
@@ -39,7 +39,7 @@ export class JumpPreviewComponent implements OnDestroy {
|
||||
|
||||
deleteJump() {
|
||||
this.isDeleting = true;
|
||||
const jump$: Observable<any> = this.jumpsService.destroy(this.jump.slug);
|
||||
const jump$: Observable<boolean> = this.jumpsService.destroy(this.jump.slug);
|
||||
this._jump = jump$.subscribe({
|
||||
next: () => {
|
||||
this.router.navigateByUrl('/');
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</button>
|
||||
<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]="!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>
|
||||
</div>
|
||||
<div class="col-md-6 col-xs-12 px-0">
|
||||
@@ -224,7 +224,7 @@
|
||||
</ng-container>
|
||||
</td>
|
||||
</ng-container> -->
|
||||
<!-- Video Column -->
|
||||
<!-- Video Column
|
||||
<ng-container matColumnDef="video">
|
||||
<th class="pl-3" mat-header-cell *matHeaderCellDef> Video </th>
|
||||
<td class="pl-3 text-nowrap" mat-cell *matCellDef="let element">
|
||||
@@ -236,6 +236,41 @@
|
||||
</ngx-skeleton-loader>
|
||||
}
|
||||
</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>
|
||||
<!-- Actions Column -->
|
||||
<ng-container matColumnDef="actions">
|
||||
@@ -247,13 +282,17 @@
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
<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)">
|
||||
<mat-icon aria-label="Modifier" fontIcon="edit" color="primary" class="mini"></mat-icon>
|
||||
<span class="text-primary">Modifier</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="openDeleteDialog(element)">
|
||||
<mat-icon aria-label="Supprimer" fontIcon="delete" color="danger" class="mini"></mat-icon>
|
||||
<span class="text-danger">Supprimer</span>
|
||||
<mat-icon aria-label="Supprimer" fontIcon="delete" color="raspberry" class="mini"></mat-icon>
|
||||
<span class="text-raspberry">Supprimer</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
}
|
||||
@@ -273,57 +312,3 @@
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true" class="accent"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;" class="text-middle accent"></tr>
|
||||
</table>
|
||||
<!--
|
||||
<table mat-table [dataSource]="jumps">
|
||||
<ng-container [matColumnDef]="col.key" *ngFor="let col of columnsSchema">
|
||||
<th mat-header-cell *matHeaderCellDef [ngSwitch]="col.key">
|
||||
<span *ngSwitchCase="'isSelected'">
|
||||
<mat-checkbox (change)="selectAll($event)" [checked]="isAllSelected()" [indeterminate]="!isAllSelected() && isAnySelected()"></mat-checkbox>
|
||||
</span>
|
||||
<span *ngSwitchDefault>{{ col.label }}</span>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
<div [ngSwitch]="col.type" *ngIf="!element.isEdit">
|
||||
<ng-container *ngSwitchCase="'isSelected'">
|
||||
<mat-checkbox (change)="element.isSelected = $event.checked" [checked]="element.isSelected">
|
||||
</mat-checkbox>
|
||||
</ng-container>
|
||||
<div class="btn-edit" *ngSwitchCase="'isEdit'">
|
||||
<button mat-button (click)="element.isEdit = !element.isEdit">
|
||||
Modifier
|
||||
</button>
|
||||
<button mat-button class="button-remove" (click)="openDeleteDialog(element)">
|
||||
Supprimer
|
||||
</button>
|
||||
</div>
|
||||
<span *ngSwitchCase="'date'">
|
||||
{{ element[col.key] | date: 'mediumDate' }}
|
||||
</span>
|
||||
<span *ngSwitchDefault>
|
||||
{{ element[col.key] }}
|
||||
</span>
|
||||
</div>
|
||||
<div [ngSwitch]="col.type" *ngIf="element.isEdit">
|
||||
<div *ngSwitchCase="'isSelected'"></div>
|
||||
<div class="btn-edit" *ngSwitchCase="'isEdit'">
|
||||
<button mat-icon-button color="primary" [hidden]="!showAdd" (click)="openEditDialog(element)" [disabled]="disableSubmit(element.id)">
|
||||
<mat-icon aria-label="Modifier" fontIcon="edit"></mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<mat-form-field class="form-input" *ngSwitchCase="'date'" appearance="fill">
|
||||
<mat-label>Choose a date</mat-label>
|
||||
<input matInput [matDatepicker]="picker" [(ngModel)]="element[col.key]" />
|
||||
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
|
||||
<mat-datepicker #picker></mat-datepicker>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-input" *ngSwitchDefault>
|
||||
<input matInput [required]="col.required!" [pattern]="col.pattern!" [type]="col.type"
|
||||
[(ngModel)]="element[col.key]" (change)="inputHandler($event, element.id, col.key)" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
|
||||
</table>
|
||||
-->
|
||||
|
||||
@@ -21,7 +21,7 @@ import { take } from 'rxjs/operators';
|
||||
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
||||
|
||||
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 { 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 {
|
||||
private _jumps: Subscription = new Subscription();
|
||||
private _subscriptions: Array<Subscription> = [];
|
||||
//private _jump: Subscription = new Subscription();
|
||||
private _query: JumpListConfig = { type: 'all', filters: {} };
|
||||
//private _lastjump: Jump = {} as Jump;
|
||||
@@ -53,13 +54,13 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
||||
'numero', 'date', 'lieu', 'oaci', 'aeronef',
|
||||
'imat', 'hauteur', 'voile', 'taille', 'categorie',
|
||||
'module', 'participants', 'programme', 'accessoires',
|
||||
'zone', 'video', 'actions'
|
||||
'zone', 'files', 'actions'
|
||||
];*/
|
||||
public displayedColumns: string[] = [
|
||||
'numero', 'date', 'lieu', 'aeronef',
|
||||
'hauteur', 'voile', 'categorie',
|
||||
'participants', 'zone', 'accessoires',
|
||||
'video', 'actions'
|
||||
'files', 'actions'
|
||||
];
|
||||
//public displayedColumns: string[] = jumpColumns.map((col) => col.key)
|
||||
public columnsSchema: Array<ColumnDefinition> = jumpColumns;
|
||||
@@ -115,7 +116,9 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
||||
|
||||
ngOnDestroy() {
|
||||
this._jumps.unsubscribe();
|
||||
//this._jump.unsubscribe();
|
||||
this._subscriptions.forEach(subscription => {
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterContentChecked() {
|
||||
@@ -155,6 +158,9 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
||||
const jumps$: Observable<JumpList> = this._jumpsService.query(this._query);
|
||||
this._jumps = jumps$.subscribe({
|
||||
next: (data: JumpList) => {
|
||||
//this.updateJumps(data.jumps);
|
||||
//this.linkSkydiverIdJumps();
|
||||
//this.getKmlJumpFiles(data.jumps);
|
||||
this.loading = false;
|
||||
this.jumps = new MatTableDataSource<Jump>(data.jumps);
|
||||
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) {
|
||||
this.isDeleting = true;
|
||||
this._jumpsService.destroy(slug).pipe(take(1))
|
||||
this._subscriptions.push(
|
||||
this._jumpsService.destroy(slug)
|
||||
.pipe(take(1))
|
||||
.subscribe(() => {
|
||||
this.router.navigateByUrl('/');
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
openDeleteDialog(jump: Jump): void {
|
||||
@@ -183,12 +327,15 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
||||
width: '60vw',
|
||||
data: jump
|
||||
});
|
||||
dialogRef.afterClosed().pipe(take(1))
|
||||
this._subscriptions.push(
|
||||
dialogRef.afterClosed()
|
||||
.pipe(take(1))
|
||||
.subscribe(result => {
|
||||
if (result != undefined) {
|
||||
this._onDelete(result.slug);
|
||||
}
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
openEditDialog(jump: Jump): void {
|
||||
@@ -196,12 +343,15 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
||||
width: '70vw',
|
||||
data: jump
|
||||
});
|
||||
dialogRef.afterClosed().pipe(take(1))
|
||||
this._subscriptions.push(
|
||||
dialogRef.afterClosed()
|
||||
.pipe(take(1))
|
||||
.subscribe(result => {
|
||||
if (result != undefined) {
|
||||
this._onEdit(result);
|
||||
}
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
openViewDialog(jump: Jump): void {
|
||||
@@ -230,6 +380,7 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
||||
private _onDelete(slug: string): void {
|
||||
try {
|
||||
this.isDeleting = true;
|
||||
this._subscriptions.push(
|
||||
this._jumpsService.destroy(slug)
|
||||
.pipe(take(1))
|
||||
.subscribe({
|
||||
@@ -243,7 +394,8 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
||||
error: (err) => {
|
||||
this.errors = err;
|
||||
}
|
||||
});
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
@@ -252,6 +404,7 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
||||
private _onEdit(jump: Jump): void {
|
||||
try {
|
||||
this.isSubmitting = true;
|
||||
this._subscriptions.push(
|
||||
this._jumpsService.update(jump)
|
||||
.pipe(take(1))
|
||||
.subscribe({
|
||||
@@ -266,7 +419,8 @@ export class JumpTableComponent implements OnChanges, OnDestroy, AfterContentChe
|
||||
this.errors = err;
|
||||
this.isSubmitting = false;
|
||||
}
|
||||
});
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<mat-toolbar class="topbar bg-primary">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="index.html">
|
||||
<a class="navbar-brand" href="/">
|
||||
<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">
|
||||
<path id="Jumper_2" fill="#FFFFFF"
|
||||
@@ -281,8 +281,8 @@
|
||||
<app-layout-footer></app-layout-footer>
|
||||
</mat-sidenav>
|
||||
<mat-sidenav-content class="page-wrapper">
|
||||
<div class="page-content">
|
||||
<!--<div class="page-content">-->
|
||||
<router-outlet><!--<app-spinner></app-spinner>--></router-outlet>
|
||||
</div>
|
||||
<!--</div>-->
|
||||
</mat-sidenav-content>
|
||||
</mat-sidenav-container>
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
|
||||
|
||||
import { Router, RouterOutlet, RouterModule } from '@angular/router';
|
||||
import { MediaMatcher } from '@angular/cdk/layout';
|
||||
import { MatBadgeModule } from '@angular/material/badge';
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -11,14 +11,19 @@ const MENUAUTH: Menu[] = [
|
||||
const MENUITEMS: Menu[] = [
|
||||
{ state: 'dashboard', type: 'link', name: 'Dashboard', icon: 'dashboard', 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: 'canopy', type: 'link', name: 'Voiles', icon: 'paragliding', desc: '' },
|
||||
{ state: 'dropzone', type: 'link', name: 'Dropzones', icon: 'adjust', desc: '' },
|
||||
{ state: 'jump', type: 'link', name: 'Sauts', icon: 'cloud_download', desc: '' },
|
||||
{ state: 'aeronefs', type: 'link', name: 'Aéronefs', icon: 'flight', desc: '' },
|
||||
{ state: 'dropzones', type: 'link', name: 'Drop Zones', icon: 'flight_takeoff', desc: '' },
|
||||
{ state: 'canopies', type: 'link', name: 'Voiles', icon: 'paragliding', desc: '' },
|
||||
{ state: 'jumps', type: 'link', name: 'Sauts', icon: 'filter_drama', desc: '' },
|
||||
{ state: 'calculator', type: 'link', name: 'Taille de voile', icon: 'calculate', 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[] = [
|
||||
{ state: 'bpa', type: 'link', name: 'BPA', icon: 'rule' },
|
||||
{ state: 'c', type: 'link', name: 'Brevet C', icon: 'rule' },
|
||||
@@ -63,4 +68,7 @@ export class MenuItems {
|
||||
getMenuPanel(): Menu[] {
|
||||
return MENUPANEL;
|
||||
}
|
||||
getMenuJump(): Menu[] {
|
||||
return MENUPJUMP;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ export class ShowAuthedDirective implements OnInit, OnDestroy {
|
||||
private _auth: Subscription = new Subscription();
|
||||
|
||||
constructor(
|
||||
private templateRef: TemplateRef<any>,
|
||||
//private templateRef: TemplateRef<any>,
|
||||
private templateRef: TemplateRef<never>,
|
||||
private userService: UserService,
|
||||
private viewContainer: ViewContainerRef
|
||||
) { }
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { inject } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivateFn, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { CanActivateFn, Router } from '@angular/router';
|
||||
import { map, take } from 'rxjs/operators';
|
||||
|
||||
import { UserService } from 'src/app/core/services';
|
||||
|
||||
export const adminGuard: CanActivateFn = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
|
||||
export const adminGuard: CanActivateFn = () => {
|
||||
const router = inject(Router);
|
||||
const userService = inject(UserService);
|
||||
return userService.currentUser.pipe(take(1)).pipe(map(data => {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { inject } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivateFn, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { CanActivateFn, Router } from '@angular/router';
|
||||
import { map, take } from 'rxjs/operators';
|
||||
|
||||
import { UserService } from 'src/app/core/services';
|
||||
|
||||
export const authGuard: CanActivateFn = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
|
||||
export const authGuard: CanActivateFn = () => {
|
||||
const router = inject(Router);
|
||||
const userService = inject(UserService);
|
||||
return userService.isAuthenticated.pipe(take(1)).pipe(map(data => {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { inject } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivateFn, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { CanActivateFn } from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, take } from 'rxjs/operators';
|
||||
|
||||
import { UserService } from 'src/app/core/services';
|
||||
|
||||
export const noauthGuard: CanActivateFn = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> => {
|
||||
export const noauthGuard: CanActivateFn = (): Observable<boolean> => {
|
||||
/*
|
||||
const router = inject(Router);
|
||||
const userService = inject(UserService);
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { Application } from './application.model';
|
||||
|
||||
export interface ApplicationList {
|
||||
applications: Array<Application>;
|
||||
applicationsCount: number;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
export interface CanopySize {
|
||||
id: string;
|
||||
key: any;
|
||||
value: any;
|
||||
doc?: CanopySizeDoc;
|
||||
}
|
||||
export interface CanopySizeDoc {
|
||||
_id: string;
|
||||
_rev: string;
|
||||
type: string;
|
||||
weight: number;
|
||||
values: [];
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { ChartConfiguration, ChartOptions } from 'chart.js';
|
||||
export interface BarConfig {
|
||||
barChartData: ChartConfiguration<'bar'>['data'],
|
||||
barChartOptions: ChartConfiguration<'bar'>['options'],
|
||||
barChartPlugins: any[],
|
||||
barChartPlugins: ChartConfiguration<'bar'>['plugins'],
|
||||
barChartLegend: boolean
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user