import { Component, Input, ViewChild, OnChanges, OnDestroy, computed, Signal, WritableSignal } from '@angular/core'; import { NgIf, DecimalPipe, DatePipe } from '@angular/common'; import { UntypedFormBuilder, UntypedFormGroup, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { Router, RouterLink } from '@angular/router'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatDialog, MatDialogModule } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; import { MatMenuModule } from '@angular/material/menu'; import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatSort, MatSortModule } from '@angular/material/sort'; import { MatTableDataSource, MatTableModule } from '@angular/material/table'; import { MatSnackBar, MatSnackBarHorizontalPosition, MatSnackBarModule, MatSnackBarVerticalPosition } from '@angular/material/snack-bar'; import { Observable, Subscription } from 'rxjs'; import { take } from 'rxjs/operators'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { Errors, Jump, JumpList, JumpListConfig } from 'src/app/core/models'; import { JumpsService, BackendService } from 'src/app/core/services'; import { JumpAddDialogComponent, JumpDeleteDialogComponent, JumpEditDialogComponent } from 'src/app/components/shared/dialogs' @Component({ standalone: true, imports: [ NgIf, DecimalPipe, DatePipe, RouterLink, FormsModule, ReactiveFormsModule, NgxSkeletonLoaderModule, MatFormFieldModule, MatInputModule, MatProgressSpinnerModule, MatButtonModule, MatCardModule, MatIconModule, MatMenuModule, MatPaginatorModule, MatTableModule, MatSortModule, MatSnackBarModule, MatDialogModule, JumpAddDialogComponent, JumpDeleteDialogComponent, JumpEditDialogComponent ], selector: 'huapp-jump-table', styleUrls: ['./jump-table.component.scss'], templateUrl: './jump-table.component.html' }) export class JumpTableComponent implements OnChanges, OnDestroy { private _jumps: Subscription = new Subscription(); private _lastjump: Subscription = new Subscription(); errors!: Errors; query: JumpListConfig = { type: 'all', filters: {} }; jump: Jump = {} as Jump; jumps!: MatTableDataSource; lastjump: Jump = {} as Jump; jumpsCount = 0; currentPage = 1; displayedColumns: string[] = [ 'numero', 'date', 'lieu', 'oaci', 'aeronef', 'imat', 'hauteur', 'voile', 'taille', 'categorie', 'module', 'participants', 'programme', 'accessoires', 'zone', 'video', 'actions' ]; lastUpdate: Date = new Date(); loading = false; isSubmitting = false; isDeleting = false; searchForm: UntypedFormGroup; @ViewChild(MatSort) sort!: MatSort; @ViewChild(MatPaginator) paginator!: MatPaginator; constructor( private router: Router, private jumpsService: JumpsService, private _dataService: BackendService, private dialog: MatDialog, private fb: UntypedFormBuilder, private snackBar: MatSnackBar ) { this._resetErrors(); this.searchForm = this.fb.group({ //numero: ['', Validators.required] numero: '' }); } @Input() limit = 0; @Input() refresh = 30000; @Input() title = ''; @Input() showAdd = false; @Input() isUser = false; @Input() set config(config: JumpListConfig) { if (config) { this.query = config; this.currentPage = 1; } } get config(): JumpListConfig { return this.query; } ngOnChanges() { this.loading = true; this.query = this.config; this.runQuery(); } ngOnDestroy() { this._jumps.unsubscribe(); this._lastjump.unsubscribe(); } runQuery() { const lastjump$: Observable = this.jumpsService.getLastJump(); this._lastjump = lastjump$.subscribe((jump) => { this.lastjump = jump; }); if (this.limit) { this.query.filters.limit = this.limit; this.query.filters.offset = (this.limit * (this.currentPage - 1)); } else { this.query.filters.limit = 0; this.query.filters.offset = 0; } const jumps$: Observable = this.jumpsService.query(this.query); this._jumps = jumps$.subscribe({ next: (data: JumpList) => { this.loading = false; this.jumps = new MatTableDataSource(data.jumps); this.jumpsCount = data.jumpsCount; this.paginator.length = data.jumpsCount; this.jumps.paginator = this.paginator; this.jumps.sort = this.sort; this._resetErrors(); }, error: (err) => { this.errors = err; } }); } deleteJump(slug: string) { this.isDeleting = true; this.jumpsService.destroy(slug).pipe(take(1)) .subscribe(() => { this.router.navigateByUrl('/'); }); } openAddDialog(): void { const dialogRef = this.dialog.open(JumpAddDialogComponent, { width: '60vw', data: this.jump }); dialogRef.afterClosed().pipe(take(1)) .subscribe(result => { if (result != undefined) { this._onEntry(result); } }); } openDeleteDialog(jump: Jump): void { const dialogRef = this.dialog.open(JumpDeleteDialogComponent, { width: '40vw', 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: '50vw', data: jump }); dialogRef.afterClosed().pipe(take(1)) .subscribe(result => { if (result != undefined) { this._onEdit(result); } }); } getErrorMessage() { if (this.searchForm.controls['numero'].errors !== null) { return 'Vous devez indiquer une valeur'; } return ''; } submitForm() { if (this.searchForm.valid) { this.query.filters.numero = this.searchForm.value.numero; this._resetErrors(); this.runQuery(); } } private _onDelete(slug: string): void { try { this.isDeleting = true; this.jumpsService.destroy(slug) .pipe(take(1)) .subscribe({ next: () => { this._resetErrors(); this._openSnackBar(`Le saut a été supprimé !`, 'OK'); this.runQuery(); }, error: (err) => { this.errors = err; } }); } catch (error) { console.error(error); } } private _onEdit(jump: Jump): void { try { this.isSubmitting = true; this.jumpsService.update(jump) .pipe(take(1)) .subscribe({ next: (jump) => { this._resetErrors(); this._openSnackBar(`Le saut n°${jump.numero} a été mis à jour !`, 'OK'); this.runQuery(); }, error: (err) => { this.errors = err; this.isSubmitting = false; } }); } catch (error) { console.error(error); } } private _onEntry(entry: NonNullable): void { try { this.isSubmitting = true; Object.assign(this.jump, entry); this.jumpsService.save(this.jump) .pipe(take(1)) .subscribe({ next: (jump) => { this._openSnackBar(`Le saut n°${jump.numero} a été ajouté !`, 'OK'); this._resetErrors(); this.runQuery(); }, error: (err) => { this.errors = err; this.isSubmitting = false; } }); } 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: {} }; } }