mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
Merged PR 1274: Merge Dev => Release
Related work items: #2737, #2790, #3150, #3157, #3158
This commit is contained in:
257
angular.json
257
angular.json
@@ -3,256 +3,6 @@
|
||||
"version": 1,
|
||||
"newProjectRoot": "apps",
|
||||
"projects": {
|
||||
"ui": {
|
||||
"root": "libs/ui",
|
||||
"sourceRoot": "libs/ui",
|
||||
"projectType": "library",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "libs/ui/tsconfig.lib.json",
|
||||
"project": "libs/ui/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "libs/ui/tsconfig.lib.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "libs/ui/src/test.ts",
|
||||
"tsConfig": "libs/ui/tsconfig.spec.json",
|
||||
"karmaConfig": "libs/ui/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"libs/ui/tsconfig.lib.json",
|
||||
"libs/ui/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sales": {
|
||||
"root": "apps/sales/",
|
||||
"sourceRoot": "apps/sales/src",
|
||||
"projectType": "application",
|
||||
"prefix": "app",
|
||||
"schematics": {},
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-builders/custom-webpack:browser",
|
||||
"options": {
|
||||
"aot": true,
|
||||
"outputPath": "dist/sales",
|
||||
"index": "apps/sales/src/index.html",
|
||||
"main": "apps/sales/src/main.ts",
|
||||
"polyfills": "apps/sales/src/polyfills.ts",
|
||||
"tsConfig": "apps/sales/tsconfig.app.json",
|
||||
"assets": [
|
||||
"apps/sales/src/favicon.ico",
|
||||
"apps/sales/src/assets",
|
||||
"apps/sales/src/manifest.webmanifest",
|
||||
"apps/sales/src/browserconfig.xml",
|
||||
"apps/sales/src/silent-refresh.html"
|
||||
],
|
||||
"styles": [
|
||||
"apps/sales/src/styles.scss"
|
||||
],
|
||||
"stylePreprocessorOptions": {
|
||||
"includePaths": [
|
||||
"apps/sales/src/scss"
|
||||
]
|
||||
},
|
||||
"scripts": [],
|
||||
"customWebpackConfig": {
|
||||
"path": "apps/sales/webpack.config.js"
|
||||
}
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "apps/sales/src/environments/environment.ts",
|
||||
"with": "apps/sales/src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"extractCss": true,
|
||||
"namedChunks": false,
|
||||
"aot": true,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "5mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "25kb"
|
||||
}
|
||||
],
|
||||
"serviceWorker": true
|
||||
},
|
||||
"development": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "25kb"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-builders/custom-webpack:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "sales:build"
|
||||
},
|
||||
"configurations": {
|
||||
"test": {
|
||||
"browserTarget": "sales:build:test"
|
||||
},
|
||||
"integration": {
|
||||
"browserTarget": "sales:build:integration"
|
||||
},
|
||||
"staging": {
|
||||
"browserTarget": "sales:build:staging"
|
||||
},
|
||||
"production": {
|
||||
"browserTarget": "sales:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "sales:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/sales/src/test.ts",
|
||||
"polyfills": "apps/sales/src/polyfills.ts",
|
||||
"tsConfig": "apps/sales/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/sales/karma.conf.js",
|
||||
"styles": [
|
||||
"apps/sales/src/styles.scss"
|
||||
],
|
||||
"stylePreprocessorOptions": {
|
||||
"includePaths": [
|
||||
"apps/sales/src/scss"
|
||||
]
|
||||
},
|
||||
"scripts": [],
|
||||
"assets": [
|
||||
"apps/sales/src/favicon.ico",
|
||||
"apps/sales/src/assets",
|
||||
"apps/sales/src/manifest.webmanifest"
|
||||
]
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"apps/sales/tsconfig.app.json",
|
||||
"apps/sales/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sales-e2e": {
|
||||
"root": "apps/sales-e2e/",
|
||||
"projectType": "application",
|
||||
"prefix": "",
|
||||
"architect": {
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "apps/sales-e2e/protractor.conf.js",
|
||||
"devServerTarget": "sales:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"integration": {
|
||||
"devServerTarget": "sales:serve:integration"
|
||||
},
|
||||
"production": {
|
||||
"devServerTarget": "sales:serve:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": "apps/sales-e2e/tsconfig.e2e.json",
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sso": {
|
||||
"root": "libs/sso",
|
||||
"sourceRoot": "libs/sso/src",
|
||||
"projectType": "library",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "libs/sso/tsconfig.lib.json",
|
||||
"project": "libs/sso/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "libs/sso/tsconfig.lib.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "libs/sso/src/test.ts",
|
||||
"tsConfig": "libs/sso/tsconfig.spec.json",
|
||||
"karmaConfig": "libs/sso/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"libs/sso/tsconfig.lib.json",
|
||||
"libs/sso/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@swagger/availability": {
|
||||
"root": "apps/swagger/availability",
|
||||
"sourceRoot": "apps/swagger/availability/src",
|
||||
@@ -3310,6 +3060,11 @@
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"allowedCommonJsDependencies": [
|
||||
"lodash",
|
||||
"pdfjs-dist/es5/build/pdf",
|
||||
"pdfjs-dist/es5/web/pdf_viewer"
|
||||
],
|
||||
"outputPath": "dist/isa-app",
|
||||
"index": "apps/isa-app/src/index.html",
|
||||
"main": "apps/isa-app/src/main.ts",
|
||||
@@ -3875,6 +3630,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
"defaultProject": "isa-app"
|
||||
}
|
||||
@@ -181,7 +181,8 @@ describe('ApplicationService', () => {
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledWith({
|
||||
type: actions.patchProcess.type,
|
||||
process: {
|
||||
processId: process.id,
|
||||
changes: {
|
||||
...process,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -60,7 +60,7 @@ describe('applicationReducer', () => {
|
||||
type: 'cart',
|
||||
};
|
||||
|
||||
const action = actions.patchProcess({ process: { ...process, name: 'Test' } });
|
||||
const action = actions.patchProcess({ processId: process.id, changes: { ...process, name: 'Test' } });
|
||||
const state = applicationReducer(
|
||||
{
|
||||
...initialState,
|
||||
@@ -81,7 +81,7 @@ describe('applicationReducer', () => {
|
||||
type: 'cart',
|
||||
};
|
||||
|
||||
const action = actions.patchProcess({ process: { ...process, id: 2 } });
|
||||
const action = actions.patchProcess({ processId: process.id, changes: { ...process, id: 2 } });
|
||||
const state = applicationReducer(
|
||||
{
|
||||
...initialState,
|
||||
|
||||
@@ -23,7 +23,7 @@ const _applicationReducer = createReducer(
|
||||
on(patchProcess, (state, { processId, changes }) => {
|
||||
const processes = state.processes.map((process) => {
|
||||
if (process.id === processId) {
|
||||
return { ...process, ...changes };
|
||||
return { ...process, ...changes, id: processId };
|
||||
}
|
||||
return process;
|
||||
});
|
||||
|
||||
@@ -877,6 +877,10 @@ export class DomainCheckoutService {
|
||||
return this.store.select(DomainCheckoutSelectors.selectOrders);
|
||||
}
|
||||
|
||||
removeAllOrders() {
|
||||
this.store.dispatch(DomainCheckoutActions.removeAllOrders());
|
||||
}
|
||||
|
||||
setSpecialComment({ processId, agentComment }: { processId: number; agentComment: string }) {
|
||||
this.store.dispatch(DomainCheckoutActions.setSpecialComment({ processId, agentComment }));
|
||||
}
|
||||
|
||||
@@ -52,6 +52,8 @@ export const removeProcess = createAction(`${prefix} Remove Process`, props<{ pr
|
||||
|
||||
export const setOrders = createAction(`${prefix} Add Orders`, props<{ orders: DisplayOrderDTO[] }>());
|
||||
|
||||
export const removeAllOrders = createAction(`${prefix} Remove All Orders`);
|
||||
|
||||
export const setBuyer = createAction(`${prefix} Set Buyer`, props<{ processId: number; buyer: BuyerDTO }>());
|
||||
|
||||
export const setPayer = createAction(`${prefix} Set Payer`, props<{ processId: number; payer: PayerDTO }>());
|
||||
|
||||
@@ -72,7 +72,11 @@ const _domainCheckoutReducer = createReducer(
|
||||
return storeCheckoutAdapter.setOne(entity, s);
|
||||
}),
|
||||
on(DomainCheckoutActions.removeProcess, (s, { processId }) => storeCheckoutAdapter.removeOne(processId, s)),
|
||||
on(DomainCheckoutActions.setOrders, (s, { orders }) => ({ ...s, orders })),
|
||||
on(DomainCheckoutActions.setOrders, (s, { orders }) => ({ ...s, orders: [...s.orders, ...orders] })),
|
||||
on(DomainCheckoutActions.removeAllOrders, (s) => ({
|
||||
...s,
|
||||
orders: [],
|
||||
})),
|
||||
on(DomainCheckoutActions.setOlaError, (s, { processId, olaErrorIds }) => {
|
||||
const entity = getOrCreateCheckoutEntity({ processId, entities: s.entities });
|
||||
entity.olaErrorIds = olaErrorIds;
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { Inject, Injectable, InjectionToken } from '@angular/core';
|
||||
import { SignalrHub, SignalRHubOptions } from '@core/signalr';
|
||||
import { merge, of } from 'rxjs';
|
||||
import { filter, map, publishReplay, shareReplay, tap } from 'rxjs/operators';
|
||||
import { BehaviorSubject, merge, of } from 'rxjs';
|
||||
import { filter, map, shareReplay, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { EnvelopeDTO, MessageBoardItemDTO } from './defs';
|
||||
|
||||
export const NOTIFICATIONS_HUB_OPTIONS = new InjectionToken<SignalRHubOptions>('hub.notifications.options');
|
||||
|
||||
@Injectable()
|
||||
export class NotificationsHub extends SignalrHub {
|
||||
updateNotification$ = new BehaviorSubject<MessageBoardItemDTO>(undefined);
|
||||
constructor(@Inject(NOTIFICATIONS_HUB_OPTIONS) options: SignalRHubOptions) {
|
||||
super(options);
|
||||
}
|
||||
@@ -16,6 +17,14 @@ export class NotificationsHub extends SignalrHub {
|
||||
of(this._getNotifications()).pipe(filter((f) => !!f)),
|
||||
this.listen<EnvelopeDTO<MessageBoardItemDTO[]>>('messageBoard')
|
||||
).pipe(
|
||||
withLatestFrom(this.updateNotification$),
|
||||
map(([d, update]) => {
|
||||
const data = d;
|
||||
if (update && !!data && !data?.data?.find((message) => message?.category === 'ISA-Update')) {
|
||||
data.data.push(update);
|
||||
}
|
||||
return data;
|
||||
}),
|
||||
tap((data) => this._storeNotifactions(data)),
|
||||
shareReplay(1)
|
||||
);
|
||||
@@ -35,19 +44,11 @@ export class NotificationsHub extends SignalrHub {
|
||||
}
|
||||
|
||||
updateNotification() {
|
||||
this.notifications$ = this.notifications$.pipe(
|
||||
map((data) => {
|
||||
const notifications = data;
|
||||
if (!!notifications?.data && !notifications?.data?.find((notification) => notification?.category === 'ISA-Update')) {
|
||||
notifications.data.push({
|
||||
category: 'ISA-Update',
|
||||
type: 'update',
|
||||
headline: 'Update Benachrichtigung',
|
||||
text: 'Es steht eine aktuellere Version der ISA bereit. Bitte aktualisieren Sie die Anwendung.',
|
||||
});
|
||||
}
|
||||
return notifications;
|
||||
})
|
||||
);
|
||||
this.updateNotification$.next({
|
||||
category: 'ISA-Update',
|
||||
type: 'update',
|
||||
headline: 'Update Benachrichtigung',
|
||||
text: 'Es steht eine aktuellere Version der ISA bereit. Bitte aktualisieren Sie die Anwendung.',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
CanActivateCustomerWithProcessIdGuard,
|
||||
CanActivateGoodsInGuard,
|
||||
CanActivateGoodsOutGuard,
|
||||
CanActivateGoodsOutWithProcessIdGuard,
|
||||
CanActivateProductGuard,
|
||||
CanActivateProductWithProcessIdGuard,
|
||||
CanActivateRemissionGuard,
|
||||
@@ -20,7 +21,10 @@ import { TokenLoginComponent, TokenLoginModule } from './token-login';
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: 'login',
|
||||
children: [{ path: ':token', component: TokenLoginComponent }],
|
||||
children: [
|
||||
{ path: ':token', component: TokenLoginComponent },
|
||||
{ path: '**', redirectTo: 'kunde', pathMatch: 'full' },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
@@ -75,6 +79,12 @@ const routes: Routes = [
|
||||
loadChildren: () => import('@page/goods-out').then((m) => m.GoodsOutModule),
|
||||
canActivate: [CanActivateGoodsOutGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/goods/out',
|
||||
loadChildren: () => import('@page/goods-out').then((m) => m.GoodsOutModule),
|
||||
canActivate: [CanActivateGoodsOutWithProcessIdGuard],
|
||||
resolve: { processId: ProcessIdResolver },
|
||||
},
|
||||
{ path: '**', redirectTo: 'dashboard', pathMatch: 'full' },
|
||||
],
|
||||
resolve: { section: CustomerSectionResolver },
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Component, Inject, OnInit, Renderer2 } from '@angular/core';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { SwUpdate } from '@angular/service-worker';
|
||||
import { SwUpdate, UpdateAvailableEvent } from '@angular/service-worker';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { Config } from '@core/config';
|
||||
import { NotificationsHub } from '@hub/notifications';
|
||||
import packageInfo from 'package';
|
||||
import { interval } from 'rxjs';
|
||||
import { interval, Observable, Subscription } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
@@ -14,7 +15,8 @@ import { interval } from 'rxjs';
|
||||
styleUrls: ['./app.component.scss'],
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
_checkForUpdates: number = this._config.get('checkForUpdates');
|
||||
private _checkForUpdates: number = this._config.get('checkForUpdates');
|
||||
updateAvailableObs: Observable<UpdateAvailableEvent>;
|
||||
|
||||
get checkForUpdates(): number {
|
||||
return this._checkForUpdates;
|
||||
@@ -25,6 +27,8 @@ export class AppComponent implements OnInit {
|
||||
this._checkForUpdates = time;
|
||||
}
|
||||
|
||||
subscriptions = new Subscription();
|
||||
|
||||
constructor(
|
||||
private readonly _config: Config,
|
||||
private readonly _title: Title,
|
||||
@@ -75,21 +79,30 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
|
||||
checkForUpdateInterval() {
|
||||
this._swUpdate.available.subscribe((availableEvent) => {
|
||||
if (availableEvent?.current?.hash !== availableEvent?.available?.hash) {
|
||||
this._notifications.updateNotification();
|
||||
}
|
||||
});
|
||||
interval(this._checkForUpdates).subscribe(async () => await this._swUpdate.checkForUpdate());
|
||||
this.updateAvailableObs = this._swUpdate.available.pipe(
|
||||
tap((availableEvent) => {
|
||||
if (availableEvent?.current?.hash !== availableEvent?.available?.hash) {
|
||||
this._notifications.updateNotification();
|
||||
this.subscriptions.unsubscribe();
|
||||
}
|
||||
})
|
||||
);
|
||||
this.subscriptions.add(
|
||||
interval(this._checkForUpdates).subscribe(async () => {
|
||||
await this._swUpdate.checkForUpdate();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
async initialCheckForUpdate() {
|
||||
const obs = this._swUpdate.available.subscribe((availableEvent) => {
|
||||
if (availableEvent?.current?.hash !== availableEvent?.available?.hash) {
|
||||
location.reload();
|
||||
}
|
||||
obs.unsubscribe();
|
||||
});
|
||||
this.updateAvailableObs = this._swUpdate.available.pipe(
|
||||
tap((availableEvent) => {
|
||||
if (availableEvent?.current?.hash !== availableEvent?.available?.hash) {
|
||||
location.reload();
|
||||
}
|
||||
})
|
||||
);
|
||||
this.subscriptions.add(this.updateAvailableObs.subscribe());
|
||||
await this._swUpdate.checkForUpdate();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
|
||||
import { ApplicationProcess, ApplicationService } from '@core/application';
|
||||
import { first } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CanActivateGoodsOutWithProcessIdGuard implements CanActivate {
|
||||
constructor(private readonly _applicationService: ApplicationService) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const process = await this._applicationService
|
||||
.getProcessById$(+route.params.processId)
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
if (!process) {
|
||||
const processes = await this._applicationService.getProcesses$('customer').pipe(first()).toPromise();
|
||||
await this._applicationService.createProcess({
|
||||
id: +route.params.processId,
|
||||
type: 'goods-out',
|
||||
section: 'customer',
|
||||
name: `Warenausgabe ${this.processNumber(processes)}`,
|
||||
});
|
||||
}
|
||||
|
||||
this._applicationService.activateProcess(+route.params.processId);
|
||||
return true;
|
||||
}
|
||||
|
||||
processNumber(processes: ApplicationProcess[]) {
|
||||
const processNumbers = processes?.map((process) => Number(process?.name?.replace(/\D/g, '')));
|
||||
return !!processNumbers && processNumbers?.length > 0 ? Math.max(...processNumbers) + 1 : 1;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,49 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
|
||||
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { Config } from '@core/config';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { first, map } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CanActivateGoodsOutGuard implements CanActivate {
|
||||
constructor(private readonly _applicationService: ApplicationService, private readonly _config: Config) {}
|
||||
constructor(private readonly _applicationService: ApplicationService, private readonly _router: Router) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const process = await this._applicationService.getProcessById$(this._config.get('process.ids.goodsOut')).pipe(first()).toPromise();
|
||||
if (!process) {
|
||||
await this._applicationService.createProcess({
|
||||
id: this._config.get('process.ids.goodsOut'),
|
||||
type: 'goods-out',
|
||||
section: 'customer',
|
||||
name: 'Warenausgabe',
|
||||
});
|
||||
const processesIds = await this._applicationService
|
||||
.getProcesses$('customer')
|
||||
.pipe(
|
||||
first(),
|
||||
map((p) => {
|
||||
return p.filter((process) => process.type === 'goods-out').map((process) => +process.name.replace('Warenausgabe', '').trim());
|
||||
})
|
||||
)
|
||||
.toPromise();
|
||||
|
||||
let lastActivatedProcessId = (
|
||||
await this._applicationService.getLastActivatedProcessWithSectionAndType$('customer', 'goods-out').pipe(first()).toPromise()
|
||||
)?.id;
|
||||
|
||||
console.log(processesIds);
|
||||
|
||||
// if (!lastActivatedProcessId) {
|
||||
lastActivatedProcessId = Date.now();
|
||||
await this._applicationService.createProcess({
|
||||
id: lastActivatedProcessId,
|
||||
type: 'goods-out',
|
||||
section: 'customer',
|
||||
name: `Warenausgabe ${Math.max(...processesIds, 0) + 1}`,
|
||||
});
|
||||
// }
|
||||
|
||||
await this._router.navigate(this.getUrlFromSnapshot(route, ['/kunde', String(lastActivatedProcessId)]));
|
||||
return false;
|
||||
}
|
||||
|
||||
getUrlFromSnapshot(route: ActivatedRouteSnapshot, url: string[] = []): string[] {
|
||||
url.push(...route.url.map((segment) => segment.path));
|
||||
if (route.firstChild) {
|
||||
return this.getUrlFromSnapshot(route.firstChild, url);
|
||||
}
|
||||
this._applicationService.activateProcess(this._config.get('process.ids.goodsOut'));
|
||||
return true;
|
||||
return url.filter((segment) => !!segment);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ export * from './can-activate-cart.guard';
|
||||
export * from './can-activate-customer-with-process-id.guard';
|
||||
export * from './can-activate-customer.guard';
|
||||
export * from './can-activate-goods-in.guard';
|
||||
export * from './can-activate-goods-out-with-process-id.guard';
|
||||
export * from './can-activate-goods-out.guard';
|
||||
export * from './can-activate-product-with-process-id.guard';
|
||||
export * from './can-activate-product.guard';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component, ChangeDetectionStrategy, ViewChildren, QueryList } from '@angular/core';
|
||||
import { ApplicationProcess, ApplicationService } from '@core/application';
|
||||
import { first, map, shareReplay, switchMap } from 'rxjs/operators';
|
||||
import { first, map, shareReplay, switchMap, tap } from 'rxjs/operators';
|
||||
import { NotificationsHub } from '@hub/notifications';
|
||||
import { ModalNotificationsComponent } from '@modal/notifications';
|
||||
import { ConfirmModalData, UiConfirmModalComponent, UiModalService } from '@ui/modal';
|
||||
@@ -27,7 +27,11 @@ export class ShellComponent {
|
||||
notificationCount$ = this.notifications$.pipe(map((message) => message?.data?.length));
|
||||
|
||||
get activatedProcessId$() {
|
||||
return this._appService.getActivatedProcessId$().pipe(shareReplay());
|
||||
return this._appService.getActivatedProcessId$().pipe(
|
||||
tap((activatedProcessId) => {
|
||||
this.processTabs?.find((process) => process?.process?.id === activatedProcessId && !process?.isActive)?.slideIntoView();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
get section$() {
|
||||
@@ -98,7 +102,6 @@ export class ShellComponent {
|
||||
|
||||
async activateProcess(activatedProcessId: number) {
|
||||
const latestCrumb = await this._breadcrumbService?.getLastActivatedBreadcrumbByKey$(activatedProcessId)?.pipe(first()).toPromise();
|
||||
|
||||
if (latestCrumb) {
|
||||
await this._router.navigate([latestCrumb.path], { queryParams: latestCrumb.params });
|
||||
} else {
|
||||
|
||||
@@ -15,7 +15,9 @@ export class TokenLoginComponent implements OnInit {
|
||||
if (this._route.snapshot.params.token && !this._authService.isAuthenticated()) {
|
||||
this._authService.setKeyCardToken(this._route.snapshot.params.token);
|
||||
this._authService.login();
|
||||
} else {
|
||||
} else if (!this._authService.isAuthenticated()) {
|
||||
this._authService.login();
|
||||
} else if (this._authService.isAuthenticated()) {
|
||||
this._router.navigate(['/']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
|
||||
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
|
||||
*/
|
||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
|
||||
/**
|
||||
* By default, zone.js will patch all possible macroTask and DomEvents
|
||||
@@ -62,3 +62,4 @@ import 'zone.js'; // Included with Angular CLI.
|
||||
/***************************************************************************************************
|
||||
* APPLICATION IMPORTS
|
||||
*/
|
||||
import 'hammerjs';
|
||||
|
||||
@@ -48,7 +48,7 @@ hr {
|
||||
|
||||
.branch-info {
|
||||
@apply flex flex-row;
|
||||
max-width: 505px;
|
||||
max-width: 485px;
|
||||
|
||||
.branch-name {
|
||||
@apply font-bold whitespace-nowrap;
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { DomainAvailabilityService, ItemData } from '@domain/availability';
|
||||
import { DomainCatalogService } from '@domain/catalog';
|
||||
import { ComponentStore, tapResponse } from '@ngrx/component-store';
|
||||
import { ItemDTO, ResponseArgsOfItemDTO } from '@swagger/cat';
|
||||
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
|
||||
import { combineLatest, Observable, of } from 'rxjs';
|
||||
import { catchError, filter, map, shareReplay, switchMap, tap } from 'rxjs/operators';
|
||||
import { catchError, filter, first, map, shareReplay, switchMap, tap } from 'rxjs/operators';
|
||||
|
||||
export interface ArticleDetailsState {
|
||||
fetchingItem?: boolean;
|
||||
@@ -241,7 +245,11 @@ export class ArticleDetailsStore extends ComponentStore<ArticleDetailsState> {
|
||||
|
||||
constructor(
|
||||
private readonly domainCatalogService: DomainCatalogService,
|
||||
private readonly domainAvailabilityService: DomainAvailabilityService
|
||||
private readonly domainAvailabilityService: DomainAvailabilityService,
|
||||
private readonly _appService: ApplicationService,
|
||||
private readonly _router: Router,
|
||||
private readonly _breadcrumb: BreadcrumbService,
|
||||
private readonly _modal: UiModalService
|
||||
) {
|
||||
super({});
|
||||
}
|
||||
@@ -253,9 +261,15 @@ export class ArticleDetailsStore extends ComponentStore<ArticleDetailsState> {
|
||||
switchMap((id) => this.domainCatalogService.getDetailsById({ id })),
|
||||
tapResponse<ResponseArgsOfItemDTO>(
|
||||
(response) => this.patchState({ item: response.result, fetchingItem: false }),
|
||||
(err) => {
|
||||
console.error('loadItemById failed', err);
|
||||
async (err) => {
|
||||
this.patchState({ item: undefined, fetchingItem: false });
|
||||
const errorModalRef = this._modal.open({
|
||||
content: UiErrorModalComponent,
|
||||
title: 'Fehler beim Laden des Artikels über die ID',
|
||||
data: { message: 'Sie kehren nun auf die ursprüngliche Artikeldetailseite zurück' },
|
||||
});
|
||||
await errorModalRef.afterClosed$.toPromise();
|
||||
await this.navigateBack();
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -268,11 +282,26 @@ export class ArticleDetailsStore extends ComponentStore<ArticleDetailsState> {
|
||||
switchMap((ean) => this.domainCatalogService.getDetailsByEan({ ean })),
|
||||
tapResponse<ResponseArgsOfItemDTO>(
|
||||
(response) => this.patchState({ item: response.result, fetchingItem: false }),
|
||||
(err) => {
|
||||
console.error('loadItemByEan failed', err);
|
||||
async (err) => {
|
||||
this.patchState({ item: undefined, fetchingItem: false });
|
||||
const errorModalRef = this._modal.open({
|
||||
content: UiErrorModalComponent,
|
||||
title: 'Fehler beim Laden des Artikels über die EAN',
|
||||
data: { message: 'Sie kehren nun auf die ursprüngliche Artikeldetailseite zurück' },
|
||||
});
|
||||
await errorModalRef.afterClosed$.toPromise();
|
||||
await this.navigateBack();
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
async navigateBack() {
|
||||
const crumb = await this._breadcrumb.getLastActivatedBreadcrumbByKey$(this._appService.activatedProcessId).pipe(first()).toPromise();
|
||||
if (crumb) {
|
||||
await this._router.navigate([crumb.path]);
|
||||
} else {
|
||||
await this._router.navigate(['/kunde', this._appService.activatedProcessId, 'product', 'search']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<ng-container *ngIf="(groupedItems$ | async)?.length <= 0">
|
||||
<ng-container *ngIf="(groupedItems$ | async)?.length <= 0 && !(fetching$ | async); else shoppingCart">
|
||||
<div class="card stretch card-empty">
|
||||
<div class="empty-message">
|
||||
<span class="cart-icon">
|
||||
@@ -20,7 +20,11 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="(groupedItems$ | async)?.length > 0">
|
||||
<div class="flex items-center justify-center card stretch card-empty" *ngIf="fetching$ | async">
|
||||
<ui-spinner show="true"> </ui-spinner>
|
||||
</div>
|
||||
|
||||
<ng-template #shoppingCart>
|
||||
<ng-container *ngIf="shoppingCart$ | async; let shoppingCart">
|
||||
<div class="card stretch">
|
||||
<div class="cta-print-wrapper">
|
||||
@@ -180,4 +184,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
|
||||
@@ -9,7 +9,7 @@ import { PrintModalData, PrintModalComponent } from '@modal/printer';
|
||||
import { PurchasingOptionsModalComponent, PurchasingOptionsModalData } from '../modals/purchasing-options-modal';
|
||||
import { PurchasingOptions } from '../modals/purchasing-options-modal/purchasing-options-modal.store';
|
||||
import { AuthService } from '@core/auth';
|
||||
import { first, map, shareReplay, switchMap, takeUntil, withLatestFrom } from 'rxjs/operators';
|
||||
import { first, map, shareReplay, switchMap, takeUntil, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { Subject, NEVER, combineLatest, BehaviorSubject } from 'rxjs';
|
||||
import { DomainCatalogService } from '@domain/catalog';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
@@ -25,6 +25,7 @@ import { ComponentStore, tapResponse } from '@ngrx/component-store';
|
||||
export interface CheckoutReviewComponentState {
|
||||
shoppingCart: ShoppingCartDTO;
|
||||
shoppingCartItems: ShoppingCartItemDTO[];
|
||||
fetching: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
@@ -52,6 +53,14 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
|
||||
}
|
||||
readonly shoppingCartItems$ = this.select((s) => s.shoppingCartItems);
|
||||
|
||||
get fetching() {
|
||||
return this.get((s) => s.fetching);
|
||||
}
|
||||
set fetching(fetching: boolean) {
|
||||
this.patchState({ fetching });
|
||||
}
|
||||
readonly fetching$ = this.select((s) => s.fetching);
|
||||
|
||||
payer$ = this.applicationService.activatedProcessId$.pipe(
|
||||
takeUntil(this._orderCompleted),
|
||||
switchMap((processId) => this.domainCheckoutService.getPayer({ processId })),
|
||||
@@ -234,6 +243,7 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
|
||||
super({
|
||||
shoppingCart: undefined,
|
||||
shoppingCartItems: [],
|
||||
fetching: false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -249,6 +259,7 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
|
||||
|
||||
loadShoppingCart = this.effect(($) =>
|
||||
$.pipe(
|
||||
tap(() => (this.fetching = true)),
|
||||
withLatestFrom(this.applicationService.activatedProcessId$),
|
||||
switchMap(([_, processId]) => {
|
||||
return this.domainCheckoutService.getShoppingCart({ processId, latest: true }).pipe(
|
||||
@@ -265,7 +276,8 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
|
||||
() => {}
|
||||
)
|
||||
);
|
||||
})
|
||||
}),
|
||||
tap(() => (this.fetching = false))
|
||||
)
|
||||
);
|
||||
|
||||
@@ -749,10 +761,11 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
|
||||
} else {
|
||||
try {
|
||||
this.showOrderButtonSpinner = true;
|
||||
await this.domainCheckoutService.completeCheckout({ processId }).toPromise();
|
||||
const orders = await this.domainCheckoutService.completeCheckout({ processId }).toPromise();
|
||||
const orderIds = orders.map((order) => order.id).join(',');
|
||||
this._orderCompleted.next();
|
||||
await this.router.navigate(['/kunde', this.applicationService.activatedProcessId, 'cart', 'summary']);
|
||||
this.applicationService.removeProcess(this.applicationService.activatedProcessId);
|
||||
await this.patchProcess(processId);
|
||||
await this.router.navigate(['/kunde', processId, 'cart', 'summary', orderIds]);
|
||||
} catch (error) {
|
||||
const response = error?.error;
|
||||
let message: string = response?.message ?? '';
|
||||
@@ -771,8 +784,8 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
|
||||
|
||||
if (error.status === 409) {
|
||||
this._orderCompleted.next();
|
||||
await this.router.navigate(['/kunde', this.applicationService.activatedProcessId, 'cart', 'summary']);
|
||||
this.applicationService.removeProcess(this.applicationService.activatedProcessId);
|
||||
await this.patchProcess(processId);
|
||||
await this.router.navigate(['/kunde', processId, 'cart', 'summary']);
|
||||
}
|
||||
} finally {
|
||||
this.showOrderButtonSpinner = false;
|
||||
@@ -780,4 +793,10 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async patchProcess(processId: number) {
|
||||
this.applicationService.patchProcess(processId, {
|
||||
type: 'cart-checkout',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
<div class="row between">
|
||||
<div class="product-name">
|
||||
<img class="thumbnail" [src]="order.product?.ean | productImage: 30:50:true" />
|
||||
<a class="name" [routerLink]="['/kunde', 'product', 'details', 'ean', order?.product?.ean]">{{ order?.product?.name }}</a>
|
||||
<a class="name" [routerLink]="['/kunde', processId, 'product', 'details', 'ean', order?.product?.ean]">{{
|
||||
order?.product?.name
|
||||
}}</a>
|
||||
</div>
|
||||
|
||||
<div class="product-details">
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, OnDestroy } from '@angular/core';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { PrintModalComponent, PrintModalData } from '@modal/printer';
|
||||
import { first, map, switchMap } from 'rxjs/operators';
|
||||
import { debounceTime, first, map, shareReplay, switchMap } from 'rxjs/operators';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
import { Router } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { DomainOmsService } from '@domain/oms';
|
||||
import { DomainCatalogService } from '@domain/catalog';
|
||||
import { DisplayOrderItemDTO } from '@swagger/oms';
|
||||
import { DisplayOrderDTO, DisplayOrderItemDTO } from '@swagger/oms';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { DomainPrinterService } from '@domain/printer';
|
||||
import { NEVER } from 'rxjs';
|
||||
import { combineLatest, NEVER } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'page-checkout-summary',
|
||||
@@ -19,18 +19,26 @@ import { NEVER } from 'rxjs';
|
||||
styleUrls: ['checkout-summary.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class CheckoutSummaryComponent {
|
||||
export class CheckoutSummaryComponent implements OnDestroy {
|
||||
processId = Date.now();
|
||||
|
||||
displayOrders$ = this.domainCheckoutService.getOrders().pipe(
|
||||
map((orders) =>
|
||||
orders.map((order) => {
|
||||
displayOrders$ = combineLatest([this.domainCheckoutService.getOrders(), this._route.params]).pipe(
|
||||
map(([orders, params]) => {
|
||||
let filteredOrders: DisplayOrderDTO[] = [];
|
||||
if (params?.orderIds) {
|
||||
const orderIds: String[] = params.orderIds.split(',');
|
||||
filteredOrders = orders.filter((order) => orderIds.find((id) => Number(id) === order.id));
|
||||
} else {
|
||||
return filteredOrders;
|
||||
}
|
||||
return filteredOrders?.map((order) => {
|
||||
return {
|
||||
...order,
|
||||
items: [...order.items]?.sort((a, b) => a.product?.name.localeCompare(b.product?.name)),
|
||||
};
|
||||
})
|
||||
)
|
||||
});
|
||||
}),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
totalItemCount$ = this.displayOrders$.pipe(
|
||||
@@ -102,6 +110,7 @@ export class CheckoutSummaryComponent {
|
||||
private customerService: CrmCustomerService,
|
||||
private domainCatalogService: DomainCatalogService,
|
||||
private router: Router,
|
||||
private _route: ActivatedRoute,
|
||||
private omsService: DomainOmsService,
|
||||
private uiModal: UiModalService,
|
||||
private breadcrumb: BreadcrumbService,
|
||||
@@ -118,13 +127,24 @@ export class CheckoutSummaryComponent {
|
||||
this.breadcrumb.addBreadcrumbIfNotExists({
|
||||
key: this.applicationService.activatedProcessId,
|
||||
name: 'Bestellbestätigung',
|
||||
path: `/kunde/${this.applicationService.activatedProcessId}/cart/summary`,
|
||||
path: `/kunde/${this.applicationService.activatedProcessId}/cart/summary/${this._route.snapshot.params.orderIds}`,
|
||||
tags: ['checkout', 'cart'],
|
||||
section: 'customer',
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async ngOnDestroy() {
|
||||
const checkoutProcess = await this.applicationService
|
||||
.getLastActivatedProcessWithSectionAndType$('customer', 'cart-checkout')
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
if (!checkoutProcess) {
|
||||
this.domainCheckoutService.removeAllOrders();
|
||||
}
|
||||
}
|
||||
|
||||
openPrintModal(id: number) {
|
||||
this.uiModal.open({
|
||||
content: PrintModalComponent,
|
||||
|
||||
@@ -10,6 +10,7 @@ const routes: Routes = [
|
||||
component: PageCheckoutComponent,
|
||||
children: [
|
||||
{ path: 'summary', component: CheckoutSummaryComponent },
|
||||
{ path: 'summary/:orderIds', component: CheckoutSummaryComponent },
|
||||
{ path: 'review', component: CheckoutReviewComponent },
|
||||
{ path: '', pathMatch: 'full', redirectTo: 'review' },
|
||||
],
|
||||
|
||||
@@ -231,7 +231,6 @@ export abstract class CustomerCreateComponentBase {
|
||||
this.control.reset(this.control.value);
|
||||
|
||||
if (invalidProperties) {
|
||||
console.log('setValidationError', invalidProperties);
|
||||
setInvalidPropertyErrors({ invalidProperties, formGroup });
|
||||
}
|
||||
|
||||
|
||||
@@ -320,6 +320,8 @@ export class CustomerDetailsComponent implements OnInit {
|
||||
name: isB2b ? (customer.organisation?.name ? customer.organisation?.name : customer.lastName) : customer.lastName,
|
||||
});
|
||||
|
||||
const currentBuyer = await this.checkoutService.getBuyer({ processId: this.application.activatedProcessId }).pipe(first()).toPromise();
|
||||
|
||||
// Set Buyer For Process
|
||||
this.checkoutService.setBuyer({
|
||||
processId: this.application.activatedProcessId,
|
||||
@@ -331,10 +333,12 @@ export class CustomerDetailsComponent implements OnInit {
|
||||
customerFeatures: this.getCusomterFeatures(customer),
|
||||
});
|
||||
|
||||
this.checkoutService.setNotificationChannels({
|
||||
processId: this.application.activatedProcessId,
|
||||
notificationChannels: customer.notificationChannels === (3 as NotificationChannel) ? 1 : customer.notificationChannels,
|
||||
});
|
||||
if (currentBuyer?.buyerNumber !== customer.customerNumber) {
|
||||
this.checkoutService.setNotificationChannels({
|
||||
processId: this.application.activatedProcessId,
|
||||
notificationChannels: customer.notificationChannels === (3 as NotificationChannel) ? 1 : customer.notificationChannels,
|
||||
});
|
||||
}
|
||||
|
||||
// Set Invoice Address If Selected
|
||||
const payer = await this.getSelectedPayerAddress();
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { ProductImageService } from '@cdn/product-image';
|
||||
import { HistoryComponent } from '@modal/history';
|
||||
import { ImageService } from '@sales/core-services';
|
||||
import { OrderDTO, OrderItemDTO, OrderItemSubsetDTO } from '@swagger/oms';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Observable, of } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'page-customer-order-item-card',
|
||||
@@ -41,13 +41,21 @@ export class CustomerOrderItemCardComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
constructor(private imageService: ImageService, private _modal: UiModalService) {}
|
||||
constructor(private imageService: ProductImageService, private _modal: UiModalService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.imageUrl = this.imageService.getImageUrl(this.orderItem.product.ean, {
|
||||
width: 60,
|
||||
height: 100,
|
||||
});
|
||||
// this.imageUrl = this.imageService.getImageUrl(this.orderItem.product.ean, {
|
||||
// width: 60,
|
||||
// height: 100,
|
||||
// });
|
||||
|
||||
this.imageUrl = of(
|
||||
this.imageService.getImageUrl({
|
||||
imageId: this.orderItem.product.ean,
|
||||
width: 60,
|
||||
height: 100,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
openHistory() {
|
||||
|
||||
@@ -177,7 +177,7 @@ export class GoodsInCleanupListComponent implements OnInit, OnDestroy {
|
||||
const customerNumber = orderItem.buyerNumber;
|
||||
const orderNumber = orderItem.orderNumber;
|
||||
const processingStatus = orderItem.processingStatus;
|
||||
const orderItemId = orderItem.orderItemId;
|
||||
const orderItemId = orderItem.orderItemSubsetId;
|
||||
|
||||
this._router.navigate([
|
||||
`/filiale/goods/in/details/customer/${encodeURIComponent(customerNumber)}/order/${encodeURIComponent(
|
||||
|
||||
@@ -54,7 +54,7 @@ export class GoodsInDetailsComponent extends ComponentStore<GoodsInDetailsCompon
|
||||
);
|
||||
|
||||
selectedItem$ = combineLatest([this.selectedOrderItemId$, this.itemsWithProcessingStatus$]).pipe(
|
||||
map(([orderItemId, items]) => items.find((item) => item.orderItemId === orderItemId) || items[0])
|
||||
map(([orderItemId, items]) => items.find((item) => item.orderItemSubsetId === orderItemId) || items[0])
|
||||
);
|
||||
|
||||
fetchingCoverItems$ = this.select((s) => s.fetchingCoverItems);
|
||||
@@ -125,7 +125,7 @@ export class GoodsInDetailsComponent extends ComponentStore<GoodsInDetailsCompon
|
||||
name: item?.orderNumber,
|
||||
path: `/filiale/goods/in/details/customer/${encodeURIComponent(item.buyerNumber)}/order/${encodeURIComponent(
|
||||
item?.orderNumber
|
||||
)}/item/${item?.orderItemId}/${item?.processingStatus}`,
|
||||
)}/item/${item?.orderItemSubsetId}/${item?.processingStatus}`,
|
||||
section: 'branch',
|
||||
tags: ['goods-in', 'details', item?.orderNumber],
|
||||
});
|
||||
@@ -151,7 +151,7 @@ export class GoodsInDetailsComponent extends ComponentStore<GoodsInDetailsCompon
|
||||
orderId: res.result[0].orderId,
|
||||
});
|
||||
this.updateBreadcrumb(
|
||||
res.result.find((item) => item.orderItemId === selectedOrderItemId && item.processingStatus === processingStatus)
|
||||
res.result.find((item) => item.orderItemSubsetId === selectedOrderItemId && item.processingStatus === processingStatus)
|
||||
);
|
||||
},
|
||||
() => {},
|
||||
@@ -202,7 +202,7 @@ export class GoodsInDetailsComponent extends ComponentStore<GoodsInDetailsCompon
|
||||
this._router.navigate([
|
||||
`/filiale/goods/in/details/customer/${encodeURIComponent(orderItem.buyerNumber)}/order/${encodeURIComponent(
|
||||
orderItem?.orderNumber
|
||||
)}/item/${orderItem?.orderItemId}/${orderItem?.processingStatus}/edit`,
|
||||
)}/item/${orderItem?.orderItemSubsetId}/${orderItem?.processingStatus}/edit`,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ export class GoodsInDetailsComponent extends ComponentStore<GoodsInDetailsCompon
|
||||
this._router.navigate([
|
||||
`/filiale/goods/in/details/customer/${encodeURIComponent(orderItem?.buyerNumber)}/order/${encodeURIComponent(
|
||||
orderItem?.orderNumber
|
||||
)}/item/${orderItem?.orderItemId}/${orderItem?.processingStatus}`,
|
||||
)}/item/${orderItem?.orderItemSubsetId}/${orderItem?.processingStatus}`,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ export class GoodsInListComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
const customerNumber = orderItem.buyerNumber;
|
||||
const orderNumber = orderItem.orderNumber;
|
||||
const processingStatus = orderItem.processingStatus;
|
||||
const orderItemId = orderItem.orderItemId;
|
||||
const orderItemId = orderItem.orderItemSubsetId;
|
||||
|
||||
this._router.navigate([
|
||||
`/filiale/goods/in/details/customer/${encodeURIComponent(customerNumber)}/order/${encodeURIComponent(
|
||||
|
||||
@@ -135,7 +135,7 @@ export class GoodsInRemissionPreviewComponent implements OnInit, OnDestroy {
|
||||
const customerNumber = orderItem.buyerNumber;
|
||||
const orderNumber = orderItem.orderNumber;
|
||||
const processingStatus = orderItem.processingStatus;
|
||||
const orderItemId = orderItem.orderItemId;
|
||||
const orderItemId = orderItem.orderItemSubsetId;
|
||||
|
||||
this._router.navigate([
|
||||
`/filiale/goods/in/details/customer/${encodeURIComponent(customerNumber)}/order/${encodeURIComponent(
|
||||
|
||||
@@ -138,7 +138,7 @@ export class GoodsInReservationComponent implements OnInit, OnDestroy {
|
||||
const customerNumber = orderItem.buyerNumber;
|
||||
const orderNumber = orderItem.orderNumber;
|
||||
const processingStatus = orderItem.processingStatus;
|
||||
const orderItemId = orderItem.orderItemId;
|
||||
const orderItemId = orderItem.orderItemSubsetId;
|
||||
|
||||
this._router.navigate([
|
||||
`/filiale/goods/in/details/customer/${encodeURIComponent(customerNumber)}/order/${encodeURIComponent(
|
||||
|
||||
@@ -74,7 +74,7 @@ export class GoodsInSearchFilterComponent implements OnInit, OnDestroy {
|
||||
this._router.navigate([
|
||||
`/filiale/goods/in/details/customer/${encodeURIComponent(orderItem.buyerNumber)}/order/${encodeURIComponent(
|
||||
orderItem.orderNumber
|
||||
)}/item/${orderItem.orderItemId}/${orderItem.processingStatus}`,
|
||||
)}/item/${orderItem.orderItemSubsetId}/${orderItem.processingStatus}`,
|
||||
]);
|
||||
} else {
|
||||
this._router.navigate(['/filiale', 'goods', 'in', 'results'], {
|
||||
|
||||
@@ -120,7 +120,7 @@ export class GoodsInSearchMainComponent implements OnInit, OnDestroy {
|
||||
this._router.navigate([
|
||||
`/filiale/goods/in/details/customer/${encodeURIComponent(orderItem.buyerNumber)}/order/${encodeURIComponent(
|
||||
orderItem.orderNumber
|
||||
)}/item/${orderItem.orderItemId}/${orderItem.processingStatus}`,
|
||||
)}/item/${orderItem.orderItemSubsetId}/${orderItem.processingStatus}`,
|
||||
]);
|
||||
} else {
|
||||
this._router.navigate(['/filiale', 'goods', 'in', 'results'], {
|
||||
|
||||
@@ -158,7 +158,7 @@ export class GoodsInSearchResultsComponent implements OnInit, OnDestroy {
|
||||
const customerNumber = orderItem.buyerNumber;
|
||||
const orderNumber = orderItem.orderNumber;
|
||||
const processingStatus = orderItem.processingStatus;
|
||||
const orderItemId = orderItem.orderItemId;
|
||||
const orderItemId = orderItem.orderItemSubsetId;
|
||||
|
||||
this._router.navigate([
|
||||
`/filiale/goods/in/details/customer/${encodeURIComponent(customerNumber)}/order/${encodeURIComponent(
|
||||
|
||||
@@ -47,6 +47,12 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
get processId() {
|
||||
return +this._activatedRoute.snapshot.parent.data.processId;
|
||||
}
|
||||
|
||||
processId$ = this._activatedRoute.parent.data.pipe(map((params) => +params.processId));
|
||||
|
||||
private _onDestroy$ = new Subject();
|
||||
|
||||
constructor(
|
||||
@@ -83,7 +89,7 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
|
||||
async updateBreadcrumb(item: OrderItemListItemDTO) {
|
||||
if (item) {
|
||||
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
|
||||
key: 1000,
|
||||
key: this.processId,
|
||||
name: item?.compartmentCode || item?.orderNumber,
|
||||
path: this.getDetailsPath(item),
|
||||
section: 'customer',
|
||||
@@ -93,7 +99,7 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
|
||||
}
|
||||
|
||||
async removeBreadcrumbs() {
|
||||
const editCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$(1000, ['goods-out', 'edit']).pipe(first()).toPromise();
|
||||
const editCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$(this.processId, ['goods-out', 'edit']).pipe(first()).toPromise();
|
||||
|
||||
editCrumbs.forEach((crumb) => {
|
||||
this._breadcrumb.removeBreadcrumb(crumb.id, true);
|
||||
@@ -101,7 +107,10 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
|
||||
}
|
||||
|
||||
async removeDetailsCrumbs() {
|
||||
const detailsCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$(1000, ['goods-out', 'details']).pipe(first()).toPromise();
|
||||
const detailsCrumbs = await this._breadcrumb
|
||||
.getBreadcrumbsByKeyAndTags$(this.processId, ['goods-out', 'details'])
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
detailsCrumbs.forEach((crumb) => {
|
||||
this._breadcrumb.removeBreadcrumb(crumb.id, true);
|
||||
@@ -150,7 +159,7 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
|
||||
}
|
||||
|
||||
navigateToLandingPage() {
|
||||
this._router.navigate(['/kunde/goods/out']);
|
||||
this._router.navigate([`/kunde/${this.processId}/goods/out`]);
|
||||
}
|
||||
|
||||
async actionHandled(handler: { orderItemsContext: OrderItemsContext; command: string; navigation: 'details' | 'main' | 'reservation' }) {
|
||||
@@ -165,13 +174,13 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
|
||||
|
||||
getDetailsPath(item: OrderItemListItemDTO) {
|
||||
return item?.compartmentCode
|
||||
? `/kunde/goods/out/details/compartment/${encodeURIComponent(item?.compartmentCode)}/${item?.processingStatus}`
|
||||
: `/kunde/goods/out/details/order/${encodeURIComponent(item?.orderNumber)}/${item?.processingStatus}`;
|
||||
? `/kunde/${this.processId}/goods/out/details/compartment/${encodeURIComponent(item?.compartmentCode)}/${item?.processingStatus}`
|
||||
: `/kunde/${this.processId}/goods/out/details/order/${encodeURIComponent(item?.orderNumber)}/${item?.processingStatus}`;
|
||||
}
|
||||
|
||||
getEditPath(item: OrderItemListItemDTO) {
|
||||
return item?.compartmentCode
|
||||
? `/kunde/goods/out/details/compartment/${encodeURIComponent(item?.compartmentCode)}/${item?.processingStatus}/edit`
|
||||
: `/kunde/goods/out/details/order/${encodeURIComponent(item?.orderNumber)}/${item?.processingStatus}/edit`;
|
||||
? `/kunde/${this.processId}/goods/out/details/compartment/${encodeURIComponent(item?.compartmentCode)}/${item?.processingStatus}/edit`
|
||||
: `/kunde/${this.processId}/goods/out/details/order/${encodeURIComponent(item?.orderNumber)}/${item?.processingStatus}/edit`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { Config } from '@core/config';
|
||||
import { DomainGoodsService } from '@domain/oms';
|
||||
import { combineLatest, Observable } from 'rxjs';
|
||||
import { map, shareReplay, switchMap, withLatestFrom } from 'rxjs/operators';
|
||||
@@ -13,6 +12,12 @@ import { map, shareReplay, switchMap, withLatestFrom } from 'rxjs/operators';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class GoodsOutEditComponent implements OnInit {
|
||||
get processId() {
|
||||
return +this._activatedRoute.snapshot.parent.data.processId;
|
||||
}
|
||||
|
||||
processId$ = this._activatedRoute.parent.data.pipe(map((params) => +params.processId));
|
||||
|
||||
orderNumber$: Observable<string> = this._activatedRoute.params.pipe(
|
||||
map((params) => decodeURIComponent(params.orderNumber ?? '') || undefined)
|
||||
);
|
||||
@@ -38,8 +43,7 @@ export class GoodsOutEditComponent implements OnInit {
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
private _domainGoodsInService: DomainGoodsService,
|
||||
private _router: Router,
|
||||
private readonly _config: Config
|
||||
private _router: Router
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -51,11 +55,11 @@ export class GoodsOutEditComponent implements OnInit {
|
||||
const compartmentCode = this._activatedRoute.snapshot.params.compartmentCode;
|
||||
const processingStatus = this._activatedRoute.snapshot.params.processingStatus;
|
||||
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
|
||||
key: this._config.get('process.ids.goodsOut'),
|
||||
key: this.processId,
|
||||
name: 'Bearbeiten',
|
||||
path: compartmentCode
|
||||
? `/kunde/goods/out/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}/edit`
|
||||
: `/kunde/goods/out/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}/edit`,
|
||||
? `/kunde/${this.processId}/goods/out/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}/edit`
|
||||
: `/kunde/${this.processId}/goods/out/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}/edit`,
|
||||
section: 'customer',
|
||||
tags: ['goods-out', 'edit', compartmentCode || orderNumber],
|
||||
});
|
||||
@@ -66,7 +70,9 @@ export class GoodsOutEditComponent implements OnInit {
|
||||
const compartmentCode = this._activatedRoute.snapshot.params.compartmentCode;
|
||||
const processingStatus = options?.processingStatus ? options.processingStatus : this._activatedRoute.snapshot.params.processingStatus;
|
||||
compartmentCode
|
||||
? this._router.navigate([`/kunde/goods/out/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}`])
|
||||
: this._router.navigate([`/kunde/goods/out/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}`]);
|
||||
? this._router.navigate([
|
||||
`/kunde/${this.processId}/goods/out/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}`,
|
||||
])
|
||||
: this._router.navigate([`/kunde/${this.processId}/goods/out/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}`]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, ChangeDetectionStrategy, Output, EventEmitter, ChangeDetectorRef, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, Output, EventEmitter, ChangeDetectorRef, OnInit, OnDestroy, Input } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { Config } from '@core/config';
|
||||
@@ -24,6 +24,9 @@ export class GoodsOutSearchFilterComponent implements OnInit, OnDestroy {
|
||||
|
||||
message: string;
|
||||
|
||||
@Input()
|
||||
processId: number;
|
||||
|
||||
private _onDestroy$ = new Subject();
|
||||
|
||||
constructor(
|
||||
@@ -74,7 +77,7 @@ export class GoodsOutSearchFilterComponent implements OnInit, OnDestroy {
|
||||
const orderItem = result.result[0];
|
||||
this._router.navigate([this.getDetailsPath(orderItem)]);
|
||||
} else {
|
||||
this._router.navigate(['/kunde', 'goods', 'out', 'results'], {
|
||||
this._router.navigate(['/kunde', this.processId, 'goods', 'out', 'results'], {
|
||||
queryParams: this._goodsOutSearchStore.filter.getQueryParams(),
|
||||
});
|
||||
}
|
||||
@@ -93,9 +96,9 @@ export class GoodsOutSearchFilterComponent implements OnInit, OnDestroy {
|
||||
|
||||
async updateBreadcrumb() {
|
||||
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
|
||||
key: this._config.get('process.ids.goodsOut'),
|
||||
key: this.processId,
|
||||
name: 'Warenausgabe',
|
||||
path: '/kunde/goods/out',
|
||||
path: `/kunde/${this.processId}/goods/out`,
|
||||
tags: ['goods-out', 'main', 'filter'],
|
||||
section: 'customer',
|
||||
params: this._goodsOutSearchStore.filter?.getQueryParams(),
|
||||
@@ -109,7 +112,7 @@ export class GoodsOutSearchFilterComponent implements OnInit, OnDestroy {
|
||||
|
||||
getDetailsPath(item: OrderItemListItemDTO) {
|
||||
return item?.compartmentCode
|
||||
? `/kunde/goods/out/details/compartment/${encodeURIComponent(item?.compartmentCode)}/${item?.processingStatus}`
|
||||
: `/kunde/goods/out/details/order/${encodeURIComponent(item?.orderNumber)}/${item?.processingStatus}`;
|
||||
? `/kunde/${this.processId}/goods/out/details/compartment/${encodeURIComponent(item?.compartmentCode)}/${item?.processingStatus}`
|
||||
: `/kunde/${this.processId}/goods/out/details/order/${encodeURIComponent(item?.orderNumber)}/${item?.processingStatus}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
<shell-filter-overlay #shellFilterOverlay>
|
||||
<page-goods-out-search-filter
|
||||
[processId]="processId$ | async"
|
||||
*ngIf="showFilterOverlay"
|
||||
(close)="toggleFilterOverlay(); shellFilterOverlay.close()"
|
||||
></page-goods-out-search-filter>
|
||||
|
||||
@@ -44,6 +44,8 @@ export class GoodsOutSearchComponent implements OnInit, OnDestroy {
|
||||
map(([filter, initialFilter]) => !isEqual(filter?.getQueryParams(), initialFilter?.getQueryParams()))
|
||||
);
|
||||
|
||||
processId$ = this._activatedRoute.data.pipe(map((data) => +data.processId));
|
||||
|
||||
constructor(
|
||||
private _goodsOutSearchStore: GoodsOutSearchStore,
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
@@ -61,12 +63,14 @@ export class GoodsOutSearchComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
});
|
||||
|
||||
this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
|
||||
key: this._config.get('process.ids.goodsOut'),
|
||||
name: 'Warenausgabe',
|
||||
path: '/kunde/goods/out',
|
||||
tags: ['goods-out', 'main', 'filter'],
|
||||
section: 'customer',
|
||||
this.processId$.pipe(takeUntil(this._onDestroy$)).subscribe((processId) => {
|
||||
this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
|
||||
key: processId,
|
||||
name: 'Warenausgabe',
|
||||
path: `/kunde/${processId}/goods/out`,
|
||||
tags: ['goods-out', 'main', 'filter'],
|
||||
section: 'customer',
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { Config } from '@core/config';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { distinctUntilChanged, first, map } from 'rxjs/operators';
|
||||
import { GoodsOutSearchStore } from '../goods-out-search.store';
|
||||
|
||||
@Component({
|
||||
@@ -22,13 +21,18 @@ export class GoodsOutSearchMainComponent implements OnInit, OnDestroy {
|
||||
|
||||
private _subscriptions = new Subscription();
|
||||
|
||||
get processId() {
|
||||
return +this._activatedRoute.snapshot.data.processId;
|
||||
}
|
||||
|
||||
processId$ = this._activatedRoute.data.pipe(map((data) => +data.processId));
|
||||
|
||||
constructor(
|
||||
private _goodsOutSearchStore: GoodsOutSearchStore,
|
||||
private _cdr: ChangeDetectorRef,
|
||||
private _router: Router,
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
private readonly _config: Config
|
||||
private _breadcrumb: BreadcrumbService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -38,29 +42,24 @@ export class GoodsOutSearchMainComponent implements OnInit, OnDestroy {
|
||||
})
|
||||
);
|
||||
|
||||
this._goodsOutSearchStore.setQueryParams(this._activatedRoute.snapshot.queryParams);
|
||||
|
||||
this.removeBreadcrumbs();
|
||||
this._subscriptions.add(
|
||||
this.processId$.pipe(distinctUntilChanged()).subscribe((processId) => {
|
||||
this._goodsOutSearchStore.setQueryParams(this._activatedRoute.snapshot.queryParams);
|
||||
// this.updateBreadcrumb(processId);
|
||||
this.removeBreadcrumbs(processId);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this._subscriptions.unsubscribe();
|
||||
}
|
||||
|
||||
async removeBreadcrumbs() {
|
||||
const resultCrumbs = await this._breadcrumb
|
||||
.getBreadcrumbsByKeyAndTags$(this._config.get('process.ids.goodsOut'), ['goods-out', 'results'])
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
const detailsCrumbs = await this._breadcrumb
|
||||
.getBreadcrumbsByKeyAndTags$(this._config.get('process.ids.goodsOut'), ['goods-out', 'details'])
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
async removeBreadcrumbs(processId: number) {
|
||||
const resultCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$(processId, ['goods-out', 'results']).pipe(first()).toPromise();
|
||||
const detailsCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$(processId, ['goods-out', 'details']).pipe(first()).toPromise();
|
||||
|
||||
const editCrumbs = await this._breadcrumb
|
||||
.getBreadcrumbsByKeyAndTags$(this._config.get('process.ids.goodsOut'), ['goods-out', 'edit'])
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
const editCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$(processId, ['goods-out', 'edit']).pipe(first()).toPromise();
|
||||
|
||||
editCrumbs.forEach((crumb) => {
|
||||
this._breadcrumb.removeBreadcrumb(crumb.id, true);
|
||||
@@ -77,7 +76,7 @@ export class GoodsOutSearchMainComponent implements OnInit, OnDestroy {
|
||||
|
||||
async search() {
|
||||
this._goodsOutSearchStore.clearResults();
|
||||
await this.updateQueryParams();
|
||||
await this.updateQueryParams(this.processId);
|
||||
this.message = undefined;
|
||||
|
||||
this._goodsOutSearchStore.searchResult$.pipe(first()).subscribe((result) => {
|
||||
@@ -86,9 +85,9 @@ export class GoodsOutSearchMainComponent implements OnInit, OnDestroy {
|
||||
if (result.hits > 0) {
|
||||
if (result.hits === 1) {
|
||||
const orderItem = result.result[0];
|
||||
this._router.navigate([this.getDetailsPath(orderItem)]);
|
||||
this._router.navigate([this.getDetailsPath(orderItem, this.processId)]);
|
||||
} else {
|
||||
this._router.navigate(['/kunde', 'goods', 'out', 'results'], {
|
||||
this._router.navigate(['/kunde', this.processId, 'goods', 'out', 'results'], {
|
||||
queryParams: this._goodsOutSearchStore.filter.getQueryParams(),
|
||||
});
|
||||
}
|
||||
@@ -103,25 +102,25 @@ export class GoodsOutSearchMainComponent implements OnInit, OnDestroy {
|
||||
this._goodsOutSearchStore.search();
|
||||
}
|
||||
|
||||
async updateBreadcrumb() {
|
||||
async updateBreadcrumb(processId: number) {
|
||||
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
|
||||
key: this._config.get('process.ids.goodsOut'),
|
||||
key: this.processId,
|
||||
name: 'Warenausgabe',
|
||||
path: '/kunde/goods/out',
|
||||
path: `/kunde/${this.processId}/goods/out`,
|
||||
tags: ['goods-out', 'main', 'filter'],
|
||||
section: 'customer',
|
||||
params: this._goodsOutSearchStore.filter?.getQueryParams(),
|
||||
});
|
||||
}
|
||||
|
||||
async updateQueryParams() {
|
||||
async updateQueryParams(processId: number) {
|
||||
await this._router.navigate([], { queryParams: this._goodsOutSearchStore.filter?.getQueryParams() });
|
||||
this.updateBreadcrumb();
|
||||
this.updateBreadcrumb(processId);
|
||||
}
|
||||
|
||||
getDetailsPath(item: OrderItemListItemDTO) {
|
||||
getDetailsPath(item: OrderItemListItemDTO, processId: number) {
|
||||
return item?.compartmentCode
|
||||
? `/kunde/goods/out/details/compartment/${encodeURIComponent(item?.compartmentCode)}/${item?.processingStatus}`
|
||||
: `/kunde/goods/out/details/order/${encodeURIComponent(item?.orderNumber)}/${item?.processingStatus}`;
|
||||
? `/kunde/${processId}/goods/out/details/compartment/${encodeURIComponent(item?.compartmentCode)}/${item?.processingStatus}`
|
||||
: `/kunde/${processId}/goods/out/details/order/${encodeURIComponent(item?.orderNumber)}/${item?.processingStatus}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,12 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
|
||||
|
||||
byCompartmentCodeFn = (item: OrderItemListItemDTO) => item.compartmentCode;
|
||||
|
||||
get processId() {
|
||||
return +this._activatedRoute.snapshot.parent.data.processId;
|
||||
}
|
||||
|
||||
processId$ = this._activatedRoute.parent.data.pipe(map((data) => +data.processId));
|
||||
|
||||
private _onDestroy$ = new Subject();
|
||||
|
||||
constructor(
|
||||
@@ -75,8 +81,7 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
private _commandService: CommandService,
|
||||
private _modal: UiModalService,
|
||||
private readonly _config: Config
|
||||
private _modal: UiModalService
|
||||
) {
|
||||
super({
|
||||
selectedOrderItemSubsetIds: [],
|
||||
@@ -84,14 +89,16 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this._goodsOutSearchStore.setQueryParams(this._activatedRoute.snapshot.queryParams);
|
||||
this._activatedRoute.queryParams.pipe(takeUntil(this._onDestroy$)).subscribe((queryParams) => {
|
||||
this.updateBreadcrumb(queryParams);
|
||||
});
|
||||
this.processId$.pipe(takeUntil(this._onDestroy$)).subscribe((processId) => {
|
||||
this._goodsOutSearchStore.setQueryParams(this._activatedRoute.snapshot.queryParams);
|
||||
this._activatedRoute.queryParams.pipe(takeUntil(this._onDestroy$)).subscribe((queryParams) => {
|
||||
this.updateBreadcrumb(queryParams);
|
||||
});
|
||||
|
||||
this.initInitialSearch();
|
||||
this.createBreadcrumb();
|
||||
this.removeBreadcrumbs();
|
||||
this.initInitialSearch(processId);
|
||||
this.createBreadcrumb(processId);
|
||||
this.removeBreadcrumbs(processId);
|
||||
});
|
||||
|
||||
this._goodsOutSearchStore.searchResultCleared.pipe(takeUntil(this._onDestroy$)).subscribe((_) => this.clearSelectedItems());
|
||||
}
|
||||
@@ -103,16 +110,10 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
|
||||
this.updateBreadcrumb(this._goodsOutSearchStore.filter?.getQueryParams());
|
||||
}
|
||||
|
||||
async removeBreadcrumbs() {
|
||||
const detailsCrumbs = await this._breadcrumb
|
||||
.getBreadcrumbsByKeyAndTags$(this._config.get('process.ids.goodsOut'), ['goods-out', 'details'])
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
async removeBreadcrumbs(processId) {
|
||||
const detailsCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$(processId, ['goods-out', 'details']).pipe(first()).toPromise();
|
||||
|
||||
const editCrumbs = await this._breadcrumb
|
||||
.getBreadcrumbsByKeyAndTags$(this._config.get('process.ids.goodsOut'), ['goods-out', 'edit'])
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
const editCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$(processId, ['goods-out', 'edit']).pipe(first()).toPromise();
|
||||
|
||||
editCrumbs.forEach((crumb) => {
|
||||
this._breadcrumb.removeBreadcrumb(crumb.id, true);
|
||||
@@ -123,11 +124,11 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
|
||||
});
|
||||
}
|
||||
|
||||
async createBreadcrumb() {
|
||||
async createBreadcrumb(processId: number) {
|
||||
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
|
||||
key: this._config.get('process.ids.goodsOut'),
|
||||
key: processId,
|
||||
name: this.getBreadcrumbName(),
|
||||
path: '/kunde/goods/out/results',
|
||||
path: `/kunde/${processId}/goods/out/results`,
|
||||
section: 'customer',
|
||||
params: this._goodsOutSearchStore.filter?.getQueryParams(),
|
||||
tags: ['goods-out', 'results', 'filter'],
|
||||
@@ -140,7 +141,7 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
|
||||
|
||||
if (queryParams) {
|
||||
const crumbs = await this._breadcrumb
|
||||
.getBreadcrumbsByKeyAndTags$(this._config.get('process.ids.goodsOut'), ['goods-out', 'results', 'filter'])
|
||||
.getBreadcrumbsByKeyAndTags$(this.processId, ['goods-out', 'results', 'filter'])
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
@@ -162,13 +163,15 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
|
||||
return input?.replace('ORD:', '') ?? 'Alle';
|
||||
}
|
||||
|
||||
initInitialSearch() {
|
||||
initInitialSearch(processId: number) {
|
||||
if (this._goodsOutSearchStore.hits === 0) {
|
||||
this._goodsOutSearchStore.searchResult$.pipe(takeUntil(this._onDestroy$)).subscribe(async (result) => {
|
||||
if (result.hits === 0) {
|
||||
await this._router.navigate(['/kunde/goods/out'], { queryParams: this._goodsOutSearchStore.filter.getQueryParams() });
|
||||
await this._router.navigate([`/kunde/${this.processId}/goods/out`], {
|
||||
queryParams: this._goodsOutSearchStore.filter.getQueryParams(),
|
||||
});
|
||||
} else {
|
||||
await this.createBreadcrumb();
|
||||
await this.createBreadcrumb(processId);
|
||||
if (result.hits === 1) {
|
||||
await this.navigateToDetails(result.result[0]);
|
||||
} else {
|
||||
@@ -200,9 +203,11 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
|
||||
const compartmentCode = orderItem.compartmentCode;
|
||||
|
||||
if (compartmentCode) {
|
||||
this._router.navigate([`/kunde/goods/out/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}`]);
|
||||
this._router.navigate([
|
||||
`/kunde/${this.processId}/goods/out/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}`,
|
||||
]);
|
||||
} else {
|
||||
this._router.navigate([`/kunde/goods/out/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}`]);
|
||||
this._router.navigate([`/kunde/${this.processId}/goods/out/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}`]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<shell-breadcrumb [key]="goodsOutKey" [includesTags]="['goods-out']"></shell-breadcrumb>
|
||||
<shell-breadcrumb [key]="processId$ | async" [includesTags]="['goods-out']"></shell-breadcrumb>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { Config } from '@core/config';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'page-goods-out',
|
||||
@@ -8,7 +9,7 @@ import { Config } from '@core/config';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class GoodsOutComponent {
|
||||
goodsOutKey = this._config.get('process.ids.goodsOut');
|
||||
processId$ = this._activatedRoute.data.pipe(map((data) => +data.processId));
|
||||
|
||||
constructor(private readonly _config: Config) {}
|
||||
constructor(private _activatedRoute: ActivatedRoute) {}
|
||||
}
|
||||
|
||||
@@ -188,17 +188,24 @@ export class RemissionListItemComponent implements OnDestroy {
|
||||
|
||||
async returnImpediment() {
|
||||
this.loading$.next(true);
|
||||
|
||||
let updatedDto: ReturnItemDTO | ReturnSuggestionDTO;
|
||||
|
||||
try {
|
||||
// Pflichtremission
|
||||
if (this.item.dtoType === 'return') {
|
||||
await this._remissionService.returnImpediment(this.item.dto?.id).toPromise();
|
||||
updatedDto = await this._remissionService.returnImpediment(this.item.dto?.id).toPromise();
|
||||
}
|
||||
// Abteilungsremission
|
||||
else if (this.item.dtoType === 'suggestion') {
|
||||
await this._remissionService.returnSuggestion(this.item.dto?.id).toPromise();
|
||||
updatedDto = await this._remissionService.returnSuggestion(this.item.dto?.id).toPromise();
|
||||
}
|
||||
|
||||
this._store.removeItem(this.item);
|
||||
if (updatedDto.impediment?.attempts > 3) {
|
||||
this._store.removeItem(this.item);
|
||||
} else {
|
||||
this._store.updateItemDto(updatedDto);
|
||||
}
|
||||
this._store.updateCache();
|
||||
} catch (err) {
|
||||
this._modal.open({
|
||||
|
||||
@@ -4,7 +4,7 @@ import { CacheService } from '@core/cache';
|
||||
import { Config } from '@core/config';
|
||||
import { DomainRemissionService, RemissionListItem } from '@domain/remission';
|
||||
import { ComponentStore, tapResponse } from '@ngrx/component-store';
|
||||
import { SupplierDTO } from '@swagger/remi';
|
||||
import { ReturnItemDTO, ReturnSuggestionDTO, SupplierDTO } from '@swagger/remi';
|
||||
import { UiFilter } from '@ui/filter';
|
||||
import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs';
|
||||
import { debounceTime, filter, switchMap, takeUntil, tap, withLatestFrom } from 'rxjs/operators';
|
||||
@@ -236,6 +236,7 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
}
|
||||
|
||||
this.setFilter(filter);
|
||||
this._filterChange$.next(true);
|
||||
},
|
||||
(err) => {}
|
||||
)
|
||||
@@ -269,6 +270,38 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
const results = options?.newSearch
|
||||
? { result: [...res.result], hits: res.hits ?? 0 }
|
||||
: { result: [...(items ?? []), ...(res.result ?? [])], hits: res.hits ?? 0 };
|
||||
|
||||
// find items that are already in the list and remove the first duplicate
|
||||
// why do we need it? when we use the action item not found we will add this item to the end of the list
|
||||
// if we load more items this item appears again at the end of the list
|
||||
// to keep the list clean we remove all duplicates and just keep the last one
|
||||
const itemsToRemove: number[] = [];
|
||||
results.result.forEach((item) => {
|
||||
const duplicates = items.filter((i) => i.dto.id === item.dto.id);
|
||||
if (duplicates.length > 1) {
|
||||
// skip the first duplicate
|
||||
// and add ids of the duplicates to the list of items to remove
|
||||
itemsToRemove.push(...duplicates.slice(1).map((i) => i.dto.id));
|
||||
}
|
||||
});
|
||||
|
||||
itemsToRemove.forEach((id) => {
|
||||
const index = results.result.findIndex((i) => i.dto.id === id);
|
||||
if (index > -1) {
|
||||
results.result.splice(index, 1);
|
||||
}
|
||||
});
|
||||
|
||||
// move all items with impediment to the end of the list
|
||||
const itemsToMoveToTheEnd = results.result.filter((i) => i.dto.impediment);
|
||||
itemsToMoveToTheEnd.forEach((item) => {
|
||||
const index = results.result.findIndex((i) => i.dto.id === item.dto.id);
|
||||
if (index > -1) {
|
||||
results.result.splice(index, 1);
|
||||
results.result.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
this.setSearchResult(results);
|
||||
this.setFetching(false);
|
||||
this._searchCompleted.next(this.get());
|
||||
@@ -347,6 +380,15 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
hits: state.hits - 1,
|
||||
}));
|
||||
|
||||
updateItemDto = this.updater<ReturnItemDTO | ReturnSuggestionDTO>((state, itemDto) => {
|
||||
const itemToUpdate = state.items.find((i) => i.dto?.id === itemDto.id);
|
||||
|
||||
return {
|
||||
...state,
|
||||
items: [...state.items.filter((i) => i.dto?.id !== itemDto?.id), { ...itemToUpdate, dto: itemDto }],
|
||||
};
|
||||
});
|
||||
|
||||
setRequiredCapacities = this.updater<any>((state, requiredCapacities) => ({
|
||||
...state,
|
||||
requiredCapacities,
|
||||
|
||||
@@ -120,6 +120,9 @@ export class RemissionListComponent implements OnInit, OnDestroy {
|
||||
ngOnInit() {
|
||||
this._activatedRoute.queryParams.pipe(takeUntil(this._onDestroy$), debounceTime(0)).subscribe(async (queryParams) => {
|
||||
const { supplier, source } = queryParams;
|
||||
|
||||
this._remissionListStore.loadFilter();
|
||||
|
||||
if (supplier) {
|
||||
this._remissionListStore.setSelectedSupplierId(+supplier);
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: ['./src/**/*.e2e-spec.ts'],
|
||||
capabilities: {
|
||||
browserName: 'chrome',
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function () {},
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: require('path').join(__dirname, './tsconfig.e2e.json'),
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
},
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
import { AppPage } from './app.po';
|
||||
|
||||
describe('workspace-project App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getTitleText()).toEqual('Welcome to sales!');
|
||||
});
|
||||
});
|
||||
@@ -1,11 +0,0 @@
|
||||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class AppPage {
|
||||
navigateTo() {
|
||||
return browser.get('/');
|
||||
}
|
||||
|
||||
getTitleText() {
|
||||
return element(by.css('app-root h1')).getText();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../out-tsc/app",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
#
|
||||
# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed
|
||||
|
||||
> 0.5%
|
||||
last 2 versions
|
||||
Firefox ESR
|
||||
not dead
|
||||
not IE 9-11
|
||||
@@ -1,32 +0,0 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma'),
|
||||
],
|
||||
client: {
|
||||
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, '../../coverage'),
|
||||
reports: ['html', 'lcovonly', 'text-summary'],
|
||||
fixWebpackSourcePaths: true,
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['ChromeHeadless'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true,
|
||||
});
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"index": "/index.html",
|
||||
"assetGroups": [
|
||||
{
|
||||
"name": "sales",
|
||||
"installMode": "prefetch",
|
||||
"resources": {
|
||||
"files": ["/favicon.ico", "/*.webmanifest", "/*.css", "/*.js"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "assets",
|
||||
"installMode": "lazy",
|
||||
"updateMode": "prefetch",
|
||||
"resources": {
|
||||
"files": [
|
||||
"assets/**",
|
||||
"/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { SignalRHubOptions } from '@core/signalr';
|
||||
import { AuthConfig } from 'angular-oauth2-oidc';
|
||||
|
||||
@Injectable()
|
||||
export class AppConfiguration {
|
||||
includeGoogleAnalytics = false;
|
||||
title?: string;
|
||||
|
||||
cdn: { [key: string]: string };
|
||||
|
||||
sso: AuthConfig;
|
||||
|
||||
hubs: { [key: string]: SignalRHubOptions };
|
||||
|
||||
swagger: { [key: string]: { rootUrl: string } };
|
||||
|
||||
remissionModuleOptions: {
|
||||
useMock: false;
|
||||
endpoints: { [key: string]: string };
|
||||
};
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes, PreloadAllModules } from '@angular/router';
|
||||
import { LogInComponent } from './components/log-in/log-in.component';
|
||||
import { DashboardComponent } from './modules/dashboard/pages/dashboard.component';
|
||||
import { AuthenticationGuard } from './resolvers/authentication.guard';
|
||||
import { ProcessIdResolver } from './resolvers/process-id.resolver';
|
||||
import { BranchSectionResolver, CustomerSectionResolver } from './resolvers/section.resolver';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: 'login',
|
||||
resolve: { section: CustomerSectionResolver },
|
||||
children: [
|
||||
{ path: '', component: LogInComponent, pathMatch: 'full' },
|
||||
{ path: ':token', component: LogInComponent },
|
||||
],
|
||||
},
|
||||
{ path: 'dashboard', resolve: { section: CustomerSectionResolver }, component: DashboardComponent, canActivate: [AuthenticationGuard] },
|
||||
{
|
||||
path: 'product',
|
||||
resolve: { processId: ProcessIdResolver, section: CustomerSectionResolver },
|
||||
loadChildren: () => import('@page/catalog').then((m) => m.PageCatalogModule),
|
||||
canActivate: [AuthenticationGuard],
|
||||
},
|
||||
{
|
||||
path: 'customer',
|
||||
resolve: { processId: ProcessIdResolver, section: CustomerSectionResolver },
|
||||
loadChildren: () => import('@page/customer').then((m) => m.PageCustomerModule),
|
||||
canActivate: [AuthenticationGuard],
|
||||
},
|
||||
{
|
||||
path: 'cart',
|
||||
resolve: { processId: ProcessIdResolver, section: CustomerSectionResolver },
|
||||
loadChildren: () => import('@page/checkout').then((m) => m.PageCheckoutModule),
|
||||
canActivate: [AuthenticationGuard],
|
||||
},
|
||||
{
|
||||
path: 'branch',
|
||||
resolve: { section: BranchSectionResolver },
|
||||
loadChildren: () => import('./modules/branch/branch.module').then((m) => m.BranchModule),
|
||||
canActivate: [AuthenticationGuard],
|
||||
},
|
||||
{
|
||||
path: 'debug',
|
||||
loadChildren: () => import('./modules/debug/debug.module').then((m) => m.DebugModule),
|
||||
canActivate: [AuthenticationGuard],
|
||||
},
|
||||
{
|
||||
path: 'goods',
|
||||
children: [
|
||||
{
|
||||
path: 'in',
|
||||
resolve: { section: BranchSectionResolver },
|
||||
loadChildren: () => import('@page/goods-in').then((m) => m.GoodsInModule),
|
||||
},
|
||||
{
|
||||
path: 'out',
|
||||
resolve: { section: CustomerSectionResolver },
|
||||
loadChildren: () => import('@page/goods-out').then((m) => m.GoodsOutModule),
|
||||
},
|
||||
],
|
||||
canActivate: [AuthenticationGuard],
|
||||
},
|
||||
{
|
||||
path: 'remission',
|
||||
resolve: { section: BranchSectionResolver },
|
||||
loadChildren: () => import('./modules/remission/remission-client.module').then((m) => m.RemissionClientModule),
|
||||
canActivate: [AuthenticationGuard],
|
||||
},
|
||||
{
|
||||
path: 'task-calendar',
|
||||
resolve: { section: BranchSectionResolver },
|
||||
loadChildren: () => import('@page/task-calendar').then((m) => m.PageTaskCalendarModule),
|
||||
canActivate: [AuthenticationGuard],
|
||||
},
|
||||
{
|
||||
path: 'shelf',
|
||||
loadChildren: () => import('./modules/shelf/shelf.module').then((m) => m.ShelfModule),
|
||||
canActivate: [AuthenticationGuard],
|
||||
},
|
||||
{ path: '**', redirectTo: 'dashboard' },
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forRoot(routes, {
|
||||
preloadingStrategy: PreloadAllModules,
|
||||
scrollPositionRestoration: 'enabled',
|
||||
relativeLinkResolution: 'legacy',
|
||||
}),
|
||||
],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AppRoutingModule {}
|
||||
@@ -1,40 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { StoreModule, MetaReducer, ActionReducer, INIT } from '@ngrx/store';
|
||||
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
|
||||
import { storeFreeze } from 'ngrx-store-freeze';
|
||||
import { environment } from '../environments/environment';
|
||||
import { RootState } from './store/root.state';
|
||||
import { rootReducer } from './store/root.reducer';
|
||||
import { EffectsModule } from '@ngrx/effects';
|
||||
import { SearchEffects } from './store/customer';
|
||||
import { HistoryEffects } from '@shelf-store/history';
|
||||
import { DetailsEffects } from '@shelf-store/details';
|
||||
import packageInfo from 'package';
|
||||
|
||||
// TODO: In Service Speichern
|
||||
export function storeInLocalStorage(reducer: ActionReducer<any>): ActionReducer<any> {
|
||||
const lsKey = 'ISA_NGRX_STATE_1';
|
||||
|
||||
return function (state, action) {
|
||||
if (action.type === INIT) {
|
||||
const storedState = JSON.parse(localStorage.getItem(lsKey));
|
||||
if (storedState?.version === packageInfo.version) {
|
||||
return reducer(storedState, action);
|
||||
}
|
||||
}
|
||||
const nextState = reducer(state, action);
|
||||
localStorage.setItem(lsKey, JSON.stringify({ ...nextState, version: packageInfo.version }));
|
||||
return nextState;
|
||||
};
|
||||
}
|
||||
|
||||
export const metaReducers: MetaReducer<RootState>[] = !environment.production ? [storeFreeze, storeInLocalStorage] : [storeInLocalStorage];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
StoreModule.forRoot(rootReducer, { metaReducers }),
|
||||
EffectsModule.forRoot([SearchEffects, HistoryEffects, DetailsEffects]),
|
||||
StoreDevtoolsModule.instrument({ name: 'ISA Ngrx Store' }),
|
||||
],
|
||||
})
|
||||
export class AppStoreModule {}
|
||||
@@ -1,64 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { PrintConfiguration } from '@swagger/print';
|
||||
import { OmsConfiguration } from '@swagger/oms';
|
||||
import { IsaConfiguration } from '@swagger/isa';
|
||||
import { CrmConfiguration } from '@swagger/crm';
|
||||
import { CheckoutConfiguration } from '@swagger/checkout';
|
||||
import { AvConfiguration } from '@swagger/availability';
|
||||
import { CatConfiguration } from '@swagger/cat';
|
||||
import { EisConfiguration } from '@swagger/eis';
|
||||
import { RemiConfiguration } from '@swagger/remi';
|
||||
|
||||
import { AppConfiguration } from './app-configuration';
|
||||
|
||||
export function catConfigurationFactory(config: AppConfiguration) {
|
||||
return config.swagger.api;
|
||||
}
|
||||
|
||||
export function avConfigurationFactory(config: AppConfiguration) {
|
||||
return config.swagger.av;
|
||||
}
|
||||
|
||||
export function checkoutConfigurationFactory(config: AppConfiguration) {
|
||||
return config.swagger.checkout;
|
||||
}
|
||||
|
||||
export function crmConfigurationFactory(config: AppConfiguration) {
|
||||
return config.swagger.crm;
|
||||
}
|
||||
|
||||
export function isaConfigurationFactory(config: AppConfiguration) {
|
||||
return config.swagger.isa;
|
||||
}
|
||||
|
||||
export function omsConfigurationFactory(config: AppConfiguration) {
|
||||
return config.swagger.oms;
|
||||
}
|
||||
|
||||
export function printConfigurationFactory(config: AppConfiguration) {
|
||||
return config.swagger.print;
|
||||
}
|
||||
|
||||
export function eisConfigurationFactory(config: AppConfiguration) {
|
||||
return config.swagger.eis;
|
||||
}
|
||||
|
||||
export function remiConfigurationFactory(config: AppConfiguration) {
|
||||
return config.swagger.remi;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
providers: [
|
||||
{ provide: CatConfiguration, useFactory: catConfigurationFactory, deps: [AppConfiguration] },
|
||||
{ provide: AvConfiguration, useFactory: avConfigurationFactory, deps: [AppConfiguration] },
|
||||
{ provide: CheckoutConfiguration, useFactory: checkoutConfigurationFactory, deps: [AppConfiguration] },
|
||||
{ provide: CrmConfiguration, useFactory: crmConfigurationFactory, deps: [AppConfiguration] },
|
||||
{ provide: IsaConfiguration, useFactory: isaConfigurationFactory, deps: [AppConfiguration] },
|
||||
{ provide: OmsConfiguration, useFactory: omsConfigurationFactory, deps: [AppConfiguration] },
|
||||
{ provide: PrintConfiguration, useFactory: printConfigurationFactory, deps: [AppConfiguration] },
|
||||
{ provide: EisConfiguration, useFactory: eisConfigurationFactory, deps: [AppConfiguration] },
|
||||
{ provide: RemiConfiguration, useFactory: remiConfigurationFactory, deps: [AppConfiguration] },
|
||||
],
|
||||
})
|
||||
export class AppSwaggerModule {}
|
||||
@@ -1,7 +0,0 @@
|
||||
<lib-offline-overlay>
|
||||
<!-- lib offline depends on these three elements to be present inside of it -->
|
||||
<app-header [ngClass]="{ loading: loading$ | async }" *ngIf="authenticated"></app-header>
|
||||
<app-content [ngClass]="{ loading: loading$ | async }"></app-content>
|
||||
<app-menu [ngClass]="{ loading: loading$ | async }" *ngIf="authenticated"></app-menu>
|
||||
<img *ngIf="loading$ | async" src="/assets/images/Icon_Loading.svg" class="app-loader" />
|
||||
</lib-offline-overlay>
|
||||
@@ -1,36 +0,0 @@
|
||||
h1 {
|
||||
color: #369;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 250%;
|
||||
}
|
||||
|
||||
.app-loader {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin: -20px 0 0 -20px;
|
||||
-webkit-animation: spin 1.5s linear infinite;
|
||||
-moz-animation: spin 1.5s linear infinite;
|
||||
animation: spin 1.5s linear infinite;
|
||||
}
|
||||
|
||||
.loading {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@-moz-keyframes spin {
|
||||
100% {
|
||||
-moz-transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes spin {
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@keyframes spin {
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [RouterTestingModule],
|
||||
declarations: [AppComponent],
|
||||
}).compileComponents();
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -1,132 +0,0 @@
|
||||
import { ChangeDetectorRef, Component, Inject, OnDestroy, OnInit, Renderer2 } from '@angular/core';
|
||||
import { Router, NavigationEnd } from '@angular/router';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { BehaviorSubject, Subject } from 'rxjs';
|
||||
import { take, filter, takeUntil } from 'rxjs/operators';
|
||||
import { SsoService } from 'sso';
|
||||
import { AppService } from './core/services/app.service';
|
||||
import { AppState } from './core/store/state/app.state';
|
||||
import { AppConfiguration } from './app-configuration';
|
||||
import { NativeContainerService } from 'shared/lib/barcode-scanner';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { Actions as NgxsActions, ofActionDispatched } from '@ngxs/store';
|
||||
import { DeleteProcess } from './core/store/actions/process.actions';
|
||||
import { DeviceDetectorService } from 'ngx-device-detector';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss'],
|
||||
})
|
||||
export class AppComponent implements OnInit, OnDestroy {
|
||||
title = 'Hugendubel InstoreApp';
|
||||
loading$ = new BehaviorSubject(true);
|
||||
includeGoogleAnalytics = this.config.includeGoogleAnalytics;
|
||||
destroy$ = new Subject();
|
||||
|
||||
get authenticated() {
|
||||
return this.ssoService.isAuthenticated();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private config: AppConfiguration,
|
||||
private ssoService: SsoService,
|
||||
private appService: AppService,
|
||||
private router: Router,
|
||||
private store: Store,
|
||||
private nativeContainer: NativeContainerService,
|
||||
@Inject(DOCUMENT) private document: Document,
|
||||
private renderer: Renderer2,
|
||||
private applicationService: ApplicationService,
|
||||
private domainCheckoutService: DomainCheckoutService,
|
||||
private ngxsActions$: NgxsActions,
|
||||
private deviceDetectorService: DeviceDetectorService
|
||||
) {
|
||||
this.appService.loader$.subscribe(() => {
|
||||
this.loading$.next(false);
|
||||
});
|
||||
|
||||
this.appService.loader$.pipe(take(1)).subscribe(() => {
|
||||
this.containerNotificationMessage();
|
||||
});
|
||||
|
||||
// intialisations done only when app loads
|
||||
this.appService.appLoadInitialisations();
|
||||
|
||||
// this.router.events.subscribe((event) => {
|
||||
// if (event instanceof NavigationStart) {
|
||||
// try {
|
||||
// throw new Error(event.toString());
|
||||
// } catch (error) {
|
||||
// console.error(error);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
this.router.events.pipe(filter((e): e is NavigationEnd => e instanceof NavigationEnd)).subscribe(() => {
|
||||
if (!this.router.url.includes('login')) {
|
||||
// send router navigation events
|
||||
this.appService.registerNavigationEvents();
|
||||
}
|
||||
});
|
||||
|
||||
this.applicationService.section$.pipe(takeUntil(this.destroy$)).subscribe((section) => {
|
||||
document.body.classList.remove('branch', 'customer');
|
||||
document.body.classList.add(section);
|
||||
});
|
||||
|
||||
this.store
|
||||
.select(AppState.getCurrentProcessId)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((processId) => this.applicationService.setActivatedProcessId(processId));
|
||||
|
||||
this.ngxsActions$.pipe(ofActionDispatched(DeleteProcess)).subscribe((action: DeleteProcess) => {
|
||||
this.domainCheckoutService.removeProcess({ processId: action.payload.id });
|
||||
this.applicationService.removeProcess(action.payload.id);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.includeGoogleAnalytics) {
|
||||
this.initGoogleAnalytics();
|
||||
}
|
||||
|
||||
this.renderer.addClass(this.document.body, this.deviceDetectorService.deviceType);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
}
|
||||
|
||||
private containerNotificationMessage() {
|
||||
// Notify the container app if the user has initialized app loggeed in or not
|
||||
// For the purpposes of removing the container Header element
|
||||
if (this.nativeContainer.isUiWebview()) {
|
||||
this.nativeContainer.sendMessage({ userAuthenticated: this.ssoService.isAuthenticated() });
|
||||
}
|
||||
}
|
||||
|
||||
private initGoogleAnalytics() {
|
||||
const htmlScript: HTMLScriptElement = this.renderer.createElement('script');
|
||||
htmlScript.text = `
|
||||
(function (i, s, o, g, r, a, m) {
|
||||
i['GoogleAnalyticsObject'] = r;
|
||||
(i[r] =
|
||||
i[r] ||
|
||||
function () {
|
||||
(i[r].q = i[r].q || []).push(arguments);
|
||||
}),
|
||||
(i[r].l = 1 * new Date());
|
||||
(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
|
||||
a.async = 1;
|
||||
a.src = g;
|
||||
m.parentNode.insertBefore(a, m);
|
||||
})(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');
|
||||
|
||||
ga('create', 'UA-76423009-5', 'auto');
|
||||
`;
|
||||
this.renderer.appendChild(this.document.body, htmlScript);
|
||||
}
|
||||
}
|
||||
@@ -1,218 +0,0 @@
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { NgModule, ErrorHandler, LOCALE_ID, APP_INITIALIZER } from '@angular/core';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { ComponentsModule } from './modules/components.module';
|
||||
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { NgxsModule } from '@ngxs/store';
|
||||
import { NgxsReduxDevtoolsPluginModule } from '@ngxs/devtools-plugin';
|
||||
import { NgxsLoggerPluginModule } from '@ngxs/logger-plugin';
|
||||
import { ProcessState } from './core/store/state/process.state';
|
||||
import { BreadcrumbsState } from './core/store/state/breadcrumbs.state';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { SharedModule } from './shared/shared.module';
|
||||
|
||||
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||
import { NotifierState } from './core/store/state/notifier.state';
|
||||
import { environment } from '../environments/environment';
|
||||
import { ModalModule, IconModule, OfflineOverlayModule } from '@libs/ui';
|
||||
import { ProductState } from './core/store/state/product.state';
|
||||
import { AppState } from './core/store/state/app.state';
|
||||
import { BranchState } from './core/store/state/branches.state';
|
||||
import { SsoModule, SsoInterface, SsoService } from 'sso';
|
||||
import { SsoAuthorizationInterceptor, HttpErrorHandlerInterceptor } from './core/interceptors';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { HimaSalesErrorHandler } from './core/error/hima-sales.error-handler';
|
||||
import { CollectingShelfState } from './core/store/state/collecting-shelf.state';
|
||||
import 'apps/sales/src/app/core/utils/app.prototypes';
|
||||
import { VatState } from './core/store/state/vat.state';
|
||||
import { SupplierState } from './core/store/state/supplier.state';
|
||||
import { GoodsInState } from './core/store/state/goods-in.state';
|
||||
import { BranchProcessState } from './core/store/state/branch-process.state';
|
||||
import { RemissionModule, RemissionModuleOptions } from '@isa/remission';
|
||||
import { RemissionState } from './core/store/state/remission.state';
|
||||
import { NgIdleKeepaliveModule } from '@ng-idle/keepalive';
|
||||
import { AppSwaggerModule } from './app-swagger.module';
|
||||
import { AppConfiguration } from './app-configuration';
|
||||
import { FormsState } from './core/store/state/forms.state';
|
||||
|
||||
import localeDe from '@angular/common/locales/de';
|
||||
import localeDeExtra from '@angular/common/locales/extra/de';
|
||||
import { registerLocaleData } from '@angular/common';
|
||||
import { RemissionStateHandler } from './core/store/handlers/remission.handlers';
|
||||
import { SsoConfigurationService } from './core/services/sso-configuration.service';
|
||||
import { OverlayModule } from '@angular/cdk/overlay';
|
||||
import { ModalDialogueModule } from './core/overlay/component';
|
||||
import { OverlaysModule } from './core/overlay/overlays.module';
|
||||
import { CoreBreadcrumbModule } from '@core/breadcrumb';
|
||||
import { ApplicationService, CoreApplicationModule, ProcessService } from '@core/application';
|
||||
import { UiModalModule } from '@ui/modal';
|
||||
import { ProcessRefactImp } from './refact-imp/process.refact-imp';
|
||||
import { DomainCheckoutModule } from '@domain/checkout';
|
||||
import { CDN_PRODUCT_PICTURES } from './tokens';
|
||||
import { DateAdapter } from '@ui/common';
|
||||
import { ApplicationRefactImp } from './refact-imp/application.refact-imp';
|
||||
import { CDN_PRODUCT_IMAGE } from 'apps/cdn/product-image/src/lib/tokens';
|
||||
import { DomainCatalogModule } from '@domain/catalog';
|
||||
import { AppStoreModule } from './app-store.module';
|
||||
import { DomainOmsModule } from '@domain/oms';
|
||||
import { DomainAvailabilityModule } from '@domain/availability';
|
||||
import { CoreCommandModule } from '@core/command';
|
||||
import { NotificationsHubModule, NOTIFICATIONS_HUB_OPTIONS } from '@hub/notifications';
|
||||
import { SignalRHubOptions } from '@core/signalr';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
|
||||
registerLocaleData(localeDe, localeDeExtra);
|
||||
registerLocaleData(localeDe, 'de', localeDeExtra);
|
||||
|
||||
const states = [
|
||||
AppState,
|
||||
ProcessState,
|
||||
BreadcrumbsState,
|
||||
NotifierState,
|
||||
ProductState,
|
||||
BranchState,
|
||||
CollectingShelfState,
|
||||
VatState,
|
||||
SupplierState,
|
||||
BranchProcessState,
|
||||
GoodsInState,
|
||||
RemissionState,
|
||||
FormsState,
|
||||
];
|
||||
|
||||
export function noop() {
|
||||
return function () {};
|
||||
}
|
||||
|
||||
export function remissionModuleOptionsFactory(config: AppConfiguration): RemissionModuleOptions {
|
||||
return config.remissionModuleOptions;
|
||||
}
|
||||
|
||||
export function cdnProdutctPictures(config: AppConfiguration): string {
|
||||
return config.cdn.productPictures;
|
||||
}
|
||||
|
||||
export function _notificationsHubOptionsFactory(config: AppConfiguration, sso: SsoService): SignalRHubOptions {
|
||||
const options = { ...config.hubs.notifications };
|
||||
|
||||
options.httpOptions.accessTokenFactory = () => sso.getToken();
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
AppRoutingModule,
|
||||
AppSwaggerModule,
|
||||
AppStoreModule,
|
||||
ComponentsModule,
|
||||
HttpClientModule,
|
||||
NgxsModule.forRoot(states, { developmentMode: !environment.production }),
|
||||
NgxsReduxDevtoolsPluginModule.forRoot({ name: 'ISA NGXS Store' }),
|
||||
NgxsLoggerPluginModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
SharedModule,
|
||||
ScrollingModule,
|
||||
IconModule,
|
||||
ModalModule.forRoot(),
|
||||
SsoModule.forRoot(environment.production),
|
||||
OfflineOverlayModule,
|
||||
NgIdleKeepaliveModule.forRoot(),
|
||||
RemissionModule.forRoot(undefined),
|
||||
OverlayModule,
|
||||
OverlaysModule,
|
||||
ModalDialogueModule,
|
||||
|
||||
/**
|
||||
* @core Modules
|
||||
*/
|
||||
CoreBreadcrumbModule.forRoot(),
|
||||
CoreApplicationModule.forRoot(),
|
||||
CoreCommandModule.forRoot([]),
|
||||
|
||||
/**
|
||||
* @domain Modules
|
||||
*/
|
||||
DomainAvailabilityModule.forRoot(),
|
||||
DomainCheckoutModule.forRoot(),
|
||||
DomainCatalogModule.forRoot(),
|
||||
DomainOmsModule.forRoot(),
|
||||
|
||||
/**
|
||||
* @ui Modules
|
||||
*/
|
||||
UiModalModule.forRoot(),
|
||||
UiIconModule,
|
||||
|
||||
/**
|
||||
* @hub Modules
|
||||
*/
|
||||
NotificationsHubModule.forRoot(),
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
useFactory: noop,
|
||||
deps: [RemissionStateHandler],
|
||||
multi: true,
|
||||
},
|
||||
{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
useClass: SsoAuthorizationInterceptor,
|
||||
multi: true,
|
||||
},
|
||||
{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
useClass: HttpErrorHandlerInterceptor,
|
||||
multi: true,
|
||||
},
|
||||
{
|
||||
provide: RemissionModuleOptions,
|
||||
useFactory: remissionModuleOptionsFactory,
|
||||
deps: [AppConfiguration],
|
||||
},
|
||||
DatePipe,
|
||||
{
|
||||
provide: ErrorHandler,
|
||||
useClass: HimaSalesErrorHandler,
|
||||
},
|
||||
{ provide: LOCALE_ID, useValue: 'de-DE' },
|
||||
{
|
||||
provide: SsoInterface,
|
||||
useClass: SsoConfigurationService,
|
||||
},
|
||||
DateAdapter,
|
||||
{
|
||||
provide: ProcessService,
|
||||
useClass: ProcessRefactImp,
|
||||
},
|
||||
{
|
||||
provide: ApplicationService,
|
||||
useClass: ApplicationRefactImp,
|
||||
},
|
||||
{
|
||||
provide: CDN_PRODUCT_PICTURES,
|
||||
useFactory: cdnProdutctPictures,
|
||||
deps: [AppConfiguration],
|
||||
},
|
||||
{
|
||||
provide: CDN_PRODUCT_IMAGE,
|
||||
useFactory: cdnProdutctPictures,
|
||||
deps: [AppConfiguration],
|
||||
},
|
||||
{
|
||||
provide: NOTIFICATIONS_HUB_OPTIONS,
|
||||
useFactory: _notificationsHubOptionsFactory,
|
||||
deps: [AppConfiguration, SsoService],
|
||||
},
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
export class AppModule {}
|
||||
@@ -1,40 +0,0 @@
|
||||
<div class="breadacrumb-grid" [ngClass]="{ 'grid-with-arrow': !showBack, 'breadcumb-mb-5': lowerMargin }" *ngIf="breadcrumbs">
|
||||
<app-back-arrow *ngIf="showBack" (back)="goBack(breadcrumbs[breadcrumbs.length - 2])" class="align-right back-arrow"></app-back-arrow>
|
||||
<div
|
||||
class="layer-fade-start"
|
||||
*ngIf="showBackNavigationArrow"
|
||||
(mouseover)="showBackNavArrow()"
|
||||
(mouseleave)="hideBackNavArrow($event)"
|
||||
></div>
|
||||
<div class="icon-start" *ngIf="showBackNavigationArrow && showBackArrow" (click)="navigateBack()" (mouseleave)="hideBackNavArrowIcon()">
|
||||
<lib-icon class="icon-start" width="40px" name="tab_Arrow_3" type="png"></lib-icon>
|
||||
</div>
|
||||
<div class="breadcrumb-start-layer-fade" *ngIf="!showBackNavigationArrow"></div>
|
||||
<div class="align-center breadcrumb-container" #container>
|
||||
<span
|
||||
*ngFor="let breadcrumb of breadcrumbs; let i = index; let last = last"
|
||||
class="breadcrumb show"
|
||||
(click)="selectBreadcrumb(breadcrumb)"
|
||||
[ngClass]="{ selected: last, branch: module === 1 }"
|
||||
>
|
||||
<lib-icon *ngIf="breadcrumbs.indexOf(breadcrumb) > 0 && i != 0 && i !== last" class="next" name="Arrow_Next" alt="next"></lib-icon>
|
||||
<span>{{ breadcrumb ? breadcrumb.name : '' }}</span>
|
||||
</span>
|
||||
<span class="breadcrumb last" *ngIf="showBack"></span>
|
||||
</div>
|
||||
<div class="breadcrumb-end-layer-fade" *ngIf="!showForwardNavigationalArrow"></div>
|
||||
<div
|
||||
class="layer-fade-end"
|
||||
*ngIf="showForwardNavigationalArrow"
|
||||
(mouseover)="showForwardNavArrow()"
|
||||
(mouseleave)="hideForwardNavArrow($event)"
|
||||
></div>
|
||||
<div
|
||||
class="icon-end"
|
||||
*ngIf="showForwardNavigationalArrow && showForrwardArrow"
|
||||
(click)="navigateForward()"
|
||||
(mouseleave)="hideForwardNavArrowIcon()"
|
||||
>
|
||||
<lib-icon class="icon-end" width="40px" name="tab_Arrow_2" type="png"></lib-icon>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,232 +0,0 @@
|
||||
@import 'variables';
|
||||
|
||||
.breadacrumb-grid {
|
||||
display: grid;
|
||||
grid-template-columns: min-content auto;
|
||||
grid-gap: 15px;
|
||||
height: 40px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.breadcumb-mb-5 {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.grid-with-arrow {
|
||||
grid-template-columns: auto;
|
||||
}
|
||||
|
||||
.breadcrumb-container {
|
||||
// display: flex;
|
||||
align-items: center;
|
||||
// justify-content: center;
|
||||
white-space: nowrap;
|
||||
overflow-y: hidden;
|
||||
scroll-behavior: smooth;
|
||||
overflow-x: scroll;
|
||||
height: 45px;
|
||||
padding-top: 10px;
|
||||
// width: calc(100% - 100px);
|
||||
}
|
||||
|
||||
:only-child {
|
||||
.breadcrumb-end-layer-fade {
|
||||
position: absolute;
|
||||
min-height: 45px;
|
||||
min-width: 5px;
|
||||
z-index: 20;
|
||||
opacity: 0.7;
|
||||
background-color: #e6eff9;
|
||||
box-shadow: -8px 0px 14px 3px #e6eff9;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumb-start-layer-fade {
|
||||
position: absolute;
|
||||
min-height: 45px;
|
||||
min-width: 5px;
|
||||
z-index: 20;
|
||||
opacity: 0.7;
|
||||
background-color: #e6eff9;
|
||||
box-shadow: 8px 0px 14px 3px #e6eff9;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
outline: none;
|
||||
font-size: 16px;
|
||||
color: #1f466c;
|
||||
line-height: 21px;
|
||||
padding: 10px 0;
|
||||
padding-bottom: 0px;
|
||||
cursor: pointer;
|
||||
|
||||
&.branch {
|
||||
color: #596470;
|
||||
}
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none;
|
||||
opacity: 0;
|
||||
|
||||
&:nth-last-child(4) {
|
||||
/*declarations*/
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
flex: 0.0001;
|
||||
animation: fadeSlide 400ms;
|
||||
}
|
||||
&:nth-last-child(-n + 3) {
|
||||
/*declarations*/
|
||||
opacity: 1;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.last {
|
||||
padding: 10px 50px;
|
||||
}
|
||||
|
||||
.back-arrow-container {
|
||||
width: 118px;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
position: absolute;
|
||||
z-index: 50;
|
||||
transform: rotate(180deg);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.foward-arrow-container {
|
||||
width: 118px;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
position: absolute;
|
||||
z-index: 50;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@keyframes fadeSlide {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateX(80px);
|
||||
flex: 0.5;
|
||||
overflow: hidden;
|
||||
}
|
||||
50% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
flex: 0.0001;
|
||||
}
|
||||
}
|
||||
|
||||
.back-arrow {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.next {
|
||||
padding: 0 7px;
|
||||
}
|
||||
|
||||
.selected {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.icon-start {
|
||||
position: absolute;
|
||||
left: 50px;
|
||||
margin-top: 1px;
|
||||
z-index: 30;
|
||||
opacity: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.layer-fade-start {
|
||||
position: absolute;
|
||||
min-height: 40px;
|
||||
min-width: 35px;
|
||||
z-index: 20;
|
||||
left: 100px;
|
||||
opacity: 0.4;
|
||||
background-color: white;
|
||||
box-shadow: 3px 0 14px 8px white;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.icon-end {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
margin-top: 1px;
|
||||
z-index: 30;
|
||||
opacity: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.layer-fade-end {
|
||||
position: absolute;
|
||||
min-height: 40px;
|
||||
min-width: 35px;
|
||||
z-index: 20;
|
||||
right: 15px;
|
||||
opacity: 0.4;
|
||||
background-color: white;
|
||||
box-shadow: 3px 0 14px 8px white;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/*
|
||||
##Device = Big Desktops
|
||||
*/
|
||||
@media (min-width: 1281px) {
|
||||
.breadcrumb-end-layer-fade {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.breadcrumb-start-layer-fade {
|
||||
left: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
##Device = Laptops, Desktops, Ipad pro
|
||||
*/
|
||||
@media (min-width: 1025px) and (max-width: 1280px) {
|
||||
.breadcrumb-end-layer-fade {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.breadcrumb-start-layer-fade {
|
||||
left: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
##Device = Tablets, Ipads
|
||||
*/
|
||||
@media (min-width: 768px) and (max-width: 1024px) {
|
||||
.breadcrumb-end-layer-fade {
|
||||
right: 15px;
|
||||
}
|
||||
|
||||
.breadcrumb-start-layer-fade {
|
||||
left: 112px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
##Device = Low Resolution Tablets, Mobiles (Landscape)
|
||||
*/
|
||||
@media (min-width: 481px) and (max-width: 767px) {
|
||||
.breadcrumb-end-layer-fade {
|
||||
right: 15px;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { BreadcrumbsComponent } from './breadcrumbs.component';
|
||||
|
||||
describe('BreadcrumbsComponent', () => {
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [BreadcrumbsComponent],
|
||||
}).compileComponents();
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -1,286 +0,0 @@
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
ChangeDetectorRef,
|
||||
ChangeDetectionStrategy,
|
||||
ViewChild,
|
||||
ElementRef,
|
||||
AfterViewInit,
|
||||
} from '@angular/core';
|
||||
import { Subject, Observable } from 'rxjs';
|
||||
import { Breadcrumb } from '../../core/models/breadcrumb.model';
|
||||
import { Process } from '../../core/models/process.model';
|
||||
import { Store, Select } from '@ngxs/store';
|
||||
import { ChangeCurrentRoute, ResetProcessProductFilters } from '../../core/store/actions/process.actions';
|
||||
import { Router } from '@angular/router';
|
||||
import { takeUntil, switchMap, distinctUntilChanged } from 'rxjs/operators';
|
||||
import { SharedSelectors } from '../../core/store/selectors/shared.selectors';
|
||||
import { ResetFilters } from '../../core/store/actions/filter.actions';
|
||||
import { AppService } from '../../core/services/app.service';
|
||||
import { ModuleSwitcher } from '../../core/models/app-switcher.enum';
|
||||
import { BranchProcess } from '../../core/models/branch-process.model';
|
||||
import { SetBranchProcessCurrentPath } from '../../core/store/actions/branch-process.actions';
|
||||
import { AppState } from '../../core/store/state/app.state';
|
||||
import { FILIALE_LANDING_PAGE } from '../../core/utils/app.constants';
|
||||
|
||||
@Component({
|
||||
selector: 'app-breadcrumbs',
|
||||
templateUrl: './breadcrumbs.component.html',
|
||||
styleUrls: ['./breadcrumbs.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class BreadcrumbsComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
@ViewChild('container', { read: ElementRef })
|
||||
public container: ElementRef<any>;
|
||||
@Select(SharedSelectors.getBreadcrumbs) breadcrumbs$: Observable<Breadcrumb[]>;
|
||||
@Select(SharedSelectors.getCurrentProcess) currentProcess$: Observable<Process>;
|
||||
module: ModuleSwitcher;
|
||||
destroy$ = new Subject();
|
||||
breadcrumbs: Breadcrumb[] = [];
|
||||
currentRoute = '';
|
||||
start: number;
|
||||
end: number;
|
||||
breadsCount: number;
|
||||
showBack = true;
|
||||
showBackNavigationArrow = false;
|
||||
showBackArrow = false;
|
||||
showForwardNavigationalArrow = false;
|
||||
showForrwardArrow = false;
|
||||
isIPad = false;
|
||||
|
||||
get firstVisibleItem() {
|
||||
if (this.start) {
|
||||
return this.start;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
get lastVisibleItem() {
|
||||
if (this.end) {
|
||||
return this.end;
|
||||
}
|
||||
return this.breadcrumbs ? this.breadcrumbs.length - 1 : 0;
|
||||
}
|
||||
|
||||
get backArrow() {
|
||||
return this.router.url.substring(0, 16) === '/product/details' && this.breadsCount > 1;
|
||||
}
|
||||
|
||||
get selectedBreadCrumbIndex() {
|
||||
if (!this.currentRoute) {
|
||||
return 0;
|
||||
}
|
||||
let route = this.currentRoute;
|
||||
const hasParams = this.currentRoute.includes('?');
|
||||
if (hasParams) {
|
||||
const endOfRouteWithOutParams = this.currentRoute.indexOf('?');
|
||||
route = this.currentRoute.substring(0, endOfRouteWithOutParams);
|
||||
}
|
||||
return this.breadcrumbs.findIndex((t) => t && t.path.indexOf(route) >= 0);
|
||||
}
|
||||
|
||||
get lowerMargin() {
|
||||
if (this.router.url === '/customer/results') {
|
||||
return true;
|
||||
}
|
||||
if (this.router.url.substring(0, 14) === '/customer/edit') {
|
||||
return true;
|
||||
}
|
||||
if (this.router.url.substring(0, 16) === '/product/details') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constructor(private store: Store, private router: Router, private cdrf: ChangeDetectorRef, private appService: AppService) {}
|
||||
|
||||
getBreadcrumbsFromCurentProcess() {
|
||||
this.currentProcess$
|
||||
.pipe(
|
||||
switchMap((process: Process | BranchProcess) => {
|
||||
if (process) {
|
||||
this.currentRoute = `${process.currentRoute}`;
|
||||
this.cdrf.detectChanges();
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this.container.nativeElement.scrollTo({
|
||||
left: this.container.nativeElement.scrollWidth,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
}, 400);
|
||||
return this.breadcrumbs$;
|
||||
}),
|
||||
takeUntil(this.destroy$),
|
||||
distinctUntilChanged()
|
||||
)
|
||||
.subscribe((breadcrumbs: Breadcrumb[]) => {
|
||||
this.showForwardNavigationalArrow = false;
|
||||
this.showBackNavigationArrow = false;
|
||||
if (breadcrumbs) {
|
||||
const breadName =
|
||||
breadcrumbs.length > 0 ? (breadcrumbs[breadcrumbs.length - 1] ? breadcrumbs[breadcrumbs.length - 1].name : '') : '';
|
||||
this.showBack = !(breadName === 'Bestellbestätigung' || breadName === 'Remission');
|
||||
this.breadcrumbs = breadcrumbs;
|
||||
this.breadsCount = Object.keys(this.breadcrumbs) ? Object.keys(this.breadcrumbs).length : 0;
|
||||
this.cdrf.detectChanges();
|
||||
if (!this.isIPad) {
|
||||
setTimeout(() => {
|
||||
try {
|
||||
this.initNavigationalArrow();
|
||||
} catch (error) {}
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
selectBreadcrumb(breadcrumb: Breadcrumb) {
|
||||
if (breadcrumb && breadcrumb.path) {
|
||||
if (breadcrumb.path === '/product/search') {
|
||||
this.store.dispatch(new ResetFilters());
|
||||
this.store.dispatch(new ResetProcessProductFilters());
|
||||
}
|
||||
if (this.module === ModuleSwitcher.Customer) {
|
||||
this.store.dispatch(new ChangeCurrentRoute(breadcrumb.path, true));
|
||||
} else {
|
||||
this.store.dispatch(new SetBranchProcessCurrentPath(breadcrumb.path, true));
|
||||
}
|
||||
this.router.navigate([breadcrumb.path], {
|
||||
queryParams: breadcrumb.queryParams ? breadcrumb.queryParams : {},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
goBack(breadcrumb: Breadcrumb) {
|
||||
if (breadcrumb && breadcrumb.path) {
|
||||
if (this.module === ModuleSwitcher.Customer) {
|
||||
this.store.dispatch(new ChangeCurrentRoute(breadcrumb.path, false));
|
||||
this.router.navigate(['/product/results']);
|
||||
} else {
|
||||
this.store.dispatch(new SetBranchProcessCurrentPath(breadcrumb.path, false));
|
||||
this.router.navigate([FILIALE_LANDING_PAGE]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.isIPad = this.appService.isIPadEnv();
|
||||
this.getBreadcrumbsFromCurentProcess();
|
||||
this.store
|
||||
.select(AppState.activeModule)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((v: ModuleSwitcher) => {
|
||||
this.module = v;
|
||||
this.cdrf.detectChanges();
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
if (!this.isIPad) {
|
||||
setTimeout(() => {
|
||||
try {
|
||||
this.initNavigationalArrow();
|
||||
} catch (error) {}
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
}
|
||||
|
||||
addOne() {
|
||||
this.breadcrumbs.push({
|
||||
name: 'test' + (this.breadcrumbs ? this.breadcrumbs.length : 0),
|
||||
path: './i',
|
||||
});
|
||||
}
|
||||
|
||||
initNavigationalArrow() {
|
||||
if (this.container) {
|
||||
const containerWidth = this.container.nativeElement.offsetWidth;
|
||||
let childrenWidth = 60;
|
||||
let elementProcessed = 0;
|
||||
if (this.container.nativeElement.children) {
|
||||
const breadcrumbs = this.container.nativeElement.children.length - 1;
|
||||
for (let i = 0; i < breadcrumbs; i++) {
|
||||
elementProcessed++;
|
||||
childrenWidth += this.container.nativeElement.children[i].offsetWidth;
|
||||
}
|
||||
if (breadcrumbs === elementProcessed && containerWidth <= childrenWidth) {
|
||||
this.showBackNavigationArrow = true;
|
||||
this.cdrf.detectChanges();
|
||||
} else {
|
||||
this.showBackNavigationArrow = false;
|
||||
this.showForwardNavigationalArrow = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
showBackNavArrow() {
|
||||
this.showBackArrow = true;
|
||||
}
|
||||
|
||||
hideBackNavArrow(event) {
|
||||
if (event) {
|
||||
const e = event.toElement || event.relatedTarget;
|
||||
if (e && e.classList && (e.classList[0] === 'icon' || e.classList[0] === 'ng-star-inserted')) {
|
||||
return;
|
||||
}
|
||||
this.showBackArrow = false;
|
||||
}
|
||||
}
|
||||
|
||||
hideBackNavArrowIcon() {
|
||||
this.showBackArrow = false;
|
||||
}
|
||||
|
||||
showForwardNavArrow() {
|
||||
this.showForrwardArrow = true;
|
||||
}
|
||||
|
||||
hideForwardNavArrow(event) {
|
||||
if (event) {
|
||||
const e = event.toElement || event.relatedTarget;
|
||||
if (e && e.classList && (e.classList[0] === 'icon' || e.classList[0] === 'ng-star-inserted')) {
|
||||
return;
|
||||
}
|
||||
this.showForrwardArrow = false;
|
||||
}
|
||||
}
|
||||
|
||||
hideForwardNavArrowIcon() {
|
||||
this.showForrwardArrow = false;
|
||||
}
|
||||
|
||||
navigateBack() {
|
||||
const scrollLeft = this.container.nativeElement.scrollLeft;
|
||||
if (scrollLeft <= 121) {
|
||||
this.showBackNavigationArrow = false;
|
||||
}
|
||||
this.container.nativeElement.scrollTo({
|
||||
left: scrollLeft - 120,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
this.showForwardNavigationalArrow = true;
|
||||
this.cdrf.detectChanges();
|
||||
}
|
||||
|
||||
navigateForward() {
|
||||
const scrollLeft = this.container.nativeElement.scrollLeft;
|
||||
const containerWidth = this.container.nativeElement.offsetWidth;
|
||||
const scrollWidth = this.container.nativeElement.scrollWidth;
|
||||
if (scrollLeft + 119 + containerWidth <= scrollWidth) {
|
||||
this.showForwardNavigationalArrow = false;
|
||||
}
|
||||
this.container.nativeElement.scrollTo({
|
||||
left: scrollLeft + 120,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
this.showBackNavigationArrow = true;
|
||||
this.cdrf.detectChanges();
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<div class="container">
|
||||
<app-breadcrumbs *ngIf="showBreadCrumbs$ | async"> </app-breadcrumbs>
|
||||
<app-filter-button
|
||||
[active]="isFilterActive$ | async"
|
||||
[module]="activeModule$ | async"
|
||||
*ngIf="showFilter$ | async"
|
||||
(toggleFilter)="toggleFilter()"
|
||||
></app-filter-button>
|
||||
</div>
|
||||
@@ -1,31 +0,0 @@
|
||||
$filter-width: 106px;
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
app-breadcrumbs {
|
||||
flex-grow: 1;
|
||||
margin-left: $filter-width;
|
||||
|
||||
::ng-deep app-back-arrow {
|
||||
margin-right: $filter-width;
|
||||
margin-left: -$filter-width;
|
||||
|
||||
& ~ .breadcrumb-container {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:only-child {
|
||||
margin-left: 0;
|
||||
|
||||
::ng-deep app-back-arrow {
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||
import { ComponentsModule } from '../../modules/components.module';
|
||||
import { ContentHeaderComponent } from './content-header.component';
|
||||
|
||||
describe('ContentHeaderComponent', () => {
|
||||
let fixture: ComponentFixture<ContentHeaderComponent>;
|
||||
let component: ContentHeaderComponent;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [ComponentsModule],
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(ContentHeaderComponent);
|
||||
component = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should create the component', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should show breadcrumbs', () => {});
|
||||
|
||||
it('should show filter button', () => {});
|
||||
});
|
||||
@@ -1,34 +0,0 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { RemissionSelectors } from '../../core/store/selectors/remission.selectors';
|
||||
import { Select } from '@ngxs/store';
|
||||
import { ContentHeaderService } from '../../core/services/content-header.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-content-header',
|
||||
templateUrl: 'content-header.component.html',
|
||||
styleUrls: ['./content-header.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ContentHeaderComponent implements OnInit {
|
||||
@Select(RemissionSelectors.getRemissionActiveFilters)
|
||||
remissionFilters$: Observable<string[]>;
|
||||
|
||||
showFilter$: Observable<boolean>;
|
||||
showBreadCrumbs$: Observable<boolean>;
|
||||
isFilterActive$: Observable<boolean>;
|
||||
activeModule$: Observable<'Customer' | 'Branch'>;
|
||||
|
||||
constructor(private contentHeaderService: ContentHeaderService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.showFilter$ = this.contentHeaderService.showFilter$;
|
||||
this.showBreadCrumbs$ = this.contentHeaderService.showBreadcrumbs$;
|
||||
this.activeModule$ = this.contentHeaderService.module$;
|
||||
this.isFilterActive$ = this.contentHeaderService.isFilterActive$;
|
||||
}
|
||||
|
||||
toggleFilter() {
|
||||
this.contentHeaderService.toggleFilter();
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
// start:ng42.barrel
|
||||
export * from './content-header.component';
|
||||
// end:ng42.barrel
|
||||
@@ -1,52 +0,0 @@
|
||||
<div class="header-wrapper" [ngClass]="{ 'branch-header-wrapper': module === 1 }">
|
||||
<div class="app-header px-16">
|
||||
<div class="three-col-grid-container">
|
||||
<div class="align-left">
|
||||
<a *ngIf="module === 0" (click)="goToDashboard()" class="nav-link">
|
||||
<lib-icon width="190px" name="Logo-Refined_2-3x" type="png"></lib-icon>
|
||||
</a>
|
||||
<a *ngIf="module === 1">
|
||||
<lib-icon width="190px" name="Logo-Refined_2-3x" type="png"></lib-icon>
|
||||
</a>
|
||||
</div>
|
||||
<div class="align-center">
|
||||
<div class="icons-grid pt-5">
|
||||
<div class="header-item align-center">
|
||||
<button class="header-icon dashboard" type="button" [routerLink]="['/dashboard']" routerLinkActive="active">
|
||||
<ui-icon icon="dashboard" size="26px"></ui-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="header-item align-center">
|
||||
<button
|
||||
class="header-icon notification"
|
||||
type="button"
|
||||
[class.active]="notificationCount$ | async"
|
||||
[disabled]="(notificationCount$ | async) === 0"
|
||||
(click)="openNotifications()"
|
||||
>
|
||||
<div class="notification-counter" *ngIf="notificationCount$ | async; let count">{{ count }}</div>
|
||||
<ui-icon icon="notification" size="26px"></ui-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="header-item align-center">
|
||||
<span class="current-branch" *ngIf="currentBranch$ | async; let currentBranch" [title]="currentBranch.name">
|
||||
{{ currentBranch.key | uppercase }}
|
||||
</span>
|
||||
<button class="header-icon logout" type="button" (click)="logoff()">
|
||||
<ui-icon icon="logout" size="26px"></ui-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="align-right">
|
||||
<div class="switch-wrapper">
|
||||
<div></div>
|
||||
<lib-double-choice-switch [model]="doubleChoiceSwitch" (change)="siteChange($event)"></lib-double-choice-switch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<app-process-header></app-process-header>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<app-log-out #logOut></app-log-out>
|
||||
@@ -1,177 +0,0 @@
|
||||
@import 'variables';
|
||||
|
||||
button.header-icon {
|
||||
@apply border-none outline-none bg-transparent;
|
||||
}
|
||||
|
||||
::ng-deep .customer app-header {
|
||||
button.header-icon {
|
||||
ui-icon {
|
||||
@apply text-wild-blue-yonder;
|
||||
}
|
||||
|
||||
&.active ui-icon {
|
||||
@apply text-inactive-customer;
|
||||
}
|
||||
}
|
||||
|
||||
.current-branch {
|
||||
@apply text-wild-blue-yonder;
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .branch app-header {
|
||||
button.header-icon {
|
||||
ui-icon {
|
||||
@apply text-cool-grey;
|
||||
}
|
||||
|
||||
&.active ui-icon {
|
||||
@apply text-active-branch;
|
||||
}
|
||||
}
|
||||
|
||||
.current-branch {
|
||||
@apply text-cool-grey;
|
||||
}
|
||||
}
|
||||
|
||||
button.notification {
|
||||
@apply relative;
|
||||
}
|
||||
|
||||
.notification-counter {
|
||||
@apply absolute flex items-center justify-center -top-2 -right-1 bg-brand text-white text-sm rounded-full w-6 h-6 font-semibold;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.header-item {
|
||||
@apply flex;
|
||||
|
||||
.current-branch {
|
||||
@apply flex items-center font-bold;
|
||||
}
|
||||
}
|
||||
|
||||
.header-wrapper {
|
||||
background-color: white;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
height: 105px;
|
||||
width: 100%;
|
||||
z-index: 150;
|
||||
padding-top: 30px;
|
||||
box-shadow: 0px 2px 6px 0px #dde5ec;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.branch-header-wrapper {
|
||||
box-shadow: 0px 2px 6px 0px #e9ebee;
|
||||
}
|
||||
|
||||
.logout {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.app-header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 737px;
|
||||
height: 105px;
|
||||
padding-top: 30px;
|
||||
z-index: 100;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.three-col-grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto auto;
|
||||
}
|
||||
|
||||
.three-col-grid-container-fixed {
|
||||
display: grid;
|
||||
grid-template-columns: auto max-content 40px;
|
||||
grid-column-gap: 1vh;
|
||||
}
|
||||
|
||||
.profile-name {
|
||||
font-weight: bold;
|
||||
color: $color-active;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.two-col-grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto;
|
||||
grid-column-gap: 2vh;
|
||||
}
|
||||
|
||||
.icons-grid {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto auto;
|
||||
grid-column-gap: 1vh;
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.switch-wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: auto min-content;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*
|
||||
##Device = Big Desktops
|
||||
*/
|
||||
@media (min-width: 1281px) {
|
||||
.app-header {
|
||||
width: 916px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
##Device = Laptops, Desktops, Ipad pro
|
||||
*/
|
||||
@media (min-width: 1025px) and (max-width: 1280px) {
|
||||
.app-header {
|
||||
width: 916px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
##Device = Tablets, Ipads
|
||||
*/
|
||||
@media (min-width: 768px) and (max-width: 1024px) {
|
||||
.app-header {
|
||||
width: 737px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
##Device = Low Resolution Tablets, Mobiles (Landscape)
|
||||
*/
|
||||
@media (min-width: 481px) and (max-width: 767px) {
|
||||
.app-header {
|
||||
width: 94%;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
##Device = Most of the Smartphones Mobiles (Portrait)
|
||||
*/
|
||||
@media (min-width: 320px) and (max-width: 480px) {
|
||||
.app-header {
|
||||
width: 94%;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { HeaderComponent } from './header.component';
|
||||
|
||||
describe('HeaderComponent', () => {
|
||||
let component: HeaderComponent;
|
||||
let fixture: ComponentFixture<HeaderComponent>;
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [HeaderComponent],
|
||||
}).compileComponents();
|
||||
})
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(HeaderComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
});
|
||||
@@ -1,112 +0,0 @@
|
||||
import { Component, OnInit, ViewChild, OnDestroy, ChangeDetectorRef } from '@angular/core';
|
||||
import { LogOutComponent } from '../log-out/log-out.component';
|
||||
import { DoubleChoiceSwitch, DoubleChoiceSwitchColor } from '@libs/ui';
|
||||
import { ModuleSwitcher } from '../../core/models/app-switcher.enum';
|
||||
import { Subject } from 'rxjs';
|
||||
import { distinctUntilChanged, first, map, takeUntil } from 'rxjs/operators';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { ChangeCurrentRoute } from '../../core/store/actions/process.actions';
|
||||
import { Router } from '@angular/router';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { NotificationsHub } from '@hub/notifications';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { ModalNotificationsComponent } from 'apps/modal/notifications/src/public-api';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
|
||||
@Component({
|
||||
selector: 'app-header',
|
||||
templateUrl: './header.component.html',
|
||||
styleUrls: ['./header.component.scss'],
|
||||
})
|
||||
export class HeaderComponent implements OnInit, OnDestroy {
|
||||
@ViewChild('logOut') logOutDialog: LogOutComponent;
|
||||
doubleChoiceSwitch: DoubleChoiceSwitch;
|
||||
module: ModuleSwitcher = ModuleSwitcher.Customer;
|
||||
destroy$ = new Subject();
|
||||
|
||||
notifications$ = this._notificationsHub.notifications$;
|
||||
|
||||
notificationCount$ = this.notifications$.pipe(map((message) => message?.data?.length));
|
||||
|
||||
currentBranch$ = this._availabilityService.getCurrentBranch();
|
||||
|
||||
constructor(
|
||||
private store: Store,
|
||||
private router: Router,
|
||||
private breadcrumb: BreadcrumbService,
|
||||
private applicationService: ApplicationService,
|
||||
private cdr: ChangeDetectorRef,
|
||||
private _notificationsHub: NotificationsHub,
|
||||
private _modal: UiModalService,
|
||||
private _availabilityService: DomainAvailabilityService
|
||||
) {}
|
||||
|
||||
customer = 'Kunden';
|
||||
|
||||
ngOnInit() {
|
||||
this.doubleChoiceSwitch = <DoubleChoiceSwitch>{
|
||||
firstChoice: 'Kunden',
|
||||
secondChoice: 'Filiale',
|
||||
firstChoiceColor: <DoubleChoiceSwitchColor>{
|
||||
selectedBackground: '#1F466C',
|
||||
selectedText: '#ffffff',
|
||||
unSelectedbackground: '#edeff0',
|
||||
unSelectedText: '#000000',
|
||||
},
|
||||
secondChoiceColor: <DoubleChoiceSwitchColor>{
|
||||
selectedBackground: '#596470',
|
||||
selectedText: '#ffffff',
|
||||
unSelectedbackground: '#E6EFF9',
|
||||
unSelectedText: '#000000',
|
||||
},
|
||||
isFirstSwitchedOn: true,
|
||||
};
|
||||
|
||||
this.applicationService.section$.pipe(distinctUntilChanged(), takeUntil(this.destroy$)).subscribe((section) => {
|
||||
this.module = section === 'branch' ? ModuleSwitcher.Branch : ModuleSwitcher.Customer;
|
||||
this.doubleChoiceSwitch.isFirstSwitchedOn = section === 'customer';
|
||||
this.cdr.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
}
|
||||
|
||||
logoff() {
|
||||
this.logOutDialog.openDialog();
|
||||
}
|
||||
|
||||
async siteChange(model: DoubleChoiceSwitch) {
|
||||
const section = model.isFirstSwitchedOn ? 'customer' : 'branch';
|
||||
|
||||
const crumb = await this.breadcrumb.getLatestBreadcrumbForSection(section).pipe(first()).toPromise();
|
||||
if (crumb) {
|
||||
return this.router.navigate([crumb.path], { queryParams: crumb.params });
|
||||
}
|
||||
|
||||
this.router.navigate([section === 'customer' ? '/dashboard' : '/task-calendar']);
|
||||
}
|
||||
|
||||
goToDashboard() {
|
||||
this.store.dispatch(new ChangeCurrentRoute('/dashboard'));
|
||||
this.router.navigate(['/dashboard']);
|
||||
}
|
||||
|
||||
notificationAction() {
|
||||
// navigations needed for development purpouse
|
||||
// this.router.navigate(['/remission/finish']);
|
||||
}
|
||||
|
||||
async openNotifications() {
|
||||
const notifications = await this.notifications$.pipe(first()).toPromise();
|
||||
this._modal.open({
|
||||
content: ModalNotificationsComponent,
|
||||
data: notifications,
|
||||
config: {
|
||||
showScrollbarY: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { SsoService } from 'sso';
|
||||
|
||||
@Component({
|
||||
selector: 'app-log-in',
|
||||
templateUrl: './log-in.component.html',
|
||||
styleUrls: ['./log-in.component.scss'],
|
||||
})
|
||||
export class LogInComponent implements OnInit {
|
||||
constructor(private route: ActivatedRoute, private ssoService: SsoService) {}
|
||||
|
||||
ngOnInit() {
|
||||
const token = this.route.snapshot.paramMap.get('token');
|
||||
this.logIn(token);
|
||||
}
|
||||
|
||||
private logIn(token: string) {
|
||||
this.ssoService.keyCardLogin(token);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
<app-modal id="logout-modal">
|
||||
<div class="logout-modal">
|
||||
<div class="header">
|
||||
<h1>Möchten Sie sich wirklich ausloggen?</h1>
|
||||
<lib-icon (click)="closeModal()" height="21px" class="close-icon" name="close" alt="close"></lib-icon>
|
||||
</div>
|
||||
<div class="body"></div>
|
||||
<div class="actions">
|
||||
<div class="align-right">
|
||||
<app-button (action)="closeModal()">Abbrechen</app-button>
|
||||
</div>
|
||||
<div class="align-right">
|
||||
<app-button [primary]="true" (action)="logoff()">Ausloggen</app-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</app-modal>
|
||||
@@ -1,36 +0,0 @@
|
||||
.logout-modal {
|
||||
font-family: 'Open Sans';
|
||||
line-height: 21px;
|
||||
margin: 16px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
min-height: 185px;
|
||||
|
||||
h1 {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.header {
|
||||
.close-icon {
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
right: 25px;
|
||||
height: 21px;
|
||||
}
|
||||
|
||||
.close-icon:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-top: 50px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { LogOutComponent } from './log-out.component';
|
||||
|
||||
describe('LogOutComponent', () => {
|
||||
let component: LogOutComponent;
|
||||
let fixture: ComponentFixture<LogOutComponent>;
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [LogOutComponent],
|
||||
}).compileComponents();
|
||||
})
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(LogOutComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
});
|
||||
@@ -1,28 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { SsoService } from 'sso';
|
||||
import { ModalService } from '@libs/ui';
|
||||
import { NativeContainerService } from 'shared/lib/barcode-scanner';
|
||||
|
||||
@Component({
|
||||
selector: 'app-log-out',
|
||||
templateUrl: './log-out.component.html',
|
||||
styleUrls: ['./log-out.component.scss'],
|
||||
})
|
||||
export class LogOutComponent implements OnInit {
|
||||
id = 'logout-modal';
|
||||
constructor(private ssoService: SsoService, private modalService: ModalService, private nativeContainer: NativeContainerService) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
logoff() {
|
||||
this.ssoService.logoff();
|
||||
}
|
||||
|
||||
openDialog() {
|
||||
this.modalService.open(this.id);
|
||||
}
|
||||
|
||||
closeModal() {
|
||||
this.modalService.close(this.id);
|
||||
}
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
<!-- Customer module menus -->
|
||||
<div class="menu" *ngIf="module === 0">
|
||||
<div class="menu-grid">
|
||||
<div class="menu-item-grid align-center active" (click)="routeToMenu('/product/search', 'productsearch')">
|
||||
<div>
|
||||
<lib-icon
|
||||
class="menu-icon"
|
||||
name="{{
|
||||
router.url === '/product/search' || router.url.startsWith('/product/results') || router.url.startsWith('/product/details')
|
||||
? 'Icon_Artikelsuche'
|
||||
: 'Icon_Artikelsuche_inactive'
|
||||
}}"
|
||||
width="34px"
|
||||
height="24px"
|
||||
></lib-icon>
|
||||
</div>
|
||||
<span
|
||||
*ngIf="
|
||||
router.url === '/product/search' || router.url.startsWith('/product/results') || router.url.startsWith('/product/details');
|
||||
else articleSearchLabelElse
|
||||
"
|
||||
class="menu-item selected"
|
||||
>Artikelsuche</span
|
||||
>
|
||||
<ng-template #articleSearchLabelElse>
|
||||
<span class="menu-item">Artikelsuche</span>
|
||||
</ng-template>
|
||||
</div>
|
||||
<div
|
||||
class="menu-item-grid align-center active"
|
||||
(click)="routeToMenu('/customer/search', 'customersearch', { customertype: 'store;loyalty;webshop' })"
|
||||
>
|
||||
<div>
|
||||
<lib-icon
|
||||
class="menu-icon"
|
||||
name="{{
|
||||
router.url === '/customer/search' ||
|
||||
router.url === '/customer/results' ||
|
||||
router.url.startsWith('/customer/edit') ||
|
||||
router.url.startsWith('/customer')
|
||||
? 'Icon_Kundensuche'
|
||||
: 'Icon_Kundensuche_inactive'
|
||||
}}"
|
||||
width="34px"
|
||||
height="24px"
|
||||
></lib-icon>
|
||||
</div>
|
||||
<span
|
||||
*ngIf="
|
||||
router.url === '/customer/search' ||
|
||||
router.url === '/customer/results' ||
|
||||
router.url.startsWith('/customer/edit') ||
|
||||
router.url.startsWith('/customer');
|
||||
else customerSearchLabelElse
|
||||
"
|
||||
class="menu-item selected"
|
||||
>Kundensuche</span
|
||||
>
|
||||
<ng-template #customerSearchLabelElse>
|
||||
<span class="menu-item">Kundensuche</span>
|
||||
</ng-template>
|
||||
</div>
|
||||
<div class="menu-item-grid align-center active" (click)="routeToMenu('/goods/out', 'shelfsearch')">
|
||||
<!-- <div class="menu-item-grid align-center"> -->
|
||||
<div>
|
||||
<lib-icon
|
||||
class="menu-icon"
|
||||
name="{{ router.url === '/goods/out' || router.url.startsWith('/goods/out') ? 'Icon_Abholfach' : 'Icon_Abholfach_inactive' }}"
|
||||
width="34px"
|
||||
height="24px"
|
||||
></lib-icon>
|
||||
</div>
|
||||
<span
|
||||
*ngIf="router.url === '/shelf/search' || router.url.startsWith('/goods/out'); else shelfSearchLabelElse"
|
||||
class="menu-item selected"
|
||||
>Warenausgabe</span
|
||||
>
|
||||
<ng-template #shelfSearchLabelElse>
|
||||
<span class="menu-item">Warenausgabe</span>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Branch module menus -->
|
||||
<div class="branch-menu" *ngIf="module === 1">
|
||||
<div class="menu-grid">
|
||||
<!-- <div class="menu-item-grid align-center disabled"></div> -->
|
||||
<div class="menu-item-grid align-center active" (click)="routeToMenu('/task-calendar/calendar', 'calendar')">
|
||||
<div>
|
||||
<lib-icon
|
||||
class="menu-icon"
|
||||
name="{{
|
||||
router.url === '/task-calendar/calendar' || router.url === '/task-calendar/tasks'
|
||||
? 'Icon_Tatigkeitskalender'
|
||||
: 'Icon_Tatigkeitskalender_inactive'
|
||||
}}"
|
||||
width="34px"
|
||||
height="24px"
|
||||
></lib-icon>
|
||||
</div>
|
||||
<span
|
||||
*ngIf="router.url === '/task-calendar/calendar' || router.url === '/task-calendar/tasks'; else taskCalendarLabelElse"
|
||||
class="branch-menu-item branch-selected"
|
||||
>Tätigkeitskalender</span
|
||||
>
|
||||
<ng-template #taskCalendarLabelElse>
|
||||
<span class="branch-menu-item">Tätigkeitskalender</span>
|
||||
</ng-template>
|
||||
</div>
|
||||
<div class="menu-item-grid align-center active" (click)="routeToMenu('/goods/in', 'goods-in')">
|
||||
<div>
|
||||
<lib-icon
|
||||
class="menu-icon"
|
||||
name="{{ router.url.startsWith('/goods/in') ? 'Icon_Abholfach_B' : 'Icon_Abholfach_B_inactive' }}"
|
||||
width="34px"
|
||||
height="24px"
|
||||
></lib-icon>
|
||||
</div>
|
||||
<span *ngIf="router.url.startsWith('/goods/in'); else abholfachLabelElse" class="branch-menu-item branch-selected">Abholfach</span>
|
||||
<ng-template #abholfachLabelElse>
|
||||
<span class="branch-menu-item">Abholfach</span>
|
||||
</ng-template>
|
||||
</div>
|
||||
<div class="menu-item-grid align-center active" (click)="routeToMenu('/remission/create', 'remission')">
|
||||
<div>
|
||||
<lib-icon
|
||||
class="menu-icon"
|
||||
name="{{
|
||||
router.url === '/remission/create' || router.url === '/remission/started' ? 'Icon_Remission' : 'Icon_Remission_inactive'
|
||||
}}"
|
||||
width="34px"
|
||||
height="24px"
|
||||
></lib-icon>
|
||||
</div>
|
||||
<span
|
||||
*ngIf="router.url === '/remission/create' || router.url === '/remission/started'; else remissionLabelElse"
|
||||
class="branch-menu-item branch-selected"
|
||||
>Remission</span
|
||||
>
|
||||
<ng-template #remissionLabelElse>
|
||||
<span class="branch-menu-item">Remission</span>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,121 +0,0 @@
|
||||
@import 'variables';
|
||||
|
||||
.menu {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
background-color: white;
|
||||
z-index: 100;
|
||||
box-shadow: 0px -2px 6px 0px #dde5ec;
|
||||
}
|
||||
|
||||
.branch-menu {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
background-color: white;
|
||||
z-index: 100;
|
||||
box-shadow: 0px -2px 6px 0px #e9ebee;
|
||||
}
|
||||
|
||||
.menu-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 33% 33% 33%;
|
||||
padding-top: 20px;
|
||||
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.menu-item-grid {
|
||||
display: grid;
|
||||
grid-template-columns: auto;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
font-size: 15px;
|
||||
line-height: 21px;
|
||||
font-weight: 600;
|
||||
color: $color-inactive;
|
||||
}
|
||||
|
||||
.selected {
|
||||
color: $color-active;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.branch-menu-item {
|
||||
font-size: 15px;
|
||||
line-height: 21px;
|
||||
font-weight: 600;
|
||||
color: $branch-color-inactive;
|
||||
|
||||
&.branch-disabled {
|
||||
color: #edeff0;
|
||||
}
|
||||
}
|
||||
|
||||
.branch-selected {
|
||||
color: $branch-color-active;
|
||||
}
|
||||
|
||||
.missing-menu {
|
||||
font-family: 'Open Sans';
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #89949e;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.active {
|
||||
cursor: pointer;
|
||||
}
|
||||
/*
|
||||
##Device = Big Desktops
|
||||
*/
|
||||
@media (min-width: 1281px) {
|
||||
.menu-grid {
|
||||
width: 980px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
##Device = Laptops, Desktops, Ipad pro
|
||||
*/
|
||||
@media (min-width: 1025px) and (max-width: 1280px) {
|
||||
.menu-grid {
|
||||
width: 980px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
##Device = Tablets, Ipads
|
||||
*/
|
||||
@media (min-width: 768px) and (max-width: 1024px) {
|
||||
.menu-grid {
|
||||
width: 768px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
##Device = Low Resolution Tablets, Mobiles (Landscape)
|
||||
*/
|
||||
@media (min-width: 481px) and (max-width: 767px) {
|
||||
.menu-grid {
|
||||
width: 94%;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
##Device = Most of the Smartphones Mobiles (Portrait)
|
||||
*/
|
||||
@media (min-width: 320px) and (max-width: 480px) {
|
||||
.menu-grid {
|
||||
width: 94%;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { MenuComponent } from './menu.component';
|
||||
|
||||
describe('MenuComponent', () => {
|
||||
let component: MenuComponent;
|
||||
let fixture: ComponentFixture<MenuComponent>;
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [MenuComponent],
|
||||
}).compileComponents();
|
||||
})
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MenuComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
});
|
||||
@@ -1,168 +0,0 @@
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { Process } from '../../core/models/process.model';
|
||||
import { Store, Select } from '@ngxs/store';
|
||||
import {
|
||||
AddProcess,
|
||||
ChangeCurrentRoute,
|
||||
ResetProcessProductFilters,
|
||||
SetOnlineCustomerCreationStatus,
|
||||
} from '../../core/store/actions/process.actions';
|
||||
import { Breadcrumb } from '../../core/models/breadcrumb.model';
|
||||
import { ResetBreadcrumbsTo } from '../../core/store/actions/breadcrumb.actions';
|
||||
import { takeUntil, distinctUntilChanged } from 'rxjs/operators';
|
||||
import { ProcessSelectors } from '../../core/store/selectors/process.selectors';
|
||||
import { ResetFilters } from '../../core/store/actions/filter.actions';
|
||||
import { ModuleSwitcher } from '../../core/models/app-switcher.enum';
|
||||
import { ModuleSwitcherService } from '../../core/services/module-switcher.service';
|
||||
import { SetBranchProcessCurrentPath } from '../../core/store/actions/branch-process.actions';
|
||||
import { InitRemissionState, SetRemissionFinishedProcessStatus, ResetRemissionState } from '../../core/store/actions/remission.actions';
|
||||
import { RemissionSelectors } from '../../core/store/selectors/remission.selectors';
|
||||
import { RemissionFinishingProcessStatus } from '../../modules/remission/models/remission-finishing-process-status.enum';
|
||||
import { DeleteFormState } from '../../core/store/actions/forms.actions';
|
||||
import { USER_FORM_STATE_KEY, USER_EXTRAS_FORM_STATE_KEY, USER_ERRORS_FORM_STATE_KEY } from '../../core/utils/app.constants';
|
||||
import { ApplicationService } from '@core/application';
|
||||
|
||||
@Component({
|
||||
selector: 'app-menu',
|
||||
templateUrl: './menu.component.html',
|
||||
styleUrls: ['./menu.component.scss'],
|
||||
})
|
||||
export class MenuComponent implements OnInit, OnDestroy {
|
||||
@Select(ProcessSelectors.getProcesses) processes$: Observable<Process[]>;
|
||||
module: ModuleSwitcher = ModuleSwitcher.Customer;
|
||||
processes: Process[] = [];
|
||||
destroy$ = new Subject();
|
||||
breadCrumbId = 'product';
|
||||
|
||||
constructor(
|
||||
public router: Router,
|
||||
private store: Store,
|
||||
private moduleSwitcherService: ModuleSwitcherService,
|
||||
private applicationService: ApplicationService
|
||||
) {}
|
||||
activeMenu = '';
|
||||
|
||||
routeToMenu(menuPath: string, menuTag: string, queryParams?: { [key: string]: string }): void {
|
||||
if (this.processes && this.processes.length < 1 && this.module === ModuleSwitcher.Customer) {
|
||||
this.createProcess(menuPath);
|
||||
}
|
||||
this.activeMenu = menuTag;
|
||||
this.store.dispatch(
|
||||
new ResetBreadcrumbsTo(
|
||||
<Breadcrumb>{
|
||||
name: this.nameFromPath(menuPath),
|
||||
path: menuPath,
|
||||
},
|
||||
this.breadCrumbId,
|
||||
true
|
||||
)
|
||||
);
|
||||
if (menuTag === 'productsearch') {
|
||||
this.store.dispatch(new ResetFilters());
|
||||
this.store.dispatch(new ResetProcessProductFilters());
|
||||
}
|
||||
if (menuTag === 'remission') {
|
||||
this.store.dispatch(new InitRemissionState());
|
||||
}
|
||||
if (menuTag === 'customersearch') {
|
||||
this.store.dispatch(new DeleteFormState(USER_FORM_STATE_KEY));
|
||||
this.store.dispatch(new DeleteFormState(USER_EXTRAS_FORM_STATE_KEY));
|
||||
this.store.dispatch(new DeleteFormState(USER_ERRORS_FORM_STATE_KEY));
|
||||
this.store.dispatch(new SetOnlineCustomerCreationStatus({ error: false, invalidProperties: null }));
|
||||
}
|
||||
if (this.router.url === '/remission/finish' && menuTag === 'remission') {
|
||||
const processStatus = this.store.selectSnapshot(RemissionSelectors.getRemissionFinishingProcessStatus);
|
||||
if (processStatus === RemissionFinishingProcessStatus.start) {
|
||||
this.store.dispatch(new SetRemissionFinishedProcessStatus(RemissionFinishingProcessStatus.notSet));
|
||||
} else {
|
||||
this.store.dispatch(new SetRemissionFinishedProcessStatus(RemissionFinishingProcessStatus.notSet));
|
||||
this.navigateToNewRemissionList();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.module === ModuleSwitcher.Branch) {
|
||||
this.store.dispatch(new SetBranchProcessCurrentPath(menuPath));
|
||||
} else {
|
||||
this.store.dispatch(new ChangeCurrentRoute(menuPath));
|
||||
}
|
||||
this.router.navigate([menuPath], { queryParams });
|
||||
}
|
||||
|
||||
routeToMenuBranch(menuPath: string, menuTag: string): void {
|
||||
this.activeMenu = menuTag;
|
||||
this.router.navigate([menuPath]);
|
||||
}
|
||||
|
||||
createProcess(menuPath: string) {
|
||||
const newProcess = <Process>{
|
||||
id: 1,
|
||||
name: 'Vorgang 1',
|
||||
currentRoute: menuPath,
|
||||
};
|
||||
this.store.dispatch(new AddProcess(newProcess));
|
||||
}
|
||||
|
||||
routeFromPath(path: string) {
|
||||
if (path) {
|
||||
return path.substring(1, path.length);
|
||||
}
|
||||
}
|
||||
|
||||
nameFromPath(path: string) {
|
||||
switch (path) {
|
||||
case '/product/search':
|
||||
this.breadCrumbId = 'product';
|
||||
return 'Artikelsuche';
|
||||
case '/customer/search':
|
||||
this.breadCrumbId = 'customer';
|
||||
return 'Kundensuche';
|
||||
case '/shelf/search':
|
||||
this.breadCrumbId = 'shelf';
|
||||
return 'Warenausgabe';
|
||||
case '/branch/main':
|
||||
this.breadCrumbId = 'goodsin';
|
||||
return 'Abholfach';
|
||||
case '/remission/create':
|
||||
this.breadCrumbId = 'remission';
|
||||
return 'Remission';
|
||||
case '/task-calendar/calendar':
|
||||
this.breadCrumbId = 'taskCalendar';
|
||||
return 'Tätigkeitskalendar';
|
||||
default:
|
||||
this.breadCrumbId = 'product';
|
||||
return 'Artikelsuche';
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.processes$.pipe(takeUntil(this.destroy$)).subscribe((data: Process[]) => (this.processes = data));
|
||||
|
||||
this.applicationService.section$.pipe(takeUntil(this.destroy$), distinctUntilChanged()).subscribe((section) => {
|
||||
this.module = section === 'branch' ? ModuleSwitcher.Branch : ModuleSwitcher.Customer;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
}
|
||||
|
||||
private navigateToNewRemissionList() {
|
||||
this.store.dispatch(new ResetRemissionState());
|
||||
const path = '/remission/create';
|
||||
this.store.dispatch(
|
||||
new ResetBreadcrumbsTo(
|
||||
<Breadcrumb>{
|
||||
name: 'Remission',
|
||||
path: path,
|
||||
},
|
||||
'remission',
|
||||
true
|
||||
)
|
||||
);
|
||||
this.store.dispatch(new SetBranchProcessCurrentPath(path));
|
||||
this.router.navigate([path]);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<app-modal id="printer-modal">
|
||||
<div class="printer-modal">
|
||||
<div class="header">
|
||||
<h1>Wählen Sie einen Drucker aus</h1>
|
||||
<lib-icon (click)="closeModal()" height="21px" class="close-icon" name="close" alt="close"></lib-icon>
|
||||
</div>
|
||||
<span *ngIf="error && errorMessage" class="error-message isa-font-color-warning">{{ errorMessage }}</span>
|
||||
<ng-container *ngIf="!error">
|
||||
<div class="body">
|
||||
<app-dropdown
|
||||
[load]="true"
|
||||
(valueChanges)="printerSelected($event)"
|
||||
[options]="options"
|
||||
[selected]="selected"
|
||||
[loading]="!loaded"
|
||||
[showFull]="true"
|
||||
></app-dropdown>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<div>
|
||||
<app-button [primary]="true" [load]="true" [disabled]="!loaded" (action)="emitPrint()" #printBtn>Drucken </app-button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</app-modal>
|
||||
@@ -1,48 +0,0 @@
|
||||
.printer-modal {
|
||||
font-family: 'Open Sans';
|
||||
line-height: 21px;
|
||||
margin: 16px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
min-height: 185px;
|
||||
|
||||
h1 {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.header {
|
||||
.close-icon {
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
right: 25px;
|
||||
height: 21px;
|
||||
}
|
||||
|
||||
.close-icon:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-top: 35px;
|
||||
margin-bottom: 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
padding: 1rem 2rem;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.body {
|
||||
padding-top: 30px;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { PrinterSelectionComponent } from './printer-selection.component';
|
||||
|
||||
describe('PrinterSelectionComponent', () => {
|
||||
let component: PrinterSelectionComponent;
|
||||
let fixture: ComponentFixture<PrinterSelectionComponent>;
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [PrinterSelectionComponent],
|
||||
}).compileComponents();
|
||||
})
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PrinterSelectionComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
});
|
||||
@@ -1,115 +0,0 @@
|
||||
import { Component, OnInit, Output, EventEmitter, OnDestroy, ViewChild, ChangeDetectorRef } from '@angular/core';
|
||||
import { PrinterService } from '../../core/services/printer.service';
|
||||
import { ModalService, ButtonComponent } from '@libs/ui';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil, map, tap, delay } from 'rxjs/operators';
|
||||
import { Printer } from '../../core/models/printer.model';
|
||||
import { PRINT_ERROR_MSG } from './printer-selection.constants';
|
||||
|
||||
@Component({
|
||||
selector: 'app-printer-selection',
|
||||
templateUrl: './printer-selection.component.html',
|
||||
styleUrls: ['./printer-selection.component.scss'],
|
||||
})
|
||||
export class PrinterSelectionComponent implements OnInit, OnDestroy {
|
||||
id = 'printer-modal';
|
||||
options: string[] | number[];
|
||||
selected: string | number;
|
||||
selectedPrinterValue: string;
|
||||
printers: { key: string; text: string; selected: boolean }[] = [];
|
||||
destroy$ = new Subject();
|
||||
error = false;
|
||||
errorMessage = PRINT_ERROR_MSG;
|
||||
loaded = false;
|
||||
printingRequested = false;
|
||||
submited = false;
|
||||
@Output() print: EventEmitter<string> = new EventEmitter();
|
||||
@Output() closed = new EventEmitter();
|
||||
@ViewChild('printBtn') printBtn: ButtonComponent;
|
||||
|
||||
constructor(private printerService: PrinterService, private modalService: ModalService, private cdr: ChangeDetectorRef) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
printerSelected(value: string | number) {
|
||||
this.selected = value;
|
||||
this.selectedPrinterValue = this.printers.find((t) => t.text === this.selected).key;
|
||||
}
|
||||
|
||||
emitPrint() {
|
||||
if (this.loaded) {
|
||||
this.print.emit(this.selectedPrinterValue);
|
||||
this.printBtn.startLoading();
|
||||
} else {
|
||||
this.printingRequested = true;
|
||||
this.printBtn.startLoading();
|
||||
}
|
||||
}
|
||||
|
||||
loadPrinters() {
|
||||
this.loaded = false;
|
||||
this.error = false;
|
||||
this.printerService
|
||||
.getAvailablePrinters()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((response) => {
|
||||
if ((response as { error: string }).error) {
|
||||
const errorResponse = response as { error: string };
|
||||
this.error = true;
|
||||
this.errorMessage = errorResponse.error;
|
||||
return;
|
||||
}
|
||||
const result = response as Printer[];
|
||||
this.printers = result.map((t) => {
|
||||
return { key: t.key, text: t.description, selected: t.selected };
|
||||
});
|
||||
const selectedPrinter = this.printers.find((printer) => printer.selected);
|
||||
this.options = this.printers.map((t) => t.text);
|
||||
this.selectedPrinterValue = selectedPrinter ? selectedPrinter.key : this.printers[0].key;
|
||||
this.selected = selectedPrinter ? selectedPrinter.text : this.options[0];
|
||||
this.error = false;
|
||||
this.loaded = true;
|
||||
if (this.printBtn) {
|
||||
this.printBtn.stopLoading();
|
||||
}
|
||||
if (!this.selected) {
|
||||
this.error = true;
|
||||
this.errorMessage = 'No available printers';
|
||||
}
|
||||
this.cdr.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
openDialog() {
|
||||
this.loadPrinters();
|
||||
this.modalService.open(this.id);
|
||||
}
|
||||
|
||||
closeModal() {
|
||||
this.modalService.close(this.id);
|
||||
if (this.printBtn) {
|
||||
this.printBtn.stopLoading();
|
||||
}
|
||||
this.closed.emit();
|
||||
}
|
||||
|
||||
setError(errorMessage?: string) {
|
||||
this.error = true;
|
||||
if (!!errorMessage) {
|
||||
this.errorMessage = errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if (this.printBtn) {
|
||||
this.printBtn.stopLoading();
|
||||
}
|
||||
this.destroy$.next();
|
||||
}
|
||||
|
||||
contentLoaded() {
|
||||
if (this.printingRequested) {
|
||||
this.print.emit(this.selectedPrinterValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export const PRINT_ERROR_MSG = 'Der Druckauftrag konnte nicht ausgeführt werden.';
|
||||
@@ -1,11 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { PrinterSelectionComponent } from './printer-selection.component';
|
||||
import { IconModule, DropdownModule, ModalModule, ButtonModule } from '@libs/ui';
|
||||
|
||||
@NgModule({
|
||||
declarations: [PrinterSelectionComponent],
|
||||
imports: [CommonModule, IconModule, DropdownModule, ModalModule, ButtonModule],
|
||||
exports: [PrinterSelectionComponent],
|
||||
})
|
||||
export class PrinterSelectionModule {}
|
||||
@@ -1,8 +0,0 @@
|
||||
import { trigger, transition, animate, style } from '@angular/animations';
|
||||
|
||||
export const addAnimation = trigger('add', [
|
||||
transition('void => true', [
|
||||
style({ opacity: 0, transform: 'translateX(200%)' }),
|
||||
animate('0.3s ease-out', style({ opacity: 1, transform: 'translateX(0%)' })),
|
||||
]),
|
||||
]);
|
||||
@@ -1,46 +0,0 @@
|
||||
<div class="grid-container">
|
||||
<div class="align-left">
|
||||
<div class="back-arrow-container" *ngIf="showBackContainer && !isIPad" (mouseover)="showBackIcon()" (mouseleave)="hideBackIcon()">
|
||||
<lib-icon class="icon" width="118px" height="50px" name="tab_Arrow" type="png" (click)="scrollBack()" *ngIf="showBack"></lib-icon>
|
||||
</div>
|
||||
<div class="process-grid-container" [ngClass]="{ adding: showAddingPadding }" *ngIf="module === 0" #panel>
|
||||
<app-process-tab
|
||||
[id]="process.id"
|
||||
style="display: inline-block; height: 100%;"
|
||||
*ngFor="let process of processes; let last = last"
|
||||
[module]="module"
|
||||
[last]="last"
|
||||
[process]="process"
|
||||
[@add]="process.new"
|
||||
></app-process-tab>
|
||||
</div>
|
||||
<div class="process-grid-container" *ngIf="module === 1" #panel>
|
||||
<app-process-tab
|
||||
id="{{ branchProcess.id }}"
|
||||
style="display: inline-block; height: 100%;"
|
||||
[module]="module"
|
||||
[process]="branchProcess"
|
||||
></app-process-tab>
|
||||
</div>
|
||||
<div
|
||||
class="foward-arrow-container"
|
||||
*ngIf="showFowardContainer && !isIPad"
|
||||
(mouseover)="showFowardIcon()"
|
||||
(mouseleave)="hideFowardIcon()"
|
||||
>
|
||||
<lib-icon class="icon" width="118px" height="50px" name="tab_Arrow" type="png" (click)="scrollFoward()" *ngIf="showNext"></lib-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="align-right">
|
||||
<div class="grid-container-fix-width-last-col">
|
||||
<div class="align-right add-process-label">
|
||||
<span *ngIf="processes && processes.length === 0 && module === 0" class="process-span" (click)="addProcess()">{{
|
||||
startProcessLabel
|
||||
}}</span>
|
||||
</div>
|
||||
<app-button *ngIf="module === 0" (action)="addProcess()" class="add-process" [type]="'small'">
|
||||
<lib-icon width="34px" height="36px" name="add-red"></lib-icon>
|
||||
</app-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,113 +0,0 @@
|
||||
@import 'variables';
|
||||
|
||||
.grid-container {
|
||||
@apply grid grid-flow-col;
|
||||
grid-template-columns: 1fr auto;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
@apply grid grid-flow-col;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
}
|
||||
|
||||
.grid-container-fix-width-last-col {
|
||||
display: grid;
|
||||
grid-template-columns: auto;
|
||||
padding-top: 7px;
|
||||
}
|
||||
|
||||
.process-span {
|
||||
color: $hima-color-red;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.process-grid-container {
|
||||
white-space: nowrap;
|
||||
padding-top: 13px;
|
||||
padding-right: 25px;
|
||||
overflow-y: scroll;
|
||||
scroll-behavior: smooth;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.adding {
|
||||
padding-right: 200px;
|
||||
}
|
||||
|
||||
.add-process-label {
|
||||
position: absolute;
|
||||
top: 99px;
|
||||
right: 63px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.back-arrow-container {
|
||||
width: 118px;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
z-index: 50;
|
||||
top: 83px;
|
||||
cursor: pointer;
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.foward-arrow-container {
|
||||
width: 118px;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
z-index: 50;
|
||||
top: 87px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.placeholder-tab {
|
||||
width: 300px;
|
||||
height: 42px;
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/*
|
||||
##Device = Big Desktops
|
||||
*/
|
||||
@media (min-width: 1281px) {
|
||||
.grid-container {
|
||||
grid-template-columns: 93% auto;
|
||||
}
|
||||
|
||||
.foward-arrow-container {
|
||||
right: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
##Device = Laptops, Desktops, Ipad pro
|
||||
*/
|
||||
@media (min-width: 1025px) and (max-width: 1280px) {
|
||||
.grid-container {
|
||||
grid-template-columns: 93% auto;
|
||||
}
|
||||
|
||||
.foward-arrow-container {
|
||||
right: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
##Device = Tablets, Ipads
|
||||
*/
|
||||
@media (min-width: 768px) and (max-width: 1024px) {
|
||||
.grid-container {
|
||||
grid-template-columns: 685px auto;
|
||||
}
|
||||
|
||||
.foward-arrow-container {
|
||||
right: 68px;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { ProcessHeaderComponent } from './process-header.component';
|
||||
|
||||
describe('ProcessHeaderComponent', () => {
|
||||
let component: ProcessHeaderComponent;
|
||||
let fixture: ComponentFixture<ProcessHeaderComponent>;
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ProcessHeaderComponent],
|
||||
}).compileComponents();
|
||||
})
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProcessHeaderComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
});
|
||||
@@ -1,248 +0,0 @@
|
||||
import { Component, OnInit, OnDestroy, ElementRef, ViewChild, ChangeDetectorRef, ChangeDetectionStrategy, Input } from '@angular/core';
|
||||
import { Process } from '../../core/models/process.model';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { Breadcrumb } from '../../core/models/breadcrumb.model';
|
||||
import { Store, Select } from '@ngxs/store';
|
||||
import { AddProcess } from '../../core/store/actions/process.actions';
|
||||
import { addAnimation } from './add.animation';
|
||||
import { Router } from '@angular/router';
|
||||
import { AddBreadcrumb } from '../../core/store/actions/breadcrumb.actions';
|
||||
import { takeUntil, switchMap, distinctUntilChanged } from 'rxjs/operators';
|
||||
import { ProcessSelectors } from '../../core/store/selectors/process.selectors';
|
||||
import { WindowRef } from '../../core/services/window-ref.service';
|
||||
import { ModuleSwitcher } from '../../core/models/app-switcher.enum';
|
||||
import { ApplicationService } from '@core/application';
|
||||
|
||||
@Component({
|
||||
selector: 'app-process-header',
|
||||
templateUrl: './process-header.component.html',
|
||||
styleUrls: ['./process-header.component.scss'],
|
||||
animations: [addAnimation],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ProcessHeaderComponent implements OnInit, OnDestroy {
|
||||
startProcessLabel = 'VORGANG STARTEN';
|
||||
@ViewChild('panel', { read: ElementRef }) public panel: ElementRef<any>;
|
||||
@Select(ProcessSelectors.getProcesses) process$: Observable<Process[]>;
|
||||
@Select(ProcessSelectors.getCurrentProcess) selectedProcess$: Observable<Process>;
|
||||
module: ModuleSwitcher;
|
||||
branchProcess = <Process>{
|
||||
id: 1,
|
||||
name: 'Wareneingang',
|
||||
};
|
||||
processes: Process[] = [];
|
||||
destroy$ = new Subject();
|
||||
showNext = false;
|
||||
showBack = false;
|
||||
showFowardContainer = false;
|
||||
showBackContainer = false;
|
||||
offset: number;
|
||||
selectedProcessId: string;
|
||||
selectedProcess: any;
|
||||
isIPad = false;
|
||||
showAddingPadding = false;
|
||||
private iPadDetected = false;
|
||||
private iPadEventRecieved = false;
|
||||
|
||||
constructor(
|
||||
private store: Store,
|
||||
private router: Router,
|
||||
private cdr: ChangeDetectorRef,
|
||||
private windowRef: WindowRef,
|
||||
private applicationService: ApplicationService
|
||||
) {}
|
||||
|
||||
addProcess() {
|
||||
const itemNo = !this.processes
|
||||
? 0
|
||||
: this.processes && this.processes.length === 0
|
||||
? 1
|
||||
: this.processes[this.processes.length - 1].id + 1;
|
||||
const newProcess = <Process>{
|
||||
id: itemNo,
|
||||
new: true,
|
||||
name: `Vorgang ${itemNo}`,
|
||||
currentRoute: '/product/search',
|
||||
};
|
||||
if (itemNo >= 4) {
|
||||
this.initializeAnimation(itemNo);
|
||||
}
|
||||
this.store
|
||||
.dispatch(new AddProcess(newProcess))
|
||||
.toPromise()
|
||||
.then(() => {
|
||||
this.store.dispatch(
|
||||
new AddBreadcrumb(
|
||||
<Breadcrumb>{
|
||||
name: 'Artikelsuche',
|
||||
path: '/product/search',
|
||||
},
|
||||
'product',
|
||||
true
|
||||
)
|
||||
);
|
||||
this.router.navigate(['/product/search']);
|
||||
});
|
||||
this.applicationService.setActivatedProcessId(newProcess.id);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.isIPad = this.isIPadEnv();
|
||||
this.selectedProcess$
|
||||
.pipe(
|
||||
switchMap((proc: Process) => {
|
||||
if (proc) {
|
||||
this.selectedProcessId = proc.id + '';
|
||||
}
|
||||
|
||||
return this.process$;
|
||||
}),
|
||||
takeUntil(this.destroy$),
|
||||
distinctUntilChanged((prev, curr) => this.processComperer(prev, curr))
|
||||
)
|
||||
.subscribe(
|
||||
(data) => {
|
||||
this.processes = data;
|
||||
this.cdr.detectChanges();
|
||||
if (this.panel?.nativeElement?.children.length > 0) {
|
||||
this.scrollableArrows();
|
||||
}
|
||||
},
|
||||
(err) => console.error(err)
|
||||
);
|
||||
|
||||
this.applicationService.section$.pipe(distinctUntilChanged(), takeUntil(this.destroy$)).subscribe((section) => {
|
||||
this.module = section === 'branch' ? ModuleSwitcher.Branch : ModuleSwitcher.Customer;
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
}
|
||||
|
||||
private initializeAnimation(processCount: number) {
|
||||
this.showAddingPadding = true;
|
||||
this.cdr.detectChanges();
|
||||
|
||||
setTimeout(() => {
|
||||
this.panel.nativeElement.scrollTo({ left: this.panel.nativeElement.scrollLeft + 300 * processCount, behavior: 'smooth' });
|
||||
this.cdr.detectChanges();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
processComperer(prev: Process[], curr: Process[]) {
|
||||
try {
|
||||
if (!prev || !curr) {
|
||||
return false;
|
||||
}
|
||||
if (prev.length !== curr.length) {
|
||||
return false;
|
||||
}
|
||||
if (prev.length === 0 || curr.length === 0) {
|
||||
return false;
|
||||
}
|
||||
const prevStr = JSON.stringify(
|
||||
prev.map((t) => {
|
||||
return { new: t.new, name: t.name };
|
||||
})
|
||||
);
|
||||
const currStr = JSON.stringify(
|
||||
curr.map((t) => {
|
||||
return { new: t.new, name: t.name };
|
||||
})
|
||||
);
|
||||
const status = prevStr === currStr;
|
||||
return status;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
}
|
||||
|
||||
isIPadEnv() {
|
||||
const navigator = this.windowRef.nativeWindow.navigator as Navigator;
|
||||
const standalone = (navigator as any).standalone,
|
||||
userAgent = navigator.userAgent.toLowerCase(),
|
||||
ios = /iphone|ipod|ipad/.test(userAgent);
|
||||
|
||||
this.iPadDetected = ios && !standalone;
|
||||
return this.iPadDetected || this.iPadEventRecieved;
|
||||
}
|
||||
|
||||
scrollableArrows() {
|
||||
this.offset = Math.ceil(this.panel.nativeElement.clientWidth / 2);
|
||||
let selected: any;
|
||||
|
||||
for (let _i = 0; _i < this.panel.nativeElement.children.length; _i++) {
|
||||
const proc = this.panel.nativeElement.children[_i];
|
||||
if (proc.id === this.selectedProcessId) {
|
||||
selected = proc;
|
||||
this.selectedProcess = proc;
|
||||
}
|
||||
}
|
||||
|
||||
const lastProcess = this.panel.nativeElement.children[this.panel.nativeElement.children.length - 1];
|
||||
|
||||
if (selected) {
|
||||
const clientWidth = this.panel.nativeElement.clientWidth;
|
||||
|
||||
this.showAddingPadding = false;
|
||||
this.cdr.detectChanges();
|
||||
|
||||
const selecetedPos = selected.offsetLeft + selected.offsetWidth;
|
||||
const lastPos = lastProcess.offsetLeft + lastProcess.offsetWidth;
|
||||
|
||||
this.showFowardContainer =
|
||||
(selecetedPos + this.offset * 2 > clientWidth || selecetedPos + this.offset < lastPos) &&
|
||||
lastPos > clientWidth &&
|
||||
lastPos > this.panel.nativeElement.scrollWidth;
|
||||
|
||||
// This number is from testing > 643
|
||||
this.showBackContainer = selecetedPos > 643;
|
||||
}
|
||||
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
scrollBack() {
|
||||
const moveCalc = this.panel.nativeElement.scrollLeft - this.offset;
|
||||
this.panel.nativeElement.scrollTo({ left: moveCalc, behavior: 'smooth' });
|
||||
this.cdr.detectChanges();
|
||||
|
||||
this.showBackContainer = this.panel.nativeElement.scrollLeft - this.offset > 0;
|
||||
this.showBack = false;
|
||||
|
||||
this.showFowardContainer = this.panel.nativeElement.scrollLeft < this.panel.nativeElement.scrollWidth;
|
||||
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
scrollFoward() {
|
||||
const moveCalc = this.panel.nativeElement.scrollLeft + this.offset;
|
||||
this.panel.nativeElement.scrollTo({ left: moveCalc, behavior: 'smooth' });
|
||||
this.cdr.detectChanges();
|
||||
|
||||
this.showFowardContainer = moveCalc + this.offset * 2 < this.panel.nativeElement.scrollWidth;
|
||||
this.showNext = false;
|
||||
|
||||
// If clicked next, then back button is always there
|
||||
this.showBackContainer = true;
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
showFowardIcon() {
|
||||
this.showNext = true;
|
||||
}
|
||||
|
||||
hideFowardIcon() {
|
||||
this.showNext = false;
|
||||
}
|
||||
|
||||
showBackIcon() {
|
||||
this.showBack = true;
|
||||
}
|
||||
|
||||
hideBackIcon() {
|
||||
this.showBack = false;
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
<!-- Customer module process -->
|
||||
<div class="grid-item" id="{{ process.id }}" *ngIf="module === 0" [ngClass]="{ last: last }">
|
||||
<div class="grid-container" [ngClass]="{ 'selected-process': process.id === (currentProcessId$ | async) }">
|
||||
<div class="process-name-container pt-3" (click)="selectProcess(process)">
|
||||
<span class="process-name">{{ process.name }}</span>
|
||||
</div>
|
||||
<ng-container *ngIf="{ length: cartCount$ | async }; let cartCount">
|
||||
<div
|
||||
[class.items-in-cart]="cartCount.length > 0"
|
||||
class="cart-container"
|
||||
[ngClass]="{ download: cartBackgroundForDownload }"
|
||||
(click)="openCart(process)"
|
||||
>
|
||||
<lib-icon
|
||||
mt="12px"
|
||||
ml="15px"
|
||||
width="17px"
|
||||
height="16px"
|
||||
name="Shopping_Cart"
|
||||
*ngIf="cartCount.length === 0 && !cartBackgroundForDownload && process.id === (currentProcessId$ | async)"
|
||||
class="process-cart-icon"
|
||||
></lib-icon>
|
||||
<lib-icon
|
||||
mt="12px"
|
||||
ml="15px"
|
||||
width="17px"
|
||||
height="16px"
|
||||
name="Shopping_Cart_Inactive"
|
||||
*ngIf="cartCount.length === 0 && !cartBackgroundForDownload && process.id !== (currentProcessId$ | async)"
|
||||
class="process-cart-icon"
|
||||
></lib-icon>
|
||||
<lib-icon
|
||||
mt="12px"
|
||||
ml="15px"
|
||||
width="17px"
|
||||
height="16px"
|
||||
name="shopping_cart_white"
|
||||
*ngIf="cartCount.length > 0 || cartBackgroundForDownload"
|
||||
class="process-cart-icon"
|
||||
></lib-icon>
|
||||
<div [@cartnumber]="cartanimation" class="pt-3 process-cart-number-container">
|
||||
<span
|
||||
[class.items-in-cart]="cartCount.length > 0"
|
||||
class="process-cart-number"
|
||||
[ngClass]="{ 'number-download': cartBackgroundForDownload }"
|
||||
>{{ cartCount.length }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<div *ngIf="process.id === (currentProcessId$ | async)">
|
||||
<a (click)="openDeleteConfirmationDialog()">
|
||||
<lib-icon class="process-delete-icon" name="close" width="15px" height="15px" mt="12px"></lib-icon>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<app-process-delete-dialog #deleteporcessdialog (deleted)="deleteProcess($event)" [process]="process"></app-process-delete-dialog>
|
||||
</div>
|
||||
@@ -1,133 +0,0 @@
|
||||
@import 'variables';
|
||||
|
||||
.grid-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 42px;
|
||||
border-bottom: 3px solid #fff;
|
||||
|
||||
& > .cart-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 38px;
|
||||
background-color: #e6eff9;
|
||||
border-radius: 25px;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
bottom: 1px;
|
||||
padding-right: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.download {
|
||||
background-color: $hima-download-cart-color !important;
|
||||
}
|
||||
|
||||
.process-name-container {
|
||||
cursor: pointer;
|
||||
max-width: 100px;
|
||||
}
|
||||
|
||||
.process-name-container-branch {
|
||||
cursor: pointer;
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.process-name {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #557596;
|
||||
// opacity: 0.3;
|
||||
margin-top: 5px;
|
||||
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-right: 10px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.process-name-branch {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #596470;
|
||||
opacity: 0.3;
|
||||
margin-top: 5px;
|
||||
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-right: 10px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.process-cart-number {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #557596;
|
||||
// opacity: 0.3;
|
||||
|
||||
position: relative;
|
||||
top: 4px;
|
||||
left: 8px;
|
||||
}
|
||||
|
||||
.number-download {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
// .process-cart-icon {
|
||||
// opacity: 0.3;
|
||||
// }
|
||||
|
||||
.selected-process {
|
||||
border-bottom: 3px solid $hima-color-red;
|
||||
|
||||
.process-name {
|
||||
color: $color-active;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.process-name-branch {
|
||||
color: #596470;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.process-cart-number {
|
||||
color: $color-active;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.process-cart-icon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.process-delete-icon {
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.process-cart-icon-numbered {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.process-cart-number-container {
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
display: inline-block;
|
||||
padding-right: 30px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.last {
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.items-in-cart {
|
||||
@apply bg-active-customer !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { ProcessTabComponent } from './process-tab.component';
|
||||
|
||||
describe('ProcessTabComponent', () => {
|
||||
let component: ProcessTabComponent;
|
||||
let fixture: ComponentFixture<ProcessTabComponent>;
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ProcessTabComponent],
|
||||
}).compileComponents();
|
||||
})
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProcessTabComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user