Import des sources angular à partir de 'headup_app'

This commit is contained in:
Rampeur
2025-08-11 23:26:29 +02:00
parent 7dcb426ef5
commit 0a6cbc0c00
335 changed files with 64362 additions and 0 deletions
@@ -0,0 +1,399 @@
import { CommonModule } from '@angular/common';
import { trigger, state, style, animate, transition } from '@angular/animations';
import { Component, AfterContentChecked, OnInit, OnDestroy, computed, signal, Signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatDividerModule } from '@angular/material/divider';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatMenuModule } from '@angular/material/menu';
import { MatSliderModule } from '@angular/material/slider';
import { MatSnackBar, MatSnackBarConfig, MatSnackBarHorizontalPosition, MatSnackBarModule, MatSnackBarVerticalPosition } from '@angular/material/snack-bar';
import { Observable, Subscription } from 'rxjs';
import { take } from 'rxjs/operators';
import { JumpAddDialogComponent } from 'src/app/components/logbook/dialogs';
import { MenuItems, JumpTableComponent } from 'src/app/components/shared';
import { Errors, Jump, JumpFile, JumpFileType, JumpListConfig, Range, User, X2Data } from 'src/app/core/models';
import { JumpsService, JumpTableService, UserService } from 'src/app/core/services';
import data from 'src/jumps.json';
//import data from 'src/jumps_02.json';
@Component({
standalone: true,
imports: [
CommonModule, RouterModule, FormsModule,
MatButtonModule, MatCardModule, MatDividerModule, MatExpansionModule,
MatIconModule, MatInputModule, MatMenuModule, MatDialogModule,
MatSliderModule, MatSnackBarModule,
JumpTableComponent
],
selector: 'app-logbook',
templateUrl: './logbook.component.html',
styleUrl: './logbook.component.scss',
animations: [
trigger('flyInOut', [
state('in', style({ transform: 'translateY(0)' })),
transition('void => *', [
style({ transform: 'translateY(-100%)' }),
animate(200)
]),
transition('* => void', [
style({ transform: 'translateY(100%)' }),
animate(200)
])
])
]
})
export class LogbookComponent implements OnInit, OnDestroy, AfterContentChecked {
private _currentUser: Subscription = new Subscription();
private _subscriptions: Array<Subscription> = [];
private _data: Subscription = new Subscription();
private _lastjump: Subscription = new Subscription();
private _lastjump$: Observable<Jump> = new Observable();
public jumpsCount = 0;
public errors!: Errors;
public title = 'Carnet de sauts';
public jump: Jump = {} as Jump;
public lastJump: Jump = {} as Jump;
public currentUser: User = {} as User;
public listConfig: JumpListConfig = { type: 'all', filters: {} };
public isAuthenticated = false;
public isUser = true;
public canModify = false;
public isSubmitting = false;
public tableRefresh = false;
public jumpRefresh = false;
public jumpsSinceHundred: Signal<number> = signal(0);
public jumpsToHundred: Signal<number> = signal(100);
public rangesMinMax: {
numero: Range;
taille: Range;
participants: Range;
hauteur: Range;
year: Range;
} = {
numero: {start: 1, end: 100000},
taille: {start: 1, end: 400},
participants: {start: 1, end: 200},
hauteur: {start: 0, end: 10000},
year: {start: 1970, end: 2020}
};
constructor(
private route: ActivatedRoute,
private router: Router,
private dialog: MatDialog,
private snackBar: MatSnackBar,
private _jumpsService: JumpsService,
private _jumpTableService: JumpTableService,
private _userService: UserService,
public menuItems: MenuItems
) { }
ngOnInit() {
//this.importJumps();
const data$: Observable<{isAuthenticated: boolean, lastjump: Jump}> = this.route.data as Observable<{isAuthenticated: boolean, lastjump: Jump}>;
this._data = data$.subscribe((data: {isAuthenticated: boolean, lastjump: Jump}) => {
this.isAuthenticated = data.isAuthenticated;
if (!this.isAuthenticated) {
this.router.navigateByUrl('/login');
return;
}
const currentUser$: Observable<User> = this._userService.currentUser;
this._currentUser = currentUser$.subscribe((userData: User) => {
this.currentUser = userData;
this.canModify = this.currentUser.role === 'Admin';
});
const currentYear: number = new Date().getFullYear();
this.lastJump = data['lastjump'];
this.rangesMinMax = {
numero: {start: 1, end: data.lastjump.numero},
taille: {start: data.lastjump.taille!, end: 230},
participants: {start: 1, end: 20},
hauteur: {start: 1000, end: 8000},
year: {start: 2018, end: currentYear}
}
this.listConfig.filters.numeroRangeStart = this.rangesMinMax.numero.start;
this.listConfig.filters.numeroRangeEnd = this.rangesMinMax.numero.end;
this.listConfig.filters.tailleRangeStart = this.rangesMinMax.taille.start;
this.listConfig.filters.tailleRangeEnd = this.rangesMinMax.taille.end;
this.listConfig.filters.participantsRangeStart = this.rangesMinMax.participants.start;
this.listConfig.filters.participantsRangeEnd = (this.rangesMinMax.participants.end / 2);
this.listConfig.filters.hauteurRangeStart = this.rangesMinMax.hauteur.start;
this.listConfig.filters.hauteurRangeEnd = this.rangesMinMax.hauteur.end;
this.listConfig.filters.yearRangeStart = this.rangesMinMax.year.start;
this.listConfig.filters.yearRangeEnd = this.rangesMinMax.year.end;
this.jumpsSinceHundred = computed(() => (this.lastJump.numero % 100));
this.jumpsToHundred = computed(() => (100 - this.jumpsSinceHundred()));
/*
this._lastjump$ = this._jumpsService.getLastJump();
this._lastjump = this._lastjump$.subscribe((jump) => {
const currentYear: number = new Date().getFullYear();
this.lastJump = jump;
this.rangesMinMax = {
numero: {start: 1, end: jump.numero},
taille: {start: jump.taille!, end: 230},
participants: {start: 1, end: 20},
hauteur: {start: 1000, end: 8000},
year: {start: 2018, end: currentYear}
}
this.listConfig.filters.numeroRangeStart = this.rangesMinMax.numero.start;
this.listConfig.filters.numeroRangeEnd = this.rangesMinMax.numero.end;
this.listConfig.filters.tailleRangeStart = this.rangesMinMax.taille.start;
this.listConfig.filters.tailleRangeEnd = this.rangesMinMax.taille.end;
this.listConfig.filters.participantsRangeStart = this.rangesMinMax.participants.start;
this.listConfig.filters.participantsRangeEnd = (this.rangesMinMax.participants.end / 2);
this.listConfig.filters.hauteurRangeStart = this.rangesMinMax.hauteur.start;
this.listConfig.filters.hauteurRangeEnd = this.rangesMinMax.hauteur.end;
this.listConfig.filters.yearRangeStart = this.rangesMinMax.year.start;
this.listConfig.filters.yearRangeEnd = this.rangesMinMax.year.end;
this.jumpsSinceHundred = computed(() => (this.lastJump.numero % 100));
this.jumpsToHundred = computed(() => (100 - this.jumpsSinceHundred()));
});
*/
});
}
ngOnDestroy() {
this._data.unsubscribe();
this._currentUser.unsubscribe();
this._lastjump.unsubscribe();
this._subscriptions.forEach(subscription => {
subscription.unsubscribe();
});
}
ngAfterContentChecked() {
if (this.tableRefresh != this._jumpTableService.tableRefresh) {
this.tableRefresh = this._jumpTableService.tableRefresh;
this._lastjump$ = this._jumpsService.getLastJump();
this._lastjump = this._lastjump$.subscribe((jump) => {
this.lastJump = jump;
});
console.log('lastjump has been updated in logbook component');
}
}
importJumps() {
try {
data.forEach((entry) => {
Object.assign(this.jump, entry);
this._jumpsService.save(this.jump)
.pipe(take(1))
.subscribe({
next: (jump) => {
console.log(`Le saut n°${jump.numero} a été ajouté !`, 'OK');
},
error: (err) => {
console.log(`Le saut n'a pas été ajouté !`, 'Error', err);
this.errors = err;
}
});
});
} catch (error) {
console.error(error);
}
}
openAddDialog(): void {
this.jump = <Jump>{};
this.jump.numero = (this.lastJump.numero + 1);
this.jump.sautants = [];
this.jump.participants = 1;
const dialogRef = this.dialog.open(JumpAddDialogComponent, {
width: '70vw',
data: {jump: this.jump, lastJump: this.lastJump}
});
dialogRef.afterClosed().pipe(take(1))
.subscribe(result => {
if (result != undefined) {
this._onEntry(result);
}
});
}
setTotalResults(value: number): void {
this.jumpsCount = value;
}
private _loadSkydiverIdJumps(jumps: Array<Jump>) {
const config: JumpListConfig = { type: 'all', filters: {} } as JumpListConfig;
config.filters.limit = 200;
config.filters.offset = 0;
config.filters.dateRangeStart = `${jumps[0].date!.substring(0, 10)} 00:00:00`;
config.filters.dateRangeEnd = `${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 = jumps.length - data.items.length;
if (diff < 0) {
console.error(`${diff} ${diff > 1 ? 'données' : 'donnée'} altimètre de trop le ${jumps[0].date!.substring(0, 10)}`);
}
if (diff > 0) {
console.error(`${diff}/${jumps.length} ${diff > 1 ? 'données altimètre manquantes' : 'donnée altimètre manquante'} le ${jumps[0].date!.substring(0, 10)}`, jumps, data.items);
}
console.log(`${jumps.length} ${jumps.length > 1 ? 'sauts' : 'saut'} le ${data.items[0].date!.substring(0, 10)}`, jumps.sort((a, b) => b.numero! - a.numero!), data.items);
this._addX2Data(data.items, jumps);
} else {
console.info('Aucune données altimètre pour le ', jumps[0].date!.substring(0, 10));
}
},
error: (err) => {
console.error('getAllFromSkydiverIdApi error');
this.errors = err;
}
});
this._subscriptions.push(subscription);
}
private _addJump(jumps: Array<Jump>, index: number = 0) {
this._jumpsService.save(jumps[index])
.pipe(take(1))
.subscribe({
next: (jump) => {
jumps[index] = jump;
console.log('Ajout du saut', jump.numero);
Object.assign(this.jump, jump);
this._openSnackBar(`Le saut n°${jump.numero} a été ajouté !`, 'Annuler');
this._resetErrors();
if (jumps.length == (index + 1)) {
this._loadSkydiverIdJumps(jumps);
} else {
this._addJump(jumps, (index + 1));
}
},
error: (err) => {
this.errors = err;
this.isSubmitting = false;
}
});
}
private _addX2Data(x2data: Array<X2Data>, jumps: Array<Jump>, index: number = 0) {
const file: JumpFile = {
name: x2data[index].name,
path: `/Volumes/Storage/Skydive/X2_Logs/${x2data[index].date!.substring(0, 4)}/`,
type: JumpFileType.CSV
} as JumpFile;
this._subscriptions.push(
this._jumpsService.saveX2Data(jumps[index].slug!, file, x2data[index])
.pipe(take(1))
.subscribe({
next: (jump) => {
jumps[index] = jump;
console.log(`Le fichier ${file.name} a été ajouté au saut n°${jump.numero} !`, 'OK');
if (jumps.length == (index + 1) || x2data.length == (index + 1)) {
this._addKmlFile(jumps);
} else {
this._addX2Data(x2data, jumps, (index + 1));
}
},
error: (err) => {
this.errors = err;
}
})
);
}
private _addKmlFile(jumps: Array<Jump>, index: number = 0) {
if (jumps[index].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: jumps[index].x2data.name.substring(0, -4) + '.kml',
path: `/Volumes/Storage/Skydive/X2_Kmls/${jumps[index].date.substring(0, 4)}/`,
type: JumpFileType.KML
} as JumpFile;
this._subscriptions.push(
this._jumpsService.saveKml(jumps[index].slug, file)
.pipe(take(1))
.subscribe({
next: (file) => {
console.log(`Le fichier ${file.path}${file.name} a été ajouté au saut n°${jumps[index].numero} !`, 'OK');
if (jumps.length == (index + 1)) {
this._resetErrors();
this.jumpRefresh = !this.jumpRefresh;
this._jumpTableService.updateJumpRefresh(this.jumpRefresh);
this._lastjump$ = this._jumpsService.getLastJump();
this._lastjump = this._lastjump$.subscribe((jump) => {
this.lastJump = jump;
});
} else {
this._addKmlFile(jumps, (index + 1));
}
},
error: (err) => {
this.errors = err;
}
})
);
}
}
private _onEntry(jumps: Array<Jump>): void {
if (jumps.length) {
this._addJump(jumps);
}
}
/*
private _onEntry(jumps: Array<Jump>): void {
const max: number = jumps.length;
let refresh: boolean = false;
jumps.forEach((jump: Jump, index: number) => {
console.log('Ajout du saut', jump.numero);
Object.assign(this.jump, jump);
if (max == index+1) {
refresh = true;
}
this._saveJump(jump, refresh);
});
}
private _saveJump(jump: Jump, refresh: boolean) {
this._jumpsService.save(jump)
.pipe(take(1))
.subscribe({
next: (jump) => {
this._openSnackBar(`Le saut n°${jump.numero} a été ajouté !`, 'Annuler');
this._resetErrors();
if (refresh) {
this.jumpRefresh = !this.jumpRefresh;
this._jumpTableService.updateJumpRefresh(this.jumpRefresh);
this._lastjump$ = this._jumpsService.getLastJump();
this._lastjump = this._lastjump$.subscribe((jump) => {
this.lastJump = jump;
});
}
},
error: (err) => {
this.errors = err;
this.isSubmitting = false;
}
});
}
*/
private _openSnackBar(content: string, title: string) {
const config: MatSnackBarConfig = {
horizontalPosition: <MatSnackBarHorizontalPosition>'end',
verticalPosition: <MatSnackBarVerticalPosition>'bottom',
duration: 4000
};
this.snackBar.open(content, title, config);
}
private _resetErrors(): void {
this.errors = { errors: {} };
}
}