From a47bbe29fe5645d33bf44b3c79445a68bc3c170d Mon Sep 17 00:00:00 2001 From: Bastian Wagner Date: Thu, 2 Jan 2025 16:53:16 +0100 Subject: [PATCH] create cylinder --- api/src/modules/cylinder/cylinder.service.ts | 14 +++-- api/src/modules/system/system.service.ts | 16 +++++- .../create-cylinder.component.html | 30 +++++++++++ .../create-cylinder.component.scss | 0 .../create-cylinder.component.spec.ts | 34 ++++++++++++ .../create-cylinder.component.ts | 53 +++++++++++++++++++ .../modules/cylinder/cylinder.component.html | 6 ++- .../modules/cylinder/cylinder.component.ts | 23 +++++++- .../dashboard/dashboard.component.html | 2 +- .../modules/dashboard/dashboard.component.ts | 2 + client/src/app/shared/api.service.ts | 4 ++ 11 files changed, 175 insertions(+), 9 deletions(-) create mode 100644 client/src/app/modules/cylinder/components/create-cylinder/create-cylinder.component.html create mode 100644 client/src/app/modules/cylinder/components/create-cylinder/create-cylinder.component.scss create mode 100644 client/src/app/modules/cylinder/components/create-cylinder/create-cylinder.component.spec.ts create mode 100644 client/src/app/modules/cylinder/components/create-cylinder/create-cylinder.component.ts diff --git a/api/src/modules/cylinder/cylinder.service.ts b/api/src/modules/cylinder/cylinder.service.ts index 3d37299..6d13572 100644 --- a/api/src/modules/cylinder/cylinder.service.ts +++ b/api/src/modules/cylinder/cylinder.service.ts @@ -1,12 +1,13 @@ import { Injectable } from '@nestjs/common'; import { Cylinder, User } from 'src/model/entitites'; -import { CylinderRepository, KeyRepository } from 'src/model/repositories'; +import { ActivityRepository, CylinderRepository, KeyRepository } from 'src/model/repositories'; @Injectable() export class CylinderService { constructor( private readonly cylinderRepo: CylinderRepository, private readonly keyRepo: KeyRepository, + private systemActivityRepo: ActivityRepository, ) {} async getCylinders(user: User): Promise { @@ -40,7 +41,14 @@ export class CylinderService { return this.cylinderRepo.save(original); } - createCylinder(user: User, cylinder: Partial) { - return this.cylinderRepo.save(this.cylinderRepo.create(cylinder)); + async createCylinder(user: User, cylinder: Partial) { + const c = await this.cylinderRepo.save(this.cylinderRepo.create(cylinder)); + + this.systemActivityRepo.save({ + message: `Zylinder ${(c as any).name} angelegt`, + user: user, + system: (c as any).system + }); + return c } } diff --git a/api/src/modules/system/system.service.ts b/api/src/modules/system/system.service.ts index 3c93ec0..50d937a 100644 --- a/api/src/modules/system/system.service.ts +++ b/api/src/modules/system/system.service.ts @@ -1,19 +1,31 @@ import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { CreateSystemDto } from './dto/create-system.dto'; import { UpdateSystemDto } from './dto/update-system.dto'; -import { KeySystemRepository, UserRepository } from 'src/model/repositories'; +import { ActivityRepository, KeySystemRepository, UserRepository } from 'src/model/repositories'; import { User } from 'src/model/entitites'; import { IUser } from 'src/model/interface'; @Injectable() export class SystemService { - constructor(private systemRepo: KeySystemRepository, private userRepo: UserRepository) {} + constructor( + private systemRepo: KeySystemRepository, + private userRepo: UserRepository, + private systemActivityRepo: ActivityRepository, + ) {} async create(user: User, createSystemDto: CreateSystemDto) { const sys = this.systemRepo.create(createSystemDto); sys.managers = [user]; try { const res = await this.systemRepo.save(sys); + + this.systemActivityRepo.save({ + message: `Schließanlage ${(res as any).name} angelegt`, + user: user, + system: res + }); + + return res; } catch (e) { throw new HttpException(e.code, HttpStatus.UNPROCESSABLE_ENTITY); diff --git a/client/src/app/modules/cylinder/components/create-cylinder/create-cylinder.component.html b/client/src/app/modules/cylinder/components/create-cylinder/create-cylinder.component.html new file mode 100644 index 0000000..0a76ad0 --- /dev/null +++ b/client/src/app/modules/cylinder/components/create-cylinder/create-cylinder.component.html @@ -0,0 +1,30 @@ +

Neuen Zylinder anlegen

+ +
+ + + Name + + @if ((createForm.controls.name.value || '').length > 20) { + {{ (createForm.controls.name.value || '').length }} / 100 Zeichen + } @else { + Wie soll der Zylinder heißen? + } + + + + Schließanlage + + @for (item of systems; track $index) { + {{ item.name }} + } + + Zu welcher Schließanlage gehört der Zylinder? + + +
+
+ + + + \ No newline at end of file diff --git a/client/src/app/modules/cylinder/components/create-cylinder/create-cylinder.component.scss b/client/src/app/modules/cylinder/components/create-cylinder/create-cylinder.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/client/src/app/modules/cylinder/components/create-cylinder/create-cylinder.component.spec.ts b/client/src/app/modules/cylinder/components/create-cylinder/create-cylinder.component.spec.ts new file mode 100644 index 0000000..9a7a36b --- /dev/null +++ b/client/src/app/modules/cylinder/components/create-cylinder/create-cylinder.component.spec.ts @@ -0,0 +1,34 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CreateCylinderComponent } from './create-cylinder.component'; +import { MatDialogRef } from '@angular/material/dialog'; +import { HotToastService } from '@ngxpert/hot-toast'; +import { ApiService } from '../../../../shared/api.service'; +import { MockApiService } from '../../../../../../mocks/services/mock.api.service'; +import { MockHotToastService } from '../../../../../../mocks/services/mock.hottoast.service'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; + +describe('CreateCylinderComponent', () => { + let component: CreateCylinderComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [CreateCylinderComponent, NoopAnimationsModule], + providers: [ + { provide: ApiService, useClass: MockApiService }, + { provide: MatDialogRef, useValue: [] }, + { provide: HotToastService, useClass: MockHotToastService } + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(CreateCylinderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/client/src/app/modules/cylinder/components/create-cylinder/create-cylinder.component.ts b/client/src/app/modules/cylinder/components/create-cylinder/create-cylinder.component.ts new file mode 100644 index 0000000..07f8c5c --- /dev/null +++ b/client/src/app/modules/cylinder/components/create-cylinder/create-cylinder.component.ts @@ -0,0 +1,53 @@ +import { Component, inject } from '@angular/core'; +import { FormGroup, FormControl, Validators, ReactiveFormsModule, FormsModule } from '@angular/forms'; +import { MatDialogModule, MatDialogRef } from '@angular/material/dialog'; +import { HotToastService } from '@ngxpert/hot-toast'; +import { ApiService } from '../../../../shared/api.service'; +import { CommonModule } from '@angular/common'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatSelectModule } from '@angular/material/select'; +import { MatButtonModule } from '@angular/material/button'; + +@Component({ + selector: 'app-create-cylinder', + standalone: true, + imports: [CommonModule, MatFormFieldModule, MatInputModule, MatDialogModule, ReactiveFormsModule, FormsModule, MatSelectModule, MatButtonModule], + templateUrl: './create-cylinder.component.html', + styleUrl: './create-cylinder.component.scss' +}) +export class CreateCylinderComponent { + private api: ApiService = inject(ApiService); + private toast: HotToastService = inject(HotToastService); + readonly dialogRef = inject(MatDialogRef); + + systems: any[] = []; + + createForm = new FormGroup({ + name: new FormControl(null, Validators.required), + system: new FormControl(null, Validators.required) + }); + + ngOnInit() { + this.api.getSystems().subscribe({ + next: systems => { + this.systems = systems; + } + }); + } + + save() { + this.api.createCylinder(this.createForm.value as any) + .pipe( + this.toast.observe({ + loading: 'Speichern...', + success: 'Gespeichert!', + error: 'Konnte nicht gespeichert werden' + }) + ).subscribe({ + next: cylinder => { + this.dialogRef.close(cylinder); + } + }); + } +} diff --git a/client/src/app/modules/cylinder/cylinder.component.html b/client/src/app/modules/cylinder/cylinder.component.html index 112977c..cb03be8 100644 --- a/client/src/app/modules/cylinder/cylinder.component.html +++ b/client/src/app/modules/cylinder/cylinder.component.html @@ -2,4 +2,8 @@ style="width: 100%; height: 100%;" (gridReady)="onGridReady($event)" [gridOptions]="gridOptions!" -/> \ No newline at end of file +/> +
+ + +
\ No newline at end of file diff --git a/client/src/app/modules/cylinder/cylinder.component.ts b/client/src/app/modules/cylinder/cylinder.component.ts index 0b404f5..7e353b1 100644 --- a/client/src/app/modules/cylinder/cylinder.component.ts +++ b/client/src/app/modules/cylinder/cylinder.component.ts @@ -5,11 +5,15 @@ import { AgGridAngular } from 'ag-grid-angular'; import { ApiService } from '../../shared/api.service'; import { DatePipe } from '@angular/common'; import { AgDeleteCylinderComponent } from '../../shared/ag-grid/components/ag-delete-cylinder/ag-delete-cylinder.component'; +import { MatDialog, MatDialogModule } from '@angular/material/dialog'; +import { CreateCylinderComponent } from './components/create-cylinder/create-cylinder.component'; +import { MatIconModule } from '@angular/material/icon'; +import { MatButtonModule } from '@angular/material/button'; @Component({ selector: 'app-cylinder', standalone: true, - imports: [AgGridAngular], + imports: [AgGridAngular, MatDialogModule, MatIconModule, MatButtonModule], providers: [DatePipe], templateUrl: './cylinder.component.html', styleUrl: './cylinder.component.scss' @@ -17,6 +21,7 @@ import { AgDeleteCylinderComponent } from '../../shared/ag-grid/components/ag-de export class CylinderComponent { private api: ApiService = inject(ApiService); private datePipe = inject(DatePipe); + private dialog = inject(MatDialog); gridApi!: GridApi; @@ -38,7 +43,6 @@ export class CylinderComponent { , cellRenderer: AgDeleteCylinderComponent } ] - } loadCylinders() { @@ -54,4 +58,19 @@ export class CylinderComponent { this.gridApi = params.api; this.loadCylinders(); } + + openCreateCylinder() { + this.dialog.open(CreateCylinderComponent, { + maxWidth: "calc(100vw - 24px)", + width: "30vw", + minWidth: "200px", + disableClose: true + }).afterClosed().subscribe({ + next: (cylinder) => { + if (cylinder) { + this.loadCylinders(); + } + } + }); + } } diff --git a/client/src/app/modules/dashboard/dashboard.component.html b/client/src/app/modules/dashboard/dashboard.component.html index 365f96b..a13a259 100644 --- a/client/src/app/modules/dashboard/dashboard.component.html +++ b/client/src/app/modules/dashboard/dashboard.component.html @@ -56,7 +56,7 @@ diff --git a/client/src/app/modules/dashboard/dashboard.component.ts b/client/src/app/modules/dashboard/dashboard.component.ts index d90bcd4..f01d084 100644 --- a/client/src/app/modules/dashboard/dashboard.component.ts +++ b/client/src/app/modules/dashboard/dashboard.component.ts @@ -7,6 +7,7 @@ import { MatIconModule } from '@angular/material/icon'; import {MatCardModule} from '@angular/material/card'; import { RouterModule } from '@angular/router'; import { AgLoadingComponent } from '../../shared/ag-grid/components/ag-loading/ag-loading.component'; +import { AG_GRID_LOCALE_DE } from '@ag-grid-community/locale'; @Component({ selector: 'app-dashboard', @@ -31,6 +32,7 @@ export class DashboardComponent { pagination: true, paginationPageSize: 10, loading: true, + localeText: AG_GRID_LOCALE_DE, loadingOverlayComponent: AgLoadingComponent }; diff --git a/client/src/app/shared/api.service.ts b/client/src/app/shared/api.service.ts index 0d4ce93..d04eb88 100644 --- a/client/src/app/shared/api.service.ts +++ b/client/src/app/shared/api.service.ts @@ -111,4 +111,8 @@ export class ApiService { getActivities(): Observable { return this.http.get('api/user/activities'); } + + createCylinder(data: any) { + return this.http.post('api/cylinder', data); + } }