This commit is contained in:
Bastian Wagner
2024-10-23 13:58:14 +02:00
parent d4ddcafd2b
commit b453945183
33 changed files with 570 additions and 19 deletions

View File

@@ -0,0 +1,12 @@
<h2 mat-dialog-title>Gelöschte Schlüssel</h2>
<mat-dialog-content>
<ag-grid-angular
style="width: 100%; height: 100%;"
(gridReady)="onGridReady($event)"
[gridOptions]="gridOptions!"
/>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button [mat-dialog-close]="dataChanged">Schließen</button>
</mat-dialog-actions>

View File

@@ -0,0 +1,3 @@
mat-dialog-content{
}

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ArchiveComponent } from './archive.component';
describe('ArchiveComponent', () => {
let component: ArchiveComponent;
let fixture: ComponentFixture<ArchiveComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ArchiveComponent]
})
.compileComponents();
fixture = TestBed.createComponent(ArchiveComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,91 @@
import { AG_GRID_LOCALE_DE } from '@ag-grid-community/locale';
import { Component, inject, LOCALE_ID } from '@angular/core';
import { MatDialogModule } from '@angular/material/dialog';
import { AgGridAngular } from 'ag-grid-angular';
import { GridApi, GridOptions, GridReadyEvent } from 'ag-grid-community';
import { ApiService } from '../../../../shared/api.service';
import { DatePipe } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { IKey } from '../../../../model/interface/key.interface';
import { HotToastService } from '@ngxpert/hot-toast';
import { AgLoadingComponent } from '../../../../shared/ag-grid/components/ag-loading/ag-loading.component';
import { HELPER } from '../../../../shared/helper.service';
@Component({
selector: 'app-archive',
standalone: true,
imports: [MatDialogModule, AgGridAngular, MatButtonModule, MatIconModule],
providers: [DatePipe, { provide: LOCALE_ID, useValue: 'de-DE' }],
templateUrl: './archive.component.html',
styleUrl: './archive.component.scss'
})
export class ArchiveComponent {
private api: ApiService = inject(ApiService);
private datePipe = inject(DatePipe);
private toast = inject(HotToastService);
public dataChanged = false;
gridApi!: GridApi;
gridOptions: GridOptions = HELPER.getGridOptions();
constructor() {
this.gridOptions.columnDefs = [
{ 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 },
{
field: 'deletedAt'
, headerName: 'Gelöscht'
, width: 160
, type: 'date'
, cellRenderer: (data: any) => this.datePipe.transform(new Date(data.value), 'short')
},
{
width: 40,
cellRenderer: () => '<div class="icon-btn-sm restore" ></div>',
onCellClicked: (event) => { this.restoreKey(event.data);}
}
]
}
onGridReady(params: GridReadyEvent) {
this.gridApi = params.api;
this.loadKeys();
}
loadKeys() {
this.gridApi.setGridOption("loading", true);
this.api.getKeyArchive().subscribe({
next: n => {
this.gridApi.setGridOption("rowData", n);
this.gridApi.setGridOption("loading", false);
}
})
}
restoreKey(key: IKey) {
this.gridApi.setGridOption("loading", true);
key.deletedAt = undefined;
this.api.restoreKey(key.id)
.pipe(
this.toast.observe({
loading: 'Stelle wiederher...',
success: 'Schlüssel wiederhergestellt',
error: 'Es ist ein Fehler aufgetreten'
})
)
.subscribe({
next: () => {
this.dataChanged = true;
this.loadKeys();
},
error: () => {
this.gridApi.setGridOption("loading", false);
}
});
}
}

View File

@@ -0,0 +1,9 @@
<h2 mat-dialog-title>Schlüssel {{key.name}} löschen?</h2>
<mat-dialog-content>
<p>Soll der Schlüssel wirklich gelöscht werden?</p>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button [mat-dialog-close]="false" >Abbrechen</button>
<button mat-button [mat-dialog-close]="true" color="warn">Ja, löschen</button>
</mat-dialog-actions>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DeleteKeyComponent } from './delete-key.component';
describe('DeleteKeyComponent', () => {
let component: DeleteKeyComponent;
let fixture: ComponentFixture<DeleteKeyComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [DeleteKeyComponent]
})
.compileComponents();
fixture = TestBed.createComponent(DeleteKeyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,17 @@
import { Component, inject } from '@angular/core';
import { IKey } from '../../../../model/interface/key.interface';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { MatButtonModule } from '@angular/material/button';
@Component({
selector: 'app-delete-key',
standalone: true,
imports: [MatDialogModule, MatButtonModule],
templateUrl: './delete-key.component.html',
styleUrl: './delete-key.component.scss'
})
export class DeleteKeyComponent {
readonly dialogRef = inject(MatDialogRef<DeleteKeyComponent>);
readonly key = inject<IKey>(MAT_DIALOG_DATA);
}

View File

@@ -51,6 +51,7 @@ export class HandoverDialogComponent {
gridOptions: GridOptions = {
localeText: AG_GRID_LOCALE_DE,
rowData: [],
isRowSelectable: () => false,
columnDefs: [
{ colId: 'customer', field: 'customer.name' , headerName: 'Kunde', flex: 1, editable: false, filter: false},
{

View File

@@ -1,15 +1,21 @@
<h2 mat-dialog-title>Schlüssel anlegen</h2>
<h2 mat-dialog-title>Neuen Schlüssel anlegen</h2>
<mat-dialog-content>
<form [formGroup]="createForm" >
<mat-form-field>
<mat-label>Name</mat-label>
<input type="text" matInput formControlName="name">
<input type="text" matInput formControlName="name" maxlength="100">
@if ((createForm.controls.name.value || '').length > 20) {
<mat-hint>{{ (createForm.controls.name.value || '').length }} / 100 Zeichen</mat-hint>
} @else {
<mat-hint>Wie soll der Schlüssel heißen?</mat-hint>
}
</mat-form-field>
<mat-form-field>
<mat-label>Schlüsselnummer</mat-label>
<input type="text" matInput formControlName="nr">
<input type="number" matInput formControlName="nr" min="0" max="999999999999">
<mat-hint>Nummer auf dem Schlüssel</mat-hint>
</mat-form-field>
<mat-form-field>
@@ -19,6 +25,7 @@
<mat-option [value]="item">{{ item.name }}</mat-option>
}
</mat-select>
<mat-hint>Wo sperrt der Schlüssel?</mat-hint>
</mat-form-field>
</form>
</mat-dialog-content>

View File

@@ -1,4 +1,5 @@
form {
display: flex;
flex-direction: column;
gap: 12px;
}

View File

@@ -1,24 +1,27 @@
import { Component, inject } from '@angular/core';
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule } from '@angular/material/dialog';
import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { ApiService } from '../../../shared/api.service';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { map, Observable, startWith } from 'rxjs';
import { MatSelectModule } from '@angular/material/select';
import { HotToastService } from '@ngxpert/hot-toast';
@Component({
selector: 'app-create',
standalone: true,
imports: [MatDialogModule, MatButtonModule, ReactiveFormsModule, FormsModule, MatFormFieldModule, MatInputModule, MatSelectModule],
imports: [MatDialogModule, MatButtonModule, ReactiveFormsModule, FormsModule, MatFormFieldModule, MatInputModule, MatSelectModule, MatDialogModule],
templateUrl: './create.component.html',
styleUrl: './create.component.scss'
})
export class CreateKeyComponent {
private api: ApiService = inject(ApiService);
private toast: HotToastService = inject(HotToastService);
readonly dialogRef = inject(MatDialogRef<CreateKeyComponent>);
createForm = new FormGroup({
name: new FormControl(null, Validators.required),
@@ -54,7 +57,19 @@ export class CreateKeyComponent {
}
save() {
console.log(this.createForm.value)
this.api.createKey(this.createForm.value as any)
.pipe(
this.toast.observe({
error: 'Konnte nicht angelegt werden...',
loading: 'Speichern...',
success: 'Gespeichert'
})
)
.subscribe({
next: key => {
this.createForm.reset();
this.dialogRef.close(key);
}
})
}
}

View File

@@ -1,9 +1,10 @@
@if (gridOptions || true) {
<ag-grid-angular
style="width: 100%; height: 100%;"
(gridReady)="onGridReady($event)"
[gridOptions]="gridOptions!"
/>
}
<ag-grid-angular
style="width: 100%; height: 100%;"
(gridReady)="onGridReady($event)"
[gridOptions]="gridOptions!"
/>
<button mat-flat-button class="btn-create" (click)="openCreateKey()" >Schlüssel anlegen</button>
<div class="floating-btn-container">
<button mat-raised-button class="btn-create" (click)="openCreateKey()" >Schlüssel anlegen</button>
<button mat-mini-fab (click)="openArchive()"><mat-icon>inventory_2</mat-icon></button>
</div>

View File

@@ -1,5 +1,7 @@
.btn-create {
.floating-btn-container {
position: absolute;
bottom: 12px;
right: 12px;
display: flex;
gap: 12px;
}

View File

@@ -10,11 +10,15 @@ import { MatButtonModule } from '@angular/material/button';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { CreateKeyComponent } from './create/create.component';
import { AgOpenHandoutComponent } from '../../shared/ag-grid/components/ag-open-handout/ag-open-handout.component';
import { AgDeleteKeyComponent } from '../../shared/ag-grid/components/ag-delete-key/ag-delete-key.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';
@Component({
selector: 'app-keys',
standalone: true,
imports: [AgGridAngular, MatButtonModule, MatDialogModule],
imports: [AgGridAngular, MatButtonModule, MatDialogModule, MatIconModule],
providers: [DatePipe],
templateUrl: './keys.component.html',
styleUrl: './keys.component.scss'
@@ -70,9 +74,24 @@ export class KeysComponent {
, cellRenderer: (data: any) => data.value ? this.datePipe.transform(new Date(data.value)) : '-'
, tooltipValueGetter: (data: any) => this.datePipe.transform(new Date(data.value), 'medium')
}
,{
colId: 'delete'
, headerName: 'Löschen'
, width: 120
, cellRenderer: AgDeleteKeyComponent
// , onCellClicked: (event) => { this.deleteKey(event.data.id)}
}
],
loading: true,
rowHeight: 36,
loadingOverlayComponent: AgLoadingComponent
}
deleteKey(id: string) {
this.api.deleteKey(id).subscribe({
next: n => console.log(n)
})
}
ngOnInit(): void {
@@ -118,6 +137,31 @@ export class KeysComponent {
}
openCreateKey() {
this.dialog.open(CreateKeyComponent)
this.dialog.open(CreateKeyComponent).afterClosed().subscribe({
next: key => {
if (key) {
let d = [...this.gridApi.getGridOption("rowData") || [], key];
this.gridApi.setGridOption("rowData", d);
this.loadKeys();
}
}
})
}
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();
}
}
})
}
}