diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index e8c18fa..31ef6d6 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -10,6 +10,10 @@ const routes: Routes = [ path: 'dashboard', loadChildren: () => import('./components/dashboard/dashboard.module').then(m => m.DashboardModule) }, + { + path: 'jump', + loadChildren: () => import('./components/jump/jump.module').then(m => m.JumpModule) + }, { path: 'logbook', loadChildren: () => import('./components/logbook/logbook.module').then(m => m.LogbookModule) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 407efe4..bb78d40 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -11,8 +11,7 @@ import { AuthModule } from './components/auth/auth.module'; import { DashboardModule } from './components/dashboard/dashboard.module'; import { SpinnerComponent } from './components/shared'; import { FullComponent } from 'src/app/components/shared/layout'; -//import { FullComponent } from 'src/app/components/shared/layout/full.component'; -//import { HeaderComponent, FooterComponent, FullComponent } from 'src/app/components/shared/layout'; +//import { HeaderComponent, FooterComponent } from 'src/app/components/shared/layout'; registerLocaleData(localeFr); @@ -26,8 +25,8 @@ registerLocaleData(localeFr); BrowserAnimationsModule, SpinnerComponent, FullComponent, - //HeaderComponent, FooterComponent, FullComponent, DashboardModule + //HeaderComponent, FooterComponent ], providers: [ Title, { provide: LOCALE_ID, useValue: 'fr-FR' } ], bootstrap: [ AppComponent ] diff --git a/src/app/components/index.ts b/src/app/components/index.ts index 87cc1cc..3f485fc 100644 --- a/src/app/components/index.ts +++ b/src/app/components/index.ts @@ -1,6 +1,7 @@ export * from './auth/auth.component'; export * from './calculator/calculator.component'; export * from './dashboard/dashboard.component'; +export * from './jump/jump.component'; export * from './logbook/logbook.component'; export * from './profile/profile.component'; export * from './shared'; \ No newline at end of file diff --git a/src/app/components/jump/jump-resolver.service.ts b/src/app/components/jump/jump-resolver.service.ts new file mode 100644 index 0000000..bca7336 --- /dev/null +++ b/src/app/components/jump/jump-resolver.service.ts @@ -0,0 +1,24 @@ +import { Injectable, } from '@angular/core'; +import { ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot } from '@angular/router'; +import { Observable } from 'rxjs'; + +import { Jump } from 'src/app/core/models'; +import { JumpsService } from 'src/app/core/services'; +import { catchError } from 'rxjs/operators'; + +@Injectable() +export class JumpResolver implements Resolve { + constructor( + private _jumpsService: JumpsService, + private router: Router + ) { } + + resolve( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): Observable { + + return this._jumpsService.get(route.params['slug']) + .pipe(catchError(() => this.router.navigateByUrl('/'))); + } +} diff --git a/src/app/components/jump/jump-routing.module.ts b/src/app/components/jump/jump-routing.module.ts new file mode 100644 index 0000000..b59bd65 --- /dev/null +++ b/src/app/components/jump/jump-routing.module.ts @@ -0,0 +1,22 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; +import { JumpComponent } from './jump.component'; +import { JumpResolver } from './jump-resolver.service'; +import { AuthGuard } from 'src/app/core/services'; + +const routes: Routes = [ + { + path: ':slug', + component: JumpComponent, + canActivate: [AuthGuard], + resolve: { + jump: JumpResolver + } + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class JumpRoutingModule { } diff --git a/src/app/components/jump/jump.component.html b/src/app/components/jump/jump.component.html new file mode 100644 index 0000000..3c97e19 --- /dev/null +++ b/src/app/components/jump/jump.component.html @@ -0,0 +1,71 @@ +
+

Saut n°{{ jump.numero }} le {{ jump.date | date: 'dd/MM/yyyy' }} à {{ jump.lieu }}

+
+
+
+
+
Lieu:
+
{{jump.lieu}}
+
Oaci:
+
{{jump.oaci}}
+
Aeronef:
+
{{jump.aeronef}}
+
Imat:
+
{{jump.imat}}
+
Voile:
+
{{jump.voile}}
+
Taille:
+
{{jump.taille}} ft2
+
Programme:
+
{{jump.programme}}
+
Participants:
+
{{jump.participants}}
+
+
+
+
+
Hauteur:
+
{{jump.hauteur}} m
+
Deploiement:
+
{{jump.deploiement}} m
+
Categorie:
+
{{jump.categorie}}
+
Module:
+
{{jump.module}}
+
Accessoires:
+
{{jump.accessoires}}
+
Zone:
+
{{jump.zone}}
+
Video:
+
{{jump.dossier}}{{jump.video}}
+
+
+
+ + + {{ sautant }} + + + + ju_solide + +
+
+
+ + + + + + +
+
\ No newline at end of file diff --git a/src/app/components/jump/jump.component.scss b/src/app/components/jump/jump.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/components/jump/jump.component.spec.ts b/src/app/components/jump/jump.component.spec.ts new file mode 100644 index 0000000..5075de8 --- /dev/null +++ b/src/app/components/jump/jump.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { JumpComponent } from './jump.component'; + +describe('JumpComponent', () => { + let component: JumpComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [JumpComponent] + }); + fixture = TestBed.createComponent(JumpComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/jump/jump.component.ts b/src/app/components/jump/jump.component.ts new file mode 100644 index 0000000..d34a4e1 --- /dev/null +++ b/src/app/components/jump/jump.component.ts @@ -0,0 +1,139 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ActivatedRoute, Router, RouterModule } from '@angular/router'; +import { MatButtonModule } from '@angular/material/button'; +import { MatNativeDateModule } from '@angular/material/core'; +import { MatDialog, MatDialogModule } from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; +import { MatSnackBar, MatSnackBarHorizontalPosition, MatSnackBarModule, MatSnackBarVerticalPosition } from '@angular/material/snack-bar'; +import { Observable, Subscription } from 'rxjs'; +import { take } from 'rxjs/operators'; + +import { Errors, Jump, User } from 'src/app/core/models'; +import { JumpsService, UserService } from 'src/app/core/services'; +import { JumpDeleteDialogComponent, JumpEditDialogComponent } from 'src/app/components/shared/dialogs' + +@Component({ + standalone: true, + imports: [ + CommonModule, RouterModule, + MatButtonModule, MatDialogModule, MatIconModule, MatNativeDateModule, MatSnackBarModule, + JumpDeleteDialogComponent, JumpEditDialogComponent + ], + selector: 'huapp-jump', + templateUrl: './jump.component.html', + styleUrls: ['./jump.component.scss'] +}) +export class JumpComponent implements OnInit, OnDestroy { + private _currentUser: Subscription = new Subscription(); + private _data: Subscription = new Subscription(); + public errors!: Errors; + public jump: Jump = {} as Jump; + public currentUser: User = {} as User; + public canModify = false; + + constructor( + private route: ActivatedRoute, + private router: Router, + private dialog: MatDialog, + private _jumpsService: JumpsService, + private _userService: UserService, + private _snackBar: MatSnackBar + ) { } + + ngOnInit() { + // Retreive the prefetched jump + const data$: Observable = this.route.data; + this._data = data$.subscribe((data: { jump: Jump }) => { + this.jump = data.jump; + }); + // Load the current user's data + const currentUser$: Observable = this._userService.currentUser; + this._currentUser = currentUser$.subscribe((userData: User) => { + this.currentUser = userData; + this.canModify = this.currentUser.username === this.jump.author.username; + }); + } + + ngOnDestroy() { + this._data.unsubscribe(); + this._currentUser.unsubscribe(); + } + + openDeleteDialog(jump: Jump): void { + const dialogRef = this.dialog.open(JumpDeleteDialogComponent, { + width: '60vw', + data: jump + }); + dialogRef.afterClosed().pipe(take(1)) + .subscribe(result => { + if (result != undefined) { + this._onDelete(result.slug); + } + }); + } + + openEditDialog(jump: Jump): void { + const dialogRef = this.dialog.open(JumpEditDialogComponent, { + width: '70vw', + data: jump + }); + dialogRef.afterClosed().pipe(take(1)) + .subscribe(result => { + if (result != undefined) { + this._onEdit(result); + } + }); + } + + private _onDelete(slug: string): void { + try { + this._jumpsService.destroy(slug) + .pipe(take(1)) + .subscribe({ + next: () => { + this.router.navigateByUrl('/logbook'); + }, + error: (err) => { + this.errors = err; + } + }); + } catch (error) { + console.error(error); + } + } + + private _onEdit(jump: Jump): void { + try { + let previousValues: Jump = {} as Jump; + Object.assign(previousValues, this.jump); + this._jumpsService.update(jump) + .pipe(take(1)) + .subscribe({ + next: (jump) => { + this._resetErrors(); + this._openSnackBar(`Le saut n°${jump.numero} a été mis à jour !`, 'Annuler'); + this.jump = jump; + }, + error: (err) => { + this.errors = err; + } + }); + } catch (error) { + console.error(error); + } + } + + private _openSnackBar(content: string, title: string) { + this._snackBar.open(content, title, { + horizontalPosition: 'end', + verticalPosition: 'bottom', + duration: 4000, + }); + } + + private _resetErrors(): void { + this.errors = { errors: {} }; + } + +} diff --git a/src/app/components/jump/jump.module.ts b/src/app/components/jump/jump.module.ts new file mode 100644 index 0000000..c8feacb --- /dev/null +++ b/src/app/components/jump/jump.module.ts @@ -0,0 +1,19 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; + +import { JumpComponent } from './jump.component'; +import { JumpResolver } from './jump-resolver.service'; + +import { JumpRoutingModule } from './jump-routing.module'; + + +@NgModule({ + imports: [ + JumpRoutingModule, + JumpComponent + ], + providers: [ + JumpResolver + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class JumpModule { }