| @@ -22,6 +22,7 @@ | |||||
| "@ngx-translate/core": "^15.0.0", | "@ngx-translate/core": "^15.0.0", | ||||
| "@ngx-translate/http-loader": "^8.0.0", | "@ngx-translate/http-loader": "^8.0.0", | ||||
| "@popperjs/core": "^2.11.8", | "@popperjs/core": "^2.11.8", | ||||
| "@types/node": "^20.11.5", | |||||
| "bootstrap": "^5.3.2", | "bootstrap": "^5.3.2", | ||||
| "bootstrap-icons": "^1.11.2", | "bootstrap-icons": "^1.11.2", | ||||
| "rxjs": "~7.8.0", | "rxjs": "~7.8.0", | ||||
| @@ -4635,10 +4636,9 @@ | |||||
| "dev": true | "dev": true | ||||
| }, | }, | ||||
| "node_modules/@types/node": { | "node_modules/@types/node": { | ||||
| "version": "20.10.5", | |||||
| "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", | |||||
| "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", | |||||
| "dev": true, | |||||
| "version": "20.11.5", | |||||
| "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.5.tgz", | |||||
| "integrity": "sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==", | |||||
| "dependencies": { | "dependencies": { | ||||
| "undici-types": "~5.26.4" | "undici-types": "~5.26.4" | ||||
| } | } | ||||
| @@ -13408,8 +13408,7 @@ | |||||
| "node_modules/undici-types": { | "node_modules/undici-types": { | ||||
| "version": "5.26.5", | "version": "5.26.5", | ||||
| "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", | ||||
| "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", | |||||
| "dev": true | |||||
| "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" | |||||
| }, | }, | ||||
| "node_modules/unicode-canonical-property-names-ecmascript": { | "node_modules/unicode-canonical-property-names-ecmascript": { | ||||
| "version": "2.0.0", | "version": "2.0.0", | ||||
| @@ -25,6 +25,7 @@ | |||||
| "@ngx-translate/core": "^15.0.0", | "@ngx-translate/core": "^15.0.0", | ||||
| "@ngx-translate/http-loader": "^8.0.0", | "@ngx-translate/http-loader": "^8.0.0", | ||||
| "@popperjs/core": "^2.11.8", | "@popperjs/core": "^2.11.8", | ||||
| "@types/node": "^20.11.5", | |||||
| "bootstrap": "^5.3.2", | "bootstrap": "^5.3.2", | ||||
| "bootstrap-icons": "^1.11.2", | "bootstrap-icons": "^1.11.2", | ||||
| "rxjs": "~7.8.0", | "rxjs": "~7.8.0", | ||||
| @@ -1,23 +1,56 @@ | |||||
| import { NgModule } from '@angular/core'; | |||||
| import { Routes, RouterModule } from '@angular/router'; | |||||
| import {NgModule} from '@angular/core'; | |||||
| import {Routes, RouterModule} from '@angular/router'; | |||||
| import { HomeComponent } from './home'; | |||||
| import { AuthGuard } from './_helpers'; | |||||
| import {HomeComponent} from './home'; | |||||
| import {AuthGuard} from './_helpers'; | |||||
| import {PartnersComponent} from "@app/partners/partners.component"; | |||||
| import {TwoColumnComponent} from "@app/layout/two-column/two-column.component"; | |||||
| import {PartnersDetailComponent} from "@app/partners/partners-detail/partners-detail.component"; | |||||
| const accountModule = () => import('./account/account.module').then(x => x.AccountModule); | const accountModule = () => import('./account/account.module').then(x => x.AccountModule); | ||||
| const usersModule = () => import('./users/users.module').then(x => x.UsersModule); | const usersModule = () => import('./users/users.module').then(x => x.UsersModule); | ||||
| const routes: Routes = [ | const routes: Routes = [ | ||||
| { path: '', component: HomeComponent, canActivate: [AuthGuard] }, | |||||
| { path: 'users', loadChildren: usersModule, canActivate: [AuthGuard] }, | |||||
| { path: 'account', loadChildren: accountModule }, | |||||
| {path: '', component: HomeComponent, canActivate: [AuthGuard]}, | |||||
| {path: 'users', loadChildren: usersModule, canActivate: [AuthGuard]}, | |||||
| {path: 'account', loadChildren: accountModule}, | |||||
| { | |||||
| path: 'customers', | |||||
| component: TwoColumnComponent, | |||||
| canActivate: [AuthGuard], | |||||
| children: [ | |||||
| {path: '', component: PartnersComponent, data: {dataType: 'customer'}}, | |||||
| {path: 'detail', component: PartnersDetailComponent, data: {dataType: 'customer-detail'}}, | |||||
| ] | |||||
| }, | |||||
| { | |||||
| path: 'suppliers', | |||||
| component: TwoColumnComponent, | |||||
| canActivate: [AuthGuard], | |||||
| children: [ | |||||
| {path: '', component: PartnersComponent, data: {dataType: 'supplier'}}, | |||||
| ] | |||||
| }, | |||||
| { | |||||
| path: 'service', | |||||
| component: TwoColumnComponent, | |||||
| canActivate: [AuthGuard], | |||||
| children: [ | |||||
| {path: '', component: PartnersComponent, data: {dataType: 'service'}}, | |||||
| ] | |||||
| }, | |||||
| // { path: 'customers', component: PartnersComponent, data: { dataType: 'customer' } }, | |||||
| // { path: 'suppliers', component: PartnersComponent, data: { dataType: 'supplier' } }, | |||||
| // { path: 'service', component: PartnersComponent, data: { dataType: 'service' } }, | |||||
| // otherwise redirect to home | // otherwise redirect to home | ||||
| { path: '**', redirectTo: '' } | |||||
| {path: '**', redirectTo: ''} | |||||
| ]; | ]; | ||||
| @NgModule({ | @NgModule({ | ||||
| imports: [RouterModule.forRoot(routes)], | imports: [RouterModule.forRoot(routes)], | ||||
| exports: [RouterModule] | exports: [RouterModule] | ||||
| }) | }) | ||||
| export class AppRoutingModule { } | |||||
| export class AppRoutingModule { | |||||
| } | |||||
| @@ -1,11 +1,11 @@ | |||||
| import { mergeApplicationConfig, ApplicationConfig } from '@angular/core'; | |||||
| import { provideServerRendering } from '@angular/platform-server'; | |||||
| import { appConfig } from './app.config'; | |||||
| import {mergeApplicationConfig, ApplicationConfig} from '@angular/core'; | |||||
| import {provideServerRendering} from '@angular/platform-server'; | |||||
| import {appConfig} from './app.config'; | |||||
| const serverConfig: ApplicationConfig = { | const serverConfig: ApplicationConfig = { | ||||
| providers: [ | |||||
| provideServerRendering() | |||||
| ] | |||||
| providers: [ | |||||
| provideServerRendering() | |||||
| ] | |||||
| }; | }; | ||||
| export const config = mergeApplicationConfig(appConfig, serverConfig); | export const config = mergeApplicationConfig(appConfig, serverConfig); | ||||
| @@ -18,6 +18,10 @@ import {MatCardModule} from "@angular/material/card"; | |||||
| import {TranslateLoader, TranslateModule} from "@ngx-translate/core"; | import {TranslateLoader, TranslateModule} from "@ngx-translate/core"; | ||||
| import {TranslateHttpLoader} from "@ngx-translate/http-loader"; | import {TranslateHttpLoader} from "@ngx-translate/http-loader"; | ||||
| import {NgOptimizedImage} from "@angular/common"; | import {NgOptimizedImage} from "@angular/common"; | ||||
| import {PartnersComponent} from './partners/partners.component'; | |||||
| import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; | |||||
| import {TwoColumnComponent} from './layout/two-column/two-column.component'; | |||||
| import {PartnersDetailComponent} from './partners/partners-detail/partners-detail.component'; | |||||
| export function apiConfigFactory(): Configuration { | export function apiConfigFactory(): Configuration { | ||||
| const params: ConfigurationParameters = { | const params: ConfigurationParameters = { | ||||
| @@ -36,6 +40,7 @@ export function HttpLoaderFactory(http: HttpClient) { | |||||
| imports: [ | imports: [ | ||||
| ApiModule.forRoot(apiConfigFactory), | ApiModule.forRoot(apiConfigFactory), | ||||
| BrowserModule, | BrowserModule, | ||||
| BrowserAnimationsModule, | |||||
| TranslateModule.forRoot({ | TranslateModule.forRoot({ | ||||
| defaultLanguage: 'de', | defaultLanguage: 'de', | ||||
| loader: { | loader: { | ||||
| @@ -49,12 +54,15 @@ export function HttpLoaderFactory(http: HttpClient) { | |||||
| NgbModule, | NgbModule, | ||||
| AppRoutingModule, | AppRoutingModule, | ||||
| MatCardModule, | MatCardModule, | ||||
| NgOptimizedImage | |||||
| NgOptimizedImage, | |||||
| PartnersComponent | |||||
| ], | ], | ||||
| declarations: [ | declarations: [ | ||||
| AppComponent, | AppComponent, | ||||
| AlertComponent, | AlertComponent, | ||||
| HomeComponent | |||||
| HomeComponent, | |||||
| TwoColumnComponent, | |||||
| PartnersDetailComponent | |||||
| ], | ], | ||||
| providers: [ | providers: [ | ||||
| {provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true}, | {provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true}, | ||||
| @@ -9,21 +9,21 @@ | |||||
| <div class="container"> | <div class="container"> | ||||
| <div class="row pt-4 pb-4 d-flex"> | <div class="row pt-4 pb-4 d-flex"> | ||||
| <div class="col d-flex"> | <div class="col d-flex"> | ||||
| <a class="card" routerLink="/users" routerLinkActive="active"> | |||||
| <a class="card" routerLink="/customers" routerLinkActive="active"> | |||||
| <div class="card-body position-relative bi bi-emoji-heart-eyes"> | <div class="card-body position-relative bi bi-emoji-heart-eyes"> | ||||
| <h3 class="position-absolute m-0">Kunden</h3> | <h3 class="position-absolute m-0">Kunden</h3> | ||||
| </div> | </div> | ||||
| </a> | </a> | ||||
| </div> | </div> | ||||
| <div class="col d-flex"> | <div class="col d-flex"> | ||||
| <a class="card" routerLink="/users" routerLinkActive="active"> | |||||
| <a class="card" routerLink="/suppliers" routerLinkActive="active"> | |||||
| <div class="card-body position-relative bi bi-emoji-kiss"> | <div class="card-body position-relative bi bi-emoji-kiss"> | ||||
| <h3 class="position-absolute m-0">Dienstleister</h3> | <h3 class="position-absolute m-0">Dienstleister</h3> | ||||
| </div> | </div> | ||||
| </a> | </a> | ||||
| </div> | </div> | ||||
| <div class="col d-flex"> | <div class="col d-flex"> | ||||
| <a class="card" routerLink="/users" routerLinkActive="active"> | |||||
| <a class="card" routerLink="/service" routerLinkActive="active"> | |||||
| <div class="card-body position-relative bi bi-emoji-smile"> | <div class="card-body position-relative bi bi-emoji-smile"> | ||||
| <h3 class="position-absolute m-0">Lieferanten</h3> | <h3 class="position-absolute m-0">Lieferanten</h3> | ||||
| </div> | </div> | ||||
| @@ -0,0 +1,51 @@ | |||||
| <div class="row ps-2"> | |||||
| <div class="col-2 pt-2" style="background: rgba(255,0,0,.7);"> | |||||
| <ul class="nav flex-column"> | |||||
| <li class="nav-item mb-3"> | |||||
| <a class="card" routerLink="/customers" routerLinkActive="active"> | |||||
| <div class="card-body position-relative bi bi-emoji-heart-eyes"> | |||||
| <h3 class="position-absolute m-0">Kunden</h3> | |||||
| </div> | |||||
| </a> | |||||
| </li> | |||||
| <li class="nav-item mb-3"> | |||||
| <a class="card" routerLink="/suppliers" routerLinkActive="active"> | |||||
| <div class="card-body position-relative bi bi-emoji-kiss"> | |||||
| <h3 class="position-absolute m-0">Dienstleister</h3> | |||||
| </div> | |||||
| </a> | |||||
| </li> | |||||
| <li class="nav-item mb-3"> | |||||
| <a class="card" routerLink="/service" routerLinkActive="active"> | |||||
| <div class="card-body position-relative bi bi-emoji-smile"> | |||||
| <h3 class="position-absolute m-0">Lieferanten</h3> | |||||
| </div> | |||||
| </a> | |||||
| </li> | |||||
| <li class="nav-item mb-3"> | |||||
| <a class="card" routerLink="/users" routerLinkActive="active"> | |||||
| <div class="card-body position-relative bi bi-droplet-fill"> | |||||
| <h3 class="position-absolute m-0">Produkte</h3> | |||||
| </div> | |||||
| </a> | |||||
| </li> | |||||
| <li class="nav-item mb-3"> | |||||
| <a class="card" routerLink="/users" routerLinkActive="active"> | |||||
| <div class="card-body position-relative bi bi-list-check"> | |||||
| <h3 class="position-absolute m-0">Aufgaben</h3> | |||||
| </div> | |||||
| </a> | |||||
| </li> | |||||
| <li class="nav-item mb-3"> | |||||
| <a class="card" routerLink="/users" routerLinkActive="active"> | |||||
| <div class="card-body position-relative bi bi-journals"> | |||||
| <h3 class="position-absolute m-0">Dokumente</h3> | |||||
| </div> | |||||
| </a> | |||||
| </li> | |||||
| </ul> | |||||
| </div> | |||||
| <div class="col-10"> | |||||
| <router-outlet></router-outlet> | |||||
| </div> | |||||
| </div> | |||||
| @@ -0,0 +1,31 @@ | |||||
| .card { | |||||
| width: 100%; | |||||
| text-decoration: none; | |||||
| } | |||||
| .card-body { | |||||
| min-height: 50px; | |||||
| text-transform: uppercase; | |||||
| text-align: right; | |||||
| &.bi { | |||||
| &:before { | |||||
| display: none; | |||||
| position: absolute; | |||||
| left: 50%; | |||||
| top: 50%; | |||||
| transform: translate(-50%,-50%); | |||||
| font-size: 50px; | |||||
| } | |||||
| } | |||||
| .active & { | |||||
| min-height: 100px; | |||||
| &.bi { | |||||
| &:before { | |||||
| display: block; | |||||
| } | |||||
| } | |||||
| } | |||||
| h3 { | |||||
| right: 10px; | |||||
| bottom: 10px; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,23 @@ | |||||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||||
| import { TwoColumnComponent } from './two-column.component'; | |||||
| describe('TwoColumnComponent', () => { | |||||
| let component: TwoColumnComponent; | |||||
| let fixture: ComponentFixture<TwoColumnComponent>; | |||||
| beforeEach(async () => { | |||||
| await TestBed.configureTestingModule({ | |||||
| declarations: [TwoColumnComponent] | |||||
| }) | |||||
| .compileComponents(); | |||||
| fixture = TestBed.createComponent(TwoColumnComponent); | |||||
| component = fixture.componentInstance; | |||||
| fixture.detectChanges(); | |||||
| }); | |||||
| it('should create', () => { | |||||
| expect(component).toBeTruthy(); | |||||
| }); | |||||
| }); | |||||
| @@ -0,0 +1,10 @@ | |||||
| import { Component } from '@angular/core'; | |||||
| @Component({ | |||||
| selector: 'app-two-column', | |||||
| templateUrl: './two-column.component.html', | |||||
| styleUrl: './two-column.component.scss' | |||||
| }) | |||||
| export class TwoColumnComponent { | |||||
| } | |||||
| @@ -0,0 +1 @@ | |||||
| <p>partners-detail works!</p> | |||||
| @@ -0,0 +1,23 @@ | |||||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||||
| import { PartnersDetailComponent } from './partners-detail.component'; | |||||
| describe('PartnersDetailComponent', () => { | |||||
| let component: PartnersDetailComponent; | |||||
| let fixture: ComponentFixture<PartnersDetailComponent>; | |||||
| beforeEach(async () => { | |||||
| await TestBed.configureTestingModule({ | |||||
| declarations: [PartnersDetailComponent] | |||||
| }) | |||||
| .compileComponents(); | |||||
| fixture = TestBed.createComponent(PartnersDetailComponent); | |||||
| component = fixture.componentInstance; | |||||
| fixture.detectChanges(); | |||||
| }); | |||||
| it('should create', () => { | |||||
| expect(component).toBeTruthy(); | |||||
| }); | |||||
| }); | |||||
| @@ -0,0 +1,10 @@ | |||||
| import { Component } from '@angular/core'; | |||||
| @Component({ | |||||
| selector: 'app-partners-detail', | |||||
| templateUrl: './partners-detail.component.html', | |||||
| styleUrl: './partners-detail.component.scss' | |||||
| }) | |||||
| export class PartnersDetailComponent { | |||||
| } | |||||
| @@ -0,0 +1,36 @@ | |||||
| <button (click)="goBack()">Zurück</button> | |||||
| <table mat-table [dataSource]="dataSource" matSort (matSortChange)="announceSortChange($event)" | |||||
| class="mat-elevation-z8"> | |||||
| <ng-container matColumnDef="position"> | |||||
| <th mat-header-cell *matHeaderCellDef mat-sort-header sortActionDescription="Nach Nummer sortieren"> | |||||
| Nr. | |||||
| </th> | |||||
| <td mat-cell *matCellDef="let element"> {{element.position}} </td> | |||||
| </ng-container> | |||||
| <ng-container matColumnDef="partner"> | |||||
| <th mat-header-cell *matHeaderCellDef mat-sort-header sortActionDescription="Nach Partner sortieren"> | |||||
| Partner | |||||
| </th> | |||||
| <td mat-cell *matCellDef="let element"> {{element.partner}} </td> | |||||
| </ng-container> | |||||
| <ng-container matColumnDef="address"> | |||||
| <th mat-header-cell *matHeaderCellDef mat-sort-header="street" sortActionDescription="Nach Adresse sortieren"> | |||||
| Adresse | |||||
| </th> | |||||
| <td mat-cell *matCellDef="let element"> {{element.street}} {{element.street_no}}<br />{{element.zip}} {{element.city}} </td> | |||||
| </ng-container> | |||||
| <ng-container matColumnDef="website"> | |||||
| <th mat-header-cell *matHeaderCellDef mat-sort-header sortActionDescription="Nach Website sortieren"> | |||||
| Website | |||||
| </th> | |||||
| <td mat-cell *matCellDef="let element"> {{element.website}} </td> | |||||
| </ng-container> | |||||
| <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> | |||||
| <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> | |||||
| </table> | |||||
| @@ -0,0 +1,7 @@ | |||||
| table { | |||||
| width: 100%; | |||||
| } | |||||
| th.mat-sort-header-sorted { | |||||
| color: black; | |||||
| } | |||||
| @@ -0,0 +1,23 @@ | |||||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||||
| import { PartnersComponent } from './partners.component'; | |||||
| describe('PartnersComponent', () => { | |||||
| let component: PartnersComponent; | |||||
| let fixture: ComponentFixture<PartnersComponent>; | |||||
| beforeEach(async () => { | |||||
| await TestBed.configureTestingModule({ | |||||
| declarations: [PartnersComponent] | |||||
| }) | |||||
| .compileComponents(); | |||||
| fixture = TestBed.createComponent(PartnersComponent); | |||||
| component = fixture.componentInstance; | |||||
| fixture.detectChanges(); | |||||
| }); | |||||
| it('should create', () => { | |||||
| expect(component).toBeTruthy(); | |||||
| }); | |||||
| }); | |||||
| @@ -0,0 +1,67 @@ | |||||
| import {AfterViewInit, Component, OnInit, ViewChild} from '@angular/core'; | |||||
| import {MatSort, Sort, MatSortModule} from "@angular/material/sort"; | |||||
| import {LiveAnnouncer} from "@angular/cdk/a11y"; | |||||
| import {MatTableDataSource, MatTableModule} from "@angular/material/table"; | |||||
| import {Location} from "@angular/common"; | |||||
| import {ActivatedRoute} from "@angular/router"; | |||||
| export interface PeriodicElement { | |||||
| position: number; | |||||
| partner: string; | |||||
| street: string; | |||||
| street_no: string; | |||||
| zip: string; | |||||
| city: string; | |||||
| website: string; | |||||
| } | |||||
| const ELEMENT_DATA: PeriodicElement[] = [ | |||||
| {position: 1, partner: 'spawntree GmbH', street: 'Bauernvogtskoppel', street_no: '6c', zip: '21465', city: 'Wentorf', website: 'http://spawntree.de'}, | |||||
| {position: 2, partner: 'Peter Pan AG', street: 'Heinrich-Löhns-Weg', street_no: '123b', zip: '22134', city: 'Hamburg', website: ''}, | |||||
| {position: 3, partner: 'Weit Weg GmbH', street: 'Hans-Werner-Olm Straße', street_no: '1', zip: '87254', city: 'München', website: 'http://weitweg.de'}, | |||||
| ]; | |||||
| @Component({ | |||||
| selector: 'app-partners', | |||||
| templateUrl: './partners.component.html', | |||||
| styleUrl: './partners.component.scss', | |||||
| standalone: true, | |||||
| imports: [MatTableModule, MatSortModule], | |||||
| }) | |||||
| export class PartnersComponent implements OnInit, AfterViewInit { | |||||
| @ViewChild(MatSort) sort; | |||||
| dataType!: string; | |||||
| displayedColumns: string[] = ['position', 'partner', 'address', 'website']; | |||||
| dataSource = new MatTableDataSource(ELEMENT_DATA); | |||||
| constructor(private _liveAnnouncer: LiveAnnouncer, private _location: Location, private route: ActivatedRoute) { | |||||
| this.sort = new MatSort(); | |||||
| } | |||||
| ngOnInit() { | |||||
| this.dataType = this.route.snapshot.data['dataType']; | |||||
| console.log('Data Type:', this.dataType); | |||||
| } | |||||
| ngAfterViewInit() { | |||||
| this.dataSource.sort = this.sort; | |||||
| } | |||||
| goBack() { | |||||
| this._location.back(); | |||||
| } | |||||
| /** Announce the change in sort state for assistive technology. */ | |||||
| announceSortChange(sortState: Sort) { | |||||
| // This example uses English messages. If your application supports | |||||
| // multiple language, you would internationalize these strings. | |||||
| // Furthermore, you can customize the message to add additional | |||||
| // details about the values being sorted. | |||||
| if (sortState.direction) { | |||||
| this._liveAnnouncer.announce(`Sorted ${sortState.direction}ending`); | |||||
| } else { | |||||
| this._liveAnnouncer.announce('Sorting cleared'); | |||||
| } | |||||
| } | |||||
| } | |||||