mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Compare commits
357 Commits
feature/rd
...
feature/39
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
967df6316b | ||
|
|
b440ddbe82 | ||
|
|
878bf44d0b | ||
|
|
d6e0d92132 | ||
|
|
da6489eb7a | ||
|
|
819827cc4c | ||
|
|
d09b5b1ce7 | ||
|
|
cc03ef4f9c | ||
|
|
b4dbd8889d | ||
|
|
483faad86a | ||
|
|
0dbc745ed0 | ||
|
|
180e93a7da | ||
|
|
5c6f416391 | ||
|
|
d97b6afac8 | ||
|
|
771816f3af | ||
|
|
0626538aea | ||
|
|
a1ad4e4a05 | ||
|
|
6df48eb555 | ||
|
|
27ab4526e2 | ||
|
|
9a24b34fbc | ||
|
|
d01e01534b | ||
|
|
5bca1f2a81 | ||
|
|
807b300885 | ||
|
|
b16ffa4352 | ||
|
|
da79d04ef4 | ||
|
|
cf619df576 | ||
|
|
8054c96315 | ||
|
|
2363f424f5 | ||
|
|
6ab1ea2e70 | ||
|
|
c9ce7d6762 | ||
|
|
6ee1b0a7f8 | ||
|
|
d881920312 | ||
|
|
516465db37 | ||
|
|
08e95cec55 | ||
|
|
9671683a93 | ||
|
|
d909d6e804 | ||
|
|
15c50779b4 | ||
|
|
1d865c47d7 | ||
|
|
5bdfec7c3f | ||
|
|
6b0beba1d9 | ||
|
|
8aafee672e | ||
|
|
9d886cd33f | ||
|
|
95d1ea3530 | ||
|
|
d3014e7e9a | ||
|
|
da143c3412 | ||
|
|
b10a7a923e | ||
|
|
08601203df | ||
|
|
526ba9f2a0 | ||
|
|
f1fc1d17a5 | ||
|
|
6e07c86eed | ||
|
|
14199391e0 | ||
|
|
bb834f6274 | ||
|
|
8688935f25 | ||
|
|
1b7d257e97 | ||
|
|
fff4b222cb | ||
|
|
c63dee8509 | ||
|
|
810653c4d1 | ||
|
|
607bc320fb | ||
|
|
72393ebca5 | ||
|
|
ecef17846b | ||
|
|
45265eedd4 | ||
|
|
04da34e677 | ||
|
|
1e504d9e0c | ||
|
|
75528d37d3 | ||
|
|
eddff0d93f | ||
|
|
f4579ef8dc | ||
|
|
fc5496fda6 | ||
|
|
5cf6f4da38 | ||
|
|
60fde8b103 | ||
|
|
734fe33f40 | ||
|
|
64da928c36 | ||
|
|
dba0b1b3c7 | ||
|
|
073746a9bc | ||
|
|
45c14e3b79 | ||
|
|
7023fe747b | ||
|
|
141c7fe1d6 | ||
|
|
44b406fad4 | ||
|
|
78e76818b5 | ||
|
|
f78a773fab | ||
|
|
60d007d9eb | ||
|
|
1ec253333e | ||
|
|
bd332b6bd9 | ||
|
|
bc9bdbebe3 | ||
|
|
0b471cc5bc | ||
|
|
c2eed61b83 | ||
|
|
2d403b4c56 | ||
|
|
b3e4ca90ee | ||
|
|
d4a3a4bc06 | ||
|
|
b674b5faf6 | ||
|
|
8416028113 | ||
|
|
edb21308d4 | ||
|
|
26ad0153d8 | ||
|
|
e9b2acca5b | ||
|
|
4180ee61d6 | ||
|
|
a442a50708 | ||
|
|
59e650a1f1 | ||
|
|
69b6470cda | ||
|
|
44b33c1e4c | ||
|
|
08f00c6578 | ||
|
|
51c4066222 | ||
|
|
6fb72e4b2f | ||
|
|
c9fbbd78a8 | ||
|
|
ce5388be61 | ||
|
|
02d60e9bd5 | ||
|
|
fce50daff6 | ||
|
|
35b7f5700f | ||
|
|
b954947bb7 | ||
|
|
ddd5d50c5d | ||
|
|
efec7ecb26 | ||
|
|
ee81f795fe | ||
|
|
ad557ff919 | ||
|
|
bf5fae08b2 | ||
|
|
88321928bf | ||
|
|
a7d50a9439 | ||
|
|
4c6dcd15da | ||
|
|
84f9d14be0 | ||
|
|
e2f173f250 | ||
|
|
fdd9617604 | ||
|
|
bc3cedfe50 | ||
|
|
78f9093931 | ||
|
|
a889c768d1 | ||
|
|
e36319a73e | ||
|
|
199ae95bcd | ||
|
|
30875f0491 | ||
|
|
95d9d17aa7 | ||
|
|
215d7ca341 | ||
|
|
1255df10e0 | ||
|
|
4c641adeda | ||
|
|
4bd4158dab | ||
|
|
4965976f6c | ||
|
|
b43f512887 | ||
|
|
e6f2b46fce | ||
|
|
01c84b361a | ||
|
|
ac35cc237e | ||
|
|
28ad07b372 | ||
|
|
6ade77d458 | ||
|
|
4187e13861 | ||
|
|
4fe5034e1c | ||
|
|
729451fa48 | ||
|
|
d77fe8c540 | ||
|
|
a257ddd8e0 | ||
|
|
90154bd497 | ||
|
|
f96224569f | ||
|
|
1c695104f9 | ||
|
|
ab9a35dd89 | ||
|
|
6daa96119d | ||
|
|
128a280dee | ||
|
|
475c885344 | ||
|
|
ee62649bf6 | ||
|
|
109999d66f | ||
|
|
9ec34b07c4 | ||
|
|
2fd2d701dd | ||
|
|
5574252b5b | ||
|
|
5e79d4dc52 | ||
|
|
bb91782079 | ||
|
|
2bbcb15740 | ||
|
|
216d302a86 | ||
|
|
e18b9a4200 | ||
|
|
310395d166 | ||
|
|
651f44914f | ||
|
|
4a97800a05 | ||
|
|
f2e124903c | ||
|
|
eec1cb5666 | ||
|
|
cb7334d63b | ||
|
|
b62e6e8e35 | ||
|
|
f98aac5231 | ||
|
|
9c4e94ce8d | ||
|
|
65a19feffc | ||
|
|
62a1be7abe | ||
|
|
ad4481cfc7 | ||
|
|
e4c20b953d | ||
|
|
e8044fae1b | ||
|
|
b845147050 | ||
|
|
c4818319aa | ||
|
|
6bc265a358 | ||
|
|
8cb25d6ca1 | ||
|
|
5a14e0afbd | ||
|
|
0804eeeccb | ||
|
|
f015169011 | ||
|
|
201ea2ee9c | ||
|
|
961211e638 | ||
|
|
22a494e31e | ||
|
|
75e24771b3 | ||
|
|
97b30d5b14 | ||
|
|
ca5dbb9d6f | ||
|
|
e065c1a8da | ||
|
|
fc76f34d38 | ||
|
|
98e963d782 | ||
|
|
27e5afacde | ||
|
|
8a4fe7aedd | ||
|
|
90268b4ec1 | ||
|
|
034693df98 | ||
|
|
5b31661f8d | ||
|
|
ba01807add | ||
|
|
3b89777648 | ||
|
|
bb510788eb | ||
|
|
d48b59b374 | ||
|
|
7d72fc56db | ||
|
|
90edb7dd7e | ||
|
|
7ee0c4d145 | ||
|
|
67f2ff54be | ||
|
|
1b85c8ff50 | ||
|
|
f0470d3faa | ||
|
|
4d5e81a638 | ||
|
|
7676ae8143 | ||
|
|
fb97db99b0 | ||
|
|
92aad95603 | ||
|
|
513cef2a66 | ||
|
|
bdf3bbc530 | ||
|
|
9a17f95026 | ||
|
|
e6b44d8365 | ||
|
|
874f8f4758 | ||
|
|
47baf2fa89 | ||
|
|
57bfc523ab | ||
|
|
23edea5fa4 | ||
|
|
7b12857a35 | ||
|
|
d6d919ed52 | ||
|
|
330c59f7e9 | ||
|
|
600687f652 | ||
|
|
0c65e9dace | ||
|
|
ed144f0a15 | ||
|
|
c0c2cc86d3 | ||
|
|
9b8ea11866 | ||
|
|
17aed38316 | ||
|
|
48a7cc4dd4 | ||
|
|
4417fd9f0d | ||
|
|
3e429cb261 | ||
|
|
48e30e795f | ||
|
|
953e528298 | ||
|
|
4276f427b9 | ||
|
|
4b2bfefc9b | ||
|
|
11e79c4830 | ||
|
|
264d914044 | ||
|
|
12f1e7c3af | ||
|
|
9eb4fbab65 | ||
|
|
8d1a63e47f | ||
|
|
e449e612c1 | ||
|
|
6ba65f031b | ||
|
|
f31ac4c2e3 | ||
|
|
f980f5aaf9 | ||
|
|
45989d7abd | ||
|
|
87a1e8a2c4 | ||
|
|
ae27da1127 | ||
|
|
ca21931d93 | ||
|
|
5bb9ebd6ec | ||
|
|
45ab1e9cc5 | ||
|
|
8d2685a8c3 | ||
|
|
d38c41a99d | ||
|
|
ff3dacde39 | ||
|
|
5c9f4c5b21 | ||
|
|
c134f645ef | ||
|
|
6f0933a350 | ||
|
|
c9a90211ee | ||
|
|
95d96dd295 | ||
|
|
86bf079f6f | ||
|
|
c202490555 | ||
|
|
da0100dd35 | ||
|
|
b634247463 | ||
|
|
84df6493f6 | ||
|
|
90b752e185 | ||
|
|
d3858c731c | ||
|
|
f247ac641c | ||
|
|
be1a9e8f7e | ||
|
|
d86f595b1f | ||
|
|
3ed9227508 | ||
|
|
74bf2133c6 | ||
|
|
e4570946c4 | ||
|
|
a8213d79fd | ||
|
|
13ec323ac4 | ||
|
|
9cfe8176d4 | ||
|
|
c544cebba9 | ||
|
|
74dffe8af2 | ||
|
|
3999b8f623 | ||
|
|
9d3bb9dcf3 | ||
|
|
05e58aa060 | ||
|
|
f74d14d573 | ||
|
|
741e651a20 | ||
|
|
4e1bd89378 | ||
|
|
c8f54b8be5 | ||
|
|
413d2f5178 | ||
|
|
503f44891f | ||
|
|
35c2a6a046 | ||
|
|
5bf326f680 | ||
|
|
1df201525c | ||
|
|
e7793b15e3 | ||
|
|
d2e16ca256 | ||
|
|
31164befc9 | ||
|
|
8f4dfa0674 | ||
|
|
eb7a01907a | ||
|
|
fb1fd1ec7c | ||
|
|
7528c7df63 | ||
|
|
e6ca19ab91 | ||
|
|
dc3e097dfd | ||
|
|
a5e8c06dda | ||
|
|
bf7fd13ef2 | ||
|
|
a424e015b4 | ||
|
|
c67fef64fe | ||
|
|
12055de1fc | ||
|
|
a2ad2f8c0b | ||
|
|
af7cebda66 | ||
|
|
2230cf2e7b | ||
|
|
aa048e8d22 | ||
|
|
4961fb9756 | ||
|
|
6801e3858a | ||
|
|
ef72dcf554 | ||
|
|
c228147c00 | ||
|
|
266358f0cc | ||
|
|
6717f0ee3d | ||
|
|
8880ed0df6 | ||
|
|
4b56b973c8 | ||
|
|
28a00b9f22 | ||
|
|
b1fe692de5 | ||
|
|
08b2f6cbc9 | ||
|
|
10e1db388f | ||
|
|
cd7f71b968 | ||
|
|
395fd544e5 | ||
|
|
2c10d6bf10 | ||
|
|
9361a631dd | ||
|
|
59c5abfd93 | ||
|
|
633c23a6f0 | ||
|
|
779e7323e2 | ||
|
|
6e7fbd940b | ||
|
|
6878b608fc | ||
|
|
a4fab8b64e | ||
|
|
21c0cc8794 | ||
|
|
7ea11ea0c4 | ||
|
|
d2c307b08a | ||
|
|
4dc98f7980 | ||
|
|
c89ee18db3 | ||
|
|
c4aa7999a6 | ||
|
|
778343f636 | ||
|
|
d2fb3b6c85 | ||
|
|
a8bfedcd5d | ||
|
|
4c7b5eec38 | ||
|
|
35068e23cd | ||
|
|
bc30b86cce | ||
|
|
461f166e33 | ||
|
|
628dbd5227 | ||
|
|
c05b290e49 | ||
|
|
696015b6a4 | ||
|
|
f2f70e1d83 | ||
|
|
b4d967f721 | ||
|
|
bf760677ef | ||
|
|
4d1dbaa2f3 | ||
|
|
595bb27d99 | ||
|
|
ad95faffa7 | ||
|
|
a0eb3c0459 | ||
|
|
fea435a6d2 | ||
|
|
7b72532c9e | ||
|
|
ea9920c4d5 | ||
|
|
6b756fe893 | ||
|
|
54c7f51766 | ||
|
|
94b787655e | ||
|
|
259d0f1648 | ||
|
|
872d3ff383 | ||
|
|
cf1c4d37b9 | ||
|
|
d68055f8a9 |
@@ -1504,5 +1504,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": false
|
||||
}
|
||||
}
|
||||
@@ -11,13 +11,10 @@ export class DevScanAdapter implements ScanAdapter {
|
||||
constructor(private _modal: UiModalService, private _environmentService: EnvironmentService) {}
|
||||
|
||||
async init(): Promise<boolean> {
|
||||
if (this._environmentService.isTablet()) {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(isDevMode());
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
return Promise.resolve(false);
|
||||
// return new Promise((resolve, reject) => {
|
||||
// resolve(isDevMode());
|
||||
// });
|
||||
}
|
||||
|
||||
scan(): Observable<string> {
|
||||
|
||||
@@ -14,7 +14,6 @@ export class ScanAdapterService {
|
||||
async init(): Promise<void> {
|
||||
for (const adapter of this.scanAdapters) {
|
||||
const isReady = await adapter.init();
|
||||
console.log('ScanAdapterService.init', adapter.name, isReady);
|
||||
this._readyAdapters[adapter.name] = isReady;
|
||||
}
|
||||
}
|
||||
@@ -24,42 +23,30 @@ export class ScanAdapterService {
|
||||
}
|
||||
|
||||
getAdapter(name: string): ScanAdapter | undefined {
|
||||
return this.scanAdapters.find((adapter) => adapter.name === name);
|
||||
return this._readyAdapters[name] && this.scanAdapters.find((adapter) => adapter.name === name);
|
||||
}
|
||||
|
||||
// return true if at least one adapter is ready
|
||||
isReady(): boolean {
|
||||
return Object.values(this._readyAdapters).some((ready) => ready);
|
||||
}
|
||||
|
||||
scan(ops: { use?: string; include?: string[]; exclude?: string[] } = { exclude: ['Dev'] }): Observable<string> {
|
||||
scan(): Observable<string> {
|
||||
const adapterOrder = ['Native', 'Scandit', 'Dev'];
|
||||
|
||||
let adapter: ScanAdapter;
|
||||
|
||||
if (ops.use == undefined) {
|
||||
// get the first adapter that is ready to use
|
||||
adapter = this.scanAdapters
|
||||
.filter((adapter) => {
|
||||
if (ops.include?.length) {
|
||||
return ops.include.includes(adapter.name);
|
||||
} else if (ops.exclude?.length) {
|
||||
return !ops.exclude.includes(adapter.name);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
})
|
||||
.find((adapter) => this._readyAdapters[adapter.name]);
|
||||
} else {
|
||||
adapter = this.getAdapter(ops.use);
|
||||
for (const name of adapterOrder) {
|
||||
adapter = this.getAdapter(name);
|
||||
|
||||
if (adapter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!adapter) {
|
||||
return throwError('No adapter found');
|
||||
}
|
||||
|
||||
if (this._readyAdapters[adapter.name] == false) {
|
||||
return throwError('Adapter is not ready');
|
||||
}
|
||||
|
||||
return adapter.scan();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ import { NgModule } from '@angular/core';
|
||||
import { ProductImagePipe } from './product-image.pipe';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ProductImagePipe],
|
||||
imports: [],
|
||||
declarations: [],
|
||||
imports: [ProductImagePipe],
|
||||
exports: [ProductImagePipe],
|
||||
})
|
||||
export class ProductImageModule {}
|
||||
|
||||
@@ -3,6 +3,8 @@ import { ProductImageService } from './product-image.service';
|
||||
|
||||
@Pipe({
|
||||
name: 'productImage',
|
||||
standalone: true,
|
||||
pure: true,
|
||||
})
|
||||
export class ProductImagePipe implements PipeTransform {
|
||||
constructor(private imageService: ProductImageService) {}
|
||||
|
||||
@@ -31,14 +31,8 @@ export class ApplicationService {
|
||||
return this.activatedProcessIdSubject.asObservable();
|
||||
}
|
||||
|
||||
title$ = this.store.select(selectTitle);
|
||||
|
||||
constructor(private store: Store) {}
|
||||
|
||||
setTitle(title: string) {
|
||||
this.store.dispatch(setTitle({ title }));
|
||||
}
|
||||
|
||||
getProcesses$(section?: 'customer' | 'branch') {
|
||||
const processes$ = this.store.select(selectProcesses);
|
||||
return processes$.pipe(map((processes) => processes.filter((process) => (section ? process.section === section : true))));
|
||||
@@ -52,6 +46,14 @@ export class ApplicationService {
|
||||
return this.store.select(selectSection);
|
||||
}
|
||||
|
||||
getTitle$() {
|
||||
return this.getSection$().pipe(
|
||||
map((section) => {
|
||||
return section === 'customer' ? 'Kundenbereich' : 'Filialbereich';
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
getActivatedProcessId$() {
|
||||
return this.store.select(selectActivatedProcess).pipe(map((process) => process?.id));
|
||||
|
||||
@@ -138,6 +138,6 @@ export class BreadcrumbService {
|
||||
getLatestBreadcrumbForSection(section: 'customer' | 'branch', predicate: (crumb: Breadcrumb) => boolean = (_) => true) {
|
||||
return this.store
|
||||
.select(selectors.selectBreadcrumbsBySection, { section })
|
||||
.pipe(map((crumbs) => crumbs.sort((a, b) => b.changed - a.changed).find((f) => predicate(f))));
|
||||
.pipe(map((crumbs) => crumbs.sort((a, b) => b.timestamp - a.timestamp).find((f) => predicate(f))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ export interface Breadcrumb {
|
||||
/**
|
||||
* Url
|
||||
*/
|
||||
path: string;
|
||||
path: string | any[];
|
||||
|
||||
/**
|
||||
* Query Parameter
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { CommandService } from './command.service';
|
||||
|
||||
export abstract class ActionHandler<T = any> {
|
||||
constructor(readonly action: string) {}
|
||||
abstract handler(data: T): Promise<T>;
|
||||
abstract handler(data: T, service?: CommandService): Promise<T>;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { ModuleWithProviders, NgModule, Type } from '@angular/core';
|
||||
import { ModuleWithProviders, NgModule, Provider, Type } from '@angular/core';
|
||||
import { ActionHandler } from './action-handler.interface';
|
||||
import { CommandService } from './command.service';
|
||||
import { FEATURE_ACTION_HANDLERS, ROOT_ACTION_HANDLERS } from './tokens';
|
||||
|
||||
export function provideActionHandlers(actionHandlers: Type<ActionHandler>[]): Provider[] {
|
||||
return [CommandService, actionHandlers.map((handler) => ({ provide: FEATURE_ACTION_HANDLERS, useClass: handler, multi: true }))];
|
||||
}
|
||||
|
||||
@NgModule({})
|
||||
export class CoreCommandModule {
|
||||
static forRoot(actionHandlers: Type<ActionHandler>[]): ModuleWithProviders<CoreCommandModule> {
|
||||
|
||||
@@ -16,7 +16,7 @@ export class CommandService {
|
||||
throw new Error('Action Handler does not exist');
|
||||
}
|
||||
|
||||
data = await handler.handler(data);
|
||||
data = await handler.handler(data, this);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -1,17 +1,77 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Platform } from '@angular/cdk/platform';
|
||||
import { NativeContainerService } from 'native-container';
|
||||
import { BreakpointObserver } from '@angular/cdk/layout';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
const MATCH_TABLET = '(max-width: 1023px)';
|
||||
|
||||
const MATCH_DESKTOP_SMALL = '(min-width: 1024px) and (max-width: 1439px)';
|
||||
|
||||
const MATCH_DESKTOP = '(min-width: 1280px)';
|
||||
|
||||
const MATCH_DESKTOP_LARGE = '(min-width: 1440px)';
|
||||
|
||||
const MATCH_DESKTOP_XLARGE = '(min-width: 1920px)';
|
||||
|
||||
const MATCH_DESKTOP_XXLARGE = '(min-width: 2736px)';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class EnvironmentService {
|
||||
constructor(private _platform: Platform, private _nativeContainer: NativeContainerService) {}
|
||||
constructor(
|
||||
private _platform: Platform,
|
||||
private _nativeContainer: NativeContainerService,
|
||||
private _breakpointObserver: BreakpointObserver
|
||||
) {}
|
||||
|
||||
matchTablet(): boolean {
|
||||
return this._breakpointObserver.isMatched(MATCH_TABLET);
|
||||
}
|
||||
|
||||
matchTablet$ = this._breakpointObserver.observe(MATCH_TABLET).pipe(map((result) => result.matches));
|
||||
|
||||
matchDesktopSmall(): boolean {
|
||||
return this._breakpointObserver.isMatched(MATCH_DESKTOP_SMALL);
|
||||
}
|
||||
|
||||
matchDesktopSmall$ = this._breakpointObserver.observe(MATCH_DESKTOP_SMALL).pipe(map((result) => result.matches));
|
||||
|
||||
matchDesktop(): boolean {
|
||||
return this._breakpointObserver.isMatched(MATCH_DESKTOP);
|
||||
}
|
||||
|
||||
matchDesktop$ = this._breakpointObserver.observe(MATCH_DESKTOP).pipe(map((result) => result.matches));
|
||||
|
||||
matchDesktopLarge(): boolean {
|
||||
return this._breakpointObserver.isMatched(MATCH_DESKTOP_LARGE);
|
||||
}
|
||||
|
||||
matchDesktopLarge$ = this._breakpointObserver.observe(MATCH_DESKTOP_LARGE).pipe(map((result) => result.matches));
|
||||
|
||||
matchDesktopXLarge(): boolean {
|
||||
return this._breakpointObserver.isMatched(MATCH_DESKTOP_XLARGE);
|
||||
}
|
||||
|
||||
matchDesktopXLarge$ = this._breakpointObserver.observe(MATCH_DESKTOP_XLARGE).pipe(map((result) => result.matches));
|
||||
|
||||
matchDesktopXXLarge(): boolean {
|
||||
return this._breakpointObserver.isMatched(MATCH_DESKTOP_XXLARGE);
|
||||
}
|
||||
|
||||
matchDesktopXXLarge$ = this._breakpointObserver.observe(MATCH_DESKTOP_XXLARGE).pipe(map((result) => result.matches));
|
||||
|
||||
/**
|
||||
* @deprecated Use `matchDesktopSmall` or 'matchDesktop' instead.
|
||||
*/
|
||||
isDesktop(): boolean {
|
||||
return !this.isTablet();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `matchTablet` instead.
|
||||
*/
|
||||
isTablet(): boolean {
|
||||
return this.isNative() || this.isSafari();
|
||||
}
|
||||
@@ -21,6 +81,6 @@ export class EnvironmentService {
|
||||
}
|
||||
|
||||
isSafari(): boolean {
|
||||
return (this._platform.ANDROID || this._platform.IOS) && this._platform.SAFARI;
|
||||
return this._platform.IOS && this._platform.SAFARI;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { AnimationTriggerMetadata, trigger, state, transition, style, animate } from '@angular/animations';
|
||||
|
||||
export const slideAnimationTime = 150;
|
||||
export const toastAnimations: {
|
||||
readonly slideToast: AnimationTriggerMetadata;
|
||||
} = {
|
||||
slideToast: trigger('slideAnimation', [
|
||||
state('default', style({ transform: 'translateY(0%)' })),
|
||||
transition('void => *', [style({ transform: 'translateY(-100%)' }), animate(`${slideAnimationTime}ms ease-in`)]),
|
||||
transition('default => closing', animate(`${slideAnimationTime}ms ease-in`, style({ transform: 'translateY(-100%)' }))),
|
||||
]),
|
||||
};
|
||||
|
||||
export type ToastAnimationState = 'default' | 'closing';
|
||||
@@ -1,4 +0,0 @@
|
||||
// start:ng42.barrel
|
||||
export * from './toast';
|
||||
export * from './toast-ref';
|
||||
// end:ng42.barrel
|
||||
@@ -1,17 +0,0 @@
|
||||
import { OverlayRef } from '@angular/cdk/overlay';
|
||||
|
||||
export class ToastRef {
|
||||
constructor(private readonly _overlay: OverlayRef) {}
|
||||
|
||||
close() {
|
||||
this._overlay.dispose();
|
||||
}
|
||||
|
||||
isVisible() {
|
||||
return this._overlay && this._overlay.overlayElement;
|
||||
}
|
||||
|
||||
getPosition() {
|
||||
return this._overlay.overlayElement.getBoundingClientRect();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import { TemplateRef } from '@angular/core';
|
||||
|
||||
export interface Toast {
|
||||
title?: string;
|
||||
text?: string;
|
||||
timer?: number;
|
||||
position?: 'top-left' | 'top' | 'top-right' | 'bottom-right' | 'bottom' | 'bottom-left';
|
||||
size?: 'width-full' | 'content';
|
||||
template?: TemplateRef<any>; // For rendering dynamic content
|
||||
templateContext?: {}; // For rendering dynamic content
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
// start:ng42.barrel
|
||||
export * from './toast.component';
|
||||
export * from './toast.module';
|
||||
export * from './toast.service';
|
||||
export * from './defs';
|
||||
export * from './animation';
|
||||
export * from './tokens';
|
||||
// end:ng42.barrel
|
||||
@@ -1,15 +0,0 @@
|
||||
<div class="toast-main" [style.width]="width" [@slideAnimation]="{ value: animationState }" (@slideAnimation.done)="onSlideFinished()">
|
||||
<button class="absolute top-2 right-2 p-6 border-none bg-transparent" (click)="close()">
|
||||
<ui-icon icon="close" size="20px"></ui-icon>
|
||||
</button>
|
||||
<div class="toast-content flex flex-col justify-center items-center">
|
||||
<h1 class="text-card-sub font-bold text-center py-3 whitespace-pre-wrap">{{ data.title }}</h1>
|
||||
<ng-container *ngIf="data.text; else templateRef">
|
||||
<p class="block text-base overflow-y-hidden pb-3 text-center overflow-x-hidden">{{ data.text }}</p>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #templateRef>
|
||||
<ng-container *ngTemplateOutlet="data.template; context: data.templateContext"> </ng-container>
|
||||
</ng-template>
|
||||
@@ -1,12 +0,0 @@
|
||||
.toast-main {
|
||||
@apply block relative mx-auto box-border text-white p-4;
|
||||
background-color: var(--toast-background);
|
||||
min-width: 18.75rem;
|
||||
max-width: calc(100vw - 2rem);
|
||||
min-height: 5rem;
|
||||
border-radius: 25px;
|
||||
}
|
||||
|
||||
.toast-content {
|
||||
min-height: 3rem;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnDestroy, OnInit } from '@angular/core';
|
||||
import { toastAnimations, ToastAnimationState, slideAnimationTime } from './animation';
|
||||
import { Toast, ToastRef } from './defs';
|
||||
import { TOAST_CONFIG_TOKEN } from './tokens';
|
||||
|
||||
@Component({
|
||||
selector: 'lib-toast',
|
||||
templateUrl: 'toast.component.html',
|
||||
styleUrls: ['toast.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
animations: [toastAnimations.slideToast],
|
||||
})
|
||||
export class ToastComponent implements OnInit, OnDestroy {
|
||||
timeoutRef?: any;
|
||||
animationState: ToastAnimationState = 'default';
|
||||
width = '55.25rem';
|
||||
|
||||
constructor(
|
||||
@Inject(TOAST_CONFIG_TOKEN) public readonly data: Toast,
|
||||
private readonly _ref: ToastRef,
|
||||
private readonly _cdr: ChangeDetectorRef
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.data?.size) {
|
||||
this.width = this.data?.size === 'width-full' ? '100vw' : '55.25rem';
|
||||
}
|
||||
|
||||
this.timeoutRef = setTimeout(() => {
|
||||
this.close();
|
||||
this._cdr.markForCheck();
|
||||
}, slideAnimationTime + (this.data.timer ?? 5000));
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
clearTimeout(this.timeoutRef);
|
||||
}
|
||||
|
||||
close() {
|
||||
this.animationState = 'closing';
|
||||
}
|
||||
|
||||
onSlideFinished() {
|
||||
if (this.animationState === 'closing') {
|
||||
this._ref.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import { OverlayModule } from '@angular/cdk/overlay';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { ToastComponent } from './toast.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ToastComponent],
|
||||
imports: [CommonModule, OverlayModule, UiIconModule],
|
||||
exports: [ToastComponent],
|
||||
})
|
||||
export class ToastModule {}
|
||||
@@ -1,79 +0,0 @@
|
||||
import { Overlay } from '@angular/cdk/overlay';
|
||||
import { ComponentPortal } from '@angular/cdk/portal';
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { Toast, ToastRef } from './defs';
|
||||
import { ToastComponent } from './toast.component';
|
||||
import { TOAST_CONFIG_TOKEN } from './tokens';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ToastService {
|
||||
private _lastToastRef: ToastRef;
|
||||
|
||||
get lastToastRef() {
|
||||
return this._lastToastRef;
|
||||
}
|
||||
|
||||
set lastToastRef(toastRef: ToastRef) {
|
||||
this._lastToastRef = toastRef;
|
||||
}
|
||||
|
||||
constructor(private readonly _overlay: Overlay, private readonly _injector: Injector) {}
|
||||
|
||||
create(data: Toast) {
|
||||
const positionStrategy = this.getPositionStrategy(data);
|
||||
const overlayRef = this._overlay.create({ positionStrategy });
|
||||
|
||||
this.lastToastRef = new ToastRef(overlayRef);
|
||||
const injector = this.getInjector(data, this.lastToastRef);
|
||||
|
||||
const toastPortal = new ComponentPortal(ToastComponent, null, injector);
|
||||
overlayRef.attach(toastPortal);
|
||||
|
||||
return this.lastToastRef;
|
||||
}
|
||||
|
||||
getInjector(data: Toast, ref: ToastRef) {
|
||||
return Injector.create({
|
||||
parent: this._injector,
|
||||
providers: [
|
||||
{ provide: TOAST_CONFIG_TOKEN, useValue: data },
|
||||
{ provide: ToastRef, useValue: ref },
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
getPositionStrategy(data: Toast) {
|
||||
switch (data?.position) {
|
||||
case 'top':
|
||||
return this._overlay.position().global().top(this.getNextPosition()).centerHorizontally();
|
||||
case 'top-left':
|
||||
return this._overlay.position().global().top(this.getNextPosition()).left('1rem');
|
||||
case 'top-right':
|
||||
return this._overlay.position().global().top(this.getNextPosition()).right('1rem');
|
||||
case 'bottom':
|
||||
return this._overlay.position().global().bottom(this.getNextPosition(true)).centerHorizontally();
|
||||
case 'bottom-left':
|
||||
return this._overlay.position().global().bottom(this.getNextPosition(true)).left('1rem');
|
||||
case 'bottom-right':
|
||||
return this._overlay.position().global().bottom(this.getNextPosition(true)).right('1rem');
|
||||
default:
|
||||
return this._overlay.position().global().top(this.getNextPosition()).centerHorizontally();
|
||||
}
|
||||
}
|
||||
|
||||
getNextPosition(fromBottom?: boolean) {
|
||||
const lastToastIsVisible = this.lastToastRef && this.lastToastRef.isVisible();
|
||||
|
||||
let position = fromBottom ? 6 : 9;
|
||||
|
||||
if (lastToastIsVisible && fromBottom) {
|
||||
position = (window.innerHeight - this.lastToastRef.getPosition().bottom + this.lastToastRef.getPosition().height + 16) / 16;
|
||||
} else if (lastToastIsVisible) {
|
||||
position = (this.lastToastRef.getPosition().bottom + 16) / 16;
|
||||
}
|
||||
|
||||
return position + 'rem';
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
import { InjectionToken } from '@angular/core';
|
||||
import { Toast } from './defs';
|
||||
|
||||
export const TOAST_CONFIG_TOKEN = new InjectionToken<Toast>('TOAST_DATA');
|
||||
@@ -1,5 +0,0 @@
|
||||
/*
|
||||
* Public API Surface of toast
|
||||
*/
|
||||
|
||||
export * from './lib';
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
StoreCheckoutSupplierService,
|
||||
SupplierDTO,
|
||||
} from '@swagger/checkout';
|
||||
import { combineLatest, Observable, of } from 'rxjs';
|
||||
import { BehaviorSubject, combineLatest, Observable, of } from 'rxjs';
|
||||
import {
|
||||
AvailabilityRequestDTO,
|
||||
AvailabilityService,
|
||||
@@ -21,11 +21,16 @@ import { isArray, memorize } from '@utils/common';
|
||||
import { LogisticianDTO, LogisticianService } from '@swagger/oms';
|
||||
import { ResponseArgsOfIEnumerableOfStockInfoDTO, StockDTO, StockInfoDTO, StockService } from '@swagger/remi';
|
||||
import { PriceDTO } from '@swagger/availability';
|
||||
import { AvailabilityByBranchDTO, ItemData } from './defs';
|
||||
import { AvailabilityByBranchDTO, ItemData, Ssc } from './defs';
|
||||
import { Availability } from './defs/availability';
|
||||
import { isEmpty } from 'lodash';
|
||||
|
||||
@Injectable()
|
||||
export class DomainAvailabilityService {
|
||||
// Ticket #3378 Keep Result List Items and Details Page SSC in sync
|
||||
sscs$ = new BehaviorSubject<Array<Ssc>>([]);
|
||||
sscsObs$ = this.sscs$.asObservable();
|
||||
|
||||
constructor(
|
||||
private _availabilityService: AvailabilityService,
|
||||
private _logisticanService: LogisticianService,
|
||||
@@ -145,6 +150,7 @@ export class DomainAvailabilityService {
|
||||
);
|
||||
}
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getTakeAwayAvailability({
|
||||
item,
|
||||
quantity,
|
||||
@@ -165,7 +171,7 @@ export class DomainAvailabilityService {
|
||||
),
|
||||
map(([response, supplier, defaultBranch]) => {
|
||||
const price = item?.price;
|
||||
return this._mapToTakeAwayAvailability({ response, supplier, branchId: branch.id ?? defaultBranch.id, quantity, price });
|
||||
return this._mapToTakeAwayAvailability({ response, supplier, branchId: branch?.id ?? defaultBranch?.id, quantity, price });
|
||||
}),
|
||||
shareReplay(1)
|
||||
);
|
||||
@@ -478,6 +484,10 @@ export class DomainAvailabilityService {
|
||||
};
|
||||
}
|
||||
|
||||
private _priceIsEmpty(price: PriceDTO) {
|
||||
return isEmpty(price?.value) || isEmpty(price?.vat);
|
||||
}
|
||||
|
||||
private _mapToTakeAwayAvailability({
|
||||
response,
|
||||
supplier,
|
||||
@@ -498,7 +508,7 @@ export class DomainAvailabilityService {
|
||||
inStock: inStock,
|
||||
supplierSSC: quantity <= inStock ? '999' : '',
|
||||
supplierSSCText: quantity <= inStock ? 'Filialentnahme' : '',
|
||||
price: price ?? stockInfo?.retailPrice,
|
||||
price: this._priceIsEmpty(price) ? stockInfo?.retailPrice : price,
|
||||
supplier: { id: supplier?.id },
|
||||
// TODO: Change after API Update
|
||||
// LH: 2021-03-09 preis Property hat nun ein Fallback auf retailPrice
|
||||
@@ -540,6 +550,7 @@ export class DomainAvailabilityService {
|
||||
return preferred.map((p) => {
|
||||
return [
|
||||
{
|
||||
orderDeadline: p?.orderDeadline,
|
||||
availabilityType: p?.status,
|
||||
ssc: p?.ssc,
|
||||
sscText: p?.sscText,
|
||||
@@ -561,7 +572,6 @@ export class DomainAvailabilityService {
|
||||
|
||||
private _mapToShippingAvailability(availabilities: SwaggerAvailabilityDTO[]) {
|
||||
const preferred = availabilities.filter((f) => f.preferred === 1);
|
||||
|
||||
return preferred.map((p) => {
|
||||
return {
|
||||
availabilityType: p?.status,
|
||||
@@ -575,6 +585,7 @@ export class DomainAvailabilityService {
|
||||
supplierInfo: p?.requestStatusCode,
|
||||
lastRequest: p?.requested,
|
||||
itemId: p.itemId,
|
||||
priceMaintained: p.priceMaintained,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './availability-by-branch-dto';
|
||||
export * from './availability';
|
||||
export * from './item-data';
|
||||
export * from './ssc';
|
||||
|
||||
5
apps/domain/availability/src/lib/defs/ssc.ts
Normal file
5
apps/domain/availability/src/lib/defs/ssc.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface Ssc {
|
||||
itemId?: number;
|
||||
ssc?: string;
|
||||
sscText?: string;
|
||||
}
|
||||
@@ -27,23 +27,55 @@ import {
|
||||
StoreCheckoutPayerService,
|
||||
StoreCheckoutBranchService,
|
||||
ItemsResult,
|
||||
ShoppingCartItemDTO,
|
||||
} from '@swagger/checkout';
|
||||
import { DisplayOrderDTO, DisplayOrderItemDTO, OrderCheckoutService, ReorderValues } from '@swagger/oms';
|
||||
import {
|
||||
DisplayOrderDTO,
|
||||
DisplayOrderItemDTO,
|
||||
OrderCheckoutService,
|
||||
ReorderValues,
|
||||
ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString,
|
||||
} from '@swagger/oms';
|
||||
import { isNullOrUndefined, memorize } from '@utils/common';
|
||||
import { combineLatest, Observable, of, concat, isObservable, throwError } from 'rxjs';
|
||||
import { bufferCount, catchError, filter, first, map, mergeMap, shareReplay, switchMap, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { combineLatest, Observable, of, concat, isObservable, throwError, interval, zip, EMPTY, Subscription } from 'rxjs';
|
||||
import {
|
||||
bufferCount,
|
||||
catchError,
|
||||
debounceTime,
|
||||
distinctUntilChanged,
|
||||
filter,
|
||||
first,
|
||||
map,
|
||||
mergeMap,
|
||||
share,
|
||||
shareReplay,
|
||||
switchMap,
|
||||
take,
|
||||
tap,
|
||||
withLatestFrom,
|
||||
} from 'rxjs/operators';
|
||||
|
||||
import * as DomainCheckoutSelectors from './store/domain-checkout.selectors';
|
||||
import * as DomainCheckoutActions from './store/domain-checkout.actions';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { DomainAvailabilityService, ItemData } from '@domain/availability';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { CustomerDTO, EntityDTOContainerOfAttributeDTO } from '@swagger/crm';
|
||||
import { CustomerDTO } from '@swagger/crm';
|
||||
import { Config } from '@core/config';
|
||||
import parseDuration from 'parse-duration';
|
||||
import { CheckoutEntity } from './store/defs/checkout.entity';
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
@Injectable()
|
||||
export class DomainCheckoutService {
|
||||
get olaExpiration() {
|
||||
const exp = this._config.get('@domain/checkout.olaExpiration') ?? '5m';
|
||||
return parseDuration(exp);
|
||||
}
|
||||
|
||||
constructor(
|
||||
private store: Store<any>,
|
||||
private _config: Config,
|
||||
private applicationService: ApplicationService,
|
||||
private storeCheckoutService: StoreCheckoutService,
|
||||
private orderCheckoutService: OrderCheckoutService,
|
||||
@@ -113,14 +145,14 @@ export class DomainCheckoutService {
|
||||
})
|
||||
.pipe(
|
||||
map((response) => response.result),
|
||||
tap((shoppingCart) =>
|
||||
tap((shoppingCart) => {
|
||||
this.store.dispatch(
|
||||
DomainCheckoutActions.setShoppingCart({
|
||||
processId,
|
||||
shoppingCart,
|
||||
})
|
||||
)
|
||||
),
|
||||
);
|
||||
}),
|
||||
tap((shoppingCart) => this.updateProcessCount(processId, shoppingCart?.items?.length))
|
||||
)
|
||||
)
|
||||
@@ -243,11 +275,24 @@ export class DomainCheckoutService {
|
||||
shoppingCartItemId: number;
|
||||
availability: AvailabilityDTO;
|
||||
}) {
|
||||
return this._shoppingCartService.StoreCheckoutShoppingCartUpdateShoppingCartItemAvailability({
|
||||
shoppingCartId,
|
||||
shoppingCartItemId,
|
||||
availability,
|
||||
});
|
||||
return this._shoppingCartService
|
||||
.StoreCheckoutShoppingCartUpdateShoppingCartItemAvailability({
|
||||
shoppingCartId,
|
||||
shoppingCartItemId,
|
||||
availability,
|
||||
})
|
||||
.pipe(
|
||||
map((response) => response.result),
|
||||
tap((shoppingCart) => {
|
||||
this.store.dispatch(
|
||||
DomainCheckoutActions.addShoppingCartItemAvailabilityToHistoryByShoppingCartId({
|
||||
shoppingCartId,
|
||||
availability,
|
||||
shoppingCartItemId,
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
updateItemInShoppingCart({
|
||||
@@ -259,7 +304,7 @@ export class DomainCheckoutService {
|
||||
shoppingCartItemId: number;
|
||||
update: UpdateShoppingCartItemDTO;
|
||||
}): Observable<ShoppingCartDTO> {
|
||||
return this.getShoppingCart({ processId }).pipe(
|
||||
return this.getShoppingCart({ processId, latest: true }).pipe(
|
||||
first(),
|
||||
mergeMap((shoppingCart) =>
|
||||
this._shoppingCartService
|
||||
@@ -270,8 +315,21 @@ export class DomainCheckoutService {
|
||||
})
|
||||
.pipe(
|
||||
map((response) => response.result),
|
||||
tap((shoppingCart) => this.store.dispatch(DomainCheckoutActions.setShoppingCart({ processId, shoppingCart }))),
|
||||
tap((shoppingCart) => this.updateProcessCount(processId, shoppingCart?.items?.length))
|
||||
tap((shoppingCart) => {
|
||||
this.store.dispatch(DomainCheckoutActions.setShoppingCart({ processId, shoppingCart }));
|
||||
|
||||
if (update.availability) {
|
||||
this.store.dispatch(
|
||||
DomainCheckoutActions.addShoppingCartItemAvailabilityToHistory({
|
||||
processId,
|
||||
availability: update.availability,
|
||||
shoppingCartItemId,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
this.updateProcessCount(processId, shoppingCart?.items?.length);
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
@@ -372,8 +430,9 @@ export class DomainCheckoutService {
|
||||
_setBuyer({ processId, buyer }: { processId: number; buyer: BuyerDTO }): Observable<CheckoutDTO> {
|
||||
return this.getCheckout({ processId }).pipe(
|
||||
first(),
|
||||
mergeMap((checkout) =>
|
||||
this._buyerService
|
||||
mergeMap((checkout) => {
|
||||
console.log('checkout', checkout, processId);
|
||||
return this._buyerService
|
||||
.StoreCheckoutBuyerSetBuyerPOST({
|
||||
checkoutId: checkout?.id,
|
||||
buyerDTO: buyer,
|
||||
@@ -381,8 +440,8 @@ export class DomainCheckoutService {
|
||||
.pipe(
|
||||
map((response) => response.result),
|
||||
tap((checkout) => this.store.dispatch(DomainCheckoutActions.setCheckout({ processId, checkout })))
|
||||
)
|
||||
)
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -540,6 +599,172 @@ export class DomainCheckoutService {
|
||||
);
|
||||
}
|
||||
|
||||
async refreshAvailability({
|
||||
processId,
|
||||
shoppingCartItemId,
|
||||
}: {
|
||||
processId: number;
|
||||
shoppingCartItemId: number;
|
||||
}): Promise<AvailabilityDTO> {
|
||||
const shoppingCart = await this.getShoppingCart({ processId }).pipe(first()).toPromise();
|
||||
const item = shoppingCart?.items.find((item) => item.id === shoppingCartItemId)?.data;
|
||||
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
const itemData: ItemData = {
|
||||
ean: item.product.ean,
|
||||
itemId: Number(item.product.catalogProductNumber),
|
||||
price: item.availability.price,
|
||||
};
|
||||
|
||||
let availability: AvailabilityDTO;
|
||||
|
||||
switch (item.features.orderType) {
|
||||
case 'Abholung':
|
||||
const abholung = await this.availabilityService
|
||||
.getPickUpAvailability({
|
||||
item: itemData,
|
||||
branch: item.destination?.data?.targetBranch?.data,
|
||||
quantity: item.quantity,
|
||||
})
|
||||
.toPromise();
|
||||
availability = abholung[0];
|
||||
break;
|
||||
case 'Rücklage':
|
||||
const ruecklage = await this.availabilityService
|
||||
.getTakeAwayAvailability({
|
||||
item: itemData,
|
||||
quantity: item.quantity,
|
||||
branch: item.destination?.data?.targetBranch?.data,
|
||||
})
|
||||
.toPromise();
|
||||
availability = ruecklage;
|
||||
break;
|
||||
case 'Download':
|
||||
const download = await this.availabilityService
|
||||
.getDownloadAvailability({
|
||||
item: itemData,
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
availability = download;
|
||||
break;
|
||||
|
||||
case 'Versand':
|
||||
const versand = await this.availabilityService
|
||||
.getDeliveryAvailability({
|
||||
item: itemData,
|
||||
quantity: item.quantity,
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
availability = versand;
|
||||
break;
|
||||
|
||||
case 'DIG-Versand':
|
||||
const digVersand = await this.availabilityService
|
||||
.getDigDeliveryAvailability({
|
||||
item: itemData,
|
||||
quantity: item.quantity,
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
availability = digVersand;
|
||||
break;
|
||||
|
||||
case 'B2B-Versand':
|
||||
const b2bVersand = await this.availabilityService
|
||||
.getB2bDeliveryAvailability({
|
||||
item: itemData,
|
||||
quantity: item.quantity,
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
availability = b2bVersand;
|
||||
break;
|
||||
}
|
||||
|
||||
await this.updateItemInShoppingCart({
|
||||
processId,
|
||||
update: { availability },
|
||||
shoppingCartItemId: item.id,
|
||||
}).toPromise();
|
||||
|
||||
return availability;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the availability of all items is valid
|
||||
* @param param0 Process Id
|
||||
* @returns true if the availability of all items is valid
|
||||
*/
|
||||
validateOlaStatus({ processId, interval }: { processId: number; interval?: number }): Observable<boolean> {
|
||||
return new Observable((observer) => {
|
||||
const enity$ = this.store.select(DomainCheckoutSelectors.selectCheckoutEntityByProcessId, { processId });
|
||||
|
||||
const olaExpiration = this.olaExpiration;
|
||||
|
||||
let timeout: any;
|
||||
|
||||
let subscription: Subscription;
|
||||
|
||||
function check() {
|
||||
const now = Date.now();
|
||||
|
||||
subscription?.unsubscribe();
|
||||
subscription = enity$.pipe(take(1)).subscribe((entity) => {
|
||||
if (!entity || !entity.shoppingCart || !entity.shoppingCart.items) {
|
||||
return;
|
||||
}
|
||||
|
||||
const itemAvailabilityTimestamp = entity.itemAvailabilityTimestamp ?? {};
|
||||
const shoppingCart = entity.shoppingCart;
|
||||
|
||||
const timestamps = shoppingCart.items
|
||||
?.map((i) => i.data)
|
||||
?.filter((item) => !!item?.features?.orderType)
|
||||
?.map((item) => itemAvailabilityTimestamp[`${item.id}_${item.features.orderType}`]);
|
||||
|
||||
if (timestamps?.length > 0) {
|
||||
const oldestTimestamp = Math.min(...timestamps);
|
||||
observer.next(now - oldestTimestamp < olaExpiration);
|
||||
}
|
||||
|
||||
timeout = setTimeout(() => {
|
||||
check.call(this);
|
||||
}, interval ?? olaExpiration / 10);
|
||||
});
|
||||
}
|
||||
|
||||
check.call(this);
|
||||
|
||||
return () => {
|
||||
subscription?.unsubscribe();
|
||||
clearTimeout(timeout);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
validateAvailabilities({ processId }: { processId: number }): Observable<boolean> {
|
||||
return this.getShoppingCart({ processId }).pipe(
|
||||
map((shoppingCart) => {
|
||||
const items = shoppingCart?.items?.map((item) => item.data) || [];
|
||||
|
||||
return items.every((i) => this.availabilityService.isAvailable({ availability: i.availability }));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
checkoutIsValid({ processId }: { processId: number }): Observable<boolean> {
|
||||
const olaStatus$ = this.validateOlaStatus({ processId, interval: 250 });
|
||||
|
||||
const availabilities$ = this.validateAvailabilities({ processId });
|
||||
|
||||
return combineLatest([olaStatus$, availabilities$]).pipe(map(([olaStatus, availabilities]) => olaStatus && availabilities));
|
||||
}
|
||||
|
||||
completeCheckout({ processId }: { processId: number }): Observable<DisplayOrderDTO[]> {
|
||||
const refreshShoppingCart$ = this.getShoppingCart({ processId, latest: true }).pipe(first());
|
||||
const refreshCheckout$ = this.getCheckout({ processId, refresh: true }).pipe(first());
|
||||
@@ -693,21 +918,64 @@ export class DomainCheckoutService {
|
||||
)
|
||||
);
|
||||
|
||||
return updateDestination$
|
||||
.pipe(tap(console.log.bind(window, 'updateDestination$')))
|
||||
return of(undefined)
|
||||
.pipe(
|
||||
mergeMap((_) => updateDestination$.pipe(tap(console.log.bind(window, 'updateDestination$')))),
|
||||
mergeMap((_) => refreshShoppingCart$.pipe(tap(console.log.bind(window, 'refreshShoppingCart$')))),
|
||||
mergeMap((_) => setSpecialComment$.pipe(tap(console.log.bind(window, 'setSpecialComment$')))),
|
||||
mergeMap((_) => refreshCheckout$.pipe(tap(console.log.bind(window, 'refreshCheckout$')))),
|
||||
mergeMap((_) => checkAvailabilities$.pipe(tap(console.log.bind(window, 'checkAvailabilities$')))),
|
||||
mergeMap((_) => updateAvailabilities$.pipe(tap(console.log.bind(window, 'updateAvailabilities$')))),
|
||||
mergeMap((_) => updateAvailabilities$.pipe(tap(console.log.bind(window, 'updateAvailabilities$'))))
|
||||
)
|
||||
.pipe(
|
||||
mergeMap((_) => setBuyer$.pipe(tap(console.log.bind(window, 'setBuyer$')))),
|
||||
mergeMap((_) => setNotificationChannels$.pipe(tap(console.log.bind(window, 'setNotificationChannels$')))),
|
||||
mergeMap((_) => setPayer$.pipe(tap(console.log.bind(window, 'setPayer$')))),
|
||||
mergeMap((_) => setPaymentType$.pipe(tap(console.log.bind(window, 'setPaymentType$')))),
|
||||
mergeMap((_) => setDestination$.pipe(tap(console.log.bind(window, 'setDestination$'))))
|
||||
mergeMap((_) => setDestination$.pipe(tap(console.log.bind(window, 'setDestination$')))),
|
||||
mergeMap((_) => completeOrder$.pipe(tap(console.log.bind(window, 'completeOrder$'))))
|
||||
);
|
||||
}
|
||||
|
||||
completeKulturpassOrder({
|
||||
processId,
|
||||
orderItemSubsetId,
|
||||
}: {
|
||||
processId: number;
|
||||
orderItemSubsetId: number;
|
||||
}): Observable<ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString> {
|
||||
const refreshShoppingCart$ = this.getShoppingCart({ processId, latest: true }).pipe(first());
|
||||
const refreshCheckout$ = this.getCheckout({ processId, refresh: true }).pipe(first());
|
||||
|
||||
const setBuyer$ = this.getBuyer({ processId }).pipe(
|
||||
first(),
|
||||
mergeMap((buyer) => this._setBuyer({ processId, buyer }))
|
||||
);
|
||||
|
||||
const setPayer$ = this.getPayer({ processId }).pipe(
|
||||
first(),
|
||||
mergeMap((payer) => this._setPayer({ processId, payer }))
|
||||
);
|
||||
|
||||
const checkAvailabilities$ = this.checkAvailabilities({ processId });
|
||||
|
||||
const updateAvailabilities$ = this.updateAvailabilities({ processId });
|
||||
|
||||
return refreshShoppingCart$.pipe(
|
||||
mergeMap((_) => refreshCheckout$),
|
||||
mergeMap((_) => checkAvailabilities$),
|
||||
mergeMap((_) => updateAvailabilities$),
|
||||
mergeMap((_) => setBuyer$),
|
||||
mergeMap((_) => setPayer$),
|
||||
mergeMap((checkout) =>
|
||||
this.orderCheckoutService.OrderCheckoutCreateKulturPassOrder({
|
||||
payload: {
|
||||
checkoutId: checkout.id,
|
||||
orderItemSubsetId: String(orderItemSubsetId),
|
||||
},
|
||||
})
|
||||
)
|
||||
.pipe(mergeMap((_) => completeOrder$.pipe(tap(console.log.bind(window, 'completeOrder$')))));
|
||||
);
|
||||
}
|
||||
|
||||
updateDestination({
|
||||
@@ -930,6 +1198,5 @@ export class DomainCheckoutService {
|
||||
private updateProcessCount(processId: number, count: number) {
|
||||
this.applicationService.patchProcessData(processId, { count });
|
||||
}
|
||||
|
||||
//#endregion
|
||||
}
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
import { BuyerDTO, CheckoutDTO, NotificationChannel, PayerDTO, ShippingAddressDTO, ShoppingCartDTO } from '@swagger/checkout';
|
||||
import {
|
||||
AvailabilityDTO,
|
||||
BuyerDTO,
|
||||
CheckoutDTO,
|
||||
NotificationChannel,
|
||||
PayerDTO,
|
||||
ShippingAddressDTO,
|
||||
ShoppingCartDTO,
|
||||
} from '@swagger/checkout';
|
||||
import { CustomerDTO } from '@swagger/crm';
|
||||
import { DisplayOrderDTO } from '@swagger/oms';
|
||||
|
||||
@@ -14,4 +22,5 @@ export interface CheckoutEntity {
|
||||
specialComment: string;
|
||||
notificationChannels: NotificationChannel;
|
||||
olaErrorIds: number[];
|
||||
itemAvailabilityTimestamp: Record<string, number>;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
ShippingAddressDTO,
|
||||
BuyerDTO,
|
||||
PayerDTO,
|
||||
AvailabilityDTO,
|
||||
} from '@swagger/checkout';
|
||||
import { CustomerDTO } from '@swagger/crm';
|
||||
import { DisplayOrderDTO, DisplayOrderItemDTO } from '@swagger/oms';
|
||||
@@ -61,3 +62,13 @@ export const setSpecialComment = createAction(`${prefix} Set Agent Comment`, pro
|
||||
export const setOlaError = createAction(`${prefix} Set Ola Error`, props<{ processId: number; olaErrorIds: number[] }>());
|
||||
|
||||
export const setCustomer = createAction(`${prefix} Set Customer`, props<{ processId: number; customer: CustomerDTO }>());
|
||||
|
||||
export const addShoppingCartItemAvailabilityToHistory = createAction(
|
||||
`${prefix} Add Shopping Cart Item Availability To History`,
|
||||
props<{ processId: number; shoppingCartItemId: number; availability: AvailabilityDTO }>()
|
||||
);
|
||||
|
||||
export const addShoppingCartItemAvailabilityToHistoryByShoppingCartId = createAction(
|
||||
`${prefix} Add Shopping Cart Item Availability To History By Shopping Cart Id`,
|
||||
props<{ shoppingCartId: number; shoppingCartItemId: number; availability: AvailabilityDTO }>()
|
||||
);
|
||||
|
||||
@@ -10,7 +10,22 @@ const _domainCheckoutReducer = createReducer(
|
||||
initialCheckoutState,
|
||||
on(DomainCheckoutActions.setShoppingCart, (s, { processId, shoppingCart }) => {
|
||||
const entity = getOrCreateCheckoutEntity({ processId, entities: s.entities });
|
||||
|
||||
const addedShoppingCartItems =
|
||||
shoppingCart?.items?.filter((item) => !entity.shoppingCart?.items?.find((i) => i.id === item.id))?.map((item) => item.data) ?? [];
|
||||
|
||||
entity.shoppingCart = shoppingCart;
|
||||
|
||||
entity.itemAvailabilityTimestamp = entity.itemAvailabilityTimestamp ? { ...entity.itemAvailabilityTimestamp } : {};
|
||||
|
||||
const now = Date.now();
|
||||
|
||||
for (let shoppingCartItem of addedShoppingCartItems) {
|
||||
if (shoppingCartItem.features?.orderType) {
|
||||
entity.itemAvailabilityTimestamp[`${shoppingCartItem.id}_${shoppingCartItem.features.orderType}`] = now;
|
||||
}
|
||||
}
|
||||
|
||||
return storeCheckoutAdapter.setOne(entity, s);
|
||||
}),
|
||||
on(DomainCheckoutActions.setCheckout, (s, { processId, checkout }) => {
|
||||
@@ -100,7 +115,40 @@ const _domainCheckoutReducer = createReducer(
|
||||
const entity = getOrCreateCheckoutEntity({ processId, entities: s.entities });
|
||||
entity.customer = customer;
|
||||
return storeCheckoutAdapter.setOne(entity, s);
|
||||
})
|
||||
}),
|
||||
on(DomainCheckoutActions.addShoppingCartItemAvailabilityToHistory, (s, { processId, shoppingCartItemId, availability }) => {
|
||||
const entity = getOrCreateCheckoutEntity({ processId, entities: s.entities });
|
||||
|
||||
const itemAvailabilityTimestamp = entity?.itemAvailabilityTimestamp ? { ...entity?.itemAvailabilityTimestamp } : {};
|
||||
|
||||
const item = entity?.shoppingCart?.items?.find((i) => i.id === shoppingCartItemId)?.data;
|
||||
|
||||
if (!item?.features?.orderType) return s;
|
||||
|
||||
itemAvailabilityTimestamp[`${item.id}_${item?.features?.orderType}`] = Date.now();
|
||||
|
||||
entity.itemAvailabilityTimestamp = itemAvailabilityTimestamp;
|
||||
|
||||
return storeCheckoutAdapter.setOne(entity, s);
|
||||
}),
|
||||
on(
|
||||
DomainCheckoutActions.addShoppingCartItemAvailabilityToHistoryByShoppingCartId,
|
||||
(s, { shoppingCartId, shoppingCartItemId, availability }) => {
|
||||
const entity = getCheckoutEntityByShoppingCartId({ shoppingCartId, entities: s.entities });
|
||||
|
||||
const itemAvailabilityTimestamp = entity?.itemAvailabilityTimestamp ? { ...entity?.itemAvailabilityTimestamp } : {};
|
||||
|
||||
const item = entity?.shoppingCart?.items?.find((i) => i.id === shoppingCartItemId)?.data;
|
||||
|
||||
if (!item?.features?.orderType) return s;
|
||||
|
||||
itemAvailabilityTimestamp[`${item.id}_${item?.features?.orderType}`] = Date.now();
|
||||
|
||||
entity.itemAvailabilityTimestamp = itemAvailabilityTimestamp;
|
||||
|
||||
return storeCheckoutAdapter.setOne(entity, s);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
export function domainCheckoutReducer(state, action) {
|
||||
@@ -123,8 +171,20 @@ function getOrCreateCheckoutEntity({ entities, processId }: { entities: Dictiona
|
||||
notificationChannels: 0,
|
||||
olaErrorIds: [],
|
||||
customer: undefined,
|
||||
// availabilityHistory: [],
|
||||
itemAvailabilityTimestamp: {},
|
||||
};
|
||||
}
|
||||
|
||||
return { ...entity };
|
||||
}
|
||||
|
||||
function getCheckoutEntityByShoppingCartId({
|
||||
entities,
|
||||
shoppingCartId,
|
||||
}: {
|
||||
entities: Dictionary<CheckoutEntity>;
|
||||
shoppingCartId: number;
|
||||
}): CheckoutEntity {
|
||||
return Object.values(entities).find((entity) => entity.shoppingCart?.id === shoppingCartId);
|
||||
}
|
||||
|
||||
@@ -18,14 +18,15 @@ import {
|
||||
NotificationChannel,
|
||||
PayerDTO,
|
||||
PayerService,
|
||||
QueryTokenDTO,
|
||||
ResponseArgsOfIEnumerableOfBonusCardInfoDTO,
|
||||
ShippingAddressDTO,
|
||||
ShippingAddressService,
|
||||
} from '@swagger/crm';
|
||||
import { isArray } from '@utils/common';
|
||||
import { isArray, memorize } from '@utils/common';
|
||||
import { PagedResult, Result } from 'apps/domain/defs/src/public-api';
|
||||
import { Observable, of, ReplaySubject } from 'rxjs';
|
||||
import { catchError, map, mergeMap, retry } from 'rxjs/operators';
|
||||
import { catchError, map, mergeMap, retry, shareReplay } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CrmCustomerService {
|
||||
@@ -38,6 +39,14 @@ export class CrmCustomerService {
|
||||
private loyaltyCardService: LoyaltyCardService
|
||||
) {}
|
||||
|
||||
@memorize()
|
||||
filterSettings() {
|
||||
return this.customerService.CustomerCustomerQuerySettings().pipe(
|
||||
map((res) => res.result),
|
||||
shareReplay(1)
|
||||
);
|
||||
}
|
||||
|
||||
complete(queryString: string, filter?: { [key: string]: string }): Observable<Result<AutocompleteDTO[]>> {
|
||||
return this.customerService.CustomerCustomerAutocomplete({
|
||||
input: queryString,
|
||||
@@ -66,6 +75,15 @@ export class CrmCustomerService {
|
||||
});
|
||||
}
|
||||
|
||||
getCustomersWithQueryToken(queryToken: QueryTokenDTO) {
|
||||
if (queryToken.skip === undefined) queryToken.skip = 0;
|
||||
if (queryToken.take === undefined) queryToken.take = 20;
|
||||
if (queryToken.input === undefined) queryToken.input = { qs: '' };
|
||||
if (queryToken.filter === undefined) queryToken.filter = {};
|
||||
|
||||
return this.customerService.CustomerListCustomers(queryToken);
|
||||
}
|
||||
|
||||
getCustomersByCustomerCardNumber(queryString: string): Observable<PagedResult<CustomerInfoDTO>> {
|
||||
return this.customerService.CustomerGetCustomerByBonuscard(!!queryString ? queryString : undefined);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ export class CollectOnDeliveryNoteActionHandler extends ActionHandler<OrderItems
|
||||
const response = await this.orderService
|
||||
.OrderCollectOnDeliveryNote({
|
||||
data,
|
||||
eagerLoading: 1,
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
@@ -29,7 +30,7 @@ export class CollectOnDeliveryNoteActionHandler extends ActionHandler<OrderItems
|
||||
|
||||
return {
|
||||
...context,
|
||||
receipts: response.result,
|
||||
receipts: response.result.map((r) => r.data),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActionHandler } from '@core/command';
|
||||
import { OrderService } from '@swagger/oms';
|
||||
import { OrderItemsContext } from './order-items.context';
|
||||
|
||||
@Injectable()
|
||||
export class CollectWithSmallAmountinvoiceActionHandler extends ActionHandler<OrderItemsContext> {
|
||||
constructor(private orderService: OrderService) {
|
||||
super('COLLECT_WITH_SMALLAMOUNTINVOICE');
|
||||
}
|
||||
|
||||
async handler(context: OrderItemsContext): Promise<OrderItemsContext> {
|
||||
const data: Record<number, number> = {};
|
||||
|
||||
context.items.forEach((orderItemSubsetId) => {
|
||||
data[orderItemSubsetId.orderItemSubsetId] =
|
||||
context.itemQuantity?.get(orderItemSubsetId.orderItemSubsetId) ?? orderItemSubsetId.quantity;
|
||||
});
|
||||
|
||||
const response = await this.orderService
|
||||
.OrderCollectWithSmallAmountInvoice({
|
||||
data,
|
||||
eagerLoading: 1,
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
// Für korrekte Navigation nach Aufruf, da ProcessingStatus Serverseitig auf abgeholt gesetzt wird
|
||||
context.items?.forEach((i) => (i.processingStatus = 256));
|
||||
|
||||
return {
|
||||
...context,
|
||||
receipts: response.result.map((r) => r.data),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
// start:ng42.barrel
|
||||
export * from './accepted.action-handler';
|
||||
export * from './arrived.action-handler';
|
||||
export * from './assembled.action-handler';
|
||||
@@ -7,6 +6,10 @@ export * from './back-to-stock.action-handler';
|
||||
export * from './canceled-by-buyer.action-handler';
|
||||
export * from './canceled-by-retailer.action-handler';
|
||||
export * from './canceled-by-supplier.action-handler';
|
||||
export * from './change-order-item-status-base.action-handler';
|
||||
export * from './collect-on-deliverynote.action-handler';
|
||||
export * from './collect-with-smallamountinvoice.action-handler';
|
||||
export * from './create-returnitem.action-handler';
|
||||
export * from './create-shipping-note.action-handler';
|
||||
export * from './delivered.action-handler';
|
||||
export * from './determine-supplier.action-handler';
|
||||
@@ -25,16 +28,15 @@ export * from './parked.action-handler';
|
||||
export * from './placed.action-handler';
|
||||
export * from './preperation-for-shipping.action-handler';
|
||||
export * from './print-compartment-label.action-handler';
|
||||
export * from './print-pricediffqrcodelabel.action-handler';
|
||||
export * from './print-shipping-note.action-handler';
|
||||
export * from './re-ordered.action-handler';
|
||||
export * from './print-smallamountinvoice.action-handler';
|
||||
export * from './re-order.action-handler';
|
||||
export * from './re-ordered.action-handler';
|
||||
export * from './redirected-internally.action-handler';
|
||||
export * from './requested.action-handler';
|
||||
export * from './reserved.action-handler';
|
||||
export * from './returned-by-buyer.action-handler';
|
||||
export * from './shipping-note.action-handler';
|
||||
export * from './shop-with-kulturpass.action-handler';
|
||||
export * from './supplier-temporarily-out-of-stock.action-handler copy';
|
||||
export * from './collect-on-deliverynote.action-handler';
|
||||
export * from './create-returnitem.action-handler';
|
||||
export * from './print-pricediffqrcodelabel.action-handler';
|
||||
// end:ng42.barrel
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { OrderItemListItemDTO, ReceiptDTO } from '@swagger/oms';
|
||||
import { OrderItemListItemDTO, ReceiptDTO, OrderDTO } from '@swagger/oms';
|
||||
|
||||
export interface OrderItemsContext {
|
||||
items: OrderItemListItemDTO[];
|
||||
@@ -12,4 +12,6 @@ export interface OrderItemsContext {
|
||||
receipts?: ReceiptDTO[];
|
||||
|
||||
shippingDelayComment?: string;
|
||||
|
||||
order?: OrderDTO;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ export class PrintShippingNoteActionHandler extends ActionHandler<OrderItemsCont
|
||||
printerType: 'Label',
|
||||
print: async (printer) => {
|
||||
try {
|
||||
for (const group of groupBy(data?.receipts, (receipt) => receipt?.buyer?.buyerNumber)) {
|
||||
const receipts = data?.receipts?.filter((r) => r?.receiptType & 1);
|
||||
for (const group of groupBy(receipts, (receipt) => receipt?.buyer?.buyerNumber)) {
|
||||
await this.domainPrinterService.printShippingNote({ printer, receipts: group?.items?.map((r) => r?.id) }).toPromise();
|
||||
}
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActionHandler } from '@core/command';
|
||||
import { OrderItemsContext } from './order-items.context';
|
||||
import { OMSPrintService } from '@swagger/print';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { PrintModalComponent, PrintModalData } from '@modal/printer';
|
||||
import { NativeContainerService } from 'native-container';
|
||||
import { groupBy } from '@ui/common';
|
||||
|
||||
@Injectable()
|
||||
export class PrintSmallamountinvoiceActionHandler extends ActionHandler<OrderItemsContext> {
|
||||
constructor(
|
||||
private uiModal: UiModalService,
|
||||
private omsPrintService: OMSPrintService,
|
||||
private nativeContainerService: NativeContainerService
|
||||
) {
|
||||
super('PRINT_SMALLAMOUNTINVOICE');
|
||||
}
|
||||
|
||||
async handler(data: OrderItemsContext): Promise<OrderItemsContext> {
|
||||
await this.uiModal
|
||||
.open({
|
||||
content: PrintModalComponent,
|
||||
config: { showScrollbarY: false },
|
||||
data: {
|
||||
printImmediately: !this.nativeContainerService.isNative,
|
||||
printerType: 'Label',
|
||||
print: async (printer) => {
|
||||
try {
|
||||
const receipts = data?.receipts?.filter((r) => r?.receiptType & 128);
|
||||
for (const group of groupBy(receipts, (receipt) => receipt?.buyer?.buyerNumber)) {
|
||||
await this.omsPrintService
|
||||
.OMSPrintKleinbetragsrechnung({
|
||||
data: group?.items?.map((r) => r?.id),
|
||||
printer,
|
||||
})
|
||||
.toPromise();
|
||||
}
|
||||
return {
|
||||
error: false,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return {
|
||||
error: true,
|
||||
message: error?.message || error,
|
||||
};
|
||||
}
|
||||
},
|
||||
} as PrintModalData,
|
||||
})
|
||||
.afterClosed$.toPromise();
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import { UiModalService } from '@ui/modal';
|
||||
import { ReorderModalComponent, ReorderResult } from '@modal/reorder';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { AvailabilityDTO2, OrderItemListItemDTO } from '@swagger/oms';
|
||||
import { ToastService } from '@core/toast';
|
||||
import { ToasterService } from '@shared/shell';
|
||||
|
||||
@Injectable()
|
||||
export class ReOrderActionHandler extends ActionHandler<OrderItemsContext> {
|
||||
@@ -13,7 +13,7 @@ export class ReOrderActionHandler extends ActionHandler<OrderItemsContext> {
|
||||
private _command: CommandService,
|
||||
private _domainCheckoutService: DomainCheckoutService,
|
||||
private _uiModal: UiModalService,
|
||||
private _toastService: ToastService
|
||||
private _toastService: ToasterService
|
||||
) {
|
||||
super('REORDER');
|
||||
}
|
||||
@@ -71,8 +71,8 @@ export class ReOrderActionHandler extends ActionHandler<OrderItemsContext> {
|
||||
case 'Falscher Titel geliefert (richtiges Etikett)':
|
||||
break;
|
||||
default:
|
||||
this._toastService.create({
|
||||
title: 'Artikel wurde nachbestellt',
|
||||
this._toastService.open({
|
||||
message: 'Artikel wurde nachbestellt',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { OrderItemsContext } from './order-items.context';
|
||||
import { ActionHandler, CommandService } from '@core/command';
|
||||
import { KulturpassOrderModalService } from '@shared/modals/kulturpass-order-modal';
|
||||
import { DisplayOrderItemSubsetDTO, OrderItemListItemDTO, ReceiptDTO } from '@swagger/oms';
|
||||
import { DomainReceiptService } from '../receipt.service';
|
||||
import { DomainGoodsService } from '../goods.service';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
export class ShopWithKulturpassActionHandler extends ActionHandler<OrderItemsContext> {
|
||||
constructor(
|
||||
private _modal: KulturpassOrderModalService,
|
||||
private _receiptService: DomainReceiptService,
|
||||
private _goodsService: DomainGoodsService
|
||||
) {
|
||||
super('SHOP_WITH_KULTURPASS');
|
||||
}
|
||||
|
||||
async handler(data: OrderItemsContext, service: CommandService): Promise<OrderItemsContext> {
|
||||
const items: OrderItemListItemDTO[] = [];
|
||||
const receipts: ReceiptDTO[] = [];
|
||||
|
||||
let command: string;
|
||||
for (const item of data.items) {
|
||||
const result = await this._modal.open({ orderItemListItem: item, order: data.order }).afterClosed$.toPromise();
|
||||
|
||||
if (result.data == null) {
|
||||
return data;
|
||||
}
|
||||
|
||||
const displayOrder = result.data[0];
|
||||
command = result.data[1];
|
||||
|
||||
if (displayOrder) {
|
||||
const subsetItems = displayOrder.items.reduce((acc, item) => [...acc, ...item.subsetItems], [] as DisplayOrderItemSubsetDTO[]);
|
||||
|
||||
const orderItems = await this.getItems(displayOrder.orderNumber);
|
||||
|
||||
items.push(...orderItems);
|
||||
|
||||
const subsetItemIds = subsetItems.map((item) => item.id);
|
||||
|
||||
const r = await this.getReceipts(subsetItemIds);
|
||||
|
||||
receipts.push(...r);
|
||||
}
|
||||
}
|
||||
|
||||
if (!command) {
|
||||
return {
|
||||
...data,
|
||||
items,
|
||||
receipts,
|
||||
};
|
||||
} else {
|
||||
return service.handleCommand(command, {
|
||||
...data,
|
||||
items,
|
||||
receipts,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getReceipts(ids: number[]) {
|
||||
return this._receiptService
|
||||
.getReceipts({
|
||||
receiptType: 128,
|
||||
eagerLoading: 1,
|
||||
ids,
|
||||
})
|
||||
.pipe(map((res) => res.result.map((data) => data.item3.data).filter((data) => !!data)))
|
||||
.toPromise();
|
||||
}
|
||||
|
||||
getItems(orderNumber: string) {
|
||||
return this._goodsService
|
||||
.getWarenausgabeItemByOrderNumber(orderNumber, false)
|
||||
.pipe(map((res) => res.result))
|
||||
.toPromise();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { AutocompleteTokenDTO, OrderService, QueryTokenDTO } from '@swagger/oms';
|
||||
import { memorize } from '@utils/common';
|
||||
import { map, shareReplay } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class DomainCustomerOrderService {
|
||||
@@ -14,16 +16,18 @@ export class DomainCustomerOrderService {
|
||||
// branch_id'
|
||||
}
|
||||
|
||||
getOrderItemsByOrderNumber(orderNumber: string) {
|
||||
getOrderItemsByOrderNumber(params: { compartmentCode?: string; orderId: number }) {
|
||||
return this._orderService.OrderKundenbestellungen({
|
||||
filter: { all_branches: 'true', archive: 'true' },
|
||||
input: {
|
||||
qs: orderNumber,
|
||||
},
|
||||
input: { order_id: String(params.orderId), compartment_code: params.compartmentCode },
|
||||
});
|
||||
}
|
||||
|
||||
@memorize()
|
||||
settings() {
|
||||
return this._orderService.OrderKundenbestellungenSettings();
|
||||
return this._orderService.OrderKundenbestellungenSettings().pipe(
|
||||
map((res) => res?.result),
|
||||
shareReplay()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
AutocompleteTokenDTO,
|
||||
BranchService,
|
||||
ChangeStockStatusCodeValues,
|
||||
HistoryDTO,
|
||||
@@ -11,9 +10,7 @@ import {
|
||||
OrderItemSubsetDTO,
|
||||
OrderListItemDTO,
|
||||
OrderService,
|
||||
QueryTokenDTO,
|
||||
ReceiptService,
|
||||
ResponseArgsOfIEnumerableOfHistoryDTO,
|
||||
StatusValues,
|
||||
StockStatusCodeService,
|
||||
ValueTupleOfLongAndReceiptTypeAndEntityDTOContainerOfReceiptDTO,
|
||||
@@ -22,7 +19,7 @@ import {
|
||||
} from '@swagger/oms';
|
||||
import { memorize } from '@utils/common';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, mergeMap, shareReplay } from 'rxjs/operators';
|
||||
import { map, shareReplay } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
export class DomainOmsService {
|
||||
@@ -191,6 +188,10 @@ export class DomainOmsService {
|
||||
);
|
||||
}
|
||||
|
||||
getOrderSource(orderId: number): Observable<string> {
|
||||
return this.getOrder(orderId).pipe(map((order) => order?.features?.orderSource));
|
||||
}
|
||||
|
||||
updateNotifications(orderId: number, changes: { selected: NotificationChannel; email: string; mobile: string }) {
|
||||
const communicationDetails = {
|
||||
email: changes.email,
|
||||
|
||||
11
apps/domain/package-inspection/src/lib/events.ts
Normal file
11
apps/domain/package-inspection/src/lib/events.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { PackageArrivalStatusDTO } from '@swagger/wws';
|
||||
|
||||
export abstract class PackageInspectionEvent {
|
||||
constructor(public readonly type: string) {}
|
||||
}
|
||||
|
||||
export class PackageStatusChangedEvent extends PackageInspectionEvent {
|
||||
constructor(public readonly packageId: string, public readonly status: PackageArrivalStatusDTO) {
|
||||
super('PackageStatusChangedEvent');
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
ListResponseArgsOfPackageDTO,
|
||||
ListResponseArgsOfPackageDTO2,
|
||||
PackageArrivalStatusDTO,
|
||||
PackageDetailResponseDTO,
|
||||
PackageDTO,
|
||||
PackageDTO2,
|
||||
QuerySettingsDTO,
|
||||
QueryTokenDTO,
|
||||
@@ -13,13 +11,18 @@ import {
|
||||
ResponseArgsOfQuerySettingsDTO,
|
||||
WareneingangService,
|
||||
} from '@swagger/wws';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { map, tap } from 'rxjs/operators';
|
||||
import { PackageInspectionEvent, PackageStatusChangedEvent } from './events';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class DomainPackageInspectionService {
|
||||
private _events = new Subject<PackageInspectionEvent>();
|
||||
|
||||
events = this._events.asObservable();
|
||||
|
||||
constructor(private _wareneingang: WareneingangService) {}
|
||||
|
||||
getQuerySettingsResponse(): Observable<ResponseArgsOfQuerySettingsDTO> {
|
||||
@@ -47,23 +50,26 @@ export class DomainPackageInspectionService {
|
||||
}
|
||||
|
||||
changePackageStatusResponse(pkg: PackageDTO2, modifier: string): Observable<ResponseArgsOfPackageArrivalStatusDTO> {
|
||||
return this._wareneingang.WareneingangChangePackageStatus({
|
||||
packageId: pkg.id,
|
||||
payload: {
|
||||
id: pkg.id,
|
||||
annotation: pkg.annotation,
|
||||
area: pkg.area,
|
||||
arrivalChecked: pkg.arrivalChecked,
|
||||
arrivalStatus: pkg.arrivalStatus,
|
||||
deliveryNoteNumber: pkg.deliveryNoteNumber,
|
||||
deliveryTarget: pkg.deliveryTarget,
|
||||
estimatedDeliveryDate: pkg.estimatedDeliveryDate,
|
||||
packageNumber: pkg.packageNumber,
|
||||
supplier: pkg.supplier,
|
||||
trackingNumber: pkg.trackingNumber,
|
||||
},
|
||||
modifier,
|
||||
});
|
||||
return this._wareneingang
|
||||
.WareneingangChangePackageStatus({
|
||||
packageId: pkg.id,
|
||||
payload: {
|
||||
id: pkg.id,
|
||||
annotation: pkg.annotation,
|
||||
area: pkg.area,
|
||||
arrivalChecked: pkg.arrivalChecked,
|
||||
arrivalStatus: pkg.arrivalStatus,
|
||||
deliveryNoteNumber: pkg.deliveryNoteNumber,
|
||||
deliveryTarget: pkg.deliveryTarget,
|
||||
estimatedDeliveryDate: pkg.estimatedDeliveryDate,
|
||||
packageNumber: pkg.packageNumber,
|
||||
supplier: pkg.supplier,
|
||||
trackingNumber: pkg.trackingNumber,
|
||||
scanId: pkg.scanId,
|
||||
},
|
||||
modifier,
|
||||
})
|
||||
.pipe(tap((res) => this._events.next(new PackageStatusChangedEvent(pkg.id, res.result))));
|
||||
}
|
||||
|
||||
changePackageStatus(pkg: PackageDTO2, modifier: string): Observable<PackageArrivalStatusDTO> {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Public API Surface of package-inspection
|
||||
*/
|
||||
|
||||
export * from './lib/events';
|
||||
export * from './lib/package-inspection.service';
|
||||
export * from './lib/package-inspection.module';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// start:ng42.barrel
|
||||
export * from './hub-notification.module';
|
||||
export * from './notifications.hub';
|
||||
export * from './defs';
|
||||
// end:ng42.barrel
|
||||
|
||||
@@ -4,61 +4,118 @@ import { SignalrHub, SignalRHubOptions } from '@core/signalr';
|
||||
import { BehaviorSubject, merge, of } from 'rxjs';
|
||||
import { filter, map, shareReplay, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { EnvelopeDTO, MessageBoardItemDTO } from './defs';
|
||||
import { cloneDeep } from 'lodash';
|
||||
|
||||
export const NOTIFICATIONS_HUB_OPTIONS = new InjectionToken<SignalRHubOptions>('hub.notifications.options');
|
||||
|
||||
@Injectable()
|
||||
export class NotificationsHub extends SignalrHub {
|
||||
updateNotification$ = new BehaviorSubject<MessageBoardItemDTO>(undefined);
|
||||
|
||||
get branchNo() {
|
||||
return String(this._auth.getClaimByKey('branch_no') || this._auth.getClaimByKey('sub'));
|
||||
}
|
||||
|
||||
// get sessionStoragesessionStorageKey() {
|
||||
// return `NOTIFICATIONS_BOARD_${this.branchNo}`;
|
||||
// }
|
||||
|
||||
get sessionStoragesessionStorageKey() {
|
||||
return `NOTIFICATIONS_BOARD_${this.branchNo}`;
|
||||
return `NOTIFICATIONS_BOARD_AREA_${this.branchNo}`;
|
||||
}
|
||||
|
||||
messageBoardItems$ = new BehaviorSubject<Record<string, MessageBoardItemDTO[]>>({});
|
||||
|
||||
constructor(@Inject(NOTIFICATIONS_HUB_OPTIONS) options: SignalRHubOptions, private _auth: AuthService) {
|
||||
super(options);
|
||||
|
||||
this.messageBoardItems$.next(this._getNotifications());
|
||||
|
||||
this.messageBoardItems$.subscribe((data) => {
|
||||
this._storeNotifactions(data);
|
||||
});
|
||||
|
||||
this.listen<EnvelopeDTO<MessageBoardItemDTO[]>>('messageBoard').subscribe((envelope) => {
|
||||
if (envelope.action === 'refresh') {
|
||||
this.refreshMessageBoardItems(envelope.target.area, envelope.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
notifications$ = merge(
|
||||
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);
|
||||
refreshMessageBoardItems(targetArea: string, messages: MessageBoardItemDTO[]) {
|
||||
const current = cloneDeep(this.messageBoardItems$.value);
|
||||
|
||||
current[targetArea] = messages ?? [];
|
||||
|
||||
this.messageBoardItems$.next(current);
|
||||
}
|
||||
|
||||
notifications$ = this.messageBoardItems$.asObservable().pipe(
|
||||
map((data) => {
|
||||
const messages = { ...data };
|
||||
const keys = Object.keys(data);
|
||||
for (let key of keys) {
|
||||
if (data[key].length === 0 || data[key] === undefined) {
|
||||
delete messages[key];
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}),
|
||||
tap((data) => this._storeNotifactions(data)),
|
||||
shareReplay(1)
|
||||
|
||||
return messages;
|
||||
})
|
||||
);
|
||||
|
||||
private _storeNotifactions(data: EnvelopeDTO<MessageBoardItemDTO[]>) {
|
||||
if (data) {
|
||||
sessionStorage.setItem(this.sessionStoragesessionStorageKey, JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
// notifications$ = merge(
|
||||
// of(this._getNotifications()).pipe(filter((f) => !!f)),
|
||||
// this.listen<EnvelopeDTO<MessageBoardItemDTO[]>>('messageBoard')
|
||||
// ).pipe(
|
||||
// withLatestFrom(this.updateNotification$),
|
||||
// map(([d, update]) => {
|
||||
// console.log('notifications$', 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)
|
||||
// );
|
||||
|
||||
private _getNotifications(): EnvelopeDTO<MessageBoardItemDTO[]> {
|
||||
// private _storeNotifactions(data: EnvelopeDTO<MessageBoardItemDTO[]>) {
|
||||
// if (data) {
|
||||
// sessionStorage.setItem(this.sessionStoragesessionStorageKey, JSON.stringify(data));
|
||||
// }
|
||||
// }
|
||||
|
||||
// private _getNotifications(): EnvelopeDTO<MessageBoardItemDTO[]> {
|
||||
// const stringData = sessionStorage.getItem(this.sessionStoragesessionStorageKey);
|
||||
// if (stringData) {
|
||||
// return JSON.parse(stringData);
|
||||
// }
|
||||
// return undefined;
|
||||
// }
|
||||
|
||||
private _getNotifications(): Record<string, MessageBoardItemDTO[]> {
|
||||
const stringData = sessionStorage.getItem(this.sessionStoragesessionStorageKey);
|
||||
if (stringData) {
|
||||
return JSON.parse(stringData);
|
||||
}
|
||||
return undefined;
|
||||
return {};
|
||||
}
|
||||
|
||||
private _storeNotifactions(data: Record<string, MessageBoardItemDTO[]>) {
|
||||
if (data) {
|
||||
delete data['messageBoard/isa-update'];
|
||||
sessionStorage.setItem(this.sessionStoragesessionStorageKey, JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
|
||||
updateNotification() {
|
||||
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.',
|
||||
});
|
||||
this.refreshMessageBoardItems('messageBoard/isa-update', [
|
||||
{
|
||||
category: 'ISA-Update',
|
||||
type: 'update',
|
||||
headline: 'Update Benachrichtigung',
|
||||
text: 'Es steht eine aktuellere Version der ISA bereit. Bitte aktualisieren Sie die Anwendung.',
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import {
|
||||
CanActivateCartGuard,
|
||||
CanActivateCartWithProcessIdGuard,
|
||||
CanActivateCustomerGuard,
|
||||
CanActivateCustomerOrdersGuard,
|
||||
CanActivateCustomerOrdersWithProcessIdGuard,
|
||||
CanActivateCustomerWithProcessIdGuard,
|
||||
CanActivateGoodsInGuard,
|
||||
CanActivateGoodsOutGuard,
|
||||
@@ -59,22 +61,22 @@ const routes: Routes = [
|
||||
{
|
||||
path: 'order',
|
||||
loadChildren: () => import('@page/customer-order').then((m) => m.CustomerOrderModule),
|
||||
canActivate: [CanActivateGoodsOutGuard],
|
||||
canActivate: [CanActivateCustomerOrdersGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/order',
|
||||
loadChildren: () => import('@page/customer-order').then((m) => m.CustomerOrderModule),
|
||||
canActivate: [CanActivateGoodsOutWithProcessIdGuard],
|
||||
canActivate: [CanActivateCustomerOrdersWithProcessIdGuard],
|
||||
resolve: { processId: ProcessIdResolver },
|
||||
},
|
||||
{
|
||||
path: 'customer',
|
||||
loadChildren: () => import('@page/customer').then((m) => m.PageCustomerModule),
|
||||
loadChildren: () => import('@page/customer-rd').then((m) => m.CustomerModule),
|
||||
canActivate: [CanActivateCustomerGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/customer',
|
||||
loadChildren: () => import('@page/customer').then((m) => m.PageCustomerModule),
|
||||
loadChildren: () => import('@page/customer-rd').then((m) => m.CustomerModule),
|
||||
canActivate: [CanActivateCustomerWithProcessIdGuard],
|
||||
resolve: { processId: ProcessIdResolver },
|
||||
},
|
||||
|
||||
@@ -116,6 +116,7 @@ export class AppComponent implements OnInit {
|
||||
checkForUpdate() {
|
||||
interval(this._checkForUpdates).subscribe(() => {
|
||||
this._swUpdate.checkForUpdate().then((value) => {
|
||||
console.log('check for update', value);
|
||||
if (value) {
|
||||
this._notifications.updateNotification();
|
||||
}
|
||||
@@ -125,6 +126,7 @@ export class AppComponent implements OnInit {
|
||||
|
||||
initialCheckForUpdate() {
|
||||
this._swUpdate.checkForUpdate().then((value) => {
|
||||
console.log('initial check for update', value);
|
||||
if (value) {
|
||||
location.reload();
|
||||
}
|
||||
|
||||
@@ -32,11 +32,11 @@ import { IsaErrorHandler } from './providers/isa.error-handler';
|
||||
import { ScanAdapterModule, ScanAdapterService, ScanditScanAdapterModule } from '@adapter/scan';
|
||||
import { RootStateService } from './store/root-state.service';
|
||||
import * as Commands from './commands';
|
||||
import { UiIconModule, UI_ICON_CFG } from '@ui/icon';
|
||||
import { PreviewComponent } from './preview';
|
||||
import { NativeContainerService } from 'native-container';
|
||||
import { ShellModule } from '@shared/shell';
|
||||
import { MainComponent } from './main.component';
|
||||
import { IconModule } from '@shared/components/icon';
|
||||
|
||||
registerLocaleData(localeDe, localeDeExtra);
|
||||
registerLocaleData(localeDe, 'de', localeDeExtra);
|
||||
@@ -106,7 +106,7 @@ export function _notificationsHubOptionsFactory(config: Config, auth: AuthServic
|
||||
ScanAdapterModule.forRoot(),
|
||||
ScanditScanAdapterModule.forRoot(),
|
||||
PlatformModule,
|
||||
UiIconModule.forRoot(),
|
||||
IconModule.forRoot(),
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
@@ -135,11 +135,6 @@ export function _notificationsHubOptionsFactory(config: Config, auth: AuthServic
|
||||
useClass: IsaErrorHandler,
|
||||
},
|
||||
{ provide: LOCALE_ID, useValue: 'de-DE' },
|
||||
{
|
||||
provide: UI_ICON_CFG,
|
||||
useFactory: (config: Config) => config.get('@ui/icon'),
|
||||
deps: [Config],
|
||||
},
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { CheckoutNavigationService } from '@shared/services';
|
||||
import { first } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CanActivateCartGuard implements CanActivate {
|
||||
constructor(private readonly _applicationService: ApplicationService, private readonly _router: Router) {}
|
||||
constructor(private readonly _applicationService: ApplicationService, private _checkoutNavigationService: CheckoutNavigationService) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const processes = await this._applicationService.getProcesses$('customer').pipe(first()).toPromise();
|
||||
@@ -21,7 +22,7 @@ export class CanActivateCartGuard implements CanActivate {
|
||||
name: `Vorgang ${processes.length + 1}`,
|
||||
});
|
||||
}
|
||||
await this._router.navigate(['/kunde', lastActivatedProcessId, 'cart']);
|
||||
await this._checkoutNavigationService.navigateToCheckoutReview({ processId: lastActivatedProcessId });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
|
||||
import { ApplicationProcess, ApplicationService } from '@core/application';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { first } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CanActivateCustomerOrdersWithProcessIdGuard implements CanActivate {
|
||||
constructor(private readonly _applicationService: ApplicationService, private readonly _breadcrumbService: BreadcrumbService) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const process = await this._applicationService
|
||||
.getProcessById$(+route.params.processId)
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
if (!process) {
|
||||
await this._applicationService.createProcess({
|
||||
id: +route.params.processId,
|
||||
type: 'customer-order',
|
||||
section: 'customer',
|
||||
name: `Kundenbestellungen`,
|
||||
});
|
||||
}
|
||||
|
||||
await this.removeBreadcrumbWithSameProcessId(route);
|
||||
this._applicationService.activateProcess(+route.params.processId);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fix #3292: Alle Breadcrumbs die nichts mit dem aktuellen Prozess zu tun haben, müssen removed werden
|
||||
async removeBreadcrumbWithSameProcessId(route: ActivatedRouteSnapshot) {
|
||||
const crumbs = await this._breadcrumbService
|
||||
.getBreadcrumbByKey$(+route.params.processId)
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
// Entferne alle Crumbs die nichts mit den Kundenbestellungen zu tun haben
|
||||
if (crumbs.length > 1) {
|
||||
const crumbsToRemove = crumbs.filter((crumb) => crumb.tags.find((tag) => tag === 'customer-order') === undefined);
|
||||
for (const crumb of crumbsToRemove) {
|
||||
await this._breadcrumbService.removeBreadcrumb(crumb.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processNumber(processes: ApplicationProcess[]) {
|
||||
const processNumbers = processes?.map((process) => Number(process?.name?.replace(/\D/g, '')));
|
||||
return !!processNumbers && processNumbers?.length > 0 ? Math.max(...processNumbers) + 1 : 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
|
||||
import { ApplicationProcess, ApplicationService } from '@core/application';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { CustomerOrdersNavigationService } from '@shared/services';
|
||||
import { first } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CanActivateCustomerOrdersGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly _applicationService: ApplicationService,
|
||||
private readonly _checkoutService: DomainCheckoutService,
|
||||
private readonly _navigationService: CustomerOrdersNavigationService
|
||||
) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const processes = await this._applicationService.getProcesses$('customer').pipe(first()).toPromise();
|
||||
|
||||
let lastActivatedProcessId = (
|
||||
await this._applicationService.getLastActivatedProcessWithSectionAndType$('customer', 'cart').pipe(first()).toPromise()
|
||||
)?.id;
|
||||
|
||||
const lastActivatedCartCheckoutProcessId = (
|
||||
await this._applicationService.getLastActivatedProcessWithSectionAndType$('customer', 'cart-checkout').pipe(first()).toPromise()
|
||||
)?.id;
|
||||
|
||||
const activatedProcessId = await this._applicationService.getActivatedProcessId$().pipe(first()).toPromise();
|
||||
|
||||
// Darf nur reinkommen wenn der aktuell aktive Tab ein Bestellabschluss Tab ist
|
||||
if (!!lastActivatedCartCheckoutProcessId && lastActivatedCartCheckoutProcessId === activatedProcessId) {
|
||||
await this.fromCartCheckoutProcess(processes, route, lastActivatedCartCheckoutProcessId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!lastActivatedProcessId) {
|
||||
await this.fromGoodsOutProcess(processes, route);
|
||||
return false;
|
||||
} else {
|
||||
await this._navigationService.navigateToCustomerOrdersSearch({ processId: lastActivatedProcessId });
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bei offenen Kundenbestellungen und Klick auf Kundenbestellungen
|
||||
async fromGoodsOutProcess(processes: ApplicationProcess[], route: ActivatedRouteSnapshot) {
|
||||
const newProcessId = Date.now();
|
||||
await this._applicationService.createProcess({
|
||||
id: newProcessId,
|
||||
type: 'cart',
|
||||
section: 'customer',
|
||||
name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === 'cart'))}`,
|
||||
});
|
||||
|
||||
await this._navigationService.navigateToCustomerOrdersSearch({ processId: newProcessId });
|
||||
}
|
||||
|
||||
// Bei offener Bestellbestätigung und Klick auf Kundenbestellungen
|
||||
async fromCartCheckoutProcess(processes: ApplicationProcess[], route: ActivatedRouteSnapshot, processId: number) {
|
||||
// Um alle Checkout Daten zu resetten die mit dem Prozess assoziiert sind
|
||||
this._checkoutService.removeProcess({ processId });
|
||||
|
||||
// Ändere type cart-checkout zu customer-order
|
||||
this._applicationService.patchProcess(processId, {
|
||||
id: processId,
|
||||
type: 'cart',
|
||||
section: 'customer',
|
||||
name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === 'cart'))}`,
|
||||
data: {},
|
||||
});
|
||||
|
||||
// Navigation
|
||||
await this._navigationService.navigateToCustomerOrdersSearch({ processId });
|
||||
}
|
||||
|
||||
getUrlFromSnapshot(route: ActivatedRouteSnapshot, url: string[] = []): string[] {
|
||||
url.push(...route.url.map((segment) => segment.path));
|
||||
if (route.firstChild) {
|
||||
return this.getUrlFromSnapshot(route.firstChild, url);
|
||||
}
|
||||
return url.filter((segment) => !!segment);
|
||||
}
|
||||
|
||||
processNumber(processes: ApplicationProcess[]) {
|
||||
const processNumbers = processes?.map((process) => Number(process?.name?.replace(/\D/g, '')));
|
||||
return !!processNumbers && processNumbers.length > 0 ? this.findMissingNumber(processNumbers) : 1;
|
||||
}
|
||||
|
||||
findMissingNumber(processNumbers: number[]) {
|
||||
for (let missingNumber = 1; missingNumber < Math.max(...processNumbers); missingNumber++) {
|
||||
if (!processNumbers.find((number) => number === missingNumber)) {
|
||||
return missingNumber;
|
||||
}
|
||||
}
|
||||
return Math.max(...processNumbers) + 1;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
|
||||
import { ApplicationProcess, ApplicationService } from '@core/application';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { ProductCatalogNavigationService } from '@shared/services';
|
||||
import { first } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
@@ -9,7 +10,7 @@ export class CanActivateProductGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly _applicationService: ApplicationService,
|
||||
private readonly _checkoutService: DomainCheckoutService,
|
||||
private readonly _router: Router
|
||||
private readonly _navigationService: ProductCatalogNavigationService
|
||||
) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
@@ -38,17 +39,17 @@ export class CanActivateProductGuard implements CanActivate {
|
||||
}
|
||||
|
||||
if (!lastActivatedProcessId) {
|
||||
await this.fromCartProcess(processes, route);
|
||||
await this.fromCartProcess(processes);
|
||||
return false;
|
||||
} else {
|
||||
await this._router.navigate(this.getUrlFromSnapshot(route, ['/kunde', String(lastActivatedProcessId)]));
|
||||
await this._navigationService.navigateToProductSearch({ processId: lastActivatedProcessId });
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bei offener Artikelsuche/Kundensuche und Klick auf Footer Artikelsuche
|
||||
async fromCartProcess(processes: ApplicationProcess[], route: ActivatedRouteSnapshot) {
|
||||
async fromCartProcess(processes: ApplicationProcess[]) {
|
||||
const newProcessId = Date.now();
|
||||
await this._applicationService.createProcess({
|
||||
id: newProcessId,
|
||||
@@ -57,7 +58,7 @@ export class CanActivateProductGuard implements CanActivate {
|
||||
name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === 'cart'))}`,
|
||||
});
|
||||
|
||||
await this._router.navigate(this.getUrlFromSnapshot(route, ['/kunde', String(newProcessId)]));
|
||||
await this._navigationService.navigateToProductSearch({ processId: newProcessId });
|
||||
}
|
||||
|
||||
// Bei offener Warenausgabe und Klick auf Footer Artikelsuche
|
||||
@@ -81,7 +82,7 @@ export class CanActivateProductGuard implements CanActivate {
|
||||
});
|
||||
|
||||
// Navigation
|
||||
await this._router.navigate(this.getUrlFromSnapshot(route, ['/kunde', String(processId)]));
|
||||
await this._navigationService.navigateToProductSearch({ processId });
|
||||
}
|
||||
|
||||
// Bei offener Bestellbestätigung und Klick auf Footer Artikelsuche
|
||||
@@ -99,7 +100,7 @@ export class CanActivateProductGuard implements CanActivate {
|
||||
});
|
||||
|
||||
// Navigation
|
||||
await this._router.navigate(this.getUrlFromSnapshot(route, ['/kunde', String(processId)]));
|
||||
await this._navigationService.navigateToProductSearch({ processId });
|
||||
}
|
||||
|
||||
getUrlFromSnapshot(route: ActivatedRouteSnapshot, url: string[] = []): string[] {
|
||||
|
||||
@@ -5,6 +5,8 @@ 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-customer-orders.guard';
|
||||
export * from './can-activate-customer-orders-with-process-id.guard';
|
||||
export * from './can-activate-product-with-process-id.guard';
|
||||
export * from './can-activate-product.guard';
|
||||
export * from './can-activate-remission.guard';
|
||||
|
||||
@@ -52,11 +52,7 @@ export class IsAuthenticatedGuard implements CanActivate {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const result = await this._scanService
|
||||
.scan({
|
||||
exclude: ['Dev'],
|
||||
})
|
||||
?.toPromise();
|
||||
const result = await this._scanService.scan()?.toPromise();
|
||||
|
||||
if (typeof result === 'string') {
|
||||
try {
|
||||
|
||||
428
apps/isa-app/src/assets/icons.json
Normal file
428
apps/isa-app/src/assets/icons.json
Normal file
File diff suppressed because one or more lines are too long
11
apps/isa-app/src/assets/images/Icon_DR.svg
Normal file
11
apps/isa-app/src/assets/images/Icon_DR.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="22px" height="18px" viewBox="0 0 22 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 52.2 (67145) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Icon_HC</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Hugendubel_Icons" transform="translate(-29.000000, -177.000000)" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.3">
|
||||
<path d="M32.725699,178.000628 C32.7430505,177.999791 32.7604307,177.999791 32.7777823,178.000628 L37.5260449,178.000628 C38.53109,178.000628 39.44018,178.547926 40.0000026,179.340692 C40.5598253,178.547926 41.4689153,178.000628 42.4739603,178.000628 L47.222223,178.000628 C47.529035,178.00066 47.7777477,178.256627 47.7777784,178.572389 L47.7777784,179.71591 L49.4444446,179.71591 C49.7512567,179.715942 49.9999694,179.971909 50,180.287671 L50,192.008763 C49.9999694,192.324524 49.7512567,192.580492 49.4444446,192.580523 L42.4739603,192.580523 C41.4766486,192.580523 40.8524541,192.949423 40.4947942,193.688309 C40.3998428,193.879608 40.208727,194 40.0000026,194 C39.7912783,194 39.6001624,193.879608 39.5052111,193.688309 C39.1475512,192.949423 38.5233566,192.580523 37.5260449,192.580523 L30.5555607,192.580523 C30.2487486,192.580492 30.0000359,192.324524 30.0000053,192.008763 L30.0000053,180.287671 C29.9987652,179.991708 30.2171687,179.743681 30.5034773,179.71591 C30.5208289,179.715072 30.5382091,179.715072 30.5555607,179.71591 L32.2222269,179.71591 L32.2222269,178.572389 C32.2209869,178.276426 32.4393904,178.028399 32.725699,178.000628 Z M33.3333377,179.14415 L33.3333377,189.43584 L36.6232674,189.43584 C37.6190746,189.43584 38.5547188,189.729711 39.2621556,190.356017 C39.3270606,190.413476 39.3849347,190.480265 39.4444472,190.543626 L39.4444472,180.957703 C39.4433388,180.936873 39.4433388,180.915996 39.4444472,180.895166 C39.4444472,180.068361 38.4768339,179.14415 37.5260449,179.14415 L33.3333377,179.14415 Z M42.4739603,179.14415 C41.5231714,179.14415 40.555558,180.068361 40.555558,180.895166 C40.5555806,180.898144 40.5555806,180.901122 40.555558,180.9041 L40.555558,190.543626 C40.6150705,190.480265 40.6729447,190.413476 40.7378497,190.356017 C41.4452864,189.729711 42.3809306,189.43584 43.3767379,189.43584 L46.6666675,189.43584 L46.6666675,179.14415 L42.4739603,179.14415 Z M31.1111161,180.859431 L31.1111161,191.437002 L37.5260449,191.437002 C38.0365968,191.437002 38.5189494,191.531483 38.9496557,191.713949 C38.8273679,191.527334 38.6888269,191.36055 38.5329891,191.222592 C38.0547048,190.799175 37.405738,190.579361 36.6232674,190.579361 L32.7777823,190.579361 C32.4709702,190.57933 32.2222575,190.323362 32.2222269,190.007601 L32.2222269,180.859431 L31.1111161,180.859431 Z M47.7777784,180.859431 L47.7777784,190.007601 C47.7777477,190.323362 47.529035,190.57933 47.222223,190.579361 L43.3767379,190.579361 C42.5942672,190.579361 41.9453004,190.799175 41.4670161,191.222592 C41.3107359,191.360944 41.1725734,191.526903 41.0503496,191.713949 C41.4810558,191.531483 41.9634085,191.437002 42.4739603,191.437002 L48.8888892,191.437002 L48.8888892,180.859431 L47.7777784,180.859431 Z M35.5,182.116677 L37.5,182.116677 C37.7761424,182.116677 38,182.340535 38,182.616677 L38,182.645847 C38,182.921989 37.7761424,183.145847 37.5,183.145847 L35.5,183.145847 C35.2238576,183.145847 35,182.921989 35,182.645847 L35,182.616677 C35,182.340535 35.2238576,182.116677 35.5,182.116677 Z M35.5,184.175016 L37.5,184.175016 C37.7761424,184.175016 38,184.398874 38,184.675016 L38,184.704185 C38,184.980328 37.7761424,185.204185 37.5,185.204185 L35.5,185.204185 C35.2238576,185.204185 35,184.980328 35,184.704185 L35,184.675016 C35,184.398874 35.2238576,184.175016 35.5,184.175016 Z M35.5,186.233355 L37.5,186.233355 C37.7761424,186.233355 38,186.457212 38,186.733355 L38,186.762524 C38,187.038666 37.7761424,187.262524 37.5,187.262524 L35.5,187.262524 C35.2238576,187.262524 35,187.038666 35,186.762524 L35,186.733355 C35,186.457212 35.2238576,186.233355 35.5,186.233355 Z M42.5,182.116677 L44.5,182.116677 C44.7761424,182.116677 45,182.340535 45,182.616677 L45,182.645847 C45,182.921989 44.7761424,183.145847 44.5,183.145847 L42.5,183.145847 C42.2238576,183.145847 42,182.921989 42,182.645847 L42,182.616677 C42,182.340535 42.2238576,182.116677 42.5,182.116677 Z M42.5,184.175016 L44.5,184.175016 C44.7761424,184.175016 45,184.398874 45,184.675016 L45,184.704185 C45,184.980328 44.7761424,185.204185 44.5,185.204185 L42.5,185.204185 C42.2238576,185.204185 42,184.980328 42,184.704185 L42,184.675016 C42,184.398874 42.2238576,184.175016 42.5,184.175016 Z M42.5,186.233355 L44.5,186.233355 C44.7761424,186.233355 45,186.457212 45,186.733355 L45,186.762524 C45,187.038666 44.7761424,187.262524 44.5,187.262524 L42.5,187.262524 C42.2238576,187.262524 42,187.038666 42,186.762524 L42,186.733355 C42,186.457212 42.2238576,186.233355 42.5,186.233355 Z" id="Icon_HC"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.0 KiB |
11
apps/isa-app/src/assets/images/Icon_GEH.svg
Normal file
11
apps/isa-app/src/assets/images/Icon_GEH.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="22px" height="18px" viewBox="0 0 22 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 52.2 (67145) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Icon_HC</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Hugendubel_Icons" transform="translate(-29.000000, -177.000000)" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.3">
|
||||
<path d="M32.725699,178.000628 C32.7430505,177.999791 32.7604307,177.999791 32.7777823,178.000628 L37.5260449,178.000628 C38.53109,178.000628 39.44018,178.547926 40.0000026,179.340692 C40.5598253,178.547926 41.4689153,178.000628 42.4739603,178.000628 L47.222223,178.000628 C47.529035,178.00066 47.7777477,178.256627 47.7777784,178.572389 L47.7777784,179.71591 L49.4444446,179.71591 C49.7512567,179.715942 49.9999694,179.971909 50,180.287671 L50,192.008763 C49.9999694,192.324524 49.7512567,192.580492 49.4444446,192.580523 L42.4739603,192.580523 C41.4766486,192.580523 40.8524541,192.949423 40.4947942,193.688309 C40.3998428,193.879608 40.208727,194 40.0000026,194 C39.7912783,194 39.6001624,193.879608 39.5052111,193.688309 C39.1475512,192.949423 38.5233566,192.580523 37.5260449,192.580523 L30.5555607,192.580523 C30.2487486,192.580492 30.0000359,192.324524 30.0000053,192.008763 L30.0000053,180.287671 C29.9987652,179.991708 30.2171687,179.743681 30.5034773,179.71591 C30.5208289,179.715072 30.5382091,179.715072 30.5555607,179.71591 L32.2222269,179.71591 L32.2222269,178.572389 C32.2209869,178.276426 32.4393904,178.028399 32.725699,178.000628 Z M33.3333377,179.14415 L33.3333377,189.43584 L36.6232674,189.43584 C37.6190746,189.43584 38.5547188,189.729711 39.2621556,190.356017 C39.3270606,190.413476 39.3849347,190.480265 39.4444472,190.543626 L39.4444472,180.957703 C39.4433388,180.936873 39.4433388,180.915996 39.4444472,180.895166 C39.4444472,180.068361 38.4768339,179.14415 37.5260449,179.14415 L33.3333377,179.14415 Z M42.4739603,179.14415 C41.5231714,179.14415 40.555558,180.068361 40.555558,180.895166 C40.5555806,180.898144 40.5555806,180.901122 40.555558,180.9041 L40.555558,190.543626 C40.6150705,190.480265 40.6729447,190.413476 40.7378497,190.356017 C41.4452864,189.729711 42.3809306,189.43584 43.3767379,189.43584 L46.6666675,189.43584 L46.6666675,179.14415 L42.4739603,179.14415 Z M31.1111161,180.859431 L31.1111161,191.437002 L37.5260449,191.437002 C38.0365968,191.437002 38.5189494,191.531483 38.9496557,191.713949 C38.8273679,191.527334 38.6888269,191.36055 38.5329891,191.222592 C38.0547048,190.799175 37.405738,190.579361 36.6232674,190.579361 L32.7777823,190.579361 C32.4709702,190.57933 32.2222575,190.323362 32.2222269,190.007601 L32.2222269,180.859431 L31.1111161,180.859431 Z M47.7777784,180.859431 L47.7777784,190.007601 C47.7777477,190.323362 47.529035,190.57933 47.222223,190.579361 L43.3767379,190.579361 C42.5942672,190.579361 41.9453004,190.799175 41.4670161,191.222592 C41.3107359,191.360944 41.1725734,191.526903 41.0503496,191.713949 C41.4810558,191.531483 41.9634085,191.437002 42.4739603,191.437002 L48.8888892,191.437002 L48.8888892,180.859431 L47.7777784,180.859431 Z M35.5,182.116677 L37.5,182.116677 C37.7761424,182.116677 38,182.340535 38,182.616677 L38,182.645847 C38,182.921989 37.7761424,183.145847 37.5,183.145847 L35.5,183.145847 C35.2238576,183.145847 35,182.921989 35,182.645847 L35,182.616677 C35,182.340535 35.2238576,182.116677 35.5,182.116677 Z M35.5,184.175016 L37.5,184.175016 C37.7761424,184.175016 38,184.398874 38,184.675016 L38,184.704185 C38,184.980328 37.7761424,185.204185 37.5,185.204185 L35.5,185.204185 C35.2238576,185.204185 35,184.980328 35,184.704185 L35,184.675016 C35,184.398874 35.2238576,184.175016 35.5,184.175016 Z M35.5,186.233355 L37.5,186.233355 C37.7761424,186.233355 38,186.457212 38,186.733355 L38,186.762524 C38,187.038666 37.7761424,187.262524 37.5,187.262524 L35.5,187.262524 C35.2238576,187.262524 35,187.038666 35,186.762524 L35,186.733355 C35,186.457212 35.2238576,186.233355 35.5,186.233355 Z M42.5,182.116677 L44.5,182.116677 C44.7761424,182.116677 45,182.340535 45,182.616677 L45,182.645847 C45,182.921989 44.7761424,183.145847 44.5,183.145847 L42.5,183.145847 C42.2238576,183.145847 42,182.921989 42,182.645847 L42,182.616677 C42,182.340535 42.2238576,182.116677 42.5,182.116677 Z M42.5,184.175016 L44.5,184.175016 C44.7761424,184.175016 45,184.398874 45,184.675016 L45,184.704185 C45,184.980328 44.7761424,185.204185 44.5,185.204185 L42.5,185.204185 C42.2238576,185.204185 42,184.980328 42,184.704185 L42,184.675016 C42,184.398874 42.2238576,184.175016 42.5,184.175016 Z M42.5,186.233355 L44.5,186.233355 C44.7761424,186.233355 45,186.457212 45,186.733355 L45,186.762524 C45,187.038666 44.7761424,187.262524 44.5,187.262524 L42.5,187.262524 C42.2238576,187.262524 42,187.038666 42,186.762524 L42,186.733355 C42,186.457212 42.2238576,186.233355 42.5,186.233355 Z" id="Icon_HC"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.0 KiB |
11
apps/isa-app/src/assets/images/Icon_PP.svg
Normal file
11
apps/isa-app/src/assets/images/Icon_PP.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="22px" height="18px" viewBox="0 0 22 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 52.2 (67145) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Icon_HC</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Hugendubel_Icons" transform="translate(-29.000000, -177.000000)" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.3">
|
||||
<path d="M32.725699,178.000628 C32.7430505,177.999791 32.7604307,177.999791 32.7777823,178.000628 L37.5260449,178.000628 C38.53109,178.000628 39.44018,178.547926 40.0000026,179.340692 C40.5598253,178.547926 41.4689153,178.000628 42.4739603,178.000628 L47.222223,178.000628 C47.529035,178.00066 47.7777477,178.256627 47.7777784,178.572389 L47.7777784,179.71591 L49.4444446,179.71591 C49.7512567,179.715942 49.9999694,179.971909 50,180.287671 L50,192.008763 C49.9999694,192.324524 49.7512567,192.580492 49.4444446,192.580523 L42.4739603,192.580523 C41.4766486,192.580523 40.8524541,192.949423 40.4947942,193.688309 C40.3998428,193.879608 40.208727,194 40.0000026,194 C39.7912783,194 39.6001624,193.879608 39.5052111,193.688309 C39.1475512,192.949423 38.5233566,192.580523 37.5260449,192.580523 L30.5555607,192.580523 C30.2487486,192.580492 30.0000359,192.324524 30.0000053,192.008763 L30.0000053,180.287671 C29.9987652,179.991708 30.2171687,179.743681 30.5034773,179.71591 C30.5208289,179.715072 30.5382091,179.715072 30.5555607,179.71591 L32.2222269,179.71591 L32.2222269,178.572389 C32.2209869,178.276426 32.4393904,178.028399 32.725699,178.000628 Z M33.3333377,179.14415 L33.3333377,189.43584 L36.6232674,189.43584 C37.6190746,189.43584 38.5547188,189.729711 39.2621556,190.356017 C39.3270606,190.413476 39.3849347,190.480265 39.4444472,190.543626 L39.4444472,180.957703 C39.4433388,180.936873 39.4433388,180.915996 39.4444472,180.895166 C39.4444472,180.068361 38.4768339,179.14415 37.5260449,179.14415 L33.3333377,179.14415 Z M42.4739603,179.14415 C41.5231714,179.14415 40.555558,180.068361 40.555558,180.895166 C40.5555806,180.898144 40.5555806,180.901122 40.555558,180.9041 L40.555558,190.543626 C40.6150705,190.480265 40.6729447,190.413476 40.7378497,190.356017 C41.4452864,189.729711 42.3809306,189.43584 43.3767379,189.43584 L46.6666675,189.43584 L46.6666675,179.14415 L42.4739603,179.14415 Z M31.1111161,180.859431 L31.1111161,191.437002 L37.5260449,191.437002 C38.0365968,191.437002 38.5189494,191.531483 38.9496557,191.713949 C38.8273679,191.527334 38.6888269,191.36055 38.5329891,191.222592 C38.0547048,190.799175 37.405738,190.579361 36.6232674,190.579361 L32.7777823,190.579361 C32.4709702,190.57933 32.2222575,190.323362 32.2222269,190.007601 L32.2222269,180.859431 L31.1111161,180.859431 Z M47.7777784,180.859431 L47.7777784,190.007601 C47.7777477,190.323362 47.529035,190.57933 47.222223,190.579361 L43.3767379,190.579361 C42.5942672,190.579361 41.9453004,190.799175 41.4670161,191.222592 C41.3107359,191.360944 41.1725734,191.526903 41.0503496,191.713949 C41.4810558,191.531483 41.9634085,191.437002 42.4739603,191.437002 L48.8888892,191.437002 L48.8888892,180.859431 L47.7777784,180.859431 Z M35.5,182.116677 L37.5,182.116677 C37.7761424,182.116677 38,182.340535 38,182.616677 L38,182.645847 C38,182.921989 37.7761424,183.145847 37.5,183.145847 L35.5,183.145847 C35.2238576,183.145847 35,182.921989 35,182.645847 L35,182.616677 C35,182.340535 35.2238576,182.116677 35.5,182.116677 Z M35.5,184.175016 L37.5,184.175016 C37.7761424,184.175016 38,184.398874 38,184.675016 L38,184.704185 C38,184.980328 37.7761424,185.204185 37.5,185.204185 L35.5,185.204185 C35.2238576,185.204185 35,184.980328 35,184.704185 L35,184.675016 C35,184.398874 35.2238576,184.175016 35.5,184.175016 Z M35.5,186.233355 L37.5,186.233355 C37.7761424,186.233355 38,186.457212 38,186.733355 L38,186.762524 C38,187.038666 37.7761424,187.262524 37.5,187.262524 L35.5,187.262524 C35.2238576,187.262524 35,187.038666 35,186.762524 L35,186.733355 C35,186.457212 35.2238576,186.233355 35.5,186.233355 Z M42.5,182.116677 L44.5,182.116677 C44.7761424,182.116677 45,182.340535 45,182.616677 L45,182.645847 C45,182.921989 44.7761424,183.145847 44.5,183.145847 L42.5,183.145847 C42.2238576,183.145847 42,182.921989 42,182.645847 L42,182.616677 C42,182.340535 42.2238576,182.116677 42.5,182.116677 Z M42.5,184.175016 L44.5,184.175016 C44.7761424,184.175016 45,184.398874 45,184.675016 L45,184.704185 C45,184.980328 44.7761424,185.204185 44.5,185.204185 L42.5,185.204185 C42.2238576,185.204185 42,184.980328 42,184.704185 L42,184.675016 C42,184.398874 42.2238576,184.175016 42.5,184.175016 Z M42.5,186.233355 L44.5,186.233355 C44.7761424,186.233355 45,186.457212 45,186.733355 L45,186.762524 C45,187.038666 44.7761424,187.262524 44.5,187.262524 L42.5,187.262524 C42.2238576,187.262524 42,187.038666 42,186.762524 L42,186.733355 C42,186.457212 42.2238576,186.233355 42.5,186.233355 Z" id="Icon_HC"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.0 KiB |
@@ -16,6 +16,9 @@
|
||||
"@core/logger": {
|
||||
"logLevel": "debug"
|
||||
},
|
||||
"@domain/checkout": {
|
||||
"olaExpiration": "5m"
|
||||
},
|
||||
"@swagger/isa": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/isa/v1"
|
||||
},
|
||||
@@ -69,6 +72,8 @@
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "AQZyKCc+BEkNL00Y3h3FjawGLF+INUj7cVb0My91hl8ffiW873T8FTV1k4TIZJx5RwcJlYxhgsxHVcnM4AJgSwJhbAfxJmP/3XGijLlLp3XUIRjQwFtf7UlZAFZ7Vrt1/WSf7kxxrFQ2SE2AQwLqPg9DL+hHEfd4xT/15n8p2q7qUlCKLsV6jF12Pd7koFNSWNL3ZIkRtd1ma99/321dnwAJHFGXqWg5nprJ7sYtqUqNQ8Er9SlvKbhnw3AipHzKpz0O3oNfUsr6NlZivRBhMhCZLo5WpXo1m9uIU8zLEWMNDJ+wGUctcGxE3eCptP2zLXUgxxjB+0EXOUtT/GWUc/Ip61CMiyUf7Paz026E2eYil2yWgfkTP5CUgDMNGZFuAA1T5PhB9FRW51CjAIvwOKVMCvfixJiVoUsXHnWH2ZnXqtbDR/uEZBE7OKoBlaPL4G3Lvgdqym5EjROAztUXb6wOmVDiGzzqgizyZnIcxFBSKJAownGj9Vh4/Y/Ag1xzGzNtjz3ngSRfMfIIq/q2Q51uiLiv7mBVliPvPWMUTfTjnqnK/OSBlR2ID+COJqnUKpQMedPyOT3IMznmM6gQCmyYO5KE0MkfhFh6+pdNi6oJM2iZsxK1Z1V+GRSOIwrJEoajjDJkh439XjXk8NExFvplrLjK/oL/dsHIZiG6U5GVWW92kGkuXkJCeUz1CET3paxbGqwrd53r5d6gFABbC12CtcP2JeH4YYCpHYyPQacf0prj9Hdq3wDztShC9tH+4UQS/GbaDHKcS1ANIyPuTxHmBFtPuCJ9Uagy5QBEc8eAz2nfsbfaUxYzco6u/zhNsFbqp6zgQIxs5OcqDQ=="
|
||||
}
|
||||
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"title": "ISA - Integration",
|
||||
"silentRefresh": {
|
||||
"interval": 300000
|
||||
"interval": 60000
|
||||
},
|
||||
"@cdn/product-image": {
|
||||
"url": "https://produktbilder.paragon-data.net"
|
||||
@@ -15,6 +15,9 @@
|
||||
"@core/logger": {
|
||||
"logLevel": "debug"
|
||||
},
|
||||
"@domain/checkout": {
|
||||
"olaExpiration": "5m"
|
||||
},
|
||||
"@swagger/isa": {
|
||||
"rootUrl": "https://isa-integration.paragon-data.net/isa/v1"
|
||||
},
|
||||
@@ -66,8 +69,9 @@
|
||||
"assortment": 6000
|
||||
}
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"checkForUpdates": 900000,
|
||||
"licence": {
|
||||
"scandit": "AQZyKCc+BEkNL00Y3h3FjawGLF+INUj7cVb0My91hl8ffiW873T8FTV1k4TIZJx5RwcJlYxhgsxHVcnM4AJgSwJhbAfxJmP/3XGijLlLp3XUIRjQwFtf7UlZAFZ7Vrt1/WSf7kxxrFQ2SE2AQwLqPg9DL+hHEfd4xT/15n8p2q7qUlCKLsV6jF12Pd7koFNSWNL3ZIkRtd1ma99/321dnwAJHFGXqWg5nprJ7sYtqUqNQ8Er9SlvKbhnw3AipHzKpz0O3oNfUsr6NlZivRBhMhCZLo5WpXo1m9uIU8zLEWMNDJ+wGUctcGxE3eCptP2zLXUgxxjB+0EXOUtT/GWUc/Ip61CMiyUf7Paz026E2eYil2yWgfkTP5CUgDMNGZFuAA1T5PhB9FRW51CjAIvwOKVMCvfixJiVoUsXHnWH2ZnXqtbDR/uEZBE7OKoBlaPL4G3Lvgdqym5EjROAztUXb6wOmVDiGzzqgizyZnIcxFBSKJAownGj9Vh4/Y/Ag1xzGzNtjz3ngSRfMfIIq/q2Q51uiLiv7mBVliPvPWMUTfTjnqnK/OSBlR2ID+COJqnUKpQMedPyOT3IMznmM6gQCmyYO5KE0MkfhFh6+pdNi6oJM2iZsxK1Z1V+GRSOIwrJEoajjDJkh439XjXk8NExFvplrLjK/oL/dsHIZiG6U5GVWW92kGkuXkJCeUz1CET3paxbGqwrd53r5d6gFABbC12CtcP2JeH4YYCpHYyPQacf0prj9Hdq3wDztShC9tH+4UQS/GbaDHKcS1ANIyPuTxHmBFtPuCJ9Uagy5QBEc8eAz2nfsbfaUxYzco6u/zhNsFbqp6zgQIxs5OcqDQ=="
|
||||
}
|
||||
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -16,6 +16,9 @@
|
||||
"@core/logger": {
|
||||
"logLevel": "debug"
|
||||
},
|
||||
"@domain/checkout": {
|
||||
"olaExpiration": "5m"
|
||||
},
|
||||
"@swagger/isa": {
|
||||
"rootUrl": "https://isa.paragon-systems.de/isa/v1"
|
||||
},
|
||||
@@ -69,6 +72,7 @@
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "AfHi/mY+RbwJD5nC7SuWn3I14pFUOfSbQ2QG//4aV3zWQjwix30kHqsqraA8ZiipDBql8YlwIyV6VPBMUiAX4s9YHDxHHsWwq2BUB3ImzDEcU1jmMH/5yakGUYpCQ68D0iZ8SG9sS0QBb3iFdCHc1r9DFr1cMTxM7zOvb/AUoIVmieHZXnx9ioUgCvczsLiuX3hwvTW3lhbvJ4uUyqTWK4sWFVwoY4AIWSFrPwwrkV2DksMKT5fMJT3GWgPypvTIGwWvpRfLWwKlc1Z3ckyb84khsnaWD2wr+hdgu/K8YIMmgGszm5KIZ/G05YfDNZtQ4jby+5RZvQwWR8rxM35rJgf73OkMSpuL9jw3T0TTAlvpkGRLzVVuCw9VjlBLqfPNEZ6VsEwFuAla9IYUvFHCsjypg2J6UpxHXrTYmbsSu5Jm8frVfS5znPPTO9D/4rF6ZVv2PxY9PgUgJUvwMa/VMc/nse3RRRf8RGT4rUItfJDFO8pujD76vVEWq/KixQRoMdLgDLyxhsFVftkxqhZhyEfFZzsEy49LSojJ28vpHpBWLeCQBmnZ7JZ4C5yOQiqSQV/assBq2zJN2q+vCDp8qy5j1rED1SX5Ec7JpgpgnU4chLIf5Zn7bP/hNGT3pEYBuXeDXXN8ke1pcc3fc3m0FysDG0o56XVCUqImZ8Ezi8eujZciKDrWbtljhKTj7cnfuJx0sVHF6Bh5i4YfgA/Z+NL+MtH2EVIF67e6hEz6PWYTcoh3ybBaJfxb2FNvGJutNKg04GwMhYq6K2IddBt0fDiBt0SGM0oSBlUP3DKCUmXcf2a6ASbrcqv6Wz1jHt0pY4U8bEpg7qSbW3VDyvdPgyQ="
|
||||
}
|
||||
"scandit": "AZZzfQ+eLFl3Dzf1QSBag1lDibIoOPh4W33erRIRe3SDUMkHDX8eczEjd2TnfRMWoE5lXOBGtESCWICN9EbrmI1S9Lu5APsvvEOD+K54ADwIVawx0HNZRAc8/+9Vf/izcEGOFQFGBQJyR6vzdzFv5HcjznhxI9E3LiF+uVQPtCqsVYzpkMWIrC5VCg2uwNrj9Bw6f8zYi/lZPrDMS5yVKVcajeK7sh9QAq17dR0opjIIuP5t5nDEJ7hnITwtTR5HaM6cX/KhKpTILOgKexvLYqrK6QJWpU85sDwqwn6T7av4V68qL3XrUo60dScop4QsvraQe1HkRsffl6DkAEoX0RNMS5qVWjGerW7lvA/DQd9hsAO3jWFDR9hVDyt2VvmzzFKnHYqTYxC5qG4bCEJ0RJjy6tEP5Q7vL5SxWygVadmjPv+TwDOCS7DxzxIjcO+BXQY7gW6qn0hx9fXzyvO3avrGWqyImMlgEApZq+36ANqtRcPD/stEe4i0N9dSPhYoHPcc/9/9jpts43FozlgfY4wY8Wt5ybB3X0caISMmB/klFIJKKN7num439z3+Xk7ENB/Xvb0XAtnOt/cuxQYsGQ7fb62GOO/7Va5fdE9ZfaIJsS5ToE6oIbV04pLUssJf9cUMsyPFVELYSJmyGPQQFRz0TTxxRvPapIWrfa2x5x3hYUpNTAdY3v0fN9l/1ZqNSBmIBLH/LoXaVJQ2DydGD1/QFZ2Z/S7zTYKg5/cSEpUgiYtbwutNZSjRH29ucSizC524k+Zst95T8G7LJaWCT8SQAcKXqCnjpiEGWzD++h0jXjn6BWjUnIHi0te+27vF/z6UQL00sWco5hUIqF66EiU="
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
@@ -16,6 +16,9 @@
|
||||
"@core/logger": {
|
||||
"logLevel": "debug"
|
||||
},
|
||||
"@domain/checkout": {
|
||||
"olaExpiration": "5m"
|
||||
},
|
||||
"@swagger/isa": {
|
||||
"rootUrl": "https://isa-staging.paragon-systems.de/isa/v1"
|
||||
},
|
||||
@@ -69,6 +72,7 @@
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "AfHi/mY+RbwJD5nC7SuWn3I14pFUOfSbQ2QG//4aV3zWQjwix30kHqsqraA8ZiipDBql8YlwIyV6VPBMUiAX4s9YHDxHHsWwq2BUB3ImzDEcU1jmMH/5yakGUYpCQ68D0iZ8SG9sS0QBb3iFdCHc1r9DFr1cMTxM7zOvb/AUoIVmieHZXnx9ioUgCvczsLiuX3hwvTW3lhbvJ4uUyqTWK4sWFVwoY4AIWSFrPwwrkV2DksMKT5fMJT3GWgPypvTIGwWvpRfLWwKlc1Z3ckyb84khsnaWD2wr+hdgu/K8YIMmgGszm5KIZ/G05YfDNZtQ4jby+5RZvQwWR8rxM35rJgf73OkMSpuL9jw3T0TTAlvpkGRLzVVuCw9VjlBLqfPNEZ6VsEwFuAla9IYUvFHCsjypg2J6UpxHXrTYmbsSu5Jm8frVfS5znPPTO9D/4rF6ZVv2PxY9PgUgJUvwMa/VMc/nse3RRRf8RGT4rUItfJDFO8pujD76vVEWq/KixQRoMdLgDLyxhsFVftkxqhZhyEfFZzsEy49LSojJ28vpHpBWLeCQBmnZ7JZ4C5yOQiqSQV/assBq2zJN2q+vCDp8qy5j1rED1SX5Ec7JpgpgnU4chLIf5Zn7bP/hNGT3pEYBuXeDXXN8ke1pcc3fc3m0FysDG0o56XVCUqImZ8Ezi8eujZciKDrWbtljhKTj7cnfuJx0sVHF6Bh5i4YfgA/Z+NL+MtH2EVIF67e6hEz6PWYTcoh3ybBaJfxb2FNvGJutNKg04GwMhYq6K2IddBt0fDiBt0SGM0oSBlUP3DKCUmXcf2a6ASbrcqv6Wz1jHt0pY4U8bEpg7qSbW3VDyvdPgyQ="
|
||||
}
|
||||
"scandit": "AZZzfQ+eLFl3Dzf1QSBag1lDibIoOPh4W33erRIRe3SDUMkHDX8eczEjd2TnfRMWoE5lXOBGtESCWICN9EbrmI1S9Lu5APsvvEOD+K54ADwIVawx0HNZRAc8/+9Vf/izcEGOFQFGBQJyR6vzdzFv5HcjznhxI9E3LiF+uVQPtCqsVYzpkMWIrC5VCg2uwNrj9Bw6f8zYi/lZPrDMS5yVKVcajeK7sh9QAq17dR0opjIIuP5t5nDEJ7hnITwtTR5HaM6cX/KhKpTILOgKexvLYqrK6QJWpU85sDwqwn6T7av4V68qL3XrUo60dScop4QsvraQe1HkRsffl6DkAEoX0RNMS5qVWjGerW7lvA/DQd9hsAO3jWFDR9hVDyt2VvmzzFKnHYqTYxC5qG4bCEJ0RJjy6tEP5Q7vL5SxWygVadmjPv+TwDOCS7DxzxIjcO+BXQY7gW6qn0hx9fXzyvO3avrGWqyImMlgEApZq+36ANqtRcPD/stEe4i0N9dSPhYoHPcc/9/9jpts43FozlgfY4wY8Wt5ybB3X0caISMmB/klFIJKKN7num439z3+Xk7ENB/Xvb0XAtnOt/cuxQYsGQ7fb62GOO/7Va5fdE9ZfaIJsS5ToE6oIbV04pLUssJf9cUMsyPFVELYSJmyGPQQFRz0TTxxRvPapIWrfa2x5x3hYUpNTAdY3v0fN9l/1ZqNSBmIBLH/LoXaVJQ2DydGD1/QFZ2Z/S7zTYKg5/cSEpUgiYtbwutNZSjRH29ucSizC524k+Zst95T8G7LJaWCT8SQAcKXqCnjpiEGWzD++h0jXjn6BWjUnIHi0te+27vF/z6UQL00sWco5hUIqF66EiU="
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
@@ -17,6 +17,9 @@
|
||||
"@core/logger": {
|
||||
"logLevel": "debug"
|
||||
},
|
||||
"@domain/checkout": {
|
||||
"olaExpiration": "5m"
|
||||
},
|
||||
"@swagger/isa": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/isa/v1"
|
||||
},
|
||||
@@ -70,6 +73,7 @@
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "AQZyKCc+BEkNL00Y3h3FjawGLF+INUj7cVb0My91hl8ffiW873T8FTV1k4TIZJx5RwcJlYxhgsxHVcnM4AJgSwJhbAfxJmP/3XGijLlLp3XUIRjQwFtf7UlZAFZ7Vrt1/WSf7kxxrFQ2SE2AQwLqPg9DL+hHEfd4xT/15n8p2q7qUlCKLsV6jF12Pd7koFNSWNL3ZIkRtd1ma99/321dnwAJHFGXqWg5nprJ7sYtqUqNQ8Er9SlvKbhnw3AipHzKpz0O3oNfUsr6NlZivRBhMhCZLo5WpXo1m9uIU8zLEWMNDJ+wGUctcGxE3eCptP2zLXUgxxjB+0EXOUtT/GWUc/Ip61CMiyUf7Paz026E2eYil2yWgfkTP5CUgDMNGZFuAA1T5PhB9FRW51CjAIvwOKVMCvfixJiVoUsXHnWH2ZnXqtbDR/uEZBE7OKoBlaPL4G3Lvgdqym5EjROAztUXb6wOmVDiGzzqgizyZnIcxFBSKJAownGj9Vh4/Y/Ag1xzGzNtjz3ngSRfMfIIq/q2Q51uiLiv7mBVliPvPWMUTfTjnqnK/OSBlR2ID+COJqnUKpQMedPyOT3IMznmM6gQCmyYO5KE0MkfhFh6+pdNi6oJM2iZsxK1Z1V+GRSOIwrJEoajjDJkh439XjXk8NExFvplrLjK/oL/dsHIZiG6U5GVWW92kGkuXkJCeUz1CET3paxbGqwrd53r5d6gFABbC12CtcP2JeH4YYCpHYyPQacf0prj9Hdq3wDztShC9tH+4UQS/GbaDHKcS1ANIyPuTxHmBFtPuCJ9Uagy5QBEc8eAz2nfsbfaUxYzco6u/zhNsFbqp6zgQIxs5OcqDQ=="
|
||||
}
|
||||
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export const environment = {
|
||||
production: true,
|
||||
debug: false,
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
export const environment = {
|
||||
production: false,
|
||||
debug: false,
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -14,26 +14,28 @@ if (environment.production) {
|
||||
|
||||
const debugService = new DebugService();
|
||||
|
||||
const consoleLog = console.log;
|
||||
if (environment.debug) {
|
||||
const consoleLog = console.log;
|
||||
|
||||
console.log = (...args) => {
|
||||
debugService.add({ type: 'log', args });
|
||||
consoleLog(...args);
|
||||
};
|
||||
console.log = (...args) => {
|
||||
debugService.add({ type: 'log', args });
|
||||
consoleLog(...args);
|
||||
};
|
||||
|
||||
const consoleWarn = console.warn;
|
||||
const consoleWarn = console.warn;
|
||||
|
||||
console.warn = (...args) => {
|
||||
debugService.add({ type: 'warn', args });
|
||||
consoleWarn(...args);
|
||||
};
|
||||
console.warn = (...args) => {
|
||||
debugService.add({ type: 'warn', args });
|
||||
consoleWarn(...args);
|
||||
};
|
||||
|
||||
const consoleError = console.error;
|
||||
const consoleError = console.error;
|
||||
|
||||
console.error = (...args) => {
|
||||
debugService.add({ type: 'error', args });
|
||||
consoleError(...args);
|
||||
};
|
||||
console.error = (...args) => {
|
||||
debugService.add({ type: 'error', args });
|
||||
consoleError(...args);
|
||||
};
|
||||
}
|
||||
|
||||
platformBrowserDynamic([{ provide: DebugService, useValue: debugService }])
|
||||
.bootstrapModule(AppModule)
|
||||
|
||||
@@ -11,15 +11,11 @@
|
||||
@import './scss/customer';
|
||||
@import './scss/branch';
|
||||
|
||||
* {
|
||||
@apply font-sans;
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--bg-color);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
body {
|
||||
@apply bg-background;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0; // remove scrollbar space
|
||||
height: 0;
|
||||
@@ -61,3 +57,18 @@ body {
|
||||
@apply block bg-gray-300 h-6;
|
||||
animation: load 1s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@layer components {
|
||||
.input-control {
|
||||
@apply rounded border border-solid border-[#AEB7C1] px-4 py-[1.125rem] outline-none;
|
||||
}
|
||||
|
||||
// .input-control:focus,
|
||||
// .input-control:not(:placeholder-shown) {
|
||||
// @apply bg-white;
|
||||
// }
|
||||
|
||||
.input-control.ng-touched.ng-invalid {
|
||||
@apply border-brand;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
@apply text-center text-regular my-6;
|
||||
@apply text-center text-p2 my-6;
|
||||
}
|
||||
|
||||
.bold {
|
||||
@@ -62,7 +62,7 @@ hr {
|
||||
@apply flex flex-row items-center;
|
||||
|
||||
.cta-reserve {
|
||||
@apply absolute bg-transparent text-brand text-base font-bold border-none px-1 -mr-1;
|
||||
@apply absolute bg-transparent text-brand text-p2 font-bold border-none px-1 -mr-1;
|
||||
right: 85px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<div class="notification-headline">
|
||||
<h1>{{ item.headline }}</h1>
|
||||
<button class="notification-edit-cta" (click)="itemSelected.emit(item)">
|
||||
Bearbeiten
|
||||
</button>
|
||||
<div class="grid grid-cols-[1fr_auto] items-center gap-4">
|
||||
<div class="grid grid-flow-row gap-4">
|
||||
<h1 class="text-left font-bold text-lg">{{ item.headline }}</h1>
|
||||
<div class="notification-text">{{ item.text }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<button *ngIf="editButton" class="notification-edit-cta text-brand font-bold text-lg px-4 py-3" (click)="itemSelected.emit(item)">
|
||||
{{ editButtonLabel }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="notification-text">{{ item.text }}</div>
|
||||
|
||||
@@ -13,5 +13,11 @@ export class ModalNotificationsListItemComponent {
|
||||
@Output()
|
||||
itemSelected = new EventEmitter<MessageBoardItemDTO>();
|
||||
|
||||
@Input()
|
||||
editButton = true;
|
||||
|
||||
@Input()
|
||||
editButtonLabel = 'Bearbeiten';
|
||||
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<div class="notification-list scroll-bar">
|
||||
<ng-container *ngFor="let notification of notifications">
|
||||
<modal-notifications-list-item
|
||||
(click)="itemSelected(notification)"
|
||||
[editButtonLabel]="'Packstück-Prüfung'"
|
||||
[item]="notification"
|
||||
(itemSelected)="itemSelected($event)"
|
||||
></modal-notifications-list-item>
|
||||
<hr />
|
||||
</ng-container>
|
||||
</div>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
|
||||
|
||||
@Component({
|
||||
selector: 'modal-notifications-package-inspection-group',
|
||||
templateUrl: 'notifications-package-inspection-group.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ModalNotificationsPackageInspectionGroupComponent {
|
||||
@Input()
|
||||
notifications: MessageBoardItemDTO[];
|
||||
|
||||
@Output()
|
||||
navigated = new EventEmitter<void>();
|
||||
|
||||
constructor(private _router: Router) {}
|
||||
|
||||
itemSelected(item: MessageBoardItemDTO) {
|
||||
this._router.navigate(['/filiale/package-inspection/packages']);
|
||||
this.navigated.emit();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,3 @@
|
||||
<div class="header">
|
||||
<div class="notification-icon">
|
||||
<span class="notification-counter">{{ notifications.length }}</span>
|
||||
<ui-icon icon="notification" size="26px"></ui-icon>
|
||||
</div>
|
||||
|
||||
<h2>Remission</h2>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<div class="notification-list scroll-bar">
|
||||
<ng-container *ngFor="let notification of notifications">
|
||||
<modal-notifications-list-item [item]="notification" (itemSelected)="itemSelected($event)"></modal-notifications-list-item>
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
import { createComponentFactory, Spectator, SpyObject } from '@ngneat/spectator';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { Router } from '@angular/router';
|
||||
import { UiFilter } from '@ui/filter';
|
||||
import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
|
||||
import { Component } from '@angular/core';
|
||||
import { ModalNotificationsListItemComponent } from '../notifications-list-item/notifications-list-item.component';
|
||||
import { ModalNotificationsRemissionGroupComponent } from './notifications-remission-group.component';
|
||||
|
||||
// DummyComponent Class
|
||||
@Component({
|
||||
selector: 'dummy-component',
|
||||
template: '<div></div>',
|
||||
})
|
||||
class DummyComponent {
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
describe('ModalNotificationsRemissionGroupComponent', () => {
|
||||
let spectator: Spectator<ModalNotificationsRemissionGroupComponent>;
|
||||
let uiFilterMock: SpyObject<UiFilter>;
|
||||
let router: Router;
|
||||
|
||||
const createComponent = createComponentFactory({
|
||||
component: ModalNotificationsRemissionGroupComponent,
|
||||
declarations: [ModalNotificationsListItemComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterTestingModule.withRoutes([
|
||||
{ path: 'filiale/goods/in/results', component: DummyComponent },
|
||||
{ path: 'filiale/remission/create', component: DummyComponent },
|
||||
]),
|
||||
UiIconModule,
|
||||
],
|
||||
providers: [],
|
||||
mocks: [UiFilter],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createComponent({ props: { notifications: [] } });
|
||||
router = spectator.inject(Router);
|
||||
uiFilterMock = spectator.inject(UiFilter);
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.component).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('notifications input', () => {
|
||||
it('should display the right notification-counter value based on the length of the input array', () => {
|
||||
spectator.setInput({ notifications: [{}, {}, {}] });
|
||||
expect(spectator.query('.notification-counter')).toHaveText('3');
|
||||
});
|
||||
|
||||
it('should not display notification-counter if input array has length 0', () => {
|
||||
spectator.setInput({ notifications: [] });
|
||||
expect(spectator.query('.notification-counter')).toHaveText('');
|
||||
});
|
||||
|
||||
it('should render modal-notifications-list-item based on the input array', () => {
|
||||
const notifications = [{}, {}];
|
||||
spectator.setInput({ notifications });
|
||||
spectator.detectComponentChanges();
|
||||
expect(spectator.queryAll('modal-notifications-list-item')).toHaveLength(notifications.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe('itemSelected()', () => {
|
||||
it('should navigate to results with queryParams from UiFilter.getQueryParamsFromQueryTokenDTO()', () => {
|
||||
const item: MessageBoardItemDTO = { queryToken: { input: { main_qs: 'test' } } };
|
||||
spyOn(UiFilter, 'getQueryParamsFromQueryTokenDTO').and.returnValue(item.queryToken.input);
|
||||
spyOn(router, 'navigate');
|
||||
spectator.component.itemSelected(item);
|
||||
expect(router.navigate).toHaveBeenCalledWith(['/filiale/goods/in/results'], { queryParams: item.queryToken.input });
|
||||
});
|
||||
|
||||
it('should emit the navigated event after select item', () => {
|
||||
const item: MessageBoardItemDTO = { queryToken: { input: { main_qs: 'test' } } };
|
||||
spyOn(spectator.component.navigated, 'emit');
|
||||
spectator.component.itemSelected(item);
|
||||
expect(spectator.component.navigated.emit).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('actions CTA', () => {
|
||||
it('should navigate to remission page after clicking the CTA', () => {
|
||||
const cta = spectator.query('.cta-primary');
|
||||
expect(cta).toHaveText('Zur Remission');
|
||||
expect(cta).toHaveAttribute('href', '/filiale/remission/create');
|
||||
});
|
||||
|
||||
it('should emit the navigated event after clicking the CTA', () => {
|
||||
const cta = spectator.query('.cta-primary') as HTMLAnchorElement;
|
||||
spyOn(spectator.component.navigated, 'emit');
|
||||
spectator.click(cta);
|
||||
expect(spectator.component.navigated.emit).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,13 +1,3 @@
|
||||
<div class="header">
|
||||
<div class="notification-icon">
|
||||
<div class="notification-counter">{{ notifications.length }}</div>
|
||||
<ui-icon icon="notification" size="26px"></ui-icon>
|
||||
</div>
|
||||
|
||||
<h2>Reservierungsanfragen</h2>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<div class="notification-list scroll-bar">
|
||||
<ng-container *ngFor="let notification of notifications">
|
||||
<modal-notifications-list-item [item]="notification" (itemSelected)="itemSelected($event)"></modal-notifications-list-item>
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
import { createComponentFactory, Spectator, SpyObject } from '@ngneat/spectator';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ModalNotificationsReservationGroupComponent } from './notifications-reservation-group.component';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { Router } from '@angular/router';
|
||||
import { UiFilter } from '@ui/filter';
|
||||
import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
|
||||
import { Component } from '@angular/core';
|
||||
import { ModalNotificationsListItemComponent } from '../notifications-list-item/notifications-list-item.component';
|
||||
|
||||
// DummyComponent Class
|
||||
@Component({
|
||||
selector: 'dummy-component',
|
||||
template: '<div></div>',
|
||||
})
|
||||
class DummyComponent {
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
describe('ModalNotificationsReservationGroupComponent', () => {
|
||||
let spectator: Spectator<ModalNotificationsReservationGroupComponent>;
|
||||
let uiFilterMock: SpyObject<UiFilter>;
|
||||
let router: Router;
|
||||
|
||||
const createComponent = createComponentFactory({
|
||||
component: ModalNotificationsReservationGroupComponent,
|
||||
declarations: [ModalNotificationsListItemComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterTestingModule.withRoutes([
|
||||
{ path: 'filiale/goods/in/results', component: DummyComponent },
|
||||
{ path: 'filiale/goods/in/reservation', component: DummyComponent },
|
||||
]),
|
||||
UiIconModule,
|
||||
],
|
||||
providers: [],
|
||||
mocks: [UiFilter],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createComponent({ props: { notifications: [] } });
|
||||
router = spectator.inject(Router);
|
||||
uiFilterMock = spectator.inject(UiFilter);
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.component).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('notifications input', () => {
|
||||
it('should display the right notification-counter value based on the length of the input array', () => {
|
||||
spectator.setInput({ notifications: [{}, {}, {}] });
|
||||
expect(spectator.query('.notification-counter')).toHaveText('3');
|
||||
});
|
||||
|
||||
it('should not display notification-counter if input array has length 0', () => {
|
||||
spectator.setInput({ notifications: [] });
|
||||
expect(spectator.query('.notification-counter')).toHaveText('');
|
||||
});
|
||||
|
||||
it('should render modal-notifications-list-item based on the input array', () => {
|
||||
const notifications = [{}, {}];
|
||||
spectator.setInput({ notifications });
|
||||
spectator.detectComponentChanges();
|
||||
expect(spectator.queryAll('modal-notifications-list-item')).toHaveLength(notifications.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe('itemSelected()', () => {
|
||||
it('should navigate to results with queryParams from UiFilter.getQueryParamsFromQueryTokenDTO()', () => {
|
||||
const item: MessageBoardItemDTO = { queryToken: { input: { main_qs: 'test' } } };
|
||||
spyOn(UiFilter, 'getQueryParamsFromQueryTokenDTO').and.returnValue(item.queryToken.input);
|
||||
spyOn(router, 'navigate');
|
||||
spectator.component.itemSelected(item);
|
||||
expect(router.navigate).toHaveBeenCalledWith(['/filiale/goods/in/results'], { queryParams: item.queryToken.input });
|
||||
});
|
||||
|
||||
it('should emit the navigated event after select item', () => {
|
||||
const item: MessageBoardItemDTO = { queryToken: { input: { main_qs: 'test' } } };
|
||||
spyOn(spectator.component.navigated, 'emit');
|
||||
spectator.component.itemSelected(item);
|
||||
expect(spectator.component.navigated.emit).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('actions CTA', () => {
|
||||
it('should navigate to reservation page after clicking the CTA', () => {
|
||||
const cta = spectator.query('.cta-primary');
|
||||
expect(cta).toHaveText('Zu den Reservierungen');
|
||||
expect(cta).toHaveAttribute('href', '/filiale/goods/in/reservation');
|
||||
});
|
||||
|
||||
it('should emit the navigated event after clicking the CTA', () => {
|
||||
const cta = spectator.query('.cta-primary') as HTMLAnchorElement;
|
||||
spyOn(spectator.component.navigated, 'emit');
|
||||
spectator.click(cta);
|
||||
expect(spectator.component.navigated.emit).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,13 +1,3 @@
|
||||
<div class="header">
|
||||
<div class="notification-icon">
|
||||
<span class="notification-counter">{{ notifications.length }}</span>
|
||||
<ui-icon icon="notification" size="26px"></ui-icon>
|
||||
</div>
|
||||
|
||||
<h2>Tätigkeitskalender</h2>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<div class="notification-list scroll-bar">
|
||||
<ng-container *ngFor="let notification of notifications">
|
||||
<modal-notifications-list-item [item]="notification" (itemSelected)="itemSelected($event)"></modal-notifications-list-item>
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
import { createComponentFactory, Spectator, SpyObject } from '@ngneat/spectator';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { Router } from '@angular/router';
|
||||
import { UiFilter } from '@ui/filter';
|
||||
import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
|
||||
import { Component } from '@angular/core';
|
||||
import { ModalNotificationsListItemComponent } from '../notifications-list-item/notifications-list-item.component';
|
||||
import { ModalNotificationsTaskCalendarGroupComponent } from './notifications-task-calendar-group.component';
|
||||
|
||||
// DummyComponent Class
|
||||
@Component({
|
||||
selector: 'dummy-component',
|
||||
template: '<div></div>',
|
||||
})
|
||||
class DummyComponent {
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
describe('ModalNotificationsTaskCalendarGroupComponent', () => {
|
||||
let spectator: Spectator<ModalNotificationsTaskCalendarGroupComponent>;
|
||||
let uiFilterMock: SpyObject<UiFilter>;
|
||||
let router: Router;
|
||||
|
||||
const createComponent = createComponentFactory({
|
||||
component: ModalNotificationsTaskCalendarGroupComponent,
|
||||
declarations: [ModalNotificationsListItemComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterTestingModule.withRoutes([
|
||||
{ path: 'filiale/goods/in/results', component: DummyComponent },
|
||||
{ path: 'filiale/task-calendar/calendar', component: DummyComponent },
|
||||
]),
|
||||
UiIconModule,
|
||||
],
|
||||
providers: [],
|
||||
mocks: [UiFilter],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createComponent({ props: { notifications: [] } });
|
||||
router = spectator.inject(Router);
|
||||
uiFilterMock = spectator.inject(UiFilter);
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.component).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('notifications input', () => {
|
||||
it('should display the right notification-counter value based on the length of the input array', () => {
|
||||
spectator.setInput({ notifications: [{}, {}, {}] });
|
||||
expect(spectator.query('.notification-counter')).toHaveText('3');
|
||||
});
|
||||
|
||||
it('should not display notification-counter if input array has length 0', () => {
|
||||
spectator.setInput({ notifications: [] });
|
||||
expect(spectator.query('.notification-counter')).toHaveText('');
|
||||
});
|
||||
|
||||
it('should render modal-notifications-list-item based on the input array', () => {
|
||||
const notifications = [{}, {}];
|
||||
spectator.setInput({ notifications });
|
||||
spectator.detectComponentChanges();
|
||||
expect(spectator.queryAll('modal-notifications-list-item')).toHaveLength(notifications.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe('itemSelected()', () => {
|
||||
it('should navigate to results with queryParams from UiFilter.getQueryParamsFromQueryTokenDTO()', () => {
|
||||
const item: MessageBoardItemDTO = { queryToken: { input: { main_qs: 'test' } } };
|
||||
spyOn(UiFilter, 'getQueryParamsFromQueryTokenDTO').and.returnValue(item.queryToken.input);
|
||||
spyOn(router, 'navigate');
|
||||
spectator.component.itemSelected(item);
|
||||
expect(router.navigate).toHaveBeenCalledWith(['/filiale/goods/in/results'], { queryParams: item.queryToken.input });
|
||||
});
|
||||
|
||||
it('should emit the navigated event after select item', () => {
|
||||
const item: MessageBoardItemDTO = { queryToken: { input: { main_qs: 'test' } } };
|
||||
spyOn(spectator.component.navigated, 'emit');
|
||||
spectator.component.itemSelected(item);
|
||||
expect(spectator.component.navigated.emit).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('actions CTA', () => {
|
||||
it('should navigate to reservation page after clicking the CTA', () => {
|
||||
const cta = spectator.query('.cta-primary');
|
||||
expect(cta).toHaveText('Zum Tätigkeitskalender');
|
||||
expect(cta).toHaveAttribute('href', '/filiale/task-calendar/calendar');
|
||||
});
|
||||
|
||||
it('should emit the navigated event after clicking the CTA', () => {
|
||||
const cta = spectator.query('.cta-primary') as HTMLAnchorElement;
|
||||
spyOn(spectator.component.navigated, 'emit');
|
||||
spectator.click(cta);
|
||||
expect(spectator.component.navigated.emit).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,13 +1,3 @@
|
||||
<div class="header">
|
||||
<div class="notification-icon">
|
||||
<span class="notification-counter">{{ notifications.length }}</span>
|
||||
<ui-icon icon="notification" size="26px"></ui-icon>
|
||||
</div>
|
||||
|
||||
<h2>ISA-Update</h2>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<div class="notification-list scroll-bar">
|
||||
<ng-container *ngFor="let notification of notifications">
|
||||
<div class="notification-headline">
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import { createComponentFactory, Spectator } from '@ngneat/spectator';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { ModalNotificationsUpdateGroupComponent } from './notifications-update-group.component';
|
||||
|
||||
describe('ModalNotificationsUpdateGroupComponent', () => {
|
||||
let spectator: Spectator<ModalNotificationsUpdateGroupComponent>;
|
||||
|
||||
const createComponent = createComponentFactory({
|
||||
component: ModalNotificationsUpdateGroupComponent,
|
||||
imports: [CommonModule, UiIconModule],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createComponent({ props: { notifications: [] } });
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.component).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('notifications input', () => {
|
||||
it('should display the right notification-counter value based on the length of the input array', () => {
|
||||
spectator.setInput({ notifications: [{}, {}, {}] });
|
||||
expect(spectator.query('.notification-counter')).toHaveText('3');
|
||||
});
|
||||
|
||||
it('should not display notification-counter if input array has length 0', () => {
|
||||
spectator.setInput({ notifications: [] });
|
||||
expect(spectator.query('.notification-counter')).toHaveText('');
|
||||
});
|
||||
|
||||
it('should render notification-headline and notification-text based on the input array', () => {
|
||||
const notifications = [{}, {}];
|
||||
spectator.setInput({ notifications });
|
||||
spectator.detectComponentChanges();
|
||||
expect(spectator.queryAll('.notification-headline')).toHaveLength(notifications.length);
|
||||
expect(spectator.queryAll('.notification-text')).toHaveLength(notifications.length);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,34 +1,39 @@
|
||||
<h1>Sie haben neue Nachrichten</h1>
|
||||
|
||||
<ng-container *ngFor="let notification of groupedNotifications$ | async">
|
||||
<button
|
||||
*ngIf="notification.group !== (activeCard$ | async)"
|
||||
type="button"
|
||||
class="notification-card"
|
||||
(click)="activeCard = notification.group"
|
||||
>
|
||||
{{ notification.group }}
|
||||
<ng-container *ngFor="let notification of notifications$ | async | keyvalue">
|
||||
<button type="button" class="notification-card" (click)="selectArea(notification.key)">
|
||||
<div class="notification-icon">
|
||||
<div class="notification-counter">{{ notification.value?.length }}</div>
|
||||
<ui-icon icon="notification" size="26px"></ui-icon>
|
||||
</div>
|
||||
<span>{{ notification.value?.[0]?.category }}</span>
|
||||
</button>
|
||||
</ng-container>
|
||||
|
||||
<ng-container [ngSwitch]="activeCard$ | async">
|
||||
<modal-notifications-update-group
|
||||
*ngSwitchCase="'ISA-Update'"
|
||||
[notifications]="activeNotifications$ | async"
|
||||
></modal-notifications-update-group>
|
||||
<modal-notifications-reservation-group
|
||||
*ngSwitchCase="'Reservierungsanfragen'"
|
||||
[notifications]="activeNotifications$ | async"
|
||||
(navigated)="close()"
|
||||
></modal-notifications-reservation-group>
|
||||
<modal-notifications-remission-group
|
||||
*ngSwitchCase="'Remission'"
|
||||
[notifications]="activeNotifications$ | async"
|
||||
(navigated)="close()"
|
||||
></modal-notifications-remission-group>
|
||||
<modal-notifications-task-calendar-group
|
||||
*ngSwitchCase="'Tätigkeitskalender'"
|
||||
[notifications]="activeNotifications$ | async"
|
||||
(navigated)="close()"
|
||||
></modal-notifications-task-calendar-group>
|
||||
<hr class="-mx-4" />
|
||||
<ng-container *ngIf="notification.key === selectedArea" [ngSwitch]="notification.value?.[0]?.category">
|
||||
<modal-notifications-update-group
|
||||
*ngSwitchCase="'ISA-Update'"
|
||||
[notifications]="notifications[selectedArea]"
|
||||
></modal-notifications-update-group>
|
||||
<modal-notifications-reservation-group
|
||||
*ngSwitchCase="'Reservierungsanfragen'"
|
||||
[notifications]="notifications[selectedArea]"
|
||||
(navigated)="close()"
|
||||
></modal-notifications-reservation-group>
|
||||
<modal-notifications-remission-group
|
||||
*ngSwitchCase="'Remission'"
|
||||
[notifications]="notifications[selectedArea]"
|
||||
(navigated)="close()"
|
||||
></modal-notifications-remission-group>
|
||||
<modal-notifications-task-calendar-group
|
||||
*ngSwitchCase="'Tätigkeitskalender'"
|
||||
[notifications]="notifications[selectedArea]"
|
||||
(navigated)="close()"
|
||||
></modal-notifications-task-calendar-group>
|
||||
<modal-notifications-package-inspection-group
|
||||
*ngSwitchCase="'Wareneingang Lagerware'"
|
||||
[notifications]="notifications[selectedArea]"
|
||||
(navigated)="close()"
|
||||
>
|
||||
</modal-notifications-package-inspection-group>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
@@ -2,46 +2,44 @@ modal-notifications {
|
||||
@apply flex flex-col relative h-full;
|
||||
|
||||
h1 {
|
||||
@apply text-xl font-bold text-center mb-10;
|
||||
@apply text-xl font-bold text-center;
|
||||
}
|
||||
|
||||
// .notification-card {
|
||||
// @apply text-center text-xl text-inactive-branch block bg-white rounded-t-card font-bold no-underline py-4 border-none outline-none shadow-card -ml-4;
|
||||
// width: calc(100% + 2rem);
|
||||
// }
|
||||
|
||||
.notification-card {
|
||||
@apply text-center text-xl text-inactive-branch block bg-white rounded-t-card font-bold no-underline py-4 border-none outline-none shadow-card -ml-4;
|
||||
width: calc(100% + 2rem);
|
||||
@apply grid grid-flow-col items-center justify-center gap-4;
|
||||
@apply text-inactive-branch bg-white;
|
||||
@apply font-bold text-xl -mx-4 py-4;
|
||||
|
||||
.notification-icon {
|
||||
@apply relative;
|
||||
|
||||
.notification-counter {
|
||||
@apply absolute font-normal text-base -top-2 -right-1 bg-brand text-white rounded-full w-5 h-5 flex items-center justify-center;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
ui-icon {
|
||||
@apply text-inactive-branch;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply font-bold text-2xl ml-4;
|
||||
}
|
||||
}
|
||||
|
||||
modal-notifications-remission-group,
|
||||
modal-notifications-reservation-group,
|
||||
modal-notifications-task-calendar-group,
|
||||
modal-notifications-update-group {
|
||||
modal-notifications-update-group,
|
||||
modal-notifications-package-inspection-group {
|
||||
@apply flex flex-col relative pb-2;
|
||||
|
||||
.header {
|
||||
@apply flex flex-row justify-center items-center mt-5;
|
||||
|
||||
.notification-icon {
|
||||
@apply relative;
|
||||
|
||||
.notification-counter {
|
||||
@apply absolute -top-2 -right-1 bg-brand text-white rounded-full w-5 h-5 flex items-center justify-center;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
ui-icon {
|
||||
@apply text-inactive-branch;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply font-bold text-2xl ml-4;
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
@apply bg-disabled-branch h-px-2 -ml-4 my-4;
|
||||
width: calc(100% + 2rem);
|
||||
}
|
||||
|
||||
.notification-list {
|
||||
@apply overflow-y-scroll -ml-4;
|
||||
max-height: calc(100vh - 450px);
|
||||
@@ -60,17 +58,17 @@ modal-notifications {
|
||||
|
||||
modal-notifications-list-item,
|
||||
modal-notifications-update-group {
|
||||
@apply flex flex-col relative py-1 px-4;
|
||||
@apply flex flex-col relative p-4;
|
||||
|
||||
.notification-headline {
|
||||
@apply flex flex-row justify-between items-start;
|
||||
|
||||
h1 {
|
||||
@apply text-regular font-bold mb-2;
|
||||
@apply text-p2 font-bold mb-2;
|
||||
}
|
||||
|
||||
.notification-edit-cta {
|
||||
@apply bg-transparent text-brand text-base font-bold border-none px-1 -mr-1;
|
||||
@apply bg-transparent text-brand text-p2 font-bold border-none px-1 -mr-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
import { createComponentFactory, mockProvider, Spectator, SpyObject } from '@ngneat/spectator';
|
||||
import { ModalNotificationsComponent } from './notifications.component';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { UiModalRef, UiModalService } from '@ui/modal';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
describe('ModalNotificationsComponent', () => {
|
||||
let spectator: Spectator<ModalNotificationsComponent>;
|
||||
let modalRefMock: SpyObject<UiModalRef>;
|
||||
|
||||
const createComponent = createComponentFactory({
|
||||
component: ModalNotificationsComponent,
|
||||
imports: [CommonModule],
|
||||
providers: [mockProvider(UiModalRef, { data: { product: {} } })],
|
||||
mocks: [UiModalService],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createComponent();
|
||||
modalRefMock = spectator.inject(UiModalRef);
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.component).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('close()', () => {
|
||||
it('should call _modalRef.close()', () => {
|
||||
spectator.component.close();
|
||||
expect(modalRefMock.close).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('get activeCard', () => {
|
||||
it('should return the activeCard', () => {
|
||||
spectator.component.activeCard = 'testCard';
|
||||
expect(spectator.component.activeCard).toBe('testCard');
|
||||
});
|
||||
});
|
||||
|
||||
describe('get activeCard$', () => {
|
||||
it('should return activeCard$', () => {
|
||||
spectator.component.activeCard = 'testCard';
|
||||
|
||||
spectator.component.activeCard$
|
||||
.subscribe((c) => {
|
||||
expect(c).toBe('testCard');
|
||||
})
|
||||
.unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
describe('get groupedNotifications', () => {
|
||||
it('should return the groupedNotifications', () => {
|
||||
spectator.component.groupedNotifications = [{ group: 'test', items: [] }];
|
||||
expect(spectator.component.groupedNotifications).toEqual([{ group: 'test', items: [] }]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('get groupedNotifications$', () => {
|
||||
it('should return the groupedNotifications$', () => {
|
||||
spectator.component.groupedNotifications = [{ group: 'test', items: [] }];
|
||||
|
||||
spectator.component.groupedNotifications$
|
||||
.subscribe((gn) => {
|
||||
expect(gn).toEqual([{ group: 'test', items: [] }]);
|
||||
})
|
||||
.unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
describe('activeNotifications$', () => {
|
||||
it('should return the item with the activeCard within the group', () => {
|
||||
spectator.component.groupedNotifications = [{ group: 'testCard', items: [{ text: 'testmessage' }] }];
|
||||
spectator.component.activeCard = 'testCard';
|
||||
spectator.component.activeNotifications$
|
||||
.subscribe((an) => {
|
||||
expect(an).toEqual([{ text: 'testmessage' }]);
|
||||
})
|
||||
.unsubscribe();
|
||||
});
|
||||
|
||||
it('should not return anything if the item with the activeCard is not within the group', () => {
|
||||
spectator.component.groupedNotifications = [{ group: 'testCard', items: [{ text: 'testmessage' }] }];
|
||||
spectator.component.activeCard = 'testCardtest';
|
||||
spectator.component.activeNotifications$
|
||||
.subscribe((an) => {
|
||||
expect(an).toBeUndefined();
|
||||
})
|
||||
.unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
describe('ngOnInit()', () => {
|
||||
it('should call patchState with activeCard', () => {
|
||||
const activeCard = 'test';
|
||||
spectator = createComponent({ props: { activeCard, groupedNotifications: [{ group: activeCard, items: [] }] } });
|
||||
spyOn(spectator.component, 'patchState');
|
||||
spectator.component.ngOnInit();
|
||||
expect(spectator.component.patchState).toHaveBeenCalledWith({
|
||||
activeCard: [{ group: activeCard, items: [] }].find((_) => true)?.group,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,14 +1,11 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ComponentStore } from '@ngrx/component-store';
|
||||
import { Group, groupBy } from '@ui/common';
|
||||
import { UiModalRef } from '@ui/modal';
|
||||
import { EnvelopeDTO, MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
|
||||
|
||||
interface ModalNotificationComponentState {
|
||||
activeCard: string;
|
||||
groupedNotifications: Group<string, MessageBoardItemDTO>[];
|
||||
selectedArea: string;
|
||||
notifications: Record<string, MessageBoardItemDTO[]>;
|
||||
}
|
||||
|
||||
@Component({
|
||||
@@ -18,44 +15,61 @@ interface ModalNotificationComponentState {
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class ModalNotificationsComponent extends ComponentStore<ModalNotificationComponentState> implements OnInit {
|
||||
set activeCard(activeCard: string) {
|
||||
if (this.activeCard !== activeCard) {
|
||||
this.patchState({ activeCard });
|
||||
export class ModalNotificationsComponent extends ComponentStore<ModalNotificationComponentState> {
|
||||
private _selectedAreaSelector = (state: ModalNotificationComponentState) => {
|
||||
if (state.selectedArea) {
|
||||
return state.selectedArea;
|
||||
}
|
||||
|
||||
const keys = Object.keys(state.notifications);
|
||||
|
||||
for (const key of keys) {
|
||||
if (state.notifications[key]?.length > 0) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
get selectedArea() {
|
||||
return this.get(this._selectedAreaSelector);
|
||||
}
|
||||
|
||||
activeCard$ = this.select((s) => s.activeCard);
|
||||
selectedArea$ = this.select(this._selectedAreaSelector);
|
||||
|
||||
get activeCard() {
|
||||
return this.get((s) => s.activeCard);
|
||||
private _categorySelector = (state: ModalNotificationComponentState) => {
|
||||
const selectedArea = this._selectedAreaSelector(state);
|
||||
console.log('_categorySelector', state.notifications[selectedArea]?.[0]?.category);
|
||||
return state.notifications[selectedArea]?.[0]?.category;
|
||||
};
|
||||
|
||||
get category() {
|
||||
return this.get(this._categorySelector);
|
||||
}
|
||||
|
||||
get groupedNotifications() {
|
||||
return this.get((s) => s.groupedNotifications);
|
||||
}
|
||||
groupedNotifications$ = this.select((s) => s.groupedNotifications);
|
||||
category$ = this.select(this._categorySelector);
|
||||
|
||||
set groupedNotifications(groupedNotifications: Group<string, MessageBoardItemDTO>[]) {
|
||||
this.patchState({ groupedNotifications });
|
||||
get notifications() {
|
||||
return this.get((s) => s.notifications);
|
||||
}
|
||||
|
||||
activeNotifications$ = combineLatest([this.activeCard$, this.groupedNotifications$]).pipe(
|
||||
map(([activeCard, notifications]) => notifications.find((n) => n.group === activeCard)?.items)
|
||||
);
|
||||
notifications$ = this.select((s) => s.notifications);
|
||||
|
||||
constructor(private _modalRef: UiModalRef<any, EnvelopeDTO<MessageBoardItemDTO[]>>) {
|
||||
constructor(private _modalRef: UiModalRef<any, Record<string, MessageBoardItemDTO[]>>) {
|
||||
super({
|
||||
activeCard: undefined,
|
||||
groupedNotifications: groupBy(_modalRef.data.data, (item: MessageBoardItemDTO) => item.category),
|
||||
selectedArea: undefined,
|
||||
notifications: _modalRef.data,
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.patchState({ activeCard: this.groupedNotifications?.find((_) => true)?.group });
|
||||
}
|
||||
|
||||
close() {
|
||||
this._modalRef.close();
|
||||
}
|
||||
|
||||
selectArea(area: string) {
|
||||
this.patchState({
|
||||
selectedArea: area,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { ModalNotificationsReservationGroupComponent } from './notifications-res
|
||||
import { ModalNotificationsTaskCalendarGroupComponent } from './notifications-task-calendar-group/notifications-task-calendar-group.component';
|
||||
import { ModalNotificationsUpdateGroupComponent } from './notifications-update-group/notifications-update-group.component';
|
||||
import { ModalNotificationsComponent } from './notifications.component';
|
||||
import { ModalNotificationsPackageInspectionGroupComponent } from './notifications-package-inspection-group/notifications-package-inspection-group.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiCommonModule, UiIconModule, RouterModule],
|
||||
@@ -19,6 +20,7 @@ import { ModalNotificationsComponent } from './notifications.component';
|
||||
ModalNotificationsTaskCalendarGroupComponent,
|
||||
ModalNotificationsUpdateGroupComponent,
|
||||
ModalNotificationsListItemComponent,
|
||||
ModalNotificationsPackageInspectionGroupComponent,
|
||||
],
|
||||
exports: [
|
||||
ModalNotificationsComponent,
|
||||
@@ -27,6 +29,7 @@ import { ModalNotificationsComponent } from './notifications.component';
|
||||
ModalNotificationsTaskCalendarGroupComponent,
|
||||
ModalNotificationsUpdateGroupComponent,
|
||||
ModalNotificationsListItemComponent,
|
||||
ModalNotificationsPackageInspectionGroupComponent,
|
||||
],
|
||||
})
|
||||
export class ModalNotificationsModule {}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
}
|
||||
|
||||
.error-message {
|
||||
@apply text-center text-regular font-semibold text-brand;
|
||||
@apply text-center text-p2 font-semibold text-brand;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ ui-select {
|
||||
@apply mt-px-35 text-center;
|
||||
|
||||
.print-btn {
|
||||
@apply border-none outline-none bg-brand text-white font-bold text-cta-l px-px-25 py-px-15 rounded-full my-8;
|
||||
@apply border-none outline-none bg-brand text-white font-bold text-p1 px-px-25 py-px-15 rounded-full my-8;
|
||||
|
||||
&:disabled {
|
||||
@apply bg-inactive-branch;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
}
|
||||
|
||||
h3 {
|
||||
@apply text-regular font-semibold text-center;
|
||||
@apply text-p2 font-semibold text-center;
|
||||
}
|
||||
|
||||
hr {
|
||||
@@ -23,11 +23,11 @@ hr {
|
||||
@apply flex flex-col ml-5;
|
||||
|
||||
.product-name {
|
||||
@apply text-regular font-bold;
|
||||
@apply text-p2 font-bold;
|
||||
}
|
||||
|
||||
.product-format {
|
||||
@apply mt-5 text-regular font-bold flex items-center;
|
||||
@apply mt-5 text-p2 font-bold flex items-center;
|
||||
|
||||
.format-icon {
|
||||
@apply mr-2;
|
||||
@@ -35,11 +35,11 @@ hr {
|
||||
}
|
||||
|
||||
.product-ean {
|
||||
@apply text-regular font-bold;
|
||||
@apply text-p2 font-bold;
|
||||
}
|
||||
|
||||
.quantity {
|
||||
@apply text-regular font-bold;
|
||||
@apply text-p2 font-bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,12 +31,12 @@
|
||||
}
|
||||
|
||||
.title {
|
||||
@apply ml-5 text-regular font-bold;
|
||||
@apply ml-5 text-p2 font-bold;
|
||||
}
|
||||
|
||||
.btn-expand,
|
||||
.btn-collapse {
|
||||
@apply border-none bg-transparent outline-none text-regular text-ucla-blue font-bold -mt-2;
|
||||
@apply border-none bg-transparent outline-none text-p2 text-ucla-blue font-bold -mt-2;
|
||||
|
||||
ui-icon {
|
||||
@apply inline mx-1 align-middle;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
|
||||
import { Config } from '@core/config';
|
||||
|
||||
@@ -14,11 +13,10 @@ export class AssortmentComponent implements OnInit {
|
||||
return this._config.get('process.ids.assortment');
|
||||
}
|
||||
|
||||
constructor(private _config: Config, private _breadcrumb: BreadcrumbService, private _app: ApplicationService) {}
|
||||
constructor(private _config: Config, private _breadcrumb: BreadcrumbService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.createBreadcrumbIfNotExists();
|
||||
this._app.setTitle('Sortiment');
|
||||
}
|
||||
|
||||
async createBreadcrumbIfNotExists(): Promise<void> {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<div
|
||||
class="page-price-update-item__item-header flex flex-row w-full items-center justify-between bg-[rgba(0,128,121,0.15)] mb-px-2 px-5 h-[53px] rounded-t-card"
|
||||
class="page-price-update-item__item-header flex flex-row w-full items-center justify-between bg-[rgba(0,128,121,0.15)] mb-px-2 px-5 h-[53px] rounded-t"
|
||||
>
|
||||
<p class="page-price-update-item__item-instruction font-bold text-lg">{{ item?.task?.instruction }}</p>
|
||||
<p class="page-price-update-item__item-due-date text-base">
|
||||
<p class="page-price-update-item__item-due-date text-p2">
|
||||
gültig ab <span class="font-bold ml-2">{{ item?.task?.dueDate | date }}</span>
|
||||
</p>
|
||||
</div>
|
||||
@@ -20,15 +20,15 @@
|
||||
|
||||
<div class="page-price-update-item__item-details">
|
||||
<div class="page-price-update-item__item-contributors flex flex-row">
|
||||
{{ environment.isTablet() ? (item?.product?.contributors | substr: 42) : item?.product?.contributors }}
|
||||
{{ environment.isTablet() ? (item?.product?.contributors | substr: 38) : item?.product?.contributors }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="page-price-update-item__item-title font-bold text-2xl"
|
||||
class="page-price-update-item__item-title font-bold text-h3"
|
||||
[class.text-xl]="item?.product?.name?.length >= 35"
|
||||
[class.text-lg]="item?.product?.name?.length >= 40"
|
||||
[class.text-md]="item?.product?.name?.length >= 50"
|
||||
[class.text-sm]="item?.product?.name?.length >= 60"
|
||||
[class.text-p3]="item?.product?.name?.length >= 60"
|
||||
[class.text-xs]="item?.product?.name?.length >= 100"
|
||||
>
|
||||
{{ item?.product?.name }}
|
||||
@@ -43,7 +43,7 @@
|
||||
src="assets/images/Icon_{{ item?.product?.format }}.svg"
|
||||
[alt]="item?.product?.formatDetail"
|
||||
/>
|
||||
{{ item?.product?.formatDetail }}
|
||||
{{ environment.isTablet() ? (item?.product?.formatDetail | substr: 25) : item?.product?.formatDetail }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
</div>
|
||||
|
||||
<div class="page-price-update-item__item-select-bullet">
|
||||
<input *ngIf="isSelectable" [ngModel]="selected$ | async" (ngModelChange)="setSelected()" class="isa-select-bullet" type="checkbox" />
|
||||
<input *ngIf="isSelectable" [ngModel]="selected" (ngModelChange)="setSelected()" class="isa-select-bullet" type="checkbox" />
|
||||
</div>
|
||||
|
||||
<div class="page-price-update-item__item-stock flex flex-row font-bold">
|
||||
|
||||
@@ -47,7 +47,7 @@ export class PriceUpdateItemComponent {
|
||||
return this._store.isSelectable(this.item);
|
||||
}
|
||||
|
||||
selected$ = this._store.selectedItemUids$.pipe(map((selectedItemUids) => selectedItemUids.includes(this.item?.uId)));
|
||||
@Input() selected: boolean = false;
|
||||
|
||||
defaultBranch$ = this._availability.getDefaultBranch();
|
||||
|
||||
@@ -59,8 +59,7 @@ export class PriceUpdateItemComponent {
|
||||
itemId: Number(item?.product?.catalogProductNumber),
|
||||
branchId: defaultBranch?.id,
|
||||
})
|
||||
),
|
||||
shareReplay(1)
|
||||
)
|
||||
);
|
||||
|
||||
constructor(
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
Drucken
|
||||
</button>
|
||||
<div class="flex flex-row items-center justify-end">
|
||||
<div *ngIf="getSelectableItems().length > 0" class="text-[#0556B4] font-bold text-sm mr-5">
|
||||
<div *ngIf="getSelectableItems().length > 0" class="text-[#0556B4] font-bold text-p3 mr-5">
|
||||
<ng-container *ngIf="selectedItemUids$ | async; let selectedItems">
|
||||
<button class="page-price-update-list__cta-unselect-all" *ngIf="selectedItems?.length > 0" type="button" (click)="unselectAll()">
|
||||
Alle entfernen ({{ selectedItems?.length }})
|
||||
@@ -18,7 +18,7 @@
|
||||
</button>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="page-price-update-list__items-count inline-flex flex-row items-center pr-5 text-sm">
|
||||
<div class="page-price-update-list__items-count inline-flex flex-row items-center pr-5 text-p3">
|
||||
{{ items?.length ??
|
||||
0 }}
|
||||
Titel
|
||||
@@ -26,7 +26,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-price-update-list__order-by h-[53px] flex flex-row items-center justify-center bg-white rounded-t-card mb-px-2">
|
||||
<div class="page-price-update-list__order-by h-[53px] flex flex-row items-center justify-center bg-white rounded-t mb-px-2">
|
||||
<ui-order-by-filter [orderBy]="orderBy$ | async" (selectedOrderByChange)="search()"> </ui-order-by-filter>
|
||||
</div>
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
<page-price-update-item
|
||||
*cdkVirtualFor="let item of items; let first; trackBy: trackByFn"
|
||||
[item]="item"
|
||||
[selected]="isSelected(item)"
|
||||
[class.mt-px-10]="!first"
|
||||
></page-price-update-item>
|
||||
|
||||
|
||||
@@ -34,6 +34,10 @@ export class PriceUpdateListComponent {
|
||||
return this._store.items.filter((item) => this._store.isSelectable(item)) ?? [];
|
||||
}
|
||||
|
||||
isSelected(item: ProductListItemDTO) {
|
||||
return this._store.selectedItemUids.includes(item.uId);
|
||||
}
|
||||
|
||||
selectAll() {
|
||||
const selectedItemUids = this.getSelectableItems().map((item) => item.uId);
|
||||
this._store.patchState({ selectedItemUids });
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<div class="flex flex-row items-center h-14 bg-white relative rounded-t font-bold shadow-lg">
|
||||
<h3 class="text-center grow font-bold text-2xl">Preisänderung</h3>
|
||||
<h3 class="text-center grow font-bold text-h3">Preisänderung</h3>
|
||||
<button
|
||||
(click)="filterOverlay.open()"
|
||||
class="absolute right-0 top-0 h-14 rounded px-5 text-lg bg-cadet-blue flex flex-row flex-nowrap items-center justify-center"
|
||||
type="button"
|
||||
>
|
||||
<ui-svg-icon class="mr-2" icon="filter-variant"></ui-svg-icon>
|
||||
<shared-icon class="mr-2" icon="filter-variant"></shared-icon>
|
||||
Filter
|
||||
</button>
|
||||
</div>
|
||||
@@ -16,7 +16,7 @@
|
||||
<shell-filter-overlay #filterOverlay class="relative">
|
||||
<div class="relative">
|
||||
<button type="button" class="absolute top-4 right-4 text-cadet" (click)="closeFilterOverlay()">
|
||||
<ui-svg-icon [icon]="'close'" [size]="28"></ui-svg-icon>
|
||||
<shared-icon [icon]="'close'" [size]="28"></shared-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -54,5 +54,5 @@
|
||||
</shell-filter-overlay>
|
||||
|
||||
<ng-template #noResults>
|
||||
<div class="bg-white text-2xl text-center pt-10 font-bold rounded-b h-[calc(100vh_-_370px)]">Keine Preisänderungen vorhanden.</div>
|
||||
<div class="bg-white text-h3 text-center pt-10 font-bold rounded-b h-[calc(100vh_-_370px)]">Keine Preisänderungen vorhanden.</div>
|
||||
</ng-template>
|
||||
|
||||
@@ -2,13 +2,13 @@ import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { SharedFilterOverlayModule } from '@shared/components/filter-overlay';
|
||||
import { UiFilterNextModule } from '@ui/filter';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { UiSpinnerModule } from '@ui/spinner';
|
||||
import { PriceUpdateListModule } from './price-update-list';
|
||||
import { PriceUpdateComponent } from './price-update.component';
|
||||
import { IconComponent } from '@shared/components/icon';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, PriceUpdateListModule, UiIconModule, UiFilterNextModule, SharedFilterOverlayModule, UiSpinnerModule],
|
||||
imports: [CommonModule, PriceUpdateListModule, UiFilterNextModule, SharedFilterOverlayModule, UiSpinnerModule, IconComponent],
|
||||
exports: [PriceUpdateComponent],
|
||||
declarations: [PriceUpdateComponent],
|
||||
providers: [],
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
:host {
|
||||
@apply text-[#0556B4];
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<a [routerLink]="route?.path" [queryParams]="route?.queryParams">
|
||||
<ng-content></ng-content>
|
||||
</a>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user