mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
RD Shell - Navigation
This commit is contained in:
1
.vscode/extensions.json
vendored
1
.vscode/extensions.json
vendored
@@ -3,6 +3,5 @@
|
||||
"johnpapa.angular2",
|
||||
"esbenp.prettier-vscode",
|
||||
"angular.ng-template",
|
||||
"eg2.vscode-npm-script"
|
||||
]
|
||||
}
|
||||
197
angular.json
197
angular.json
@@ -375,37 +375,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@shell/breadcrumb": {
|
||||
"projectType": "library",
|
||||
"root": "apps/shell/breadcrumb",
|
||||
"sourceRoot": "apps/shell/breadcrumb/src",
|
||||
"prefix": "shell",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/shell/breadcrumb/tsconfig.lib.json",
|
||||
"project": "apps/shell/breadcrumb/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/shell/breadcrumb/tsconfig.lib.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"tsConfig": "apps/shell/breadcrumb/tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"polyfills": [
|
||||
"zone.js",
|
||||
"zone.js/testing"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@domain/defs": {
|
||||
"projectType": "library",
|
||||
"root": "apps/domain/defs",
|
||||
@@ -840,37 +809,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@shell/header": {
|
||||
"projectType": "library",
|
||||
"root": "apps/shell/header",
|
||||
"sourceRoot": "apps/shell/header/src",
|
||||
"prefix": "shell",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/shell/header/tsconfig.lib.json",
|
||||
"project": "apps/shell/header/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/shell/header/tsconfig.lib.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"tsConfig": "apps/shell/header/tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"polyfills": [
|
||||
"zone.js",
|
||||
"zone.js/testing"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@modal/reorder": {
|
||||
"projectType": "library",
|
||||
"root": "apps/modal/reorder",
|
||||
@@ -1058,74 +996,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@shell/footer": {
|
||||
"projectType": "library",
|
||||
"root": "apps/shell/footer",
|
||||
"sourceRoot": "apps/shell/footer/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"project": "apps/shell/footer/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/shell/footer/tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "apps/shell/footer/tsconfig.lib.json"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"tsConfig": "apps/shell/footer/tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"polyfills": [
|
||||
"zone.js",
|
||||
"zone.js/testing"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@shell/process": {
|
||||
"projectType": "library",
|
||||
"root": "apps/shell/process",
|
||||
"sourceRoot": "apps/shell/process/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"project": "apps/shell/process/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/shell/process/tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "apps/shell/process/tsconfig.lib.json"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"tsConfig": "apps/shell/process/tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"polyfills": [
|
||||
"zone.js",
|
||||
"zone.js/testing"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@domain/isa": {
|
||||
"projectType": "library",
|
||||
"root": "apps/domain/isa",
|
||||
@@ -1160,40 +1030,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@shell/filter-overlay": {
|
||||
"projectType": "library",
|
||||
"root": "apps/shell/filter-overlay",
|
||||
"sourceRoot": "apps/shell/filter-overlay/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"project": "apps/shell/filter-overlay/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/shell/filter-overlay/tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "apps/shell/filter-overlay/tsconfig.lib.json"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"tsConfig": "apps/shell/filter-overlay/tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"polyfills": [
|
||||
"zone.js",
|
||||
"zone.js/testing"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@store/search-component-store": {
|
||||
"projectType": "library",
|
||||
"root": "apps/store/search-component-store",
|
||||
@@ -1634,6 +1470,39 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"shell": {
|
||||
"projectType": "library",
|
||||
"root": "apps/shell",
|
||||
"sourceRoot": "apps/shell/src",
|
||||
"prefix": "shell",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"project": "apps/shell/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/shell/tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "apps/shell/tsconfig.lib.json"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"tsConfig": "apps/shell/tsconfig.spec.json",
|
||||
"polyfills": [
|
||||
"zone.js",
|
||||
"zone.js/testing"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { BranchDTO } from '@swagger/checkout';
|
||||
import { isBoolean, isNumber } from '@utils/common';
|
||||
@@ -16,25 +15,30 @@ import {
|
||||
selectActivatedProcess,
|
||||
patchProcess,
|
||||
patchProcessData,
|
||||
selectTitle,
|
||||
setTitle,
|
||||
} from './store';
|
||||
|
||||
@Injectable()
|
||||
export class ApplicationService {
|
||||
/** @deprecated */
|
||||
private activatedProcessIdSubject = new BehaviorSubject<number>(undefined);
|
||||
|
||||
/** @deprecated */
|
||||
get activatedProcessId() {
|
||||
return this.activatedProcessIdSubject.value;
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
get activatedProcessId$() {
|
||||
return this.activatedProcessIdSubject.asObservable();
|
||||
}
|
||||
|
||||
title$ = this.store.select(selectTitle);
|
||||
|
||||
constructor(private store: Store) {}
|
||||
|
||||
setTitle(title: string) {
|
||||
this.store.dispatch(setTitle({ title }));
|
||||
}
|
||||
|
||||
getProcesses$(section?: 'customer' | 'branch') {
|
||||
const processes$ = this.store.select(selectProcesses);
|
||||
return processes$.pipe(map((processes) => processes.filter((process) => (section ? process.section === section : true))));
|
||||
|
||||
@@ -3,6 +3,8 @@ import { ApplicationProcess } from '..';
|
||||
|
||||
const prefix = '[CORE-APPLICATION]';
|
||||
|
||||
export const setTitle = createAction(`${prefix} Set Title`, props<{ title: string }>());
|
||||
|
||||
export const setSection = createAction(`${prefix} Set Section`, props<{ section: 'customer' | 'branch' }>());
|
||||
|
||||
export const addProcess = createAction(`${prefix} Add Process`, props<{ process: ApplicationProcess }>());
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
import { Action, createReducer, on } from '@ngrx/store';
|
||||
import { setSection, addProcess, removeProcess, setActivatedProcess, patchProcess, patchProcessData } from './application.actions';
|
||||
import {
|
||||
setSection,
|
||||
addProcess,
|
||||
removeProcess,
|
||||
setActivatedProcess,
|
||||
patchProcess,
|
||||
patchProcessData,
|
||||
setTitle,
|
||||
} from './application.actions';
|
||||
import { ApplicationState, INITIAL_APPLICATION_STATE } from './application.state';
|
||||
|
||||
const _applicationReducer = createReducer(
|
||||
INITIAL_APPLICATION_STATE,
|
||||
on(setTitle, (state, { title }) => ({ ...state, title })),
|
||||
on(setSection, (state, { section }) => ({ ...state, section })),
|
||||
on(addProcess, (state, { process }) => ({ ...state, processes: [...state.processes, { data: {}, ...process }] })),
|
||||
on(removeProcess, (state, { processId }) => {
|
||||
|
||||
@@ -2,6 +2,8 @@ import { createFeatureSelector, createSelector } from '@ngrx/store';
|
||||
import { ApplicationState } from './application.state';
|
||||
export const selectApplicationState = createFeatureSelector<ApplicationState>('core-application');
|
||||
|
||||
export const selectTitle = createSelector(selectApplicationState, (s) => s.title);
|
||||
|
||||
export const selectSection = createSelector(selectApplicationState, (s) => s.section);
|
||||
|
||||
export const selectProcesses = createSelector(selectApplicationState, (s) => s.processes);
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { ApplicationProcess } from '../defs';
|
||||
|
||||
export interface ApplicationState {
|
||||
title: string;
|
||||
processes: ApplicationProcess[];
|
||||
section: 'customer' | 'branch';
|
||||
}
|
||||
|
||||
export const INITIAL_APPLICATION_STATE: ApplicationState = {
|
||||
title: '',
|
||||
processes: [],
|
||||
section: 'customer',
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { isDevMode, NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { DebugComponent } from './debug/debug.component';
|
||||
import {
|
||||
CanActivateCartGuard,
|
||||
CanActivateCartWithProcessIdGuard,
|
||||
@@ -17,9 +16,9 @@ import {
|
||||
} from './guards';
|
||||
import { CanActivateAssortmentGuard } from './guards/can-activate-assortment.guard';
|
||||
import { CanActivatePackageInspectionGuard } from './guards/can-activate-package-inspection.guard';
|
||||
import { MainComponent } from './main.component';
|
||||
import { PreviewComponent } from './preview';
|
||||
import { BranchSectionResolver, CustomerSectionResolver, ProcessIdResolver } from './resolvers';
|
||||
import { ShellComponent, ShellModule } from './shell';
|
||||
import { TokenLoginComponent, TokenLoginModule } from './token-login';
|
||||
|
||||
const routes: Routes = [
|
||||
@@ -40,7 +39,7 @@ const routes: Routes = [
|
||||
children: [
|
||||
{
|
||||
path: 'kunde',
|
||||
component: ShellComponent,
|
||||
component: MainComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'dashboard',
|
||||
@@ -106,7 +105,7 @@ const routes: Routes = [
|
||||
},
|
||||
{
|
||||
path: 'filiale',
|
||||
component: ShellComponent,
|
||||
component: MainComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'task-calendar',
|
||||
@@ -152,7 +151,7 @@ if (isDevMode()) {
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes), ShellModule, TokenLoginModule],
|
||||
imports: [RouterModule.forRoot(routes), TokenLoginModule],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AppRoutingModule {}
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
:host {
|
||||
@apply block box-border;
|
||||
}
|
||||
|
||||
button {
|
||||
@apply fixed bottom-4 right-2 bg-blue-500 text-white font-bold py-2 px-4 rounded z-tooltip;
|
||||
@apply block;
|
||||
}
|
||||
|
||||
@@ -32,9 +32,11 @@ import { IsaErrorHandler } from './providers/isa.error-handler';
|
||||
import { ScanAdapterModule, ScanAdapterService, ScanditScanAdapterModule } from '@adapter/scan';
|
||||
import { RootStateService } from './store/root-state.service';
|
||||
import * as Commands from './commands';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { UiIconModule, UI_ICON_CFG } from '@ui/icon';
|
||||
import { PreviewComponent } from './preview';
|
||||
import { NativeContainerService } from 'native-container';
|
||||
import { ShellModule } from '@shared/shell';
|
||||
import { MainComponent } from './main.component';
|
||||
|
||||
registerLocaleData(localeDe, localeDeExtra);
|
||||
registerLocaleData(localeDe, 'de', localeDeExtra);
|
||||
@@ -74,11 +76,12 @@ export function _notificationsHubOptionsFactory(config: Config, auth: AuthServic
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent],
|
||||
declarations: [AppComponent, MainComponent],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
HttpClientModule,
|
||||
ShellModule.forRoot(),
|
||||
AppRoutingModule,
|
||||
AppSwaggerModule,
|
||||
AppDomainModule,
|
||||
@@ -103,31 +106,7 @@ export function _notificationsHubOptionsFactory(config: Config, auth: AuthServic
|
||||
ScanAdapterModule.forRoot(),
|
||||
ScanditScanAdapterModule.forRoot(),
|
||||
PlatformModule,
|
||||
UiIconModule.forRoot({
|
||||
aliases: [
|
||||
{ alias: 'd-account', name: 'account' },
|
||||
{ alias: 'd-no-account', name: 'package-variant-closed' },
|
||||
{ name: 'isa-audio', alias: 'AU' },
|
||||
{ name: 'isa-audio', alias: 'CAS' },
|
||||
{ name: 'isa-audio', alias: 'DL' },
|
||||
{ name: 'isa-audio', alias: 'KAS' },
|
||||
{ name: 'isa-hard-cover', alias: 'BUCH' },
|
||||
{ name: 'isa-hard-cover', alias: 'GEB' },
|
||||
{ name: 'isa-hard-cover', alias: 'HC' },
|
||||
{ name: 'isa-hard-cover', alias: 'KT' },
|
||||
{ name: 'isa-ebook', alias: 'EB' },
|
||||
{ name: 'isa-non-book', alias: 'GLO' },
|
||||
{ name: 'isa-non-book', alias: 'HDL' },
|
||||
{ name: 'isa-non-book', alias: 'NB' },
|
||||
{ name: 'isa-non-book', alias: 'SPL' },
|
||||
{ name: 'isa-calendar', alias: 'KA' },
|
||||
{ name: 'isa-scroll', alias: 'MA' },
|
||||
{ name: 'isa-software', alias: 'SW' },
|
||||
{ name: 'isa-soft-cover', alias: 'TB' },
|
||||
{ name: 'isa-video', alias: 'VI' },
|
||||
{ name: 'isa-news-paper', alias: 'ZS' },
|
||||
],
|
||||
}),
|
||||
UiIconModule.forRoot(),
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
@@ -156,6 +135,11 @@ export function _notificationsHubOptionsFactory(config: Config, auth: AuthServic
|
||||
useClass: IsaErrorHandler,
|
||||
},
|
||||
{ provide: LOCALE_ID, useValue: 'de-DE' },
|
||||
{
|
||||
provide: UI_ICON_CFG,
|
||||
useFactory: (config: Config) => config.get('@ui/icon'),
|
||||
deps: [Config],
|
||||
},
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
|
||||
3
apps/isa-app/src/app/main.component.html
Normal file
3
apps/isa-app/src/app/main.component.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<shell-root>
|
||||
<router-outlet></router-outlet>
|
||||
</shell-root>
|
||||
10
apps/isa-app/src/app/main.component.ts
Normal file
10
apps/isa-app/src/app/main.component.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-main',
|
||||
templateUrl: 'main.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class MainComponent {
|
||||
constructor() {}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
// start:ng42.barrel
|
||||
export * from './shell.component';
|
||||
export * from './shell.module';
|
||||
// end:ng42.barrel
|
||||
@@ -1,88 +0,0 @@
|
||||
<div class="shell-header-wrapper">
|
||||
<shell-header [section]="section$ | async" (sectionChange)="setSection($event)">
|
||||
<a [routerLink]="['/kunde/dashboard']" routerLinkActive="active" class="dashboard-btn">
|
||||
<ui-icon icon="dashboard" size="26px"></ui-icon>
|
||||
</a>
|
||||
<button class="notifications-btn" [disabled]="(notificationCount$ | async) === 0" (click)="openNotifications()">
|
||||
<ui-icon icon="notification" size="26px"></ui-icon>
|
||||
<span class="notification-counter" *ngIf="notificationCount$ | async; let count">{{ count }}</span>
|
||||
</button>
|
||||
<button (click)="logout()" class="logout-btn">
|
||||
<span *ngIf="currentBranch$ | async; let currentBranch">{{ currentBranch.key | uppercase }}</span>
|
||||
<ui-icon icon="logout" size="26px"></ui-icon>
|
||||
</button>
|
||||
</shell-header>
|
||||
</div>
|
||||
<div class="shell-process-wrapper">
|
||||
<shell-process
|
||||
[label]="addProcessLabel$ | async"
|
||||
[canAddProcess]="canAddProcess$ | async"
|
||||
(addProcess)="addProcess(); processTabs?.last?.triggerAnimation()"
|
||||
>
|
||||
<shell-process-tab
|
||||
#processTabs
|
||||
(activateProcess)="activateProcess($event)"
|
||||
(closeProcess)="closeProcess($event)"
|
||||
(processAction)="processAction($event)"
|
||||
*ngFor="let process of processes$ | async; trackBy: trackByIdFn"
|
||||
[isActive]="(activatedProcessId$ | async) === process.id"
|
||||
[process]="process"
|
||||
></shell-process-tab>
|
||||
</shell-process>
|
||||
</div>
|
||||
<div class="main-wrapper">
|
||||
<main>
|
||||
<router-outlet></router-outlet>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div class="shell-footer-wrapper">
|
||||
<shell-footer *ngIf="section$ | async; let section">
|
||||
<ng-container *ngIf="section === 'customer'">
|
||||
<a [routerLink]="[customerBasePath$ | async, 'product']" routerLinkActive="active">
|
||||
<ui-icon icon="catalog" size="30px"></ui-icon>
|
||||
Artikelsuche
|
||||
</a>
|
||||
<a [routerLink]="[customerBasePath$ | async, 'customer']" routerLinkActive="active">
|
||||
<ui-icon icon="customer" size="24px"></ui-icon>
|
||||
Kundensuche
|
||||
</a>
|
||||
<a *ifRole="'Store'" [routerLink]="[customerBasePath$ | async, 'goods', 'out']" routerLinkActive="active">
|
||||
<ui-icon icon="box_out" size="24px"></ui-icon>
|
||||
Warenausgabe
|
||||
</a>
|
||||
<a *ifRole="'CallCenter'" [routerLink]="[customerBasePath$ | async, 'order']" routerLinkActive="active">
|
||||
<ui-svg-icon icon="package-variant-closed" [size]="28"></ui-svg-icon>
|
||||
Kundenbestellungen
|
||||
</a>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="section === 'branch'">
|
||||
<a [routerLink]="['/filiale/assortment']" routerLinkActive="active">
|
||||
<ui-svg-icon icon="shape-outline" [size]="24"></ui-svg-icon>
|
||||
Sortiment
|
||||
</a>
|
||||
<a [routerLink]="['/filiale/task-calendar']" routerLinkActive="active">
|
||||
<ui-icon icon="calendar_check" size="24px"></ui-icon>
|
||||
Tätigkeitskalender
|
||||
</a>
|
||||
<a [routerLink]="['/filiale/goods/in']" routerLinkActive="active">
|
||||
<ui-icon icon="box_return" size="24px"></ui-icon>
|
||||
Abholfach
|
||||
</a>
|
||||
<a [routerLink]="[remissionUrl$ | async]" [queryParams]="remissionQueryParams$ | async" routerLinkActive="active">
|
||||
<ui-icon icon="documents_refresh" size="24px"></ui-icon>
|
||||
Remission
|
||||
</a>
|
||||
<a [routerLink]="['/filiale/package-inspection']" routerLinkActive="active" (click)="fetchAndOpenPackages()">
|
||||
<ui-svg-icon icon="clipboard-check-outline" [size]="24"></ui-svg-icon>
|
||||
Wareneingang
|
||||
</a>
|
||||
</ng-container>
|
||||
</shell-footer>
|
||||
</div>
|
||||
|
||||
<button *ngIf="isDevelopment" class="block absolute bottom-0 right-0 z-tooltip p-4 opacity-5" (click)="debugOpen = !debugOpen">
|
||||
<ui-svg-icon icon="bug-outline"></ui-svg-icon>
|
||||
</button>
|
||||
|
||||
<app-debug *ngIf="debugOpen" class="absolute inset-x-0 top-0 max-h-[calc(100vh-80px)]"></app-debug>
|
||||
@@ -1,60 +0,0 @@
|
||||
:host {
|
||||
@apply block relative min-h-screen;
|
||||
}
|
||||
|
||||
.main-wrapper {
|
||||
@apply fixed right-0 left-0 overflow-auto;
|
||||
top: 8.375rem;
|
||||
bottom: 5rem;
|
||||
|
||||
main {
|
||||
@apply w-full max-w-content mx-auto px-4 self-stretch;
|
||||
}
|
||||
}
|
||||
|
||||
.shell-header-wrapper {
|
||||
@apply fixed top-0 left-0 right-0 bg-white;
|
||||
|
||||
shell-header {
|
||||
@apply w-full max-w-content mx-auto;
|
||||
}
|
||||
|
||||
button.notifications-btn {
|
||||
@apply relative;
|
||||
|
||||
.notification-counter {
|
||||
@apply absolute flex items-center justify-center top-2 right-px-3 text-sm rounded-full w-6 h-6 font-semibold;
|
||||
background-color: var(--shell-notification-counter-background);
|
||||
color: var(--shell-notification-counter-text);
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.shell-process-wrapper {
|
||||
@apply fixed left-0 right-0 bg-white;
|
||||
top: 5.125rem;
|
||||
|
||||
shell-process {
|
||||
@apply w-full max-w-content mx-auto;
|
||||
height: 52px;
|
||||
}
|
||||
}
|
||||
|
||||
shell-process {
|
||||
height: 52px;
|
||||
grid-area: process;
|
||||
}
|
||||
|
||||
.shell-footer-wrapper {
|
||||
@apply fixed bottom-0 left-0 right-0 bg-white z-fixed shadow-card;
|
||||
|
||||
shell-footer {
|
||||
@apply w-full max-w-content mx-auto;
|
||||
|
||||
.active {
|
||||
@apply font-bold;
|
||||
color: var(--shell-footer-link-active);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,445 +0,0 @@
|
||||
// unit test ShellComponent with Spectator
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { ApplicationProcess, ApplicationService } from '@core/application';
|
||||
import { AuthModule, AuthService } from '@core/auth';
|
||||
import { Config } from '@core/config';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { DomainDashboardService } from '@domain/isa';
|
||||
import { NotificationsHub } from '@hub/notifications';
|
||||
import { ModalNotificationsComponent } from '@modal/notifications';
|
||||
import { Spectator, createComponentFactory, SpyObject, createSpyObject } from '@ngneat/spectator';
|
||||
import { DashboardComponent } from '@page/dashboard';
|
||||
import { ShellFooterComponent } from '@shell/footer';
|
||||
import { ShellHeaderComponent } from '@shell/header';
|
||||
import { ShellProcessComponent, ShellProcessTabComponent } from '@shell/process';
|
||||
import { IconRegistry, UiIconComponent, UiIconModule } from '@ui/icon';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { EnvelopeDTO, MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
|
||||
import { MockComponent } from 'ng-mocks';
|
||||
import { of } from 'rxjs';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { ShellComponent } from './shell.component';
|
||||
import { WrongDestinationModalService } from 'apps/page/package-inspection/src/lib/components/wrong-destination-modal/wrong-destination-modal.service';
|
||||
|
||||
// DummyComponent Class
|
||||
@Component({
|
||||
selector: 'dummy-component',
|
||||
template: '<div></div>',
|
||||
})
|
||||
class DummyComponent {
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
describe('ShellComponent', () => {
|
||||
let spectator: Spectator<ShellComponent>;
|
||||
let applicationServiceMock: SpyObject<ApplicationService>;
|
||||
let modalServiceMock: SpyObject<UiModalService>;
|
||||
let notificationsHubMock: SpyObject<NotificationsHub>;
|
||||
let router: Router;
|
||||
let breadcrumbServiceMock: SpyObject<BreadcrumbService>;
|
||||
let authServiceMock: SpyObject<AuthService>;
|
||||
|
||||
const createComponent = createComponentFactory({
|
||||
component: ShellComponent,
|
||||
imports: [
|
||||
UiIconModule,
|
||||
RouterTestingModule.withRoutes([
|
||||
{ path: 'kunde', component: DummyComponent },
|
||||
{ path: 'kunde/dashboard', component: DashboardComponent },
|
||||
]),
|
||||
AuthModule,
|
||||
],
|
||||
declarations: [
|
||||
MockComponent(ShellHeaderComponent),
|
||||
MockComponent(ShellFooterComponent),
|
||||
MockComponent(ShellProcessComponent),
|
||||
MockComponent(ShellProcessTabComponent),
|
||||
],
|
||||
mocks: [
|
||||
BreadcrumbService,
|
||||
DomainAvailabilityService,
|
||||
AuthService,
|
||||
DomainDashboardService,
|
||||
Config,
|
||||
WrongDestinationModalService,
|
||||
IconRegistry,
|
||||
],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
applicationServiceMock = createSpyObject(ApplicationService);
|
||||
applicationServiceMock.getSection$.and.returnValue(of('customer'));
|
||||
applicationServiceMock.getProcesses$.and.returnValue(of([]));
|
||||
applicationServiceMock.getProcessById$.and.returnValue(of({ id: 4000 }));
|
||||
applicationServiceMock.getActivatedProcessId$.and.returnValue(of(undefined));
|
||||
applicationServiceMock.getLastActivatedProcessWithSectionAndType$.and.returnValue(of({}));
|
||||
applicationServiceMock.getLastActivatedProcessWithSection$.and.returnValue(of({}));
|
||||
|
||||
notificationsHubMock = createSpyObject(NotificationsHub);
|
||||
notificationsHubMock.notifications$ = of({});
|
||||
|
||||
modalServiceMock = createSpyObject(UiModalService);
|
||||
|
||||
authServiceMock = createSpyObject(AuthService);
|
||||
|
||||
spectator = createComponent({
|
||||
providers: [
|
||||
{ provide: ApplicationService, useValue: applicationServiceMock },
|
||||
{ provide: NotificationsHub, useValue: notificationsHubMock },
|
||||
{ provide: UiModalService, useValue: modalServiceMock },
|
||||
{ provide: AuthService, useValue: authServiceMock },
|
||||
],
|
||||
});
|
||||
|
||||
breadcrumbServiceMock = spectator.inject(BreadcrumbService);
|
||||
router = spectator.inject(Router);
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.component).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('shell-header', () => {
|
||||
it('should call setSection() on sectionChange event with the section argument', () => {
|
||||
spyOn(spectator.component, 'setSection');
|
||||
spectator.triggerEventHandler('shell-header', 'sectionChange', 'branch');
|
||||
expect(spectator.component.setSection).toHaveBeenCalledWith('branch');
|
||||
});
|
||||
|
||||
it('should render the header buttons', () => {
|
||||
// Test verhält sich anders, wenn die größe des Browserfensters kleiner ist als 640px, da
|
||||
// die Buttons dann unsichtbar werden und ins Drei-Punkt Menü verschoben werden.
|
||||
if (document.body.clientWidth > 639) {
|
||||
expect(spectator.query('shell-header .notifications-btn')).toBeVisible();
|
||||
expect(spectator.query('shell-header .dashboard-btn')).toBeVisible();
|
||||
expect(spectator.query('shell-header .logout-btn')).toBeVisible();
|
||||
} else {
|
||||
expect(spectator.query('shell-header .notifications-btn')).not.toBeVisible();
|
||||
expect(spectator.query('shell-header .dashboard-btn')).not.toBeVisible();
|
||||
expect(spectator.query('shell-header .logout-btn')).not.toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
it('should have a anchor tag which navigates to /kunde/dashboard', () => {
|
||||
const anchor = spectator.query('shell-header a');
|
||||
expect(anchor).toHaveAttribute('href', '/kunde/dashboard');
|
||||
});
|
||||
});
|
||||
|
||||
describe('shell-process', () => {
|
||||
it('should call addProcess() on addProcess event', () => {
|
||||
spyOn(spectator.component, 'addProcess');
|
||||
spectator.triggerEventHandler('shell-process', 'addProcess', undefined);
|
||||
expect(spectator.component.addProcess).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('shell-process-tab', () => {
|
||||
it('should render for each process', () => {
|
||||
const processes = [{}, {}, {}];
|
||||
applicationServiceMock.getSection$.and.returnValue(of('customer'));
|
||||
applicationServiceMock.getProcesses$.and.returnValue(of(processes));
|
||||
spectator.detectComponentChanges();
|
||||
expect(spectator.queryAll('shell-process-tab')).toHaveLength(processes.length);
|
||||
});
|
||||
|
||||
it('should call activateProcess() on activateProcess event', () => {
|
||||
const processes = [{ id: 1 }];
|
||||
|
||||
applicationServiceMock.getProcesses$.and.returnValue(of(processes));
|
||||
spectator.detectComponentChanges();
|
||||
|
||||
spyOn(spectator.component, 'activateProcess');
|
||||
spectator.triggerEventHandler('shell-process-tab', 'activateProcess', processes[0].id);
|
||||
expect(spectator.component.activateProcess).toHaveBeenCalledWith(1);
|
||||
});
|
||||
|
||||
it('should call closeProcess() on closeProcess event', () => {
|
||||
const processes = [{ id: 1 }];
|
||||
|
||||
applicationServiceMock.getProcesses$.and.returnValue(of(processes));
|
||||
spectator.detectComponentChanges();
|
||||
|
||||
spyOn(spectator.component, 'closeProcess');
|
||||
spectator.triggerEventHandler('shell-process-tab', 'closeProcess', processes[0].id);
|
||||
expect(spectator.component.closeProcess).toHaveBeenCalledWith(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('shell-footer', () => {
|
||||
it('should render when section is set', () => {
|
||||
applicationServiceMock.getSection$.and.returnValue(of('customer'));
|
||||
spectator.detectComponentChanges();
|
||||
expect(spectator.query('shell-footer')).toBeVisible();
|
||||
});
|
||||
|
||||
it('should not render when section is undefined', () => {
|
||||
applicationServiceMock.getSection$.and.returnValue(of(undefined));
|
||||
spectator.detectComponentChanges();
|
||||
expect(spectator.query('shell-footer')).not.toBeVisible();
|
||||
});
|
||||
|
||||
xit('should display the menu items for section customer', () => {
|
||||
applicationServiceMock.getSection$.and.returnValue(of('customer'));
|
||||
spectator.component.customerBasePath$ = of('/kunde/1');
|
||||
spectator.detectComponentChanges();
|
||||
|
||||
authServiceMock.hasRole.and.returnValue(true);
|
||||
|
||||
const anchors = spectator.queryAll('shell-footer a');
|
||||
expect(anchors[0]).toHaveText('Artikelsuche');
|
||||
expect(anchors[0]).toHaveAttribute('href', '/kunde/1/product');
|
||||
expect(anchors[1]).toHaveText('Kundensuche');
|
||||
expect(anchors[1]).toHaveAttribute('href', '/kunde/1/customer');
|
||||
expect(anchors[2]).toHaveText('Warenausgabe');
|
||||
expect(anchors[2]).toHaveAttribute('href', '/kunde/1/goods/out');
|
||||
});
|
||||
|
||||
it('should display the menu items for section branch', () => {
|
||||
applicationServiceMock.getSection$.and.returnValue(of('branch'));
|
||||
spectator.detectComponentChanges();
|
||||
|
||||
const anchors = spectator.queryAll('shell-footer a');
|
||||
expect(anchors[0]).toHaveText('Sortiment');
|
||||
expect(anchors[0]).toHaveAttribute('href', '/filiale/assortment');
|
||||
expect(anchors[1]).toHaveText('Tätigkeitskalender');
|
||||
expect(anchors[1]).toHaveAttribute('href', '/filiale/task-calendar');
|
||||
expect(anchors[2]).toHaveText('Abholfach');
|
||||
expect(anchors[2]).toHaveAttribute('href', '/filiale/goods/in');
|
||||
expect(anchors[3]).toHaveText('Remission');
|
||||
expect(anchors[3]).toHaveAttribute('href', '/filiale/remission');
|
||||
expect(anchors[4]).toHaveText('Wareneingang');
|
||||
expect(anchors[4]).toHaveAttribute('href', '/filiale/package-inspection');
|
||||
});
|
||||
});
|
||||
|
||||
describe('activatedProcessId$', () => {
|
||||
it('should call _appService.getActivatedProcessId$() and return its value', async () => {
|
||||
applicationServiceMock.getActivatedProcessId$.and.returnValue(of(1));
|
||||
const processId = await spectator.component.activatedProcessId$.pipe(first()).toPromise();
|
||||
expect(processId).toBe(1);
|
||||
expect(applicationServiceMock.getActivatedProcessId$).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('section$', () => {
|
||||
it('should call _appService.getSection$() and return its value', async () => {
|
||||
applicationServiceMock.getSection$.and.returnValue(of('branch'));
|
||||
const section = await spectator.component.section$.pipe(first()).toPromise();
|
||||
expect(section).toBe('branch');
|
||||
expect(applicationServiceMock.getSection$).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('processes$', () => {
|
||||
it('should call _appService.processes$() and return its value', async () => {
|
||||
applicationServiceMock.getProcesses$.and.returnValue(of([{}, {}]));
|
||||
const processes = await spectator.component.processes$.pipe(first()).toPromise();
|
||||
expect(processes).toHaveLength(2);
|
||||
expect(applicationServiceMock.getProcesses$).toHaveBeenCalledWith('customer');
|
||||
});
|
||||
});
|
||||
|
||||
describe('remissionProcess$', () => {
|
||||
it('should call _appService.getProcessById$() with Remission Id and return its value', async () => {
|
||||
applicationServiceMock.getProcessById$.and.returnValue(of({ id: 4000 }));
|
||||
await spectator.component.remissionProcess$.pipe(first()).toPromise();
|
||||
expect(applicationServiceMock.getProcessById$).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('remissionUrl$', () => {
|
||||
it('should return the correct url if process.data.active is available', async () => {
|
||||
const process = {
|
||||
id: 4000,
|
||||
data: {
|
||||
active: 9999,
|
||||
},
|
||||
};
|
||||
applicationServiceMock.getProcessById$.and.returnValue(of(process));
|
||||
const url = await spectator.component.remissionUrl$.pipe(first()).toPromise();
|
||||
expect(url).toBe('/filiale/remission/9999/list');
|
||||
});
|
||||
|
||||
it('should return the correct url if process.data.active is not available', async () => {
|
||||
const process = {
|
||||
id: 4000,
|
||||
data: {},
|
||||
};
|
||||
applicationServiceMock.getProcessById$.and.returnValue(of(process));
|
||||
const url = await spectator.component.remissionUrl$.pipe(first()).toPromise();
|
||||
expect(url).toBe('/filiale/remission');
|
||||
});
|
||||
});
|
||||
|
||||
describe('remissionQueryParams$', () => {
|
||||
it('should return the correct queryParams if process.data.active and process.data.queryParams are available', async () => {
|
||||
const process = {
|
||||
id: 4000,
|
||||
data: {
|
||||
active: 9999,
|
||||
queryParams: { filter: 'test' },
|
||||
},
|
||||
};
|
||||
applicationServiceMock.getProcessById$.and.returnValue(of(process));
|
||||
const queryParams = await spectator.component.remissionQueryParams$.pipe(first()).toPromise();
|
||||
expect(queryParams).toEqual(process.data.queryParams);
|
||||
});
|
||||
|
||||
it('should return the correct queryParams if process.data.active and process.data.queryParams are not available', async () => {
|
||||
const process = {
|
||||
id: 4000,
|
||||
data: {},
|
||||
};
|
||||
applicationServiceMock.getProcessById$.and.returnValue(of(process));
|
||||
const queryParams = await spectator.component.remissionQueryParams$.pipe(first()).toPromise();
|
||||
expect(queryParams).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('setSection()', () => {
|
||||
it('should call _appService.setSection() with the argument section', async () => {
|
||||
await spectator.component.setSection('customer');
|
||||
expect(applicationServiceMock.setSection).toHaveBeenCalledWith('customer');
|
||||
});
|
||||
|
||||
it('should call activateProcess if getLastActivatedProcessWithSection returns a value', async () => {
|
||||
applicationServiceMock.getLastActivatedProcessWithSection$.and.returnValue(of({ id: 1 }));
|
||||
spyOn(spectator.component, 'activateProcess');
|
||||
await spectator.component.setSection('customer');
|
||||
expect(spectator.component.activateProcess).toHaveBeenCalledWith(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('logout()', () => {
|
||||
it('should call _authService.logout()', () => {
|
||||
spectator.component.logout();
|
||||
expect(authServiceMock.logout).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('addProcess()', () => {
|
||||
it('should call navigate to /kunde/{timestamp}/product', () => {
|
||||
spyOn(router, 'navigate');
|
||||
spyOn(Date, 'now').and.returnValue(123);
|
||||
spectator.component.addProcess();
|
||||
expect(router.navigate).toHaveBeenCalledWith(['/kunde', 123, 'product']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('closeProcess()', () => {
|
||||
it('should call _appService.removeProcess() with the processId argument', () => {
|
||||
const processes = [{}, {}, {}];
|
||||
applicationServiceMock.getSection$.and.returnValue(of('customer'));
|
||||
applicationServiceMock.getProcesses$.and.returnValue(of(processes));
|
||||
spectator.component.closeProcess(1);
|
||||
expect(applicationServiceMock.removeProcess).toHaveBeenCalledWith(1);
|
||||
});
|
||||
|
||||
it('should navigate to kunde/dashboard if no process is available', async () => {
|
||||
spyOn(router, 'navigate');
|
||||
applicationServiceMock.getSection$.and.returnValue(of('customer'));
|
||||
applicationServiceMock.getProcesses$.and.returnValue(of([]));
|
||||
spectator.detectComponentChanges();
|
||||
await spectator.component.closeProcess(1);
|
||||
expect(router.navigate).toHaveBeenCalledWith(['/kunde', 'dashboard']);
|
||||
});
|
||||
|
||||
it('should not navigate to kunde/dashboard if processes are available', async () => {
|
||||
spyOn(router, 'navigate');
|
||||
const processes = [
|
||||
{ id: 1, name: 'test', section: 'customer' },
|
||||
{ id: 2, name: 'test', section: 'customer' },
|
||||
];
|
||||
|
||||
applicationServiceMock.getLastActivatedProcessWithSection$.and.returnValue(of({}));
|
||||
applicationServiceMock.getSection$.and.returnValue(of('customer'));
|
||||
applicationServiceMock.getProcesses$.and.returnValue(of(processes));
|
||||
await spectator.component.closeProcess(1);
|
||||
expect(router.navigate).not.toHaveBeenCalledWith(['/kunde', 'dashboard']);
|
||||
});
|
||||
|
||||
it('should activate the next process when it was not the last process', async () => {
|
||||
spyOn(spectator.component, 'activateProcess');
|
||||
|
||||
applicationServiceMock.getLastActivatedProcessWithSection$.and.returnValue(
|
||||
of({
|
||||
id: 2,
|
||||
name: 'test',
|
||||
section: 'customer',
|
||||
activated: 2,
|
||||
})
|
||||
);
|
||||
|
||||
const processes = [
|
||||
{ id: 1, name: 'test', section: 'customer', activated: 1 },
|
||||
{ id: 2, name: 'test', section: 'customer', activated: 2 },
|
||||
];
|
||||
applicationServiceMock.getSection$.and.returnValue(of('customer'));
|
||||
applicationServiceMock.getProcesses$.and.returnValue(of(processes));
|
||||
await spectator.component.closeProcess(1);
|
||||
|
||||
expect(spectator.component.activateProcess).toHaveBeenCalledWith(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('activateProcess()', () => {
|
||||
it('should get the last activated breadcrumb by key and if it is defined it navigates to its path with queryParams', async () => {
|
||||
const crumb = { path: '/kunde/product', params: { id: 1 } };
|
||||
spyOn(router, 'navigate');
|
||||
breadcrumbServiceMock.getLastActivatedBreadcrumbByKey$.and.returnValue(of(crumb));
|
||||
|
||||
await spectator.component.activateProcess(1);
|
||||
expect(router.navigate).toHaveBeenCalledWith([crumb.path], { queryParams: crumb.params });
|
||||
});
|
||||
|
||||
it('should navigate to /kunde if no breadcrumb for this process exists', async () => {
|
||||
breadcrumbServiceMock.getLastActivatedBreadcrumbByKey$.and.returnValue(of(undefined));
|
||||
spyOn(router, 'navigate');
|
||||
|
||||
await spectator.component.activateProcess(1);
|
||||
expect(router.navigate).toHaveBeenCalledWith(['/kunde', 1, 'product']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('processAction()', () => {
|
||||
it('should navigate to cart when process type is cart', () => {
|
||||
spyOn(router, 'navigate');
|
||||
|
||||
const process: ApplicationProcess = { id: 1, name: 'Vorgang', section: 'customer', type: 'cart' };
|
||||
spectator.component.processAction(process);
|
||||
expect(router.navigate).toHaveBeenCalledWith(['/kunde', process.id, 'cart']);
|
||||
});
|
||||
|
||||
it('should not navigate to when process type is not cart', () => {
|
||||
spyOn(router, 'navigate');
|
||||
|
||||
const process: ApplicationProcess = { id: 1, name: 'Vorgang', section: 'customer', type: 'goods-out' };
|
||||
spectator.component.processAction(process);
|
||||
expect(router.navigate).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('openNotifications()', () => {
|
||||
it('should call modalService.open() with the ModalNotificationComponent', async () => {
|
||||
const notifications: EnvelopeDTO<MessageBoardItemDTO[]> = {
|
||||
data: [{}, {}, {}],
|
||||
};
|
||||
|
||||
spectator.component.notifications$ = of(notifications);
|
||||
|
||||
await spectator.component.openNotifications();
|
||||
expect(modalServiceMock.open).toHaveBeenCalledWith({
|
||||
content: ModalNotificationsComponent,
|
||||
data: notifications,
|
||||
config: {
|
||||
showScrollbarY: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,174 +0,0 @@
|
||||
import { Component, ChangeDetectionStrategy, ViewChildren, QueryList, TrackByFunction, NgZone } from '@angular/core';
|
||||
import { ApplicationProcess, ApplicationService } from '@core/application';
|
||||
import { first, map, shareReplay, switchMap, take, tap } from 'rxjs/operators';
|
||||
import { NotificationsHub } from '@hub/notifications';
|
||||
import { ModalNotificationsComponent } from '@modal/notifications';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { Router } from '@angular/router';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { AuthService } from '@core/auth';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { ShellProcessTabComponent } from '@shell/process';
|
||||
import { Config } from '@core/config';
|
||||
import { WrongDestinationModalService } from 'apps/page/package-inspection/src/lib/components/wrong-destination-modal/wrong-destination-modal.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-shell',
|
||||
templateUrl: 'shell.component.html',
|
||||
styleUrls: ['shell.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ShellComponent {
|
||||
isDevelopment = Boolean(this._config.get('debug'));
|
||||
|
||||
debugOpen = false;
|
||||
|
||||
@ViewChildren('processTabs')
|
||||
readonly processTabs: QueryList<ShellProcessTabComponent>;
|
||||
|
||||
notifications$ = this._notificationsHub.notifications$;
|
||||
|
||||
notificationCount$ = this.notifications$.pipe(map((message) => message?.data?.length));
|
||||
|
||||
get activatedProcessId$() {
|
||||
return this._appService.getActivatedProcessId$().pipe(
|
||||
tap((activatedProcessId) => {
|
||||
this.processTabs?.find((process) => process?.process?.id === activatedProcessId && !process?.isActive)?.slideIntoView();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
customerBasePath$ = this.activatedProcessId$.pipe(
|
||||
switchMap((processId) => this._appService.getProcessById$(processId)),
|
||||
map((process) => {
|
||||
if (!!process && process.section === 'customer' && process.type !== 'cart-checkout') {
|
||||
// Übernehme aktiven Prozess
|
||||
return `/kunde/${process.id}`;
|
||||
} else {
|
||||
// Über Guards wird ein neuer Prozess erstellt
|
||||
return '/kunde';
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
get section$() {
|
||||
return this._appService.getSection$().pipe(shareReplay());
|
||||
}
|
||||
|
||||
get processes$() {
|
||||
return this.section$.pipe(switchMap((section) => this._appService.getProcesses$(section)));
|
||||
}
|
||||
|
||||
get remissionProcess$() {
|
||||
return this._appService.getProcessById$(this._config.get('process.ids.remission'));
|
||||
}
|
||||
|
||||
get remissionUrl$() {
|
||||
return this.remissionProcess$.pipe(
|
||||
map((process) => (process?.data?.active ? `/filiale/remission/${process.data.active}/list` : '/filiale/remission'))
|
||||
);
|
||||
}
|
||||
|
||||
get remissionQueryParams$() {
|
||||
return this.remissionProcess$.pipe(
|
||||
map((process) => (process?.data?.active && process?.data?.queryParams ? process.data.queryParams : {}))
|
||||
);
|
||||
}
|
||||
|
||||
get addProcessLabel$() {
|
||||
return combineLatest([this.section$, this.processes$]).pipe(
|
||||
map(([section, processes]) => (section === 'customer' && processes.length === 0 ? 'VORGANG STARTEN' : ''))
|
||||
);
|
||||
}
|
||||
|
||||
get canAddProcess$() {
|
||||
return this.section$.pipe(map((section) => section === 'customer'));
|
||||
}
|
||||
|
||||
get currentBranch$() {
|
||||
return this._availabilityService.getDefaultBranch();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly _appService: ApplicationService,
|
||||
private readonly _config: Config,
|
||||
private readonly _notificationsHub: NotificationsHub,
|
||||
private readonly _modal: UiModalService,
|
||||
private readonly _router: Router,
|
||||
private readonly _breadcrumbService: BreadcrumbService,
|
||||
private readonly _authService: AuthService,
|
||||
private readonly _availabilityService: DomainAvailabilityService,
|
||||
private readonly _zone: NgZone,
|
||||
private readonly _wrongDestinationModalService: WrongDestinationModalService
|
||||
) {}
|
||||
|
||||
async setSection(section: 'customer' | 'branch') {
|
||||
this._appService.setSection(section);
|
||||
|
||||
const lastProcessId = (await this._appService.getLastActivatedProcessWithSection$(section).pipe(first()).toPromise())?.id;
|
||||
if (lastProcessId) {
|
||||
this.activateProcess(lastProcessId);
|
||||
} else {
|
||||
this._router.navigate([section === 'customer' ? '/kunde' : '/filiale']);
|
||||
}
|
||||
}
|
||||
|
||||
// Process werden über Guards erstellt und aktiviert. An dieser Stelle wird nur navigiert
|
||||
async addProcess() {
|
||||
const processId = Date.now();
|
||||
await this._router.navigate(['/kunde', processId, 'product']);
|
||||
}
|
||||
|
||||
async activateProcess(activatedProcessId: number) {
|
||||
try {
|
||||
const latestCrumb = await this._breadcrumbService?.getLastActivatedBreadcrumbByKey$(activatedProcessId)?.pipe(take(1)).toPromise();
|
||||
await this._zone.run(async () => {
|
||||
if (latestCrumb) {
|
||||
await this._router.navigate([latestCrumb.path], { queryParams: latestCrumb.params });
|
||||
} else {
|
||||
await this._router.navigate(['/kunde', activatedProcessId, 'product']);
|
||||
}
|
||||
});
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
async closeProcess(processId: number) {
|
||||
this._appService.removeProcess(processId);
|
||||
|
||||
const processes = await this.processes$.pipe(first()).toPromise();
|
||||
if (processes.length === 0) {
|
||||
await this._router.navigate(['/kunde', 'dashboard']);
|
||||
return;
|
||||
}
|
||||
|
||||
const section = await this.section$.pipe(first()).toPromise();
|
||||
const lastActivatedProcess = await this._appService.getLastActivatedProcessWithSection$(section).pipe(first()).toPromise();
|
||||
this.activateProcess(lastActivatedProcess?.id);
|
||||
}
|
||||
|
||||
processAction(process: ApplicationProcess) {
|
||||
if (process?.type === 'cart') {
|
||||
this._router.navigate(['/kunde', process.id, 'cart']);
|
||||
}
|
||||
}
|
||||
|
||||
async logout() {
|
||||
await this._authService.logout();
|
||||
}
|
||||
|
||||
async openNotifications() {
|
||||
const notifications = await this.notifications$.pipe(first()).toPromise();
|
||||
this._modal.open({
|
||||
content: ModalNotificationsComponent,
|
||||
data: notifications,
|
||||
config: {
|
||||
showScrollbarY: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
trackByIdFn: TrackByFunction<ApplicationProcess> = (_, process) => process.id;
|
||||
|
||||
fetchAndOpenPackages = () => this._wrongDestinationModalService.fetchAndOpen();
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { OverlayModule } from '@angular/cdk/overlay';
|
||||
|
||||
import { ShellHeaderModule } from '@shell/header';
|
||||
import { ShellProcessModule } from '@shell/process';
|
||||
import { ShellFooterModule } from '@shell/footer';
|
||||
|
||||
import { ShellComponent } from './shell.component';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { AuthModule } from '@core/auth';
|
||||
import { DebugComponent } from '../debug/debug.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule,
|
||||
CommonModule,
|
||||
ShellHeaderModule,
|
||||
ShellProcessModule,
|
||||
ShellFooterModule,
|
||||
UiIconModule,
|
||||
OverlayModule,
|
||||
AuthModule,
|
||||
DebugComponent,
|
||||
],
|
||||
exports: [ShellComponent],
|
||||
declarations: [ShellComponent],
|
||||
providers: [],
|
||||
})
|
||||
export class ShellModule {}
|
||||
@@ -1,20 +0,0 @@
|
||||
@font-face {
|
||||
font-family: 'Material Symbols Outlined';
|
||||
font-style: normal;
|
||||
font-weight: 100 700;
|
||||
src: url(./materials-icons-outlined.woff2) format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Material Symbols Rounded';
|
||||
font-style: normal;
|
||||
font-weight: 100 700;
|
||||
src: url(./materials-icons-rounded.woff2) format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Material Symbols Sharp';
|
||||
font-style: normal;
|
||||
font-weight: 100 700;
|
||||
src: url(./materials-icons-sharp.woff2) format('woff2');
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -7,7 +7,6 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||||
<link href="/assets/fonts/fonts.css" rel="stylesheet" />
|
||||
<link href="/assets/icons/icons.css" rel="stylesheet" />
|
||||
<link rel="manifest" href="manifest.webmanifest" />
|
||||
<meta name="theme-color" content="#1976d2" />
|
||||
</head>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
|
||||
import { Config } from '@core/config';
|
||||
|
||||
@@ -13,10 +14,11 @@ export class AssortmentComponent implements OnInit {
|
||||
return this._config.get('process.ids.assortment');
|
||||
}
|
||||
|
||||
constructor(private _config: Config, private _breadcrumb: BreadcrumbService) {}
|
||||
constructor(private _config: Config, private _breadcrumb: BreadcrumbService, private _app: ApplicationService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.createBreadcrumbIfNotExists();
|
||||
this._app.setTitle('Sortiment');
|
||||
}
|
||||
|
||||
async createBreadcrumbIfNotExists(): Promise<void> {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Config } from '@core/config';
|
||||
import { provideComponentStore } from '@ngrx/component-store';
|
||||
import { ShellFilterOverlayComponent } from '@shell/filter-overlay';
|
||||
import { SharedFilterOverlayComponent } from '@shared/components/filter-overlay';
|
||||
import { UiFilter, UiFilterComponent } from '@ui/filter';
|
||||
import { PriceUpdateComponentStore } from './price-update.component.store';
|
||||
import { combineLatest, Subject, Subscription } from 'rxjs';
|
||||
@@ -26,8 +26,8 @@ export class PriceUpdateComponent implements OnInit {
|
||||
|
||||
hint$ = new Subject<string>();
|
||||
|
||||
@ViewChild(ShellFilterOverlayComponent)
|
||||
filterOverlay: ShellFilterOverlayComponent;
|
||||
@ViewChild(SharedFilterOverlayComponent)
|
||||
filterOverlay: SharedFilterOverlayComponent;
|
||||
|
||||
/**
|
||||
* Zeigt die liste an, wenn entweder keine items geladen werden oder wenn items geladen wurden
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ShellFilterOverlayModule } from '@shell/filter-overlay';
|
||||
import { SharedFilterOverlayModule } from '@shared/components/filter-overlay';
|
||||
import { UiFilterNextModule } from '@ui/filter';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { UiSpinnerModule } from '@ui/spinner';
|
||||
@@ -8,7 +8,7 @@ import { PriceUpdateListModule } from './price-update-list';
|
||||
import { PriceUpdateComponent } from './price-update.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, PriceUpdateListModule, UiIconModule, UiFilterNextModule, ShellFilterOverlayModule, UiSpinnerModule],
|
||||
imports: [CommonModule, PriceUpdateListModule, UiIconModule, UiFilterNextModule, SharedFilterOverlayModule, UiSpinnerModule],
|
||||
exports: [PriceUpdateComponent],
|
||||
declarations: [PriceUpdateComponent],
|
||||
providers: [],
|
||||
|
||||
@@ -6,10 +6,10 @@ import { ArticleSearchComponent } from './article-search.component';
|
||||
import { SearchResultsModule } from './search-results/search-results.module';
|
||||
import { SearchMainModule } from './search-main/search-main.module';
|
||||
import { SearchFilterModule } from './search-filter/search-filter.module';
|
||||
import { ShellFilterOverlayModule } from '@shell/filter-overlay';
|
||||
import { SharedFilterOverlayModule } from '@shared/components/filter-overlay';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, RouterModule, UiIconModule, SearchResultsModule, SearchMainModule, SearchFilterModule, ShellFilterOverlayModule],
|
||||
imports: [CommonModule, RouterModule, UiIconModule, SearchResultsModule, SearchMainModule, SearchFilterModule, SharedFilterOverlayModule],
|
||||
exports: [ArticleSearchComponent],
|
||||
declarations: [ArticleSearchComponent],
|
||||
providers: [],
|
||||
|
||||
@@ -38,6 +38,8 @@ export class PageCatalogComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.activatedProcessId$ = this.application.activatedProcessId$.pipe(map((processId) => String(processId)));
|
||||
|
||||
this.selectedBranch$ = this.activatedProcessId$.pipe(switchMap((processId) => this.application.getSelectedBranch$(Number(processId))));
|
||||
|
||||
this.application.setTitle('Artikelsuche');
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
|
||||
@@ -2,22 +2,13 @@ import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BranchSelectorComponent } from '@shared/components/branch-selector';
|
||||
import { BreadcrumbModule } from '@shared/components/breadcrumb';
|
||||
import { ShellBreadcrumbModule } from '@shell/breadcrumb';
|
||||
import { ArticleDetailsModule } from './article-details/article-details.module';
|
||||
import { ArticleSearchModule } from './article-search/article-search.module';
|
||||
import { PageCatalogRoutingModule } from './page-catalog-routing.module';
|
||||
import { PageCatalogComponent } from './page-catalog.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
PageCatalogRoutingModule,
|
||||
ShellBreadcrumbModule,
|
||||
ArticleSearchModule,
|
||||
ArticleDetailsModule,
|
||||
BreadcrumbModule,
|
||||
BranchSelectorComponent,
|
||||
],
|
||||
imports: [CommonModule, PageCatalogRoutingModule, ArticleSearchModule, ArticleDetailsModule, BreadcrumbModule, BranchSelectorComponent],
|
||||
exports: [],
|
||||
declarations: [PageCatalogComponent],
|
||||
})
|
||||
|
||||
@@ -1 +1 @@
|
||||
<shell-breadcrumb [key]="breadcrumbKey$ | async" [includesTags]="['checkout']"></shell-breadcrumb> <router-outlet></router-outlet>
|
||||
<shared-breadcrumb [key]="breadcrumbKey$ | async" [tags]="['checkout']"></shared-breadcrumb> <router-outlet></router-outlet>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@@ -8,8 +8,12 @@ import { map } from 'rxjs/operators';
|
||||
styleUrls: ['page-checkout.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PageCheckoutComponent {
|
||||
export class PageCheckoutComponent implements OnInit {
|
||||
readonly breadcrumbKey$ = this.applicationService.activatedProcessId$.pipe(map((processId) => String(processId)));
|
||||
|
||||
constructor(private applicationService: ApplicationService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.applicationService.setTitle('Warenkorb');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ShellBreadcrumbModule } from '@shell/breadcrumb';
|
||||
import { BreadcrumbModule } from '@shared/components/breadcrumb';
|
||||
import { CheckoutDummyModule } from './checkout-dummy/checkout-dummy.module';
|
||||
import { CheckoutReviewModule } from './checkout-review/checkout-review.module';
|
||||
import { CheckoutSummaryModule } from './checkout-summary/checkout-summary.module';
|
||||
@@ -8,14 +8,7 @@ import { PageCheckoutRoutingModule } from './page-checkout-routing.module';
|
||||
import { PageCheckoutComponent } from './page-checkout.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
CheckoutSummaryModule,
|
||||
PageCheckoutRoutingModule,
|
||||
CheckoutReviewModule,
|
||||
CheckoutDummyModule,
|
||||
ShellBreadcrumbModule,
|
||||
],
|
||||
imports: [CommonModule, CheckoutSummaryModule, PageCheckoutRoutingModule, CheckoutReviewModule, CheckoutDummyModule, BreadcrumbModule],
|
||||
declarations: [PageCheckoutComponent],
|
||||
exports: [],
|
||||
})
|
||||
|
||||
@@ -6,7 +6,7 @@ import { CustomerOrderSearchFilterComponent, OrderBranchIdInputComponent } from
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { UiFilterNextModule } from '@ui/filter';
|
||||
import { ShellFilterOverlayModule } from '@shell/filter-overlay';
|
||||
import { SharedFilterOverlayModule } from '@shared/components/filter-overlay';
|
||||
import { UiSpinnerModule } from '@ui/spinner';
|
||||
|
||||
@NgModule({
|
||||
@@ -15,7 +15,7 @@ import { UiSpinnerModule } from '@ui/spinner';
|
||||
UiIconModule,
|
||||
RouterModule,
|
||||
UiFilterNextModule,
|
||||
ShellFilterOverlayModule,
|
||||
SharedFilterOverlayModule,
|
||||
UiSpinnerModule,
|
||||
OrderBranchIdInputComponent,
|
||||
],
|
||||
|
||||
@@ -38,6 +38,8 @@ export class CustomerOrderComponent implements OnInit {
|
||||
this.selectedBranch$ = this.application.activatedProcessId$.pipe(
|
||||
switchMap((processId) => this.application.getSelectedBranch$(Number(processId)))
|
||||
);
|
||||
|
||||
this.application.setTitle('Kundenbestellung');
|
||||
}
|
||||
|
||||
async patchProcessData(selectedBranch: BranchDTO) {
|
||||
|
||||
@@ -11,7 +11,7 @@ import { UiCommonModule } from '@ui/common';
|
||||
import { CustomerResultCardComponent } from './search-results/customer-result-card/customer-result-card.component';
|
||||
import { CustomerSearchFilterComponent } from './search-filter/search-filter.component';
|
||||
import { UiFilterNextModule } from '@ui/filter';
|
||||
import { ShellFilterOverlayModule } from '@shell/filter-overlay';
|
||||
import { SharedFilterOverlayModule } from '@shared/components/filter-overlay';
|
||||
import { UiScrollContainerModule } from '@ui/scroll-container';
|
||||
import { UiSpinnerModule } from '@ui/spinner';
|
||||
|
||||
@@ -23,7 +23,7 @@ import { UiSpinnerModule } from '@ui/spinner';
|
||||
UiCommonModule,
|
||||
UiIconModule,
|
||||
ReactiveFormsModule,
|
||||
ShellFilterOverlayModule,
|
||||
SharedFilterOverlayModule,
|
||||
UiFilterNextModule,
|
||||
UiScrollContainerModule,
|
||||
UiSpinnerModule,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<shell-breadcrumb [key]="activatedProcessId$ | async" [includesTags]="['customer']"></shell-breadcrumb>
|
||||
<shared-breadcrumb [key]="activatedProcessId$ | async" tags="customer"></shared-breadcrumb>
|
||||
|
||||
<div class="content-container">
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@@ -9,8 +9,12 @@ import { map } from 'rxjs/operators';
|
||||
providers: [],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PageCustomerComponent {
|
||||
export class PageCustomerComponent implements OnInit {
|
||||
activatedProcessId$ = this.application.activatedProcessId$.pipe(map((p) => String(p)));
|
||||
|
||||
constructor(public application: ApplicationService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.application.setTitle('Kundensuche');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { CommonModule } from '@angular/common';
|
||||
|
||||
import { PageCustomerComponent } from './page-customer.component';
|
||||
import { PageCustomerRoutingModule } from './page-customer-routing.module';
|
||||
import { ShellBreadcrumbModule } from '@shell/breadcrumb';
|
||||
import { BreadcrumbModule } from '@shared/components/breadcrumb';
|
||||
import { CustomerSearchModule } from './customer-search/customer-search.module';
|
||||
import { CustomerDetailsModule } from './customer-details/customer-details.module';
|
||||
import { UiInputModule } from '@ui/input';
|
||||
@@ -14,7 +14,7 @@ import { CustomerModalModuleModule } from './modals';
|
||||
imports: [
|
||||
CommonModule,
|
||||
PageCustomerRoutingModule,
|
||||
ShellBreadcrumbModule,
|
||||
BreadcrumbModule,
|
||||
CustomerSearchModule,
|
||||
CustomerDetailsModule,
|
||||
UiInputModule,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { DomainDashboardService } from '@domain/isa';
|
||||
import { of } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
@@ -14,7 +15,12 @@ export class DashboardComponent implements OnInit {
|
||||
catchError(() => of([]))
|
||||
);
|
||||
|
||||
constructor(private readonly _domainIsaDashboardService: DomainDashboardService) {}
|
||||
constructor(private readonly _domainIsaDashboardService: DomainDashboardService, private _app: ApplicationService) {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
ngOnInit(): void {
|
||||
this._app.setSection('customer');
|
||||
this._app.activateProcess(undefined);
|
||||
|
||||
this._app.setTitle('Dashboard');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@ import { UiIconModule } from '@ui/icon';
|
||||
import { GoodsInSearchFilterComponent } from './goods-in-search-filter';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { UiFilterNextModule } from '@ui/filter';
|
||||
import { ShellFilterOverlayModule } from '@shell/filter-overlay';
|
||||
import { SharedFilterOverlayModule } from '@shared/components/filter-overlay';
|
||||
import { UiSpinnerModule } from '@ui/spinner';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, RouterModule, UiIconModule, UiFilterNextModule, ShellFilterOverlayModule, UiSpinnerModule],
|
||||
imports: [CommonModule, RouterModule, UiIconModule, UiFilterNextModule, SharedFilterOverlayModule, UiSpinnerModule],
|
||||
exports: [GoodsInSearchComponent],
|
||||
declarations: [GoodsInSearchComponent, GoodsInSearchFilterComponent],
|
||||
})
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<shell-breadcrumb [key]="goodsInKey"></shell-breadcrumb>
|
||||
<shared-breadcrumb [key]="goodsInKey"></shared-breadcrumb>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { Config } from '@core/config';
|
||||
|
||||
@Component({
|
||||
@@ -10,7 +11,9 @@ import { Config } from '@core/config';
|
||||
export class GoodsInComponent implements OnInit {
|
||||
goodsInKey = this._config.get('process.ids.goodsIn');
|
||||
|
||||
constructor(private readonly _config: Config) {}
|
||||
constructor(private readonly _config: Config, private _app: ApplicationService) {}
|
||||
|
||||
ngOnInit() {}
|
||||
ngOnInit() {
|
||||
this._app.setTitle('Abholfach');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { GoodsInRoutingModule } from './good-in-routing.module';
|
||||
import { GoodsInComponent } from './goods-in.component';
|
||||
import { ShellBreadcrumbModule } from '@shell/breadcrumb';
|
||||
import { BreadcrumbModule } from '@shared/components/breadcrumb';
|
||||
import { CoreCommandModule } from '@core/command';
|
||||
import {
|
||||
AcceptedActionHandler,
|
||||
@@ -42,11 +42,12 @@ import {
|
||||
CreateReturnItemActionHandler,
|
||||
PrintPriceDiffQrCodeLabelActionHandler,
|
||||
} from '@domain/oms';
|
||||
|
||||
@NgModule({
|
||||
declarations: [GoodsInComponent],
|
||||
imports: [
|
||||
GoodsInRoutingModule,
|
||||
ShellBreadcrumbModule,
|
||||
BreadcrumbModule,
|
||||
CoreCommandModule.forChild([
|
||||
AcceptedActionHandler,
|
||||
ArrivedActionHandler,
|
||||
|
||||
@@ -6,11 +6,11 @@ import { GoodsOutSearchFilterComponent } from './goods-out-search-filter';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { UiFilterNextModule } from '@ui/filter';
|
||||
import { ShellFilterOverlayModule } from '@shell/filter-overlay';
|
||||
import { SharedFilterOverlayModule } from '@shared/components/filter-overlay';
|
||||
import { UiSpinnerModule } from '@ui/spinner';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiIconModule, RouterModule, UiFilterNextModule, ShellFilterOverlayModule, UiSpinnerModule],
|
||||
imports: [CommonModule, UiIconModule, RouterModule, UiFilterNextModule, SharedFilterOverlayModule, UiSpinnerModule],
|
||||
exports: [GoodsOutSearchComponent],
|
||||
declarations: [GoodsOutSearchComponent, GoodsOutSearchFilterComponent],
|
||||
})
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<shell-breadcrumb [key]="processId$ | async" [includesTags]="['goods-out']"></shell-breadcrumb>
|
||||
<shared-breadcrumb [key]="processId$ | async" tags="goods-out"></shared-breadcrumb>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
@@ -8,8 +9,12 @@ import { map } from 'rxjs/operators';
|
||||
styleUrls: ['goods-out.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class GoodsOutComponent {
|
||||
export class GoodsOutComponent implements OnInit {
|
||||
processId$ = this._activatedRoute.data.pipe(map((data) => String(data.processId)));
|
||||
|
||||
constructor(private _activatedRoute: ActivatedRoute) {}
|
||||
constructor(private _activatedRoute: ActivatedRoute, private _app: ApplicationService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this._app.setTitle('Warenausgabe');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ import {
|
||||
PrintPriceDiffQrCodeLabelActionHandler,
|
||||
} from '@domain/oms';
|
||||
import { CoreCommandModule } from '@core/command';
|
||||
import { ShellBreadcrumbModule } from '@shell/breadcrumb';
|
||||
import { BreadcrumbModule } from '@shared/components/breadcrumb';
|
||||
import { GoodsInRoutingModule } from './good-out-routing.module';
|
||||
|
||||
@NgModule({
|
||||
@@ -49,7 +49,7 @@ import { GoodsInRoutingModule } from './good-out-routing.module';
|
||||
imports: [
|
||||
CommonModule,
|
||||
GoodsInRoutingModule,
|
||||
ShellBreadcrumbModule,
|
||||
BreadcrumbModule,
|
||||
CoreCommandModule.forChild([
|
||||
AcceptedActionHandler,
|
||||
ArrivedActionHandler,
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { PackageInspectionPipesModule } from '../../pipes/package-inspection-pipes.module';
|
||||
import { PackageDetailsListComponent } from './package-details-list.component';
|
||||
import { PackageDetailsListItemComponent } from './package-details-list-item.component';
|
||||
import { ProductImageModule } from '@cdn/product-image';
|
||||
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||
import { UiTooltipModule } from '@ui/tooltip';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { PackageInspectionPipesModule } from '@shared/pipes/package-inspection';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, ProductImageModule, PackageInspectionPipesModule, ScrollingModule, UiTooltipModule, UiCommonModule],
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
export * from './package-list.component';
|
||||
export * from './package-list.module';
|
||||
@@ -2,12 +2,12 @@ import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { PackageDetailsComponent } from './package-details.component';
|
||||
import { PackageInspectionPipesModule } from '../pipes';
|
||||
import { PackageDetailsListModule } from '../components/package-details-list';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { UiTooltipModule } from '@ui/tooltip';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { ElementLifecycleModule } from '@shared/directives/element-lifecycle';
|
||||
import { PackageInspectionPipesModule } from '@shared/pipes/package-inspection';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
|
||||
import { Config } from '@core/config';
|
||||
|
||||
@@ -13,10 +14,12 @@ export class PackageInspectionComponent implements OnInit {
|
||||
return this._config.get('process.ids.packageInspection');
|
||||
}
|
||||
|
||||
constructor(private _config: Config, private _breadcrumb: BreadcrumbService) {}
|
||||
constructor(private _config: Config, private _breadcrumb: BreadcrumbService, private _app: ApplicationService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.createBreadcrumbIfNotExists();
|
||||
|
||||
this._app.setTitle('Packstück Prüfung');
|
||||
}
|
||||
|
||||
async createBreadcrumbIfNotExists(): Promise<void> {
|
||||
|
||||
@@ -4,16 +4,15 @@ import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
|
||||
import { CacheService } from '@core/cache';
|
||||
import { Config } from '@core/config';
|
||||
import { provideComponentStore } from '@ngrx/component-store';
|
||||
import { ShellFilterOverlayComponent } from '@shell/filter-overlay';
|
||||
import { ArrivalStatus, ListResponseArgsOfPackageDTO2 } from '@swagger/wws';
|
||||
import { UiFilter, UiFilterComponent } from '@ui/filter';
|
||||
import { isNumber, isString } from 'lodash';
|
||||
import { UiFilter } from '@ui/filter';
|
||||
import moment from 'moment';
|
||||
import { combineLatest, Subject, Subscription } from 'rxjs';
|
||||
import { filter, first, map } from 'rxjs/operators';
|
||||
import { PackageListComponent } from '../components/package-list';
|
||||
import { PackageResultCacheData } from './package-result-cache-data';
|
||||
import { PackageResultComponentStore } from './package-result.component.store';
|
||||
import { SharedFilterOverlayComponent } from '@shared/components/filter-overlay';
|
||||
import { PackageListComponent } from '@shared/components/package-inspection/package-list';
|
||||
|
||||
@Component({
|
||||
selector: 'page-package-result',
|
||||
@@ -31,8 +30,8 @@ export class PackageResultComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
|
||||
hint$ = new Subject<string>();
|
||||
|
||||
@ViewChild(ShellFilterOverlayComponent)
|
||||
filterOverlay: ShellFilterOverlayComponent;
|
||||
@ViewChild(SharedFilterOverlayComponent)
|
||||
filterOverlay: SharedFilterOverlayComponent;
|
||||
|
||||
/**
|
||||
* Zeigt die liste an, wenn entweder keine packages geladen werden oder wenn packages geladen wurden
|
||||
|
||||
@@ -2,14 +2,14 @@ import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { PackageResultComponent } from './package-result.component';
|
||||
import { PackageListModule } from '../components/package-list';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { ShellFilterOverlayModule } from '@shell/filter-overlay';
|
||||
import { SharedFilterOverlayModule } from '@shared/components/filter-overlay';
|
||||
import { UiFilterNextModule } from '@ui/filter';
|
||||
import { UiSpinnerModule } from '@ui/spinner';
|
||||
import { PackageListModule } from '@shared/components/package-inspection/package-list';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, PackageListModule, UiIconModule, UiFilterNextModule, ShellFilterOverlayModule, UiSpinnerModule],
|
||||
imports: [CommonModule, PackageListModule, UiIconModule, UiFilterNextModule, SharedFilterOverlayModule, UiSpinnerModule],
|
||||
exports: [PackageResultComponent],
|
||||
declarations: [PackageResultComponent],
|
||||
})
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export * from './arrival-status-color-class.pipe';
|
||||
export * from './arrival-status.pipe';
|
||||
export * from './package-inspection-pipes.module';
|
||||
@@ -2,7 +2,7 @@ import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||
import { RemissionListComponent } from './remission-list.component';
|
||||
import { ShellFilterOverlayModule } from '@shell/filter-overlay';
|
||||
import { SharedFilterOverlayModule } from '@shared/components/filter-overlay';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { RemissionFilterModule } from './remission-filter/remission-filter.module';
|
||||
import { RemissionListItemModule } from './remission-list-item';
|
||||
@@ -14,7 +14,7 @@ import { RemissionListItemLoadingModule } from './remission-list-item-loading/re
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
ShellFilterOverlayModule,
|
||||
SharedFilterOverlayModule,
|
||||
UiIconModule,
|
||||
RemissionFilterModule,
|
||||
RemissionListItemModule,
|
||||
|
||||
@@ -1 +1 @@
|
||||
<shell-breadcrumb key="4000"></shell-breadcrumb> <router-outlet></router-outlet>
|
||||
<shared-breadcrumb key="4000"></shared-breadcrumb> <router-outlet></router-outlet>
|
||||
|
||||
@@ -23,7 +23,6 @@ export class RemissionComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly _remissionListComponentStore: RemissionListComponentStore,
|
||||
private readonly _breadcrumb: BreadcrumbService,
|
||||
private readonly _config: Config,
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
@@ -46,6 +45,8 @@ export class RemissionComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
|
||||
this.updateProcess();
|
||||
|
||||
this._applicationService.setTitle('Remission');
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ShellBreadcrumbModule } from '@shell/breadcrumb';
|
||||
import { BreadcrumbModule } from '@shared/components/breadcrumb';
|
||||
import { RemissionRoutingModule } from './remission-routing.module';
|
||||
import { RemissionComponent } from './remission.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [RemissionComponent],
|
||||
imports: [RemissionRoutingModule, ShellBreadcrumbModule],
|
||||
imports: [RemissionRoutingModule, BreadcrumbModule],
|
||||
exports: [RemissionComponent],
|
||||
})
|
||||
export class PageRemissionModule {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="pt-2">
|
||||
<shell-breadcrumb [key]="taskCalendarKey" [includesTags]="['task-calendar']"></shell-breadcrumb>
|
||||
<shared-breadcrumb [key]="taskCalendarKey" tags="task-calendar"></shared-breadcrumb>
|
||||
</div>
|
||||
|
||||
<div class="content-header">
|
||||
|
||||
@@ -7,6 +7,7 @@ import { BehaviorSubject, combineLatest, Subject } from 'rxjs';
|
||||
import { first, map, shareReplay, takeUntil, debounceTime } from 'rxjs/operators';
|
||||
import { TaskSearchbarComponent } from './components/task-searchbar/task-searchbar.component';
|
||||
import { TaskCalendarStore } from './task-calendar.store';
|
||||
import { ApplicationService } from '@core/application';
|
||||
|
||||
@Component({
|
||||
selector: 'page-task-calendar',
|
||||
@@ -37,7 +38,12 @@ export class PageTaskCalendarComponent implements OnInit, OnDestroy {
|
||||
@ViewChild(TaskSearchbarComponent)
|
||||
searchbar: TaskSearchbarComponent;
|
||||
|
||||
constructor(private taskCalendarStore: TaskCalendarStore, private _activatedRoute: ActivatedRoute, private readonly _config: Config) {
|
||||
constructor(
|
||||
private taskCalendarStore: TaskCalendarStore,
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private readonly _config: Config,
|
||||
private _app: ApplicationService
|
||||
) {
|
||||
this.taskCalendarStore.loadFilter();
|
||||
}
|
||||
|
||||
@@ -55,6 +61,8 @@ export class PageTaskCalendarComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
|
||||
this.taskCalendarStore.loadItems();
|
||||
|
||||
this._app.setTitle('Tätigkeitenkalender');
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ShellBreadcrumbModule } from '@shell/breadcrumb';
|
||||
import { ShellFilterOverlayModule } from '@shell/filter-overlay';
|
||||
import { BreadcrumbModule } from '@shared/components/breadcrumb';
|
||||
import { SharedFilterOverlayModule } from '@shared/components/filter-overlay';
|
||||
import { UiFilterNextModule } from '@ui/filter';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { TaskSearchbarModule } from './components/task-searchbar/task-searchbar.module';
|
||||
@@ -15,11 +15,11 @@ import { PageTaskCalendarComponent } from './page-task-calendar.component';
|
||||
imports: [
|
||||
CommonModule,
|
||||
PageTaskCalendarRoutingModule,
|
||||
ShellBreadcrumbModule,
|
||||
BreadcrumbModule,
|
||||
UiIconModule,
|
||||
ModalsModule,
|
||||
UiFilterNextModule,
|
||||
ShellFilterOverlayModule,
|
||||
SharedFilterOverlayModule,
|
||||
TaskSearchbarModule,
|
||||
],
|
||||
exports: [PageTaskCalendarComponent],
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
import {
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
ElementRef,
|
||||
Input,
|
||||
QueryList,
|
||||
ViewChildren,
|
||||
ViewEncapsulation,
|
||||
} from '@angular/core';
|
||||
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, Input, QueryList, ViewChildren } from '@angular/core';
|
||||
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
|
||||
import { ComponentStore } from '@ngrx/component-store';
|
||||
import { isEqual } from 'lodash';
|
||||
import { combineLatest, Observable } from 'rxjs';
|
||||
import { debounceTime, map, switchMap, tap } from 'rxjs/operators';
|
||||
import { BreadcrumbComponentState, DEFAULT_BREADCRUMB_COMPONENT_STATE } from './breadcrumb.component-state';
|
||||
import { coerceArray } from '@angular/cdk/coercion';
|
||||
|
||||
@Component({
|
||||
selector: 'shared-breadcrumb',
|
||||
@@ -47,13 +39,14 @@ export class BreadcrumbComponent extends ComponentStore<BreadcrumbComponentState
|
||||
* Hier können auch nut Teile der Tags angeben werden die in der Breadcrumb enthalten sein sollen.
|
||||
*/
|
||||
@Input()
|
||||
get tags(): string[] {
|
||||
get tags(): string[] | string {
|
||||
return this.get((s) => s.tags);
|
||||
}
|
||||
|
||||
set tags(tags: string[]) {
|
||||
if (isEqual(this.tags, tags)) return;
|
||||
this.patchState({ tags });
|
||||
set tags(tags: string[] | string) {
|
||||
const tagsArray = coerceArray(tags);
|
||||
if (isEqual(this.tags, tagsArray)) return;
|
||||
this.patchState({ tags: tagsArray });
|
||||
}
|
||||
|
||||
readonly tags$: Observable<string[]> = this.select((s) => s.tags);
|
||||
|
||||
6
apps/shared/components/filter-overlay/ng-package.json
Normal file
6
apps/shared/components/filter-overlay/ng-package.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "../../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ShellFilterOverlayComponent } from './filter-overlay.component';
|
||||
import { SharedFilterOverlayComponent } from './filter-overlay.component';
|
||||
|
||||
describe('ShellFilterOverlayComponent', () => {
|
||||
let component: ShellFilterOverlayComponent;
|
||||
let fixture: ComponentFixture<ShellFilterOverlayComponent>;
|
||||
let component: SharedFilterOverlayComponent;
|
||||
let fixture: ComponentFixture<SharedFilterOverlayComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ShellFilterOverlayComponent],
|
||||
declarations: [SharedFilterOverlayComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ShellFilterOverlayComponent);
|
||||
fixture = TestBed.createComponent(SharedFilterOverlayComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
@@ -27,7 +27,7 @@ import { Subject } from 'rxjs';
|
||||
]),
|
||||
],
|
||||
})
|
||||
export class ShellFilterOverlayComponent implements OnInit, OnDestroy {
|
||||
export class SharedFilterOverlayComponent implements OnInit, OnDestroy {
|
||||
@ViewChild('filterOverlay')
|
||||
filterOverlay: TemplateRef<any>;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { SharedFilterOverlayComponent } from './filter-overlay.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [SharedFilterOverlayComponent],
|
||||
imports: [],
|
||||
exports: [SharedFilterOverlayComponent],
|
||||
})
|
||||
export class SharedFilterOverlayModule {}
|
||||
6
apps/shared/components/menu/ng-package.json
Normal file
6
apps/shared/components/menu/ng-package.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "../../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
30
apps/shared/components/menu/src/lib/menu-item.directive.ts
Normal file
30
apps/shared/components/menu/src/lib/menu-item.directive.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Highlightable } from '@angular/cdk/a11y';
|
||||
import { Directive, ElementRef, HostListener, Input, Renderer2 } from '@angular/core';
|
||||
|
||||
@Directive({ selector: '[menuItem]', host: { class: 'menu-item', role: 'menuitem', tabindex: '-1' } })
|
||||
export class MenuItemDirective implements Highlightable {
|
||||
private _onClick = (_: MenuItemDirective) => {};
|
||||
|
||||
constructor(private _elementRef: ElementRef, private _renderer: Renderer2) {}
|
||||
|
||||
setActiveStyles(): void {
|
||||
this._renderer.addClass(this._elementRef.nativeElement, 'active');
|
||||
}
|
||||
|
||||
setInactiveStyles(): void {
|
||||
this._renderer.removeClass(this._elementRef.nativeElement, 'active');
|
||||
}
|
||||
|
||||
getLabel?(): string {
|
||||
return this._elementRef.nativeElement.innerText;
|
||||
}
|
||||
|
||||
registerOnClick(fn: (item: MenuItemDirective) => void) {
|
||||
this._onClick = fn;
|
||||
}
|
||||
|
||||
@HostListener('click')
|
||||
onClick() {
|
||||
this._onClick.call(this, this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Component, OnInit, ContentChild, ViewChild, TemplateRef } from '@angular/core';
|
||||
import { MenuComponent } from './menu.component';
|
||||
|
||||
@Component({
|
||||
selector: 'menu-template',
|
||||
template: `<ng-template #menuTpl><ng-content selector="menu"></ng-content></ng-template>`,
|
||||
exportAs: 'menuTemplate',
|
||||
})
|
||||
export class MenuTemplateComponent implements OnInit {
|
||||
@ContentChild(MenuComponent)
|
||||
menu: MenuComponent;
|
||||
|
||||
@ViewChild('menuTpl', { read: TemplateRef, static: true })
|
||||
templateRef: TemplateRef<any>;
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import { Directive, ElementRef, HostListener, Input, OnDestroy, ViewContainerRef } from '@angular/core';
|
||||
import { MenuTemplateComponent } from './menu-template.component';
|
||||
import { HorizontalConnectionPos, Overlay, OverlayRef, VerticalConnectionPos } from '@angular/cdk/overlay';
|
||||
import { TemplatePortal } from '@angular/cdk/portal';
|
||||
import { asapScheduler } from 'rxjs';
|
||||
|
||||
@Directive({ selector: '[menuTrigger]' })
|
||||
export class MenuTriggerDirective implements OnDestroy {
|
||||
@Input('menuTrigger')
|
||||
menuTemplate: MenuTemplateComponent;
|
||||
|
||||
private _overlayRef: OverlayRef;
|
||||
|
||||
@Input()
|
||||
originX: HorizontalConnectionPos = 'start';
|
||||
|
||||
@Input()
|
||||
originY: VerticalConnectionPos = 'bottom';
|
||||
|
||||
@Input()
|
||||
overlayX: HorizontalConnectionPos = 'start';
|
||||
|
||||
@Input()
|
||||
overlayY: VerticalConnectionPos = 'top';
|
||||
|
||||
constructor(private _elementRef: ElementRef, private _overlay: Overlay, private _viewContainerRef: ViewContainerRef) {}
|
||||
|
||||
ngOnDestroy() {
|
||||
this._overlayRef?.dispose();
|
||||
}
|
||||
|
||||
createOverlayRef() {
|
||||
if (!this._overlayRef) {
|
||||
this._overlayRef = this._overlay.create({
|
||||
positionStrategy: this._overlay
|
||||
.position()
|
||||
.flexibleConnectedTo(this._elementRef)
|
||||
.withPositions([{ originX: this.originX, originY: this.originY, overlayX: this.overlayX, overlayY: this.overlayY }]),
|
||||
scrollStrategy: this._overlay.scrollStrategies.reposition(),
|
||||
hasBackdrop: false,
|
||||
});
|
||||
}
|
||||
return this._overlayRef;
|
||||
}
|
||||
|
||||
@HostListener('click')
|
||||
click() {
|
||||
if (this._overlayRef && this._overlayRef.hasAttached()) {
|
||||
this.close();
|
||||
} else {
|
||||
this.open();
|
||||
}
|
||||
}
|
||||
|
||||
open() {
|
||||
const overlayRef = this.createOverlayRef();
|
||||
|
||||
const portal = new TemplatePortal(this.menuTemplate.templateRef, this._viewContainerRef);
|
||||
|
||||
this.menuTemplate.menu.registerOnClick((item) => {
|
||||
asapScheduler.schedule(() => {
|
||||
this.close();
|
||||
});
|
||||
});
|
||||
|
||||
portal.attach(overlayRef);
|
||||
}
|
||||
|
||||
close() {
|
||||
this._overlayRef?.detach();
|
||||
}
|
||||
|
||||
@HostListener('focusout', ['$event'])
|
||||
onKeyUp(event: Event) {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
26
apps/shared/components/menu/src/lib/menu.component.ts
Normal file
26
apps/shared/components/menu/src/lib/menu.component.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Component, ContentChildren, QueryList } from '@angular/core';
|
||||
import { MenuItemDirective } from './menu-item.directive';
|
||||
|
||||
@Component({
|
||||
selector: 'menu',
|
||||
template: `<ng-content [selector]="[menuItem]"></ng-content>`,
|
||||
host: { class: 'menu', role: 'menu' },
|
||||
exportAs: 'menu',
|
||||
})
|
||||
export class MenuComponent {
|
||||
private _menuItems: QueryList<MenuItemDirective>;
|
||||
|
||||
@ContentChildren(MenuItemDirective, { descendants: true })
|
||||
set menuItems(items: QueryList<MenuItemDirective>) {
|
||||
this._menuItems = items;
|
||||
}
|
||||
get menuItems() {
|
||||
return this._menuItems;
|
||||
}
|
||||
|
||||
constructor() {}
|
||||
|
||||
registerOnClick(fn: (item: MenuItemDirective) => void) {
|
||||
this.menuItems.forEach((item) => item.registerOnClick(fn));
|
||||
}
|
||||
}
|
||||
13
apps/shared/components/menu/src/lib/menu.module.ts
Normal file
13
apps/shared/components/menu/src/lib/menu.module.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MenuComponent } from './menu.component';
|
||||
import { MenuItemDirective } from './menu-item.directive';
|
||||
import { MenuTemplateComponent } from './menu-template.component';
|
||||
import { MenuTriggerDirective } from './menu-trigger.directive';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule],
|
||||
exports: [MenuComponent, MenuItemDirective, MenuTemplateComponent, MenuTriggerDirective],
|
||||
declarations: [MenuComponent, MenuItemDirective, MenuTemplateComponent, MenuTriggerDirective],
|
||||
})
|
||||
export class SharedMenuModule {}
|
||||
5
apps/shared/components/menu/src/public-api.ts
Normal file
5
apps/shared/components/menu/src/public-api.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from './lib/menu-item.directive';
|
||||
export * from './lib/menu-template.component';
|
||||
export * from './lib/menu-trigger.directive';
|
||||
export * from './lib/menu.component';
|
||||
export * from './lib/menu.module';
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "../../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { createComponentFactory, Spectator } from '@ngneat/spectator';
|
||||
import { MockPipe } from 'ng-mocks';
|
||||
import { ArrivalStatusColorClassPipe, ArrivalStatusPipe } from '../../pipes';
|
||||
import { PackageListItemComponent } from './package-list-item.component';
|
||||
import { ArrivalStatusColorClassPipe, ArrivalStatusPipe } from '@shared/pipes/package-inspection';
|
||||
|
||||
describe('PackageListItemComponent', () => {
|
||||
let spectator: Spectator<PackageListItemComponent>;
|
||||
@@ -1,20 +1,8 @@
|
||||
import {
|
||||
Component,
|
||||
ChangeDetectionStrategy,
|
||||
Input,
|
||||
EventEmitter,
|
||||
Output,
|
||||
ViewChild,
|
||||
AfterViewInit,
|
||||
OnDestroy,
|
||||
OnChanges,
|
||||
SimpleChanges,
|
||||
NgZone,
|
||||
} from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, Input, EventEmitter, Output, ViewChild, AfterViewInit, OnDestroy } from '@angular/core';
|
||||
import { PackageDTO2 } from '@swagger/wws';
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
import { asapScheduler, Subject } from 'rxjs';
|
||||
import { debounceTime, first, takeUntil } from 'rxjs/operators';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'page-package-list',
|
||||
@@ -4,9 +4,9 @@ import { CommonModule } from '@angular/common';
|
||||
import { PackageListComponent } from './package-list.component';
|
||||
import { PackageListItemComponent } from './package-list-item.component';
|
||||
import { PackageListItemLoaderComponent } from './package-list-item-loader.component';
|
||||
import { PackageInspectionPipesModule } from '../../pipes';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||
import { PackageInspectionPipesModule } from '@shared/pipes/package-inspection';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, PackageInspectionPipesModule, RouterModule, ScrollingModule],
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from './lib/package-list-item-loader.component';
|
||||
export * from './lib/package-list-item.component';
|
||||
export * from './lib/package-list.component';
|
||||
export * from './lib/package-list.module';
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "../../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@ import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { DomainPackageInspectionService } from '@domain/package-inspection';
|
||||
import { PackageArrivalStatusDTO, PackageDTO2 } from '@swagger/wws';
|
||||
import { UiModalRef } from '@ui/modal';
|
||||
import { PackageListModule } from '../package-list';
|
||||
import { WrongDestinationModalData } from './wrong-destination-modal.data';
|
||||
import { PackageListModule } from '@shared/components/package-inspection/package-list';
|
||||
|
||||
@Component({
|
||||
selector: 'page-package-inspection-wrong-destination-modal',
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './lib/wrong-destination-modal.component';
|
||||
export * from './lib/wrong-destination-modal.data';
|
||||
export * from './lib/wrong-destination-modal.service';
|
||||
6
apps/shared/pipes/package-inspection/ng-package.json
Normal file
6
apps/shared/pipes/package-inspection/ng-package.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "../../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user