diff --git a/api/src/model/entitites/key.entity.ts b/api/src/model/entitites/key.entity.ts index ca7c9a3..20ab033 100644 --- a/api/src/model/entitites/key.entity.ts +++ b/api/src/model/entitites/key.entity.ts @@ -20,7 +20,7 @@ export class Key implements IKey { name: string; @Column({ name: 'key_number', unique: false }) - nr: number; + nr: string; @Column({ name: 'handed_out', default: false }) handedOut: boolean; diff --git a/api/src/model/entitites/key_activity.entity.ts b/api/src/model/entitites/key_activity.entity.ts index 0393616..fac6d45 100644 --- a/api/src/model/entitites/key_activity.entity.ts +++ b/api/src/model/entitites/key_activity.entity.ts @@ -22,7 +22,7 @@ export class KeyActivity implements IKey { name: string; @Column({ name: 'key_number' }) - nr: number; + nr: string; @Column({ name: 'handed_out', default: false }) handedOut: boolean; diff --git a/api/src/model/interface/key.interface.ts b/api/src/model/interface/key.interface.ts index 2cf819a..dbb30a3 100644 --- a/api/src/model/interface/key.interface.ts +++ b/api/src/model/interface/key.interface.ts @@ -3,7 +3,7 @@ import { Customer, Cylinder } from '../entitites'; export interface IKey { id: string; name: string; - nr: number; + nr: string; handedOut: boolean; cylinder: Cylinder; customer: Customer; diff --git a/api/src/modules/auth/auth.controller.ts b/api/src/modules/auth/auth.controller.ts index 17cb44a..d96c896 100644 --- a/api/src/modules/auth/auth.controller.ts +++ b/api/src/modules/auth/auth.controller.ts @@ -22,7 +22,6 @@ export class AuthController { @Body() authDto: AuthCodeDto, ): Promise { const user = await this.authService.registerOrLoginWithAuthCode(authDto); - console.log(user) if (user == null) { throw new HttpException('forbidden', HttpStatus.FORBIDDEN); } diff --git a/api/src/modules/auth/auth.service.ts b/api/src/modules/auth/auth.service.ts index d5e0113..5e85ffc 100644 --- a/api/src/modules/auth/auth.service.ts +++ b/api/src/modules/auth/auth.service.ts @@ -131,6 +131,7 @@ export class AuthService { this.generateTokens(user); return user; } catch (e) { + console.log(e); throw new HttpException('invalid token', HttpStatus.BAD_REQUEST); } } diff --git a/api/src/modules/key/key.controller.ts b/api/src/modules/key/key.controller.ts index 0f14213..0bbea48 100644 --- a/api/src/modules/key/key.controller.ts +++ b/api/src/modules/key/key.controller.ts @@ -3,8 +3,6 @@ import { Controller, Delete, Get, - HttpException, - HttpStatus, Param, Post, Put, diff --git a/api/src/modules/key/key.service.ts b/api/src/modules/key/key.service.ts index d3678ac..bcd7d96 100644 --- a/api/src/modules/key/key.service.ts +++ b/api/src/modules/key/key.service.ts @@ -10,6 +10,7 @@ import { } from 'src/model/repositories'; import { KeyHandoutRepository } from 'src/model/repositories/key-handout.repository'; import { IsNull, Not } from 'typeorm'; +import { faker } from '@faker-js/faker'; @Injectable() export class KeyService { @@ -19,7 +20,27 @@ export class KeyService { private readonly systemRepo: KeySystemRepository, private activityRepo: KeyActivityRepository, private handoverRepo: KeyHandoutRepository, - ) {} + ) { + this.create() + } + + async create() { + const c = await this.cylinderRepository.findOneBy({ name: 'DevCylinder1' }); + + const keys = []; + for (let x = 0; x < 1000; x++) { + keys.push( + this.keyrepository.create({ + name: faker.commerce.productName(), + nr: faker.commerce.isbn(), + cylinder: c, + createdAt: new Date(faker.date.past()) + }) + ); + } + await this.keyrepository.save(keys); + console.log("edn") + } async getUsersKeys(user: User): Promise { return this.keyrepository.find({ diff --git a/client/package-lock.json b/client/package-lock.json index df644f1..ad756ff 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -32,6 +32,7 @@ "@angular-devkit/build-angular": "^18.0.2", "@angular/cli": "^18.0.2", "@angular/compiler-cli": "^18.0.0", + "@faker-js/faker": "^9.0.3", "@types/jasmine": "~5.1.0", "jasmine-core": "~5.1.0", "karma": "~6.4.0", @@ -2752,6 +2753,23 @@ "node": ">=18" } }, + "node_modules/@faker-js/faker": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.0.3.tgz", + "integrity": "sha512-lWrrK4QNlFSU+13PL9jMbMKLJYXDFu3tQfayBsMXX7KL/GiQeqfB1CzHkqD5UHBUtPAuPo6XwGbMFNdVMZObRA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/fakerjs" + } + ], + "license": "MIT", + "engines": { + "node": ">=18.0.0", + "npm": ">=9.0.0" + } + }, "node_modules/@inquirer/checkbox": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-2.5.0.tgz", diff --git a/client/package.json b/client/package.json index 0a48e7e..0c3e1da 100644 --- a/client/package.json +++ b/client/package.json @@ -34,6 +34,7 @@ "@angular-devkit/build-angular": "^18.0.2", "@angular/cli": "^18.0.2", "@angular/compiler-cli": "^18.0.0", + "@faker-js/faker": "^9.0.3", "@types/jasmine": "~5.1.0", "jasmine-core": "~5.1.0", "karma": "~6.4.0", diff --git a/client/src/app/core/layout/layout.component.html b/client/src/app/core/layout/layout.component.html index ec8bfba..8a6d4ca 100644 --- a/client/src/app/core/layout/layout.component.html +++ b/client/src/app/core/layout/layout.component.html @@ -11,7 +11,7 @@ - + diff --git a/client/src/app/modules/auth/login/login.component.ts b/client/src/app/modules/auth/login/login.component.ts index c453443..ccbd6ac 100644 --- a/client/src/app/modules/auth/login/login.component.ts +++ b/client/src/app/modules/auth/login/login.component.ts @@ -1,14 +1,21 @@ import { Component, inject } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { AuthService } from '../../../core/auth/auth.service'; +import { MatDialog, MatDialogActions, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; @Component({ selector: 'app-login', standalone: true, - imports: [MatButtonModule], + imports: [MatButtonModule, MatDialogModule], templateUrl: './login.component.html', styleUrl: './login.component.scss' }) export class LoginComponent { public authService: AuthService = inject(AuthService); + readonly dialogRef = inject(MatDialog); + + ngOnInit() { + + this.dialogRef.closeAll(); + } } diff --git a/client/src/app/modules/keys/components/archive/archive.component.ts b/client/src/app/modules/keys/components/archive/archive.component.ts index 088ae36..a742913 100644 --- a/client/src/app/modules/keys/components/archive/archive.component.ts +++ b/client/src/app/modules/keys/components/archive/archive.component.ts @@ -44,10 +44,12 @@ export class ArchiveComponent { }, { width: 40, - cellRenderer: () => '
', - onCellClicked: (event) => { this.restoreKey(event.data);} + cellRenderer: () => '
', + onCellClicked: (event) => { this.restoreKey(event.data);}, + sortable: false } - ] + ]; + this.gridOptions.rowHeight = 36; } onGridReady(params: GridReadyEvent) { diff --git a/client/src/app/modules/keys/keys.component.html b/client/src/app/modules/keys/keys.component.html index 6bcc26b..b21620b 100644 --- a/client/src/app/modules/keys/keys.component.html +++ b/client/src/app/modules/keys/keys.component.html @@ -5,6 +5,6 @@ />
- +
diff --git a/client/src/app/modules/keys/keys.component.scss b/client/src/app/modules/keys/keys.component.scss index 495a9a3..ae1108a 100644 --- a/client/src/app/modules/keys/keys.component.scss +++ b/client/src/app/modules/keys/keys.component.scss @@ -1,7 +1,7 @@ .floating-btn-container { position: absolute; - bottom: 12px; - right: 12px; + bottom: 48px; + right: 24px; display: flex; gap: 12px; } \ No newline at end of file diff --git a/client/src/app/modules/keys/keys.component.ts b/client/src/app/modules/keys/keys.component.ts index 80f3fff..b401cb0 100644 --- a/client/src/app/modules/keys/keys.component.ts +++ b/client/src/app/modules/keys/keys.component.ts @@ -9,7 +9,6 @@ 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 { 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'; @@ -37,14 +36,7 @@ export class KeysComponent { localeText: AG_GRID_LOCALE_DE, rowData: [], columnDefs: [ - { - cellRenderer: AgOpenHandoutComponent, - width: 100, - headerName: 'Übergabe', - sortable: false, - colId: 'handover', - }, - { colId: 'handedOut', field: 'handedOut' , headerName: 'Ausgegeben', width: 100, editable: false, filter: false, headerTooltip: 'Ausgegeben' }, + { 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: true, filter: true, cellRenderer: (data: any) => {return data.value?.name}, cellEditor: 'agSelectCellEditor', @@ -54,8 +46,9 @@ export class KeysComponent { } }, valueFormatter: (val) => { - return val.value?.name; - } + return val.value?.name + ` (${val.value?.system?.name})`; + }, + cellEditorPopup: false }, { colId: 'system', field: 'cylinder.system' , headerName: 'Schließanlage', flex: 1, editable: false, filter: true, cellRenderer: (data: any) => {return data.value?.name} }, { @@ -73,19 +66,20 @@ export class KeysComponent { , type: 'date' , 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' + }, + { colId: 'handedOut', field: 'handedOut' , headerName: 'Ausgegeben', width: 100, editable: false, filter: false, headerTooltip: 'Ausgegeben' }, + { + colId: 'actions' + , headerName: 'Aktionen' , width: 120 , cellRenderer: AgDeleteKeyComponent // , onCellClicked: (event) => { this.deleteKey(event.data.id)} } ], loading: true, - rowHeight: 36, - loadingOverlayComponent: AgLoadingComponent + rowHeight: 54, + loadingOverlayComponent: AgLoadingComponent, + pagination: true, } deleteKey(id: string) { diff --git a/client/src/app/shared/ag-grid/components/ag-delete-key/ag-delete-key.component.html b/client/src/app/shared/ag-grid/components/ag-delete-key/ag-delete-key.component.html index 322d90b..caa34ff 100644 --- a/client/src/app/shared/ag-grid/components/ag-delete-key/ag-delete-key.component.html +++ b/client/src/app/shared/ag-grid/components/ag-delete-key/ag-delete-key.component.html @@ -1 +1,3 @@ -
\ No newline at end of file +
+ +
\ No newline at end of file diff --git a/client/src/app/shared/ag-grid/components/ag-delete-key/ag-delete-key.component.scss b/client/src/app/shared/ag-grid/components/ag-delete-key/ag-delete-key.component.scss index 9584b42..f2521a8 100644 --- a/client/src/app/shared/ag-grid/components/ag-delete-key/ag-delete-key.component.scss +++ b/client/src/app/shared/ag-grid/components/ag-delete-key/ag-delete-key.component.scss @@ -1,8 +1,13 @@ :host { display: flex; - flex-direction: column; + flex-direction: row; align-items: center; justify-content: center; width: 100%; height: 100%; + gap: 12px; +} + +.handover { + background-image: url('../../../../../assets/img/key_2.svg'); } \ No newline at end of file diff --git a/client/src/app/shared/ag-grid/components/ag-delete-key/ag-delete-key.component.ts b/client/src/app/shared/ag-grid/components/ag-delete-key/ag-delete-key.component.ts index 5472e8e..1cdb072 100644 --- a/client/src/app/shared/ag-grid/components/ag-delete-key/ag-delete-key.component.ts +++ b/client/src/app/shared/ag-grid/components/ag-delete-key/ag-delete-key.component.ts @@ -6,11 +6,13 @@ import { ApiService } from '../../../api.service'; import { MatDialog, MatDialogModule } from '@angular/material/dialog'; import { DeleteKeyComponent } from '../../../../modules/keys/components/delete-key/delete-key.component'; import { HotToastService } from '@ngxpert/hot-toast'; +import { HandoverDialogComponent } from '../../../../modules/keys/components/handover-dialog/handover-dialog.component'; +import { MatTooltipModule } from '@angular/material/tooltip'; @Component({ selector: 'app-ag-delete-key', standalone: true, - imports: [MatDialogModule], + imports: [MatDialogModule, MatTooltipModule], templateUrl: './ag-delete-key.component.html', styleUrl: './ag-delete-key.component.scss' }) @@ -66,4 +68,20 @@ export class AgDeleteKeyComponent implements ICellRendererAngularComp { }) } + + openHandoutDialog() { + this.dialog.open(HandoverDialogComponent, { + data: this.key, + autoFocus: false, + maxWidth: '100vw', + maxHeight: '100vh' + }).afterClosed().subscribe({ + next: n => { + if (n != null) { + this.key.handedOut = n; + this.params.api.refreshCells(); + } + } + }) + } } diff --git a/client/src/app/shared/ag-grid/components/ag-open-handout/ag-open-handout.component.html b/client/src/app/shared/ag-grid/components/ag-open-handout/ag-open-handout.component.html deleted file mode 100644 index fba54ca..0000000 --- a/client/src/app/shared/ag-grid/components/ag-open-handout/ag-open-handout.component.html +++ /dev/null @@ -1 +0,0 @@ -
diff --git a/client/src/app/shared/ag-grid/components/ag-open-handout/ag-open-handout.component.scss b/client/src/app/shared/ag-grid/components/ag-open-handout/ag-open-handout.component.scss deleted file mode 100644 index b8c9b12..0000000 --- a/client/src/app/shared/ag-grid/components/ag-open-handout/ag-open-handout.component.scss +++ /dev/null @@ -1,11 +0,0 @@ -:host { - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; - height: 100%; -} - -.handover { - background-image: url('../../../../../assets/img/key_2.svg'); -} \ No newline at end of file diff --git a/client/src/app/shared/ag-grid/components/ag-open-handout/ag-open-handout.component.ts b/client/src/app/shared/ag-grid/components/ag-open-handout/ag-open-handout.component.ts deleted file mode 100644 index 4cce201..0000000 --- a/client/src/app/shared/ag-grid/components/ag-open-handout/ag-open-handout.component.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Component, HostBinding, inject } from '@angular/core'; -import { ICellRendererAngularComp } from 'ag-grid-angular'; -import { ICellRendererParams } from 'ag-grid-community'; -import { IKey } from '../../../../model/interface/key.interface'; -import { MatDialog, MatDialogModule } from '@angular/material/dialog'; -import { HandoverDialogComponent } from '../../../../modules/keys/components/handover-dialog/handover-dialog.component'; -import {MatTooltipModule} from '@angular/material/tooltip'; - -@Component({ - selector: 'app-ag-open-handout', - standalone: true, - imports: [MatDialogModule, MatTooltipModule], - templateUrl: './ag-open-handout.component.html', - styleUrl: './ag-open-handout.component.scss' -}) -export class AgOpenHandoutComponent implements ICellRendererAngularComp { - private dialog: MatDialog = inject(MatDialog); - key!: IKey; - params!: ICellRendererParams; - - agInit(params: ICellRendererParams): void { - this.params = params; - this.key = params.data; - } - refresh(params: ICellRendererParams): boolean { - return false; - } - - - openDialog() { - this.dialog.open(HandoverDialogComponent, { - data: this.key, - autoFocus: false, - maxWidth: '100vw', - maxHeight: '100vh' - }).afterClosed().subscribe({ - next: n => { - if (n != null) { - this.key.handedOut = n; - this.params.api.refreshCells(); - } - } - }) - } -} diff --git a/client/src/app/shared/helper.service.ts b/client/src/app/shared/helper.service.ts index 0e8b2a9..57faaad 100644 --- a/client/src/app/shared/helper.service.ts +++ b/client/src/app/shared/helper.service.ts @@ -10,7 +10,8 @@ export class HELPER { rowData: [], columnDefs: [], loading: true, - loadingOverlayComponent: AgLoadingComponent + loadingOverlayComponent: AgLoadingComponent, + rowHeight: 54, } } } \ No newline at end of file diff --git a/client/src/styles.scss b/client/src/styles.scss index ebd7531..6f49393 100644 --- a/client/src/styles.scss +++ b/client/src/styles.scss @@ -1,4 +1,8 @@ /* You can add global styles to this file, and also import other style files */ +/* Core Data Grid CSS */ +@import "ag-grid-community/styles/ag-grid.css"; +/* Quartz Theme Specific CSS */ +@import 'ag-grid-community/styles/ag-theme-quartz.css'; html, body { height: 100vh; width: 100vw; @@ -6,6 +10,7 @@ html, body { margin: 0; padding: 0; background-color: #e2e2e2; + font-family: Roboto, "Helvetica Neue", sans-serif; } .flex { @@ -22,7 +27,7 @@ html, body { } .icon-btn-sm { - box-shadow: 0 0 0 4px transparent,0 1px 2px #0c111d11; + // box-shadow: 0 0 0 4px transparent,0 1px 2px #0c111d11; border: 1px solid #d0d5dd; background-color: white; cursor: pointer; @@ -32,9 +37,23 @@ html, body { background-size: 20px; background-position: center; background-repeat: no-repeat; - width: 26px; - height: 26px; + width: 38px; + height: 38px; + transition: box-shadow 0.1s ease-in-out; + &:hover { + // box-shadow: 0 0 0 4px transparent,0 1px 2px #0c111d11; + box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2), + 0px 6px 10px 0px rgba(0, 0, 0, 0.14), + 0px 1px 18px 0px rgba(0, 0, 0, 0.12); + } + +} + +.icon-btn-xs { + width: 28px; + height: 28px; + background-size: 20px; } .loading-spinner { @@ -59,9 +78,15 @@ html, body { background-image: url("./assets/img/restore.svg"); } -/* Core Data Grid CSS */ -@import "ag-grid-community/styles/ag-grid.css"; -/* Quartz Theme Specific CSS */ -@import 'ag-grid-community/styles/ag-theme-quartz.css'; -html, body { height: 100%; } -body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } +.ag-row { + transition: background-color 0.2s ease-in-out; +} + +.ag-row .ag-cell { + display: flex; + // justify-content: center; /* align horizontal */ + align-items: center; +} + + +