import { Component, inject } from '@angular/core'; import { AG_GRID_LOCALE_DE } from '@ag-grid-community/locale'; import { AgGridAngular } from 'ag-grid-angular'; import { GridOptions,GridApi, GridReadyEvent, CellEditingStoppedEvent, ICellEditorParams, FilterActionParams, FilterAction, themeQuartz, Theme, ThemeDefaultParams, AgGridEvent, CellClickedEvent, CellDoubleClickedEvent, ColDef } from 'ag-grid-community'; import { DatePipe } from '@angular/common'; import { ApiService } from '../../shared/api.service'; import { IKey } from '../../model/interface/key.interface'; import { HotToastService } from '@ngxpert/hot-toast'; import { MatButtonModule } from '@angular/material/button'; import { MatDialog, MatDialogModule } from '@angular/material/dialog'; import { CreateKeyComponent } from './create/create.component'; import { AgKeyActionsComponent } from '../../shared/ag-grid/components/ag-key-actions/ag-key-actions.component'; import { MatIconModule } from '@angular/material/icon'; import { ArchiveComponent } from './components/archive/archive.component'; import { AgLoadingComponent } from '../../shared/ag-grid/components/ag-loading/ag-loading.component'; import { map, of } from 'rxjs'; import { ICylinder } from '../../model/interface/cylinder.interface'; import { LostKeysComponent } from './components/lost-keys/lost-keys.component'; import { MatTooltipModule } from '@angular/material/tooltip'; import { SelectKeyCylinderComponent } from './create/select-key-cylinder/select-key-cylinder.component'; import { ActivatedRoute, Route } from '@angular/router'; import { ModuleRegistry } from 'ag-grid-community'; import { AgGridService } from '../../shared/ag-grid/ag-grid.service'; import { AgGridContainerComponent } from '../../shared/ag-grid/components/ag-grid-container/ag-grid-container.component'; @Component({ selector: 'app-keys', imports: [AgGridAngular, MatButtonModule, MatDialogModule, MatIconModule, MatTooltipModule], providers: [DatePipe, ModuleRegistry], templateUrl: './keys.component.html', styleUrl: './keys.component.scss' }) export class KeysComponent extends AgGridContainerComponent { private api: ApiService = inject(ApiService); private datePipe = inject(DatePipe); private toast: HotToastService = inject(HotToastService); private dialog: MatDialog = inject(MatDialog); private route: ActivatedRoute = inject(ActivatedRoute); // cylinders: any[] = []; gridApi!: GridApi; gridOptions: GridOptions = { localeText: AG_GRID_LOCALE_DE, rowData: [], columnDefs: [ { colId: 'id', field: 'id', headerName: 'ID', hide: true }, { colId: 'name', field: 'name' , headerName: 'Name', flex: 1, editable: true, sort: 'asc', filter: true }, { colId: 'nr', field: 'nr' , headerName: 'Schlüsselnummer', flex: 1, editable: true, filter: true }, { colId: 'cylinder', field: 'cylinder' , headerName: 'Zylinder', flex: 1, editable: false, filter: true, valueFormatter: (data: any) => { return data; }, cellRenderer: (data: any) => {return data.value?.map((m: ICylinder) => m.name).join(', ')}, tooltipValueGetter: (data: any) => data.value?.map((m: ICylinder) => m.name).join(','), onCellDoubleClicked: (event) => { this.openSelectCylinder(event) }, cellEditorPopup: true, filterValueGetter: (params: any) => {return params.data.cylinder?.map((m: ICylinder) => m.name).join(', ')}, }, { colId: 'system', field: 'cylinder' , headerName: 'Schließanlage', flex: 1, editable: false, filter: true, cellRenderer: (data: any) => { const s = new Set(data.value?.map((m: ICylinder) => m.system?.name)); return [...s].join(', ') }, filterValueGetter: (params: any) => { const s = new Set(params.data.cylinder?.map((m: ICylinder) => m.system?.name)); return [...s].join(', ') }, valueFormatter: (data: any) => { return data; }, }, { colId: 'customer', field: 'customer' , headerName: 'Mieter', flex: 1, editable: false, filter: true, cellRenderer: (data: any) => {return data.value?.name}, filterValueGetter: (params: any) => {return params.data.customer?.name}, valueFormatter: (data: any) => { return data; }, }, { field: 'createdAt', headerName: 'Erstellt', width: 120 , cellRenderer: (data: any) => this.datePipe.transform(new Date(data.value)) , tooltipValueGetter: (data: any) => this.datePipe.transform(new Date(data.value), 'medium'), valueFormatter: (data: any) => { return data; }, },{ colId: 'updatedAt', field: 'updatedAt', headerName: 'Geändert', width: 120, hide: true , cellRenderer: (data: any) => data.value ? this.datePipe.transform(new Date(data.value)) : '-' , tooltipValueGetter: (data: any) => this.datePipe.transform(new Date(data.value), 'medium') }, { colId: 'handedOut', field: 'handedOut' , headerName: 'Ausgegeben', width: 100, editable: false, filter: true, headerTooltip: 'Ausgegeben' }, { colId: 'digital', field: 'digital', headerName: 'Digital', hide: true }, { colId: 'actions', headerName: 'Aktionen', width: 140, sortable: false , cellRenderer: AgKeyActionsComponent ,valueFormatter: (data: any) => { return data; }, } ], loading: true, loadingOverlayComponent: AgLoadingComponent, pagination: true, } editKey(id: string) { } ngOnInit(): void { } private setFilterToParams() { const params = this.route.snapshot.queryParams; if (Object.keys(params).includes('handedOut')) { this.gridApi.setFilterModel({ handedOut: { filterType: 'text', type: params['handedOut'] } }) } if (Object.keys(params).includes('nr')) { this.gridApi.setFilterModel({ nr: { filterType: 'text', type: 'equals', filter: params['nr'] } }) } } loadKeys() { this.gridApi.setGridOption("loading", true); this.api.refreshKeys(); } onGridReady(params: GridReadyEvent) { this.gridApi = params.api; this.gridApi.addEventListener("cellEditingStopped", evt => this.cellEditEnd(evt)); this.api.keys.asObservable().subscribe({ next: keys => { this.gridApi.setGridOption("rowData", keys); this.gridApi.setGridOption("loading", false); } }) this.loadKeys(); this.setFilterToParams(); } async cellEditEnd(event: CellEditingStoppedEvent) { const key: IKey = event.data; if (!event.valueChanged || event.newValue == event.oldValue) { return; } this.gridApi.setGridOption("loading", true); await this.api.updateKey(key) this.gridApi.setGridOption("loading", false); } openCreateKey() { this.dialog.open(CreateKeyComponent, { maxWidth: "calc(100vw - 48px)", width: "800px", minWidth: "200px", disableClose: true }).afterClosed().subscribe({ next: key => { if (key) { let d = [...this.gridApi.getGridOption("rowData") || [], key]; this.gridApi.setGridOption("rowData", d); this.loadKeys(); } } }) } async openSelectCylinder(event: CellDoubleClickedEvent) { const key: IKey = event.data; this.gridApi.setGridOption("loading", true); const cylinders = await this.api.refreshCylinders() this.gridApi.setGridOption('loading', false) const ref = this.dialog.open(SelectKeyCylinderComponent, { data: cylinders, maxHeight: "calc(100vh - 48px)", maxWidth: "calc(100vw - 48px)", width: "50vw", minWidth: "300px", height: "70vh", disableClose: true, }); ref.afterOpened().subscribe({ next: () => { ref.componentInstance.preselectCylinders(event.data.cylinder); } }) ref.afterClosed().subscribe({ next: (cylinders: ICylinder[]) => { if (cylinders == null) { return; } key.cylinder = cylinders; this.api.updateKey(key) } }); } openArchive() { this.dialog.open(ArchiveComponent, { maxHeight: "calc(100vh - 24px)", maxWidth: "calc(100vw - 24px)", width: "50vw", minWidth: "300px", height: "70vh", disableClose: true }).afterClosed().subscribe({ next: changed => { if (changed) { this.loadKeys(); } } }) } openLostKeys() { this.dialog.open(LostKeysComponent, { maxHeight: "calc(100vh - 24px)", maxWidth: "calc(100vw - 24px)", width: "50vw", minWidth: "min(700px,calc(100vw - 24px))", height: "70vh", disableClose: true }).afterClosed().subscribe({ next: changed => { if (changed) { this.loadKeys(); } } }) } }