mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Compare commits
329 Commits
fix/3051-R
...
feature/sc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3bd33ffc3 | ||
|
|
38c2fd07ae | ||
|
|
77ebafd018 | ||
|
|
dfab7e3540 | ||
|
|
e4410fe2c7 | ||
|
|
1dbd3fd274 | ||
|
|
abdbab807d | ||
|
|
718077025d | ||
|
|
08161c29d3 | ||
|
|
942f84dfcf | ||
|
|
41defdc291 | ||
|
|
045b8e162a | ||
|
|
e3d7813edb | ||
|
|
189dc64a0f | ||
|
|
2f0ede7170 | ||
|
|
c7e444d446 | ||
|
|
f5ac916663 | ||
|
|
b3b9f0223e | ||
|
|
70455df6d3 | ||
|
|
b89889a3e9 | ||
|
|
7ec00925ed | ||
|
|
d3e3d127b3 | ||
|
|
11c4d8fb72 | ||
|
|
9b02a19b9c | ||
|
|
57262919b8 | ||
|
|
f787a15347 | ||
|
|
bc74eac86d | ||
|
|
0a1df250cb | ||
|
|
8a7b9de29d | ||
|
|
8efb87a1f7 | ||
|
|
27ee667bfb | ||
|
|
c64ff772e7 | ||
|
|
313efebb8b | ||
|
|
9eee4fff6c | ||
|
|
b5a7c96181 | ||
|
|
5bea71e19e | ||
|
|
751e533dce | ||
|
|
9e58e8aad9 | ||
|
|
d62a7d704a | ||
|
|
f8d7d12d61 | ||
|
|
2ad71cad78 | ||
|
|
689d8ead24 | ||
|
|
b6a7df76f6 | ||
|
|
41e8145858 | ||
|
|
3a5b80657c | ||
|
|
41c6897224 | ||
|
|
8d644cdd65 | ||
|
|
7a68229432 | ||
|
|
4dab0ef6f6 | ||
|
|
75cad811bc | ||
|
|
0709f1dd6a | ||
|
|
478950c446 | ||
|
|
b5e5601671 | ||
|
|
0ee86faa00 | ||
|
|
fa7b204f89 | ||
|
|
22f9ba80fe | ||
|
|
065878a6e9 | ||
|
|
5df433d603 | ||
|
|
21375855dd | ||
|
|
b847ca6b3e | ||
|
|
50caf9811d | ||
|
|
f0df9e1157 | ||
|
|
3e1347f17e | ||
|
|
86082bbfda | ||
|
|
6e6551ceae | ||
|
|
08ef5f0853 | ||
|
|
92131453e8 | ||
|
|
888a95d2a0 | ||
|
|
ab745cba18 | ||
|
|
dfe6b3977f | ||
|
|
e7e8b71a70 | ||
|
|
c158e16bd3 | ||
|
|
464fac660b | ||
|
|
79b1920b15 | ||
|
|
f071e7b2d5 | ||
|
|
3afb8d6ed1 | ||
|
|
87a2e94dd6 | ||
|
|
d711d4a816 | ||
|
|
a4b4aeed64 | ||
|
|
3707572bd8 | ||
|
|
aef5c06f0a | ||
|
|
a021ac0da3 | ||
|
|
1e4e6da44e | ||
|
|
6b0d9774c5 | ||
|
|
e1720e6023 | ||
|
|
3078724ced | ||
|
|
f3eb0a67f6 | ||
|
|
65d7a6f5a4 | ||
|
|
b2b5456400 | ||
|
|
a598be069d | ||
|
|
bf61f2c982 | ||
|
|
63225491f1 | ||
|
|
0dbc773775 | ||
|
|
47b7d42dd3 | ||
|
|
d713c787e6 | ||
|
|
68a2eab425 | ||
|
|
886f063d1b | ||
|
|
ed6ee36509 | ||
|
|
ab345dae0d | ||
|
|
fbb1e6c4a2 | ||
|
|
4ede9226b4 | ||
|
|
fbfecbd8ae | ||
|
|
3c4612d15c | ||
|
|
7fa2e7862d | ||
|
|
114267362c | ||
|
|
4050e9605d | ||
|
|
fdd5373aaf | ||
|
|
2dfe7ec05b | ||
|
|
82513b5dde | ||
|
|
14d1bb6ac8 | ||
|
|
d589c94681 | ||
|
|
eca19bb507 | ||
|
|
282ff30b3e | ||
|
|
5d0b810674 | ||
|
|
e32482c634 | ||
|
|
650026b0c0 | ||
|
|
cd25d6da38 | ||
|
|
9dd0954967 | ||
|
|
fdaceb9bf8 | ||
|
|
4ab3a3b3cf | ||
|
|
eb8b54dc63 | ||
|
|
4703aee60c | ||
|
|
93b0d43bd7 | ||
|
|
1029310e0d | ||
|
|
c083684db2 | ||
|
|
d6775aad69 | ||
|
|
3eff10bbb4 | ||
|
|
e4cbab8365 | ||
|
|
18212e7a4c | ||
|
|
0cd0b1abfd | ||
|
|
a66137873c | ||
|
|
469110eabf | ||
|
|
55474fa4e3 | ||
|
|
3bdcdee031 | ||
|
|
246c5a61dd | ||
|
|
0c8bfba515 | ||
|
|
3c8d9bb1e5 | ||
|
|
da2c1c8316 | ||
|
|
0334b2dd33 | ||
|
|
96356042af | ||
|
|
21adff8d0c | ||
|
|
35def2a7c7 | ||
|
|
e3d82794a3 | ||
|
|
20cbac8f17 | ||
|
|
6067e02729 | ||
|
|
eb77664ea1 | ||
|
|
8b1baf9ebd | ||
|
|
12fb774b73 | ||
|
|
d79dbb11fe | ||
|
|
19ccb29248 | ||
|
|
199c4f30e7 | ||
|
|
732c0d4e35 | ||
|
|
fa1769da9f | ||
|
|
029997d624 | ||
|
|
d2546409cb | ||
|
|
cb2bc8d65b | ||
|
|
57bd8d4dd4 | ||
|
|
cc1e210799 | ||
|
|
4bee08d483 | ||
|
|
8cfb160989 | ||
|
|
6325167eda | ||
|
|
8925eae4c5 | ||
|
|
9282bcd779 | ||
|
|
5aa6499598 | ||
|
|
f766781928 | ||
|
|
02834b7102 | ||
|
|
a9e3430505 | ||
|
|
4b9a23001a | ||
|
|
8de7ec9124 | ||
|
|
19a0a3c7c3 | ||
|
|
42a7d6e4b7 | ||
|
|
66818b1647 | ||
|
|
bc8ba9adc8 | ||
|
|
4ae5759361 | ||
|
|
b5cfcf8036 | ||
|
|
061982cf2c | ||
|
|
0e1422c2c4 | ||
|
|
3e534029a0 | ||
|
|
8d9ee9fe5c | ||
|
|
675aa04564 | ||
|
|
88c8885a81 | ||
|
|
151760aef9 | ||
|
|
6c89969b60 | ||
|
|
0fd5e66c33 | ||
|
|
c8aa526e4d | ||
|
|
f2c492c6ea | ||
|
|
11cf845235 | ||
|
|
ae6fbc7c64 | ||
|
|
71eda539f6 | ||
|
|
f43b948ac9 | ||
|
|
1b77020b6a | ||
|
|
1f62040560 | ||
|
|
cc5c3167b1 | ||
|
|
b9b79b949f | ||
|
|
a0d729fe6d | ||
|
|
f618dd3865 | ||
|
|
3fd3f972db | ||
|
|
2311655e5e | ||
|
|
c589836097 | ||
|
|
dbc641cfce | ||
|
|
f13bc58925 | ||
|
|
94d5892cf1 | ||
|
|
8e32b15f26 | ||
|
|
fe5f0ef2eb | ||
|
|
daa27d5f2d | ||
|
|
bb7626609e | ||
|
|
9ed58b685b | ||
|
|
4eb81ad30a | ||
|
|
a1f2cb57b3 | ||
|
|
62b8e387ca | ||
|
|
07498db711 | ||
|
|
2adc8c6f5d | ||
|
|
f15a43f303 | ||
|
|
e35aea5a7e | ||
|
|
0e1ed9d8cc | ||
|
|
f62ef06e51 | ||
|
|
30f4d4588f | ||
|
|
e102396dab | ||
|
|
f60815ef63 | ||
|
|
7b11b53774 | ||
|
|
abff7715ee | ||
|
|
83c0a20d61 | ||
|
|
a4de2391e9 | ||
|
|
732566eacd | ||
|
|
2c98128531 | ||
|
|
9a45823bdb | ||
|
|
fa43a08831 | ||
|
|
6fb8bdaff1 | ||
|
|
35e6d60ac0 | ||
|
|
ecfc241fb5 | ||
|
|
866a5100b9 | ||
|
|
3d972fd740 | ||
|
|
59c9275cc4 | ||
|
|
3ada83efff | ||
|
|
e263048a35 | ||
|
|
63980298b6 | ||
|
|
b904e94156 | ||
|
|
78f91b937f | ||
|
|
1ecd08d053 | ||
|
|
8c03accae7 | ||
|
|
456d3f2f3a | ||
|
|
fa2838ea5c | ||
|
|
e228490812 | ||
|
|
13d0ac0cbd | ||
|
|
09bed1456e | ||
|
|
c6827e499e | ||
|
|
d54cc7a2fd | ||
|
|
67dae94524 | ||
|
|
3273a21246 | ||
|
|
b40b61a46c | ||
|
|
813f611843 | ||
|
|
1abacb75be | ||
|
|
42028a2777 | ||
|
|
0a25eeadbe | ||
|
|
70a4451f90 | ||
|
|
d859395f50 | ||
|
|
97948df14e | ||
|
|
dc84efb3ef | ||
|
|
12676a4314 | ||
|
|
3aafb9f8e7 | ||
|
|
4518db2bdd | ||
|
|
2cb161b62e | ||
|
|
9d052284be | ||
|
|
98d9029dde | ||
|
|
040c67215e | ||
|
|
d577312b24 | ||
|
|
fa10bc9c30 | ||
|
|
055339956a | ||
|
|
6cffa53ea9 | ||
|
|
fe83ef56ea | ||
|
|
abd1cacdc0 | ||
|
|
85b448ab85 | ||
|
|
5749f0018c | ||
|
|
b65d2c5ff3 | ||
|
|
348b2c4aca | ||
|
|
dfc3f32086 | ||
|
|
68d331864d | ||
|
|
24a008b20d | ||
|
|
0e5c35fae4 | ||
|
|
4d4b989dcd | ||
|
|
2983d5a068 | ||
|
|
efdc365b90 | ||
|
|
c4a8e3eb96 | ||
|
|
8cb3c98b8d | ||
|
|
9c12eda210 | ||
|
|
90afcc008d | ||
|
|
7409d096fe | ||
|
|
a4c4a3c0c8 | ||
|
|
2148af7b63 | ||
|
|
d984bc04ec | ||
|
|
1b7dfcc3ac | ||
|
|
c762871cce | ||
|
|
007ea92bd5 | ||
|
|
688b758da2 | ||
|
|
39147d7afa | ||
|
|
50cc17a44b | ||
|
|
73f592df74 | ||
|
|
821042d8b6 | ||
|
|
7123f6cc15 | ||
|
|
6c2e9906b0 | ||
|
|
37648b79c3 | ||
|
|
6b00c2c81a | ||
|
|
cd5599ff1c | ||
|
|
e870eb241b | ||
|
|
fbf8c282e8 | ||
|
|
811e363dd4 | ||
|
|
d206ba1606 | ||
|
|
c529134cd2 | ||
|
|
dafb1d335e | ||
|
|
445899e731 | ||
|
|
b21fbc974c | ||
|
|
4c98a73204 | ||
|
|
e99d669086 | ||
|
|
913ffbda97 | ||
|
|
ec2bd0bd5d | ||
|
|
08fefb1c4b | ||
|
|
e7f20bc553 | ||
|
|
f5993ca5c4 | ||
|
|
9f0c81c20f | ||
|
|
42199c8cda | ||
|
|
bc525fbffc | ||
|
|
dd6821642f | ||
|
|
b2dd96f044 | ||
|
|
0ca8a1fabf | ||
|
|
d46643cf8c | ||
|
|
fc3bea28e8 | ||
|
|
b29323864e | ||
|
|
c4cad5d56f | ||
|
|
1d83c82919 |
7
.browserslistrc
Normal file
7
.browserslistrc
Normal file
@@ -0,0 +1,7 @@
|
||||
last 1 Chrome version
|
||||
last 1 Firefox version
|
||||
last 2 Edge major versions
|
||||
last 2 iOS major versions
|
||||
safari > 11
|
||||
Firefox ESR
|
||||
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -31,6 +31,7 @@ speed-measure-plugin.json
|
||||
.history/*
|
||||
|
||||
# misc
|
||||
/.angular/cache
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
|
||||
4
.npmrc
4
.npmrc
@@ -1,3 +1 @@
|
||||
@isa:registry=https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel%40Local/npm/registry/
|
||||
@cmf:registry=https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel%40Local/npm/registry/
|
||||
always-auth=true
|
||||
@paragondata:registry=https://npm.pkg.github.com
|
||||
1329
angular.json
1329
angular.json
File diff suppressed because it is too large
Load Diff
@@ -1,22 +1,18 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Injectable, isDevMode } from '@angular/core';
|
||||
import { PromptModalData, UiModalService, UiPromptModalComponent } from '@ui/modal';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ScanAdapter } from './scan-adapter';
|
||||
|
||||
@Injectable()
|
||||
export class DevScanAdapter implements ScanAdapter {
|
||||
readonly name = 'Dev';
|
||||
|
||||
constructor(private _modal: UiModalService) {}
|
||||
|
||||
getName(): string {
|
||||
return 'Dev Scanner';
|
||||
}
|
||||
|
||||
isPrimary(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
isReady(): boolean {
|
||||
return true;
|
||||
init(): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(isDevMode());
|
||||
});
|
||||
}
|
||||
|
||||
scan(): Observable<string> {
|
||||
|
||||
@@ -6,20 +6,14 @@ import { ScanAdapter } from './scan-adapter';
|
||||
|
||||
@Injectable()
|
||||
export class NativeScanAdapter implements ScanAdapter {
|
||||
readonly name = 'Native';
|
||||
|
||||
constructor(private readonly nativeContainerService: NativeContainerService) {}
|
||||
|
||||
getName(): string {
|
||||
return 'Native Scanner';
|
||||
}
|
||||
|
||||
isPrimary(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
isReady(): boolean {
|
||||
// TODO: Fix Login Keycard Dauerschleife
|
||||
return this.nativeContainerService.isUiWebview().isNative || this.nativeContainerService.isIpadMini6();
|
||||
// return false;
|
||||
init(): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(this.nativeContainerService.isUiWebview().isNative);
|
||||
});
|
||||
}
|
||||
|
||||
scan(): Observable<string> {
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
export interface ScanAdapter {
|
||||
getName(): string;
|
||||
/**
|
||||
* Name to identify the adapter
|
||||
*/
|
||||
readonly name: string;
|
||||
|
||||
isPrimary(): boolean;
|
||||
|
||||
isReady(): boolean;
|
||||
/**
|
||||
* @returns true if this adapter can be used
|
||||
*/
|
||||
init(): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* scan for a barcode
|
||||
*/
|
||||
scan(): Observable<string>;
|
||||
}
|
||||
|
||||
@@ -5,10 +5,13 @@ import { SCAN_ADAPTER } from './tokens';
|
||||
|
||||
@NgModule({})
|
||||
export class ScanAdapterModule {
|
||||
static forRoot(dev?: boolean) {
|
||||
static forRoot() {
|
||||
return {
|
||||
ngModule: ScanAdapterModule,
|
||||
providers: [{ provide: SCAN_ADAPTER, useClass: NativeScanAdapter, multi: true }],
|
||||
providers: [
|
||||
{ provide: SCAN_ADAPTER, useClass: NativeScanAdapter, multi: true },
|
||||
{ provide: SCAN_ADAPTER, useClass: DevScanAdapter, multi: true },
|
||||
],
|
||||
// Use for testing:
|
||||
// providers: [{ provide: SCAN_ADAPTER, useClass: dev ? DevScanAdapter : NativeScanAdapter, multi: true }],
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { ScanAdapter } from './scan-adapter';
|
||||
import { SCAN_ADAPTER } from './tokens';
|
||||
|
||||
@@ -6,25 +7,59 @@ import { SCAN_ADAPTER } from './tokens';
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ScanAdapterService {
|
||||
private _readyAdapters: Record<string, boolean> = {};
|
||||
|
||||
constructor(@Inject(SCAN_ADAPTER) private readonly scanAdapters: ScanAdapter[]) {}
|
||||
|
||||
scanners() {
|
||||
return this.scanAdapters.filter((adapter) => adapter.isReady());
|
||||
}
|
||||
|
||||
scanner() {
|
||||
return this.scanners().find((scanner) => scanner.isPrimary()) || this.scanners().find(() => true);
|
||||
}
|
||||
|
||||
isReady() {
|
||||
return this.scanAdapters.some((adapter) => adapter.isReady());
|
||||
}
|
||||
|
||||
scan() {
|
||||
const primaryScanner = this.scanner();
|
||||
if (primaryScanner) {
|
||||
return primaryScanner.scan();
|
||||
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;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
adapters(): ScanAdapter[] {
|
||||
return [...this.scanAdapters];
|
||||
}
|
||||
|
||||
getAdapter(name: string): ScanAdapter | undefined {
|
||||
return 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> {
|
||||
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);
|
||||
}
|
||||
|
||||
if (!adapter) {
|
||||
return throwError('No adapter found');
|
||||
}
|
||||
|
||||
if (this._readyAdapters[adapter.name] == false) {
|
||||
return throwError('Adapter is not ready');
|
||||
}
|
||||
|
||||
return adapter.scan();
|
||||
}
|
||||
}
|
||||
|
||||
3
apps/adapter/scan/src/lib/scandit/index.ts
Normal file
3
apps/adapter/scan/src/lib/scandit/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './scandit-overlay.component';
|
||||
export * from './scandit-scan-adapter.module';
|
||||
export * from './scandit.scan-adapter';
|
||||
@@ -0,0 +1,20 @@
|
||||
:host {
|
||||
@apply block relative;
|
||||
}
|
||||
|
||||
.scanner-container {
|
||||
width: 100vw;
|
||||
max-width: 95vw;
|
||||
max-height: calc(95vh - 120px);
|
||||
}
|
||||
|
||||
.close-scanner {
|
||||
@apply block px-6 py-4 bg-white text-brand border-2 border-solid border-brand rounded-full text-lg font-bold mx-auto mt-4;
|
||||
}
|
||||
|
||||
@screen desktop {
|
||||
.scanner-container {
|
||||
max-width: 900px;
|
||||
max-height: 900px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<div class="scanner-container" #scanContainer></div>
|
||||
<button class="close-scanner" type="button" (click)="close()">
|
||||
Scan abbrechen
|
||||
</button>
|
||||
100
apps/adapter/scan/src/lib/scandit/scandit-overlay.component.ts
Normal file
100
apps/adapter/scan/src/lib/scandit/scandit-overlay.component.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { Component, ChangeDetectionStrategy, ElementRef, ViewChild, NgZone, AfterViewInit, OnDestroy } from '@angular/core';
|
||||
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
|
||||
import { Barcode, BarcodePicker, ScanResult, ScanSettings } from 'scandit-sdk';
|
||||
|
||||
@Component({
|
||||
selector: 'app-scandit-overlay',
|
||||
templateUrl: 'scandit-overlay.component.html',
|
||||
styleUrls: ['scandit-overlay.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ScanditOverlayComponent implements AfterViewInit, OnDestroy {
|
||||
private _barcodePicker: BarcodePicker;
|
||||
|
||||
private _onScan?: (code: string) => void;
|
||||
|
||||
private _onClose?: () => void;
|
||||
|
||||
@ViewChild('scanContainer', { read: ElementRef, static: true }) scanContainer: ElementRef;
|
||||
|
||||
constructor(private _zone: NgZone, private _modal: UiModalService) {}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.createBarcodePicker()
|
||||
.then(() => {
|
||||
this._barcodePicker.on('scan', (scanResult) => {
|
||||
this._zone.run(() => this.handleScanrResult(scanResult));
|
||||
});
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
this._modal
|
||||
.open({
|
||||
content: UiMessageModalComponent,
|
||||
title: 'Zugriff auf Kamera verweigert',
|
||||
data: { message: 'Falls Sie den Zugriff erlauben möchten, können Sie das über die Webseiteinstellung Ihres Browsers.' },
|
||||
})
|
||||
.afterClosed$.subscribe(() => {
|
||||
this._onClose?.();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async createBarcodePicker() {
|
||||
this._barcodePicker = await BarcodePicker.create(this.scanContainer.nativeElement, {
|
||||
playSoundOnScan: true,
|
||||
vibrateOnScan: true,
|
||||
});
|
||||
|
||||
this._barcodePicker.applyScanSettings(this.getScanSettings());
|
||||
}
|
||||
|
||||
getScanSettings(): ScanSettings {
|
||||
return new ScanSettings({
|
||||
blurryRecognition: false,
|
||||
|
||||
enabledSymbologies: [
|
||||
Barcode.Symbology.EAN8,
|
||||
Barcode.Symbology.EAN13,
|
||||
Barcode.Symbology.UPCA,
|
||||
Barcode.Symbology.UPCE,
|
||||
Barcode.Symbology.CODE128,
|
||||
Barcode.Symbology.CODE39,
|
||||
Barcode.Symbology.CODE93,
|
||||
Barcode.Symbology.INTERLEAVED_2_OF_5,
|
||||
Barcode.Symbology.QR,
|
||||
],
|
||||
codeDuplicateFilter: 1000,
|
||||
});
|
||||
}
|
||||
|
||||
onScan(fn: (code: string) => void) {
|
||||
this._onScan = fn;
|
||||
}
|
||||
|
||||
onClose(fn: () => void) {
|
||||
this._onClose = fn;
|
||||
}
|
||||
|
||||
handleScanrResult(scanRestul: ScanResult) {
|
||||
let result: string | undefined;
|
||||
if (scanRestul.barcodes.length) {
|
||||
result = scanRestul.barcodes[0].data;
|
||||
} else if (scanRestul.texts.length) {
|
||||
result = scanRestul.texts[0].value;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
this._onScan?.(result);
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
this._onClose?.();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this._zone.runOutsideAngular(() => {
|
||||
this._barcodePicker?.destroy(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { ScanditOverlayComponent } from './scandit-overlay.component';
|
||||
import { ScanditScanAdapter } from './scandit.scan-adapter';
|
||||
import { SCAN_ADAPTER } from '../tokens';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule],
|
||||
exports: [ScanditOverlayComponent],
|
||||
declarations: [ScanditOverlayComponent],
|
||||
})
|
||||
export class ScanditScanAdapterModule {
|
||||
static forRoot() {
|
||||
return {
|
||||
ngModule: ScanditScanAdapterModule,
|
||||
providers: [{ provide: SCAN_ADAPTER, useClass: ScanditScanAdapter, multi: true }],
|
||||
};
|
||||
}
|
||||
}
|
||||
77
apps/adapter/scan/src/lib/scandit/scandit.scan-adapter.ts
Normal file
77
apps/adapter/scan/src/lib/scandit/scandit.scan-adapter.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, Subscriber } from 'rxjs';
|
||||
import { ScanAdapter } from '../scan-adapter';
|
||||
import { Overlay } from '@angular/cdk/overlay';
|
||||
|
||||
import { configure } from 'scandit-sdk';
|
||||
// import { ScanditModalComponent } from './scandit-modal';
|
||||
import { Config } from '@core/config';
|
||||
import { ComponentPortal } from '@angular/cdk/portal';
|
||||
import { ScanditOverlayComponent } from './scandit-overlay.component';
|
||||
|
||||
@Injectable()
|
||||
export class ScanditScanAdapter implements ScanAdapter {
|
||||
readonly name = 'Scandit';
|
||||
|
||||
constructor(private readonly _config: Config, private _overlay: Overlay) {}
|
||||
|
||||
async init(): Promise<boolean> {
|
||||
await configure(this._config.get('licence.scandit'), {
|
||||
engineLocation: '/scandit/',
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
scan(): Observable<string> {
|
||||
return new Observable((observer) => {
|
||||
const overlay = this.createOverlay();
|
||||
|
||||
const portal = this.createPortal();
|
||||
|
||||
const ref = overlay.attach(portal);
|
||||
|
||||
const sub = new Subscriber();
|
||||
|
||||
const complete = () => {
|
||||
overlay.detach();
|
||||
ref.destroy();
|
||||
sub.unsubscribe();
|
||||
sub.complete();
|
||||
observer.complete();
|
||||
};
|
||||
|
||||
sub.add(
|
||||
overlay.backdropClick().subscribe(() => {
|
||||
complete();
|
||||
})
|
||||
);
|
||||
|
||||
ref.instance.onScan((code) => {
|
||||
observer.next(code);
|
||||
complete();
|
||||
});
|
||||
|
||||
ref.instance.onClose(() => {
|
||||
complete();
|
||||
});
|
||||
|
||||
return complete;
|
||||
});
|
||||
}
|
||||
|
||||
createOverlay() {
|
||||
const overlay = this._overlay.create({
|
||||
positionStrategy: this._overlay.position().global().centerHorizontally().centerVertically(),
|
||||
hasBackdrop: true,
|
||||
});
|
||||
|
||||
return overlay;
|
||||
}
|
||||
|
||||
createPortal() {
|
||||
const portal = new ComponentPortal(ScanditOverlayComponent);
|
||||
|
||||
return portal;
|
||||
}
|
||||
}
|
||||
@@ -2,5 +2,10 @@
|
||||
* Public API Surface of scan
|
||||
*/
|
||||
|
||||
export * from './lib/scan.service';
|
||||
export * from './lib/scandit';
|
||||
export * from './lib/dev.scan-adapter';
|
||||
export * from './lib/native.scan-adapter';
|
||||
export * from './lib/scan-adapter';
|
||||
export * from './lib/scan.module';
|
||||
export * from './lib/scan.service';
|
||||
export * from './lib/tokens';
|
||||
|
||||
@@ -5,21 +5,5 @@ import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { teardown: { destroyAfterEach: true } });
|
||||
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
|
||||
@@ -5,20 +5,7 @@ import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
|
||||
teardown: { destroyAfterEach: false },
|
||||
});
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +181,8 @@ describe('ApplicationService', () => {
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledWith({
|
||||
type: actions.patchProcess.type,
|
||||
process: {
|
||||
processId: process.id,
|
||||
changes: {
|
||||
...process,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -60,7 +60,7 @@ describe('applicationReducer', () => {
|
||||
type: 'cart',
|
||||
};
|
||||
|
||||
const action = actions.patchProcess({ process: { ...process, name: 'Test' } });
|
||||
const action = actions.patchProcess({ processId: process.id, changes: { ...process, name: 'Test' } });
|
||||
const state = applicationReducer(
|
||||
{
|
||||
...initialState,
|
||||
@@ -81,7 +81,7 @@ describe('applicationReducer', () => {
|
||||
type: 'cart',
|
||||
};
|
||||
|
||||
const action = actions.patchProcess({ process: { ...process, id: 2 } });
|
||||
const action = actions.patchProcess({ processId: process.id, changes: { ...process, id: 2 } });
|
||||
const state = applicationReducer(
|
||||
{
|
||||
...initialState,
|
||||
|
||||
@@ -23,7 +23,7 @@ const _applicationReducer = createReducer(
|
||||
on(patchProcess, (state, { processId, changes }) => {
|
||||
const processes = state.processes.map((process) => {
|
||||
if (process.id === processId) {
|
||||
return { ...process, ...changes };
|
||||
return { ...process, ...changes, id: processId };
|
||||
}
|
||||
return process;
|
||||
});
|
||||
|
||||
@@ -5,20 +5,7 @@ import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
|
||||
teardown: { destroyAfterEach: false },
|
||||
});
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,11 @@ export class AuthService {
|
||||
this._oAuthService.tokenValidationHandler = new JwksValidationHandler();
|
||||
|
||||
this._oAuthService.setupAutomaticSilentRefresh();
|
||||
await this._oAuthService.loadDiscoveryDocumentAndTryLogin();
|
||||
try {
|
||||
await this._oAuthService.loadDiscoveryDocumentAndTryLogin();
|
||||
} catch (error) {
|
||||
this.login();
|
||||
}
|
||||
|
||||
this._initialized.next(true);
|
||||
}
|
||||
|
||||
@@ -5,21 +5,5 @@ import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { teardown: { destroyAfterEach: true } });
|
||||
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
|
||||
@@ -20,7 +20,7 @@ export const selectBreadcrumbById = createSelector(selectEntities, (entities, id
|
||||
/**
|
||||
* Gibt alle Breadcrumb Entities als Array zurück die den key enthalten
|
||||
*/
|
||||
export const selectBreadcrumbsByKey = createSelector(selectAll, (entities, key: string) => entities.filter((crumb) => crumb.key === key));
|
||||
export const selectBreadcrumbsByKey = createSelector(selectAll, (entities, key: string) => entities.filter((crumb) => crumb.key == key));
|
||||
|
||||
/**
|
||||
* Gibt alle Breadcrumb Entities als Array zurück die den key und tag enthalten
|
||||
@@ -28,7 +28,7 @@ export const selectBreadcrumbsByKey = createSelector(selectAll, (entities, key:
|
||||
export const selectBreadcrumbsByKeyAndTag = createSelector(
|
||||
selectAll,
|
||||
(entities: Breadcrumb[], { key, tag }: { key: string; tag: string }) =>
|
||||
entities.filter((crumb) => crumb.key === key && isArray(crumb.tags) && crumb.tags.includes(tag))
|
||||
entities.filter((crumb) => crumb.key == key && isArray(crumb.tags) && crumb.tags.includes(tag))
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -37,7 +37,7 @@ export const selectBreadcrumbsByKeyAndTag = createSelector(
|
||||
export const selectBreadcrumbsByKeyAndTags = createSelector(
|
||||
selectAll,
|
||||
(entities: Breadcrumb[], { key, tags }: { key: string; tags: string[] }) =>
|
||||
entities.filter((crumb) => crumb.key === key && isArray(crumb.tags) && tags.every((tag) => crumb.tags.includes(tag)))
|
||||
entities.filter((crumb) => crumb.key == key && isArray(crumb.tags) && tags.every((tag) => crumb.tags.includes(tag)))
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,20 +5,7 @@ import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
|
||||
teardown: { destroyAfterEach: false },
|
||||
});
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
|
||||
11
apps/core/cache/src/lib/cache.service.ts
vendored
11
apps/core/cache/src/lib/cache.service.ts
vendored
@@ -1,7 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CacheOptions } from './cache-options';
|
||||
import { Cached } from './cached';
|
||||
import { sha1 } from 'object-hash';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@@ -60,7 +59,15 @@ export class CacheService {
|
||||
}
|
||||
|
||||
private getKey(token: Object) {
|
||||
return sha1(token);
|
||||
return this.hash(JSON.stringify(token));
|
||||
}
|
||||
|
||||
private hash(data: string): string {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
hash = data.charCodeAt(i) + ((hash << 5) - hash);
|
||||
}
|
||||
return hash.toString(16);
|
||||
}
|
||||
|
||||
private serialize(data: Cached): string {
|
||||
|
||||
19
apps/core/cache/src/test.ts
vendored
19
apps/core/cache/src/test.ts
vendored
@@ -5,20 +5,7 @@ import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
|
||||
teardown: { destroyAfterEach: false },
|
||||
});
|
||||
|
||||
1
apps/core/cache/tsconfig.lib.json
vendored
1
apps/core/cache/tsconfig.lib.json
vendored
@@ -3,7 +3,6 @@
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
|
||||
2
apps/core/cache/tsconfig.lib.prod.json
vendored
2
apps/core/cache/tsconfig.lib.prod.json
vendored
@@ -5,6 +5,6 @@
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { Injectable, Injector, Optional, SkipSelf } from '@angular/core';
|
||||
import { ActionHandler } from './action-handler.interface';
|
||||
import { FEATURE_ACTION_HANDLERS, ROOT_ACTION_HANDLERS } from './tokens';
|
||||
|
||||
@Injectable()
|
||||
export class CommandService {
|
||||
constructor(private injector: Injector) {}
|
||||
constructor(private injector: Injector, @Optional() @SkipSelf() private _parent: CommandService) {}
|
||||
|
||||
async handleCommand<T>(command: string, data?: T): Promise<T> {
|
||||
const actions = this.getActions(command);
|
||||
@@ -15,7 +15,7 @@ export class CommandService {
|
||||
console.error('CommandService.handleCommand', 'Action Handler does not exist', { action });
|
||||
throw new Error('Action Handler does not exist');
|
||||
}
|
||||
console.log('handle command', handler, data);
|
||||
|
||||
data = await handler.handler(data);
|
||||
}
|
||||
return data;
|
||||
@@ -25,10 +25,16 @@ export class CommandService {
|
||||
return command?.split('|') || [];
|
||||
}
|
||||
|
||||
getActionHandler(action: string): ActionHandler {
|
||||
getActionHandler(action: string): ActionHandler | undefined {
|
||||
const featureActionHandlers: ActionHandler[] = this.injector.get(FEATURE_ACTION_HANDLERS, []);
|
||||
const rootActionHandlers: ActionHandler[] = this.injector.get(ROOT_ACTION_HANDLERS, []);
|
||||
|
||||
return [...featureActionHandlers, ...rootActionHandlers].find((handler) => handler.action === action);
|
||||
let handler = [...featureActionHandlers, ...rootActionHandlers].find((handler) => handler.action === action);
|
||||
|
||||
if (this._parent && !handler) {
|
||||
handler = this._parent.getActionHandler(action);
|
||||
}
|
||||
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,20 +5,7 @@ import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
|
||||
teardown: { destroyAfterEach: false },
|
||||
});
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,21 +5,5 @@ import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { teardown: { destroyAfterEach: true } });
|
||||
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
|
||||
@@ -5,20 +5,7 @@ import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
|
||||
teardown: { destroyAfterEach: false },
|
||||
});
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,21 +5,5 @@ import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { teardown: { destroyAfterEach: true } });
|
||||
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
|
||||
@@ -5,20 +5,7 @@ import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
|
||||
teardown: { destroyAfterEach: false },
|
||||
});
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
|
||||
25
apps/core/toast/README.md
Normal file
25
apps/core/toast/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Toast
|
||||
|
||||
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.2.0.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name --project toast` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project toast`.
|
||||
|
||||
> Note: Don't forget to add `--project toast` or else it will be added to the default project in your `angular.json` file.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build toast` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
|
||||
## Publishing
|
||||
|
||||
After building your library with `ng build toast`, go to the dist folder `cd dist/toast` and run `npm publish`.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test toast` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
||||
@@ -9,23 +9,32 @@ module.exports = function (config) {
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('karma-coverage'),
|
||||
require('@angular-devkit/build-angular/plugins/karma'),
|
||||
],
|
||||
client: {
|
||||
jasmine: {
|
||||
// you can add configuration options for Jasmine here
|
||||
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
||||
// for example, you can disable the random execution with `random: false`
|
||||
// or set a specific seed with `seed: 4321`
|
||||
},
|
||||
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, '../../coverage'),
|
||||
reports: ['html', 'lcovonly', 'text-summary'],
|
||||
fixWebpackSourcePaths: true,
|
||||
jasmineHtmlReporter: {
|
||||
suppressAll: true, // removes the duplicated traces
|
||||
},
|
||||
coverageReporter: {
|
||||
dir: require('path').join(__dirname, '../../../coverage/core/toast'),
|
||||
subdir: '.',
|
||||
reporters: [{ type: 'html' }, { type: 'text-summary' }],
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['ChromeHeadless'],
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true,
|
||||
});
|
||||
7
apps/core/toast/ng-package.json
Normal file
7
apps/core/toast/ng-package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../../dist/core/toast",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
11
apps/core/toast/package.json
Normal file
11
apps/core/toast/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "@core/toast",
|
||||
"version": "0.0.1",
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^12.2.0",
|
||||
"@angular/core": "^12.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
// start:ng42.barrel
|
||||
export * from './focus.directive';
|
||||
export * from './toast-animation';
|
||||
// end:ng42.barrel
|
||||
14
apps/core/toast/src/lib/animation/toast-animation.ts
Normal file
14
apps/core/toast/src/lib/animation/toast-animation.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
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';
|
||||
4
apps/core/toast/src/lib/defs/index.ts
Normal file
4
apps/core/toast/src/lib/defs/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
// start:ng42.barrel
|
||||
export * from './toast';
|
||||
export * from './toast-ref';
|
||||
// end:ng42.barrel
|
||||
17
apps/core/toast/src/lib/defs/toast-ref.ts
Normal file
17
apps/core/toast/src/lib/defs/toast-ref.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
11
apps/core/toast/src/lib/defs/toast.ts
Normal file
11
apps/core/toast/src/lib/defs/toast.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
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
|
||||
}
|
||||
8
apps/core/toast/src/lib/index.ts
Normal file
8
apps/core/toast/src/lib/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
// 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
|
||||
15
apps/core/toast/src/lib/toast.component.html
Normal file
15
apps/core/toast/src/lib/toast.component.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<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>
|
||||
12
apps/core/toast/src/lib/toast.component.scss
Normal file
12
apps/core/toast/src/lib/toast.component.scss
Normal file
@@ -0,0 +1,12 @@
|
||||
.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;
|
||||
}
|
||||
24
apps/core/toast/src/lib/toast.component.spec.ts
Normal file
24
apps/core/toast/src/lib/toast.component.spec.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ToastComponent } from './toast.component';
|
||||
|
||||
describe('ToastComponent', () => {
|
||||
let component: ToastComponent;
|
||||
let fixture: ComponentFixture<ToastComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ToastComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ToastComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
48
apps/core/toast/src/lib/toast.component.ts
Normal file
48
apps/core/toast/src/lib/toast.component.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
12
apps/core/toast/src/lib/toast.module.ts
Normal file
12
apps/core/toast/src/lib/toast.module.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
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 {}
|
||||
16
apps/core/toast/src/lib/toast.service.spec.ts
Normal file
16
apps/core/toast/src/lib/toast.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ToastService } from './toast.service';
|
||||
|
||||
describe('ToastService', () => {
|
||||
let service: ToastService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(ToastService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
79
apps/core/toast/src/lib/toast.service.ts
Normal file
79
apps/core/toast/src/lib/toast.service.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
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';
|
||||
}
|
||||
}
|
||||
4
apps/core/toast/src/lib/tokens.ts
Normal file
4
apps/core/toast/src/lib/tokens.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { InjectionToken } from '@angular/core';
|
||||
import { Toast } from './defs';
|
||||
|
||||
export const TOAST_CONFIG_TOKEN = new InjectionToken<Toast>('TOAST_DATA');
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Public API Surface of sso
|
||||
* Public API Surface of toast
|
||||
*/
|
||||
|
||||
export * from './lib';
|
||||
@@ -1,14 +1,9 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js';
|
||||
import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: any;
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { teardown: { destroyAfterEach: true } });
|
||||
19
apps/core/toast/tsconfig.lib.json
Normal file
19
apps/core/toast/tsconfig.lib.json
Normal file
@@ -0,0 +1,19 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"types": [],
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2018"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"src/test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.lib.json",
|
||||
"compilerOptions": {
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
}
|
||||
17
apps/core/toast/tsconfig.spec.json
Normal file
17
apps/core/toast/tsconfig.spec.json
Normal file
@@ -0,0 +1,17 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"src/test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
@@ -1,34 +1,42 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ItemDTO, SearchService } from '@swagger/cat';
|
||||
import { AvailabilityDTO, BranchDTO, OLAAvailabilityDTO, StoreCheckoutService, SupplierDTO } from '@swagger/checkout';
|
||||
import { ItemDTO } from '@swagger/cat';
|
||||
import {
|
||||
AvailabilityDTO,
|
||||
BranchDTO,
|
||||
OLAAvailabilityDTO,
|
||||
StoreCheckoutBranchService,
|
||||
StoreCheckoutSupplierService,
|
||||
SupplierDTO,
|
||||
} from '@swagger/checkout';
|
||||
import { combineLatest, Observable, of } from 'rxjs';
|
||||
import {
|
||||
AvailabilityRequestDTO,
|
||||
AvailabilityService as SwaggerAvailabilityService,
|
||||
AvailabilityService,
|
||||
AvailabilityDTO as SwaggerAvailabilityDTO,
|
||||
AvailabilityType,
|
||||
} from '@swagger/availability';
|
||||
import { AvailabilityDTO as CatAvailabilityDTO } from '@swagger/cat';
|
||||
import { map, shareReplay, switchMap, withLatestFrom, mergeMap, timeout } from 'rxjs/operators';
|
||||
import { isArray, memorize } from '@utils/common';
|
||||
import { OrderService } from '@swagger/oms';
|
||||
import { LogisticianDTO, LogisticianService } from '@swagger/oms';
|
||||
import { ResponseArgsOfIEnumerableOfStockInfoDTO, StockDTO, StockInfoDTO, StockService } from '@swagger/remi';
|
||||
import { ItemData } from './defs/item-data.model';
|
||||
import { PriceDTO } from '@swagger/availability';
|
||||
import { AvailabilityByBranchDTO } from './defs/availability-by-branch-dto.model';
|
||||
import { AvailabilityByBranchDTO, ItemData } from './defs';
|
||||
import { Availability } from './defs/availability';
|
||||
|
||||
@Injectable()
|
||||
export class DomainAvailabilityService {
|
||||
constructor(
|
||||
private swaggerAvailabilityService: SwaggerAvailabilityService,
|
||||
private storeCheckoutService: StoreCheckoutService,
|
||||
private orderService: OrderService,
|
||||
private _stock: StockService
|
||||
private _availabilityService: AvailabilityService,
|
||||
private _logisticanService: LogisticianService,
|
||||
private _stockService: StockService,
|
||||
private _supplierService: StoreCheckoutSupplierService,
|
||||
private _branchService: StoreCheckoutBranchService
|
||||
) {}
|
||||
|
||||
@memorize()
|
||||
getSuppliers(): Observable<SupplierDTO[]> {
|
||||
return this.storeCheckoutService.StoreCheckoutGetSuppliers({}).pipe(
|
||||
return this._supplierService.StoreCheckoutSupplierGetSuppliers({}).pipe(
|
||||
map((response) => response.result),
|
||||
shareReplay()
|
||||
);
|
||||
@@ -36,15 +44,15 @@ export class DomainAvailabilityService {
|
||||
|
||||
@memorize()
|
||||
getTakeAwaySupplier(): Observable<SupplierDTO> {
|
||||
return this.storeCheckoutService.StoreCheckoutGetSuppliers({}).pipe(
|
||||
map(({ result }) => result.find((supplier) => supplier?.supplierNumber === 'F')),
|
||||
return this._supplierService.StoreCheckoutSupplierGetSuppliers({}).pipe(
|
||||
map(({ result }) => result?.find((supplier) => supplier?.supplierNumber === 'F')),
|
||||
shareReplay()
|
||||
);
|
||||
}
|
||||
|
||||
@memorize()
|
||||
getBranches(): Observable<BranchDTO[]> {
|
||||
return this.storeCheckoutService.StoreCheckoutGetBranches({}).pipe(
|
||||
return this._branchService.StoreCheckoutBranchGetBranches({}).pipe(
|
||||
map((response) => response.result),
|
||||
shareReplay()
|
||||
);
|
||||
@@ -52,7 +60,7 @@ export class DomainAvailabilityService {
|
||||
|
||||
@memorize()
|
||||
getCurrentStock(): Observable<StockDTO> {
|
||||
return this._stock.StockCurrentStock().pipe(
|
||||
return this._stockService.StockCurrentStock().pipe(
|
||||
map((response) => response.result),
|
||||
shareReplay()
|
||||
);
|
||||
@@ -60,7 +68,7 @@ export class DomainAvailabilityService {
|
||||
|
||||
@memorize()
|
||||
getCurrentBranch(): Observable<BranchDTO> {
|
||||
return this._stock.StockCurrentBranch().pipe(
|
||||
return this._stockService.StockCurrentBranch().pipe(
|
||||
map((response) => ({
|
||||
id: response.result.id,
|
||||
name: response.result.name,
|
||||
@@ -83,8 +91,8 @@ export class DomainAvailabilityService {
|
||||
}
|
||||
|
||||
@memorize({})
|
||||
getLogisticians() {
|
||||
return this.orderService.OrderGetLogisticians({}).pipe(
|
||||
getLogisticians(): Observable<LogisticianDTO> {
|
||||
return this._logisticanService.LogisticianGetLogisticians({}).pipe(
|
||||
map((response) => response.result?.find((l) => l.logisticianNumber === '2470')),
|
||||
shareReplay()
|
||||
);
|
||||
@@ -101,7 +109,7 @@ export class DomainAvailabilityService {
|
||||
price: PriceDTO;
|
||||
quantity: number;
|
||||
}): Observable<AvailabilityByBranchDTO[]> {
|
||||
return this._stock.StockStockRequest({ stockRequest: { branchIds, itemId } }).pipe(
|
||||
return this._stockService.StockStockRequest({ stockRequest: { branchIds, itemId } }).pipe(
|
||||
map((response) => response.result),
|
||||
withLatestFrom(this.getTakeAwaySupplier()),
|
||||
map(([result, supplier]) => {
|
||||
@@ -125,8 +133,13 @@ export class DomainAvailabilityService {
|
||||
|
||||
getTakeAwayAvailability({ item, quantity }: { item: ItemData; quantity: number }): Observable<AvailabilityDTO> {
|
||||
return this.getCurrentStock().pipe(
|
||||
switchMap((s) => this._stock.StockInStock({ articleIds: [item.itemId], stockId: s.id })),
|
||||
withLatestFrom(this.getTakeAwaySupplier(), this.getCurrentBranch()),
|
||||
switchMap((s) =>
|
||||
combineLatest([
|
||||
this._stockService.StockInStock({ articleIds: [item.itemId], stockId: s.id }),
|
||||
this.getTakeAwaySupplier(),
|
||||
this.getCurrentBranch(),
|
||||
])
|
||||
),
|
||||
map(([response, supplier, branch]) => {
|
||||
const price = item?.price;
|
||||
return this._mapToTakeAwayAvailability({ response, supplier, branch, quantity, price });
|
||||
@@ -148,7 +161,7 @@ export class DomainAvailabilityService {
|
||||
quantity: number;
|
||||
}): Observable<AvailabilityDTO> {
|
||||
return combineLatest([
|
||||
this._stock.StockStockRequest({ stockRequest: { branchIds: [branch.id], itemId } }),
|
||||
this._stockService.StockStockRequest({ stockRequest: { branchIds: [branch.id], itemId } }),
|
||||
this.getTakeAwaySupplier(),
|
||||
]).pipe(
|
||||
map(([response, supplier]) => {
|
||||
@@ -168,7 +181,7 @@ export class DomainAvailabilityService {
|
||||
quantity: number;
|
||||
}): Observable<AvailabilityDTO> {
|
||||
return this.getCurrentStock().pipe(
|
||||
switchMap((s) => this._stock.StockInStockByEAN({ eans, stockId: s.id })),
|
||||
switchMap((s) => this._stockService.StockInStockByEAN({ eans, stockId: s.id })),
|
||||
withLatestFrom(this.getTakeAwaySupplier(), this.getCurrentBranch()),
|
||||
map(([response, supplier, branch]) => {
|
||||
return this._mapToTakeAwayAvailability({ response, supplier, branch, quantity, price });
|
||||
@@ -180,7 +193,7 @@ export class DomainAvailabilityService {
|
||||
getTakeAwayAvailabilitiesByEans({ eans }: { eans: string[] }): Observable<StockInfoDTO[]> {
|
||||
const eansFiltered = Array.from(new Set(eans));
|
||||
return this.getCurrentStock().pipe(
|
||||
switchMap((s) => this._stock.StockInStockByEAN({ eans: eansFiltered, stockId: s.id })),
|
||||
switchMap((s) => this._stockService.StockInStockByEAN({ eans: eansFiltered, stockId: s.id })),
|
||||
withLatestFrom(this.getTakeAwaySupplier(), this.getCurrentBranch()),
|
||||
map((response) => response[0].result),
|
||||
shareReplay()
|
||||
@@ -188,8 +201,16 @@ export class DomainAvailabilityService {
|
||||
}
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getPickUpAvailability({ item, branch, quantity }: { item: ItemData; quantity: number; branch: BranchDTO }): Observable<AvailabilityDTO> {
|
||||
return this.swaggerAvailabilityService
|
||||
getPickUpAvailability({
|
||||
item,
|
||||
branch,
|
||||
quantity,
|
||||
}: {
|
||||
item: ItemData;
|
||||
quantity: number;
|
||||
branch: BranchDTO;
|
||||
}): Observable<Availability<AvailabilityDTO, SwaggerAvailabilityDTO>> {
|
||||
return this._availabilityService
|
||||
.AvailabilityStoreAvailability([
|
||||
{
|
||||
qty: quantity,
|
||||
@@ -207,7 +228,7 @@ export class DomainAvailabilityService {
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getDeliveryAvailability({ item, quantity }: { item: ItemData; quantity: number }): Observable<AvailabilityDTO> {
|
||||
return this.swaggerAvailabilityService
|
||||
return this._availabilityService
|
||||
.AvailabilityShippingAvailability([
|
||||
{
|
||||
ean: item?.ean,
|
||||
@@ -225,7 +246,7 @@ export class DomainAvailabilityService {
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getDigDeliveryAvailability({ item, quantity }: { item: ItemData; quantity: number }): Observable<AvailabilityDTO> {
|
||||
return this.swaggerAvailabilityService
|
||||
return this._availabilityService
|
||||
.AvailabilityShippingAvailability([
|
||||
{
|
||||
qty: quantity,
|
||||
@@ -270,7 +291,11 @@ export class DomainAvailabilityService {
|
||||
timeout(5000),
|
||||
mergeMap((branch) =>
|
||||
this.getPickUpAvailability({ item, quantity, branch }).pipe(
|
||||
mergeMap((availability) => logistician$.pipe(map((logistician) => ({ ...availability, logistician: { id: logistician.id } })))),
|
||||
mergeMap((availability) =>
|
||||
logistician$.pipe(
|
||||
map((logistician) => ({ ...(availability?.length > 0 ? availability[0] : []), logistician: { id: logistician.id } }))
|
||||
)
|
||||
),
|
||||
shareReplay()
|
||||
)
|
||||
)
|
||||
@@ -279,7 +304,7 @@ export class DomainAvailabilityService {
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getDownloadAvailability({ item }: { item: ItemData }): Observable<AvailabilityDTO> {
|
||||
return this.swaggerAvailabilityService
|
||||
return this._availabilityService
|
||||
.AvailabilityShippingAvailability([
|
||||
{
|
||||
ean: item?.ean,
|
||||
@@ -314,11 +339,11 @@ export class DomainAvailabilityService {
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getTakeAwayAvailabilities(items: { id: number; price: PriceDTO }[], branchId: number) {
|
||||
return this._stock.StockGetStocksByBranch({ branchId }).pipe(
|
||||
return this._stockService.StockGetStocksByBranch({ branchId }).pipe(
|
||||
map((req) => req.result?.find((_) => true)?.id),
|
||||
switchMap((stockId) =>
|
||||
stockId
|
||||
? this._stock.StockInStock({ articleIds: items.map((i) => i.id), stockId })
|
||||
? this._stockService.StockInStock({ articleIds: items.map((i) => i.id), stockId })
|
||||
: of({ result: [] } as ResponseArgsOfIEnumerableOfStockInfoDTO)
|
||||
),
|
||||
timeout(20000),
|
||||
@@ -339,7 +364,7 @@ export class DomainAvailabilityService {
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getPickUpAvailabilities(payload: AvailabilityRequestDTO[], preferred?: boolean) {
|
||||
return this.swaggerAvailabilityService.AvailabilityStoreAvailability(payload).pipe(
|
||||
return this._availabilityService.AvailabilityStoreAvailability(payload).pipe(
|
||||
timeout(20000),
|
||||
map((response) => (preferred ? this._mapToPickUpAvailability(response.result) : response.result))
|
||||
);
|
||||
@@ -347,7 +372,7 @@ export class DomainAvailabilityService {
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getDeliveryAvailabilities(payload: AvailabilityRequestDTO[]) {
|
||||
return this.swaggerAvailabilityService.AvailabilityShippingAvailability(payload).pipe(
|
||||
return this._availabilityService.AvailabilityShippingAvailability(payload).pipe(
|
||||
timeout(20000),
|
||||
map((response) => this._mapToShippingAvailability(response.result))
|
||||
);
|
||||
@@ -355,7 +380,7 @@ export class DomainAvailabilityService {
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getDigDeliveryAvailabilities(payload: AvailabilityRequestDTO[]) {
|
||||
return this.swaggerAvailabilityService.AvailabilityShippingAvailability(payload).pipe(
|
||||
return this._availabilityService.AvailabilityShippingAvailability(payload).pipe(
|
||||
timeout(20000),
|
||||
map((response) => this._mapToShippingAvailability(response.result))
|
||||
);
|
||||
@@ -381,7 +406,7 @@ export class DomainAvailabilityService {
|
||||
): PriceDTO {
|
||||
switch (purchasingOption) {
|
||||
case 'take-away':
|
||||
return availability?.price || availability?.retailPrice;
|
||||
return availability?.price || catalogAvailability?.price;
|
||||
case 'delivery':
|
||||
case 'dig-delivery':
|
||||
if (catalogAvailability?.price?.value?.value < availability?.price?.value?.value) {
|
||||
@@ -442,9 +467,11 @@ export class DomainAvailabilityService {
|
||||
inStock: inStock,
|
||||
supplierSSC: quantity <= inStock ? '999' : '',
|
||||
supplierSSCText: quantity <= inStock ? 'Filialentnahme' : '',
|
||||
price,
|
||||
price: price ?? stockInfo?.retailPrice,
|
||||
supplier: { id: supplier?.id },
|
||||
retailPrice: (stockInfo as any)?.retailPrice, // TODO: Change after API Update
|
||||
// TODO: Change after API Update
|
||||
// LH: 2021-03-09 preis Property hat nun ein Fallback auf retailPrice
|
||||
// retailPrice: (stockInfo as any)?.retailPrice,
|
||||
};
|
||||
return availability;
|
||||
}
|
||||
@@ -474,26 +501,29 @@ export class DomainAvailabilityService {
|
||||
return availability;
|
||||
}
|
||||
|
||||
private _mapToPickUpAvailability(availabilities: SwaggerAvailabilityDTO[]) {
|
||||
private _mapToPickUpAvailability(availabilities: SwaggerAvailabilityDTO[]): Availability<AvailabilityDTO, SwaggerAvailabilityDTO>[] {
|
||||
if (isArray(availabilities)) {
|
||||
const preferred = availabilities.filter((f) => f.preferred === 1);
|
||||
const totalAvailable = availabilities.reduce((sum, av) => sum + (av?.qty || 0), 0);
|
||||
|
||||
return preferred.map((p) => {
|
||||
return {
|
||||
availabilityType: p?.status,
|
||||
ssc: p?.ssc,
|
||||
sscText: p?.sscText,
|
||||
supplier: { id: p?.supplierId },
|
||||
isPrebooked: p?.isPrebooked,
|
||||
estimatedShippingDate: p?.requestStatusCode === '32' ? p?.altAt : p?.at,
|
||||
price: p?.price,
|
||||
inStock: totalAvailable,
|
||||
supplierProductNumber: p?.supplierProductNumber,
|
||||
supplierInfo: p?.requestStatusCode,
|
||||
lastRequest: p?.requested,
|
||||
itemId: p.itemId,
|
||||
};
|
||||
return [
|
||||
{
|
||||
availabilityType: p?.status,
|
||||
ssc: p?.ssc,
|
||||
sscText: p?.sscText,
|
||||
supplier: { id: p?.supplierId },
|
||||
isPrebooked: p?.isPrebooked,
|
||||
estimatedShippingDate: p?.requestStatusCode === '32' ? p?.altAt : p?.at,
|
||||
price: p?.price,
|
||||
inStock: totalAvailable,
|
||||
supplierProductNumber: p?.supplierProductNumber,
|
||||
supplierInfo: p?.requestStatusCode,
|
||||
lastRequest: p?.requested,
|
||||
itemId: p.itemId,
|
||||
},
|
||||
p,
|
||||
];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
1
apps/domain/availability/src/lib/defs/availability.ts
Normal file
1
apps/domain/availability/src/lib/defs/availability.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type Availability<T, S> = [T, S];
|
||||
@@ -1,3 +1,3 @@
|
||||
// start:ng42.barrel
|
||||
export * from './item-data.model';
|
||||
// end:ng42.barrel
|
||||
export * from './availability-by-branch-dto';
|
||||
export * from './availability';
|
||||
export * from './item-data';
|
||||
|
||||
@@ -5,20 +5,7 @@ import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
|
||||
teardown: { destroyAfterEach: false },
|
||||
});
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,20 +5,7 @@ import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
|
||||
teardown: { destroyAfterEach: false },
|
||||
});
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ export class ThumbnailUrlPipe implements PipeTransform, OnDestroy {
|
||||
this.input$.complete();
|
||||
}
|
||||
|
||||
transform(ean: string, width: number, height: number): any {
|
||||
transform(ean: string, width?: number, height?: number): any {
|
||||
this.input$.next({ ean, width, height });
|
||||
|
||||
this.input$
|
||||
|
||||
@@ -5,20 +5,7 @@ import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
|
||||
teardown: { destroyAfterEach: false },
|
||||
});
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,13 @@ import {
|
||||
UpdateShoppingCartItemDTO,
|
||||
InputDTO,
|
||||
ItemPayload,
|
||||
StoreCheckoutShoppingCartService,
|
||||
StoreCheckoutPaymentService,
|
||||
StoreCheckoutBuyerService,
|
||||
StoreCheckoutPayerService,
|
||||
StoreCheckoutBranchService,
|
||||
} from '@swagger/checkout';
|
||||
import { DisplayOrderDTO, OrderCheckoutService, ReorderValues } from '@swagger/oms';
|
||||
import { DisplayOrderDTO, DisplayOrderItemDTO, OrderCheckoutService, ReorderValues } 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';
|
||||
@@ -32,6 +37,7 @@ import * as DomainCheckoutActions from './store/domain-checkout.actions';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { CustomerDTO, EntityDTOContainerOfAttributeDTO } from '@swagger/crm';
|
||||
|
||||
@Injectable()
|
||||
export class DomainCheckoutService {
|
||||
@@ -40,7 +46,12 @@ export class DomainCheckoutService {
|
||||
private applicationService: ApplicationService,
|
||||
private storeCheckoutService: StoreCheckoutService,
|
||||
private orderCheckoutService: OrderCheckoutService,
|
||||
private availabilityService: DomainAvailabilityService
|
||||
private availabilityService: DomainAvailabilityService,
|
||||
private _shoppingCartService: StoreCheckoutShoppingCartService,
|
||||
private _paymentService: StoreCheckoutPaymentService,
|
||||
private _buyerService: StoreCheckoutBuyerService,
|
||||
private _payerService: StoreCheckoutPayerService,
|
||||
private _branchService: StoreCheckoutBranchService
|
||||
) {}
|
||||
|
||||
//#region shoppingcart
|
||||
@@ -53,8 +64,8 @@ export class DomainCheckoutService {
|
||||
return false;
|
||||
} else if (cart && _latest) {
|
||||
_latest = false;
|
||||
this.storeCheckoutService
|
||||
.StoreCheckoutGetShoppingCart({
|
||||
this._shoppingCartService
|
||||
.StoreCheckoutShoppingCartGetShoppingCart({
|
||||
shoppingCartId: cart.id,
|
||||
})
|
||||
.pipe(
|
||||
@@ -77,7 +88,7 @@ export class DomainCheckoutService {
|
||||
}
|
||||
|
||||
createShoppingCart({ processId }: { processId: number }): Observable<ShoppingCartDTO> {
|
||||
return this.storeCheckoutService.StoreCheckoutCreateShoppingCart().pipe(
|
||||
return this._shoppingCartService.StoreCheckoutShoppingCartCreateShoppingCart().pipe(
|
||||
map((response) => response.result),
|
||||
tap((shoppingCart) =>
|
||||
this.store.dispatch(
|
||||
@@ -94,8 +105,8 @@ export class DomainCheckoutService {
|
||||
return this.getShoppingCart({ processId }).pipe(
|
||||
first(),
|
||||
mergeMap((cart) =>
|
||||
this.storeCheckoutService
|
||||
.StoreCheckoutAddItemToShoppingCart({
|
||||
this._shoppingCartService
|
||||
.StoreCheckoutShoppingCartAddItemToShoppingCart({
|
||||
items,
|
||||
shoppingCartId: cart.id,
|
||||
})
|
||||
@@ -125,8 +136,8 @@ export class DomainCheckoutService {
|
||||
return this.getShoppingCart({ processId }).pipe(
|
||||
first(),
|
||||
mergeMap((shoppingCart) =>
|
||||
this.storeCheckoutService
|
||||
.StoreCheckoutSetLogisticianOnDestinationsByBuyer({
|
||||
this._shoppingCartService
|
||||
.StoreCheckoutShoppingCartSetLogisticianOnDestinationsByBuyer({
|
||||
shoppingCartId: shoppingCart?.id,
|
||||
payload: { customerFeatures },
|
||||
})
|
||||
@@ -139,7 +150,7 @@ export class DomainCheckoutService {
|
||||
return this.getShoppingCart({ processId }).pipe(
|
||||
first(),
|
||||
mergeMap((cart) =>
|
||||
this.storeCheckoutService.StoreCheckoutCanAddDestination({
|
||||
this._shoppingCartService.StoreCheckoutShoppingCartCanAddDestination({
|
||||
shoppingCartId: cart.id,
|
||||
payload: destinationDTO,
|
||||
})
|
||||
@@ -166,8 +177,8 @@ export class DomainCheckoutService {
|
||||
first(),
|
||||
withLatestFrom(this.store.select(DomainCheckoutSelectors.selectCustomerFeaturesByProcessId, { processId })),
|
||||
mergeMap(([shoppingCart, customerFeatures]) =>
|
||||
this.storeCheckoutService
|
||||
.StoreCheckoutCanAddItem({
|
||||
this._shoppingCartService
|
||||
.StoreCheckoutShoppingCartCanAddItem({
|
||||
shoppingCartId: shoppingCart?.id,
|
||||
payload: {
|
||||
customerFeatures,
|
||||
@@ -199,8 +210,8 @@ export class DomainCheckoutService {
|
||||
orderType,
|
||||
};
|
||||
});
|
||||
return this.storeCheckoutService
|
||||
.StoreCheckoutCanAddItems({
|
||||
return this._shoppingCartService
|
||||
.StoreCheckoutShoppingCartCanAddItems({
|
||||
shoppingCartId: shoppingCart.id,
|
||||
payload,
|
||||
})
|
||||
@@ -222,7 +233,7 @@ export class DomainCheckoutService {
|
||||
shoppingCartItemId: number;
|
||||
availability: AvailabilityDTO;
|
||||
}) {
|
||||
return this.storeCheckoutService.StoreCheckoutUpdateShoppingCartItemAvailability({
|
||||
return this._shoppingCartService.StoreCheckoutShoppingCartUpdateShoppingCartItemAvailability({
|
||||
shoppingCartId,
|
||||
shoppingCartItemId,
|
||||
availability,
|
||||
@@ -241,8 +252,8 @@ export class DomainCheckoutService {
|
||||
return this.getShoppingCart({ processId }).pipe(
|
||||
first(),
|
||||
mergeMap((shoppingCart) =>
|
||||
this.storeCheckoutService
|
||||
.StoreCheckoutUpdateShoppingCartItem({
|
||||
this._shoppingCartService
|
||||
.StoreCheckoutShoppingCartUpdateShoppingCartItem({
|
||||
shoppingCartId: shoppingCart.id,
|
||||
shoppingCartItemId,
|
||||
values: update,
|
||||
@@ -318,8 +329,8 @@ export class DomainCheckoutService {
|
||||
return this.getCheckout({ processId }).pipe(
|
||||
first(),
|
||||
mergeMap((checkout) =>
|
||||
this.storeCheckoutService
|
||||
.StoreCheckoutGetCheckoutPayment({
|
||||
this._paymentService
|
||||
.StoreCheckoutPaymentGetCheckoutPayment({
|
||||
checkoutId: checkout.id,
|
||||
})
|
||||
.pipe(map((response) => response.result))
|
||||
@@ -335,8 +346,8 @@ export class DomainCheckoutService {
|
||||
return this.getCheckout({ processId }).pipe(
|
||||
first(),
|
||||
mergeMap((checkout) =>
|
||||
this.storeCheckoutService
|
||||
.StoreCheckoutSetPaymentType({
|
||||
this._paymentService
|
||||
.StoreCheckoutPaymentSetPaymentType({
|
||||
checkoutId: checkout?.id,
|
||||
paymentType,
|
||||
})
|
||||
@@ -352,8 +363,8 @@ export class DomainCheckoutService {
|
||||
return this.getCheckout({ processId }).pipe(
|
||||
first(),
|
||||
mergeMap((checkout) =>
|
||||
this.storeCheckoutService
|
||||
.StoreCheckoutSetBuyer({
|
||||
this._buyerService
|
||||
.StoreCheckoutBuyerSetBuyerPOST({
|
||||
checkoutId: checkout?.id,
|
||||
buyerDTO: buyer,
|
||||
})
|
||||
@@ -369,8 +380,8 @@ export class DomainCheckoutService {
|
||||
return this.getCheckout({ processId }).pipe(
|
||||
first(),
|
||||
mergeMap((checkout) =>
|
||||
this.storeCheckoutService
|
||||
.StoreCheckoutSetPayer({
|
||||
this._payerService
|
||||
.StoreCheckoutPayerSetPayerPOST({
|
||||
checkoutId: checkout?.id,
|
||||
payerDTO: payer,
|
||||
})
|
||||
@@ -389,7 +400,7 @@ export class DomainCheckoutService {
|
||||
mergeMap((cart) =>
|
||||
concat(
|
||||
...cart.items.map((item) =>
|
||||
this.storeCheckoutService.StoreCheckoutUpdateShoppingCartItem({
|
||||
this._shoppingCartService.StoreCheckoutShoppingCartUpdateShoppingCartItem({
|
||||
shoppingCartId: cart.id,
|
||||
shoppingCartItemId: item.id,
|
||||
values: { specialComment },
|
||||
@@ -650,7 +661,7 @@ export class DomainCheckoutService {
|
||||
first(),
|
||||
mergeMap((checkout) =>
|
||||
this.orderCheckoutService
|
||||
.OrderCheckoutCreateOrder({
|
||||
.OrderCheckoutCreateOrderPOST({
|
||||
checkoutId: checkout.id,
|
||||
})
|
||||
.pipe(
|
||||
@@ -734,8 +745,8 @@ export class DomainCheckoutService {
|
||||
return this.getShoppingCart({ processId }).pipe(
|
||||
first(),
|
||||
mergeMap((shoppingCart) =>
|
||||
this.storeCheckoutService
|
||||
.StoreCheckoutCanAddBuyer({
|
||||
this._shoppingCartService
|
||||
.StoreCheckoutShoppingCartCanAddBuyer({
|
||||
shoppingCartId: shoppingCart.id,
|
||||
payload: { customerFeatures },
|
||||
})
|
||||
@@ -771,35 +782,39 @@ export class DomainCheckoutService {
|
||||
return this.canSetCustomer({ processId, customerFeatures: undefined }).pipe(
|
||||
map((res) => {
|
||||
let setableTypes: { [key: string]: boolean } = {
|
||||
store: true,
|
||||
guest: true,
|
||||
webshop: true,
|
||||
b2b: true,
|
||||
store: false,
|
||||
guest: false,
|
||||
webshop: false,
|
||||
b2b: false,
|
||||
};
|
||||
|
||||
if (Object.keys(res.filter).length === 0) {
|
||||
return setableTypes;
|
||||
}
|
||||
res.create?.options?.values?.forEach((option) => {
|
||||
setableTypes[option.value] = option.enabled !== false;
|
||||
});
|
||||
|
||||
const customerTypes = res.filter?.customertype?.split(';') || [];
|
||||
const customerAttributes = res.filter?.customerattributes?.split(';') || [];
|
||||
// if (Object.keys(res.filter).length === 0) {
|
||||
// return setableTypes;
|
||||
// }
|
||||
|
||||
const typesAndAttributes = [...customerTypes, ...customerAttributes];
|
||||
if (typesAndAttributes.includes('webshop') && !typesAndAttributes.includes('!guest')) {
|
||||
typesAndAttributes.push('guest');
|
||||
}
|
||||
// const customerTypes = res.filter?.customertype?.split(';') || [];
|
||||
// const customerAttributes = res.filter?.customerattributes?.split(';') || [];
|
||||
|
||||
for (const key in setableTypes) {
|
||||
if (Object.prototype.hasOwnProperty.call(setableTypes, key)) {
|
||||
if (typesAndAttributes.includes(key)) {
|
||||
setableTypes[key] = true;
|
||||
} else if (typesAndAttributes.includes(`!${key}`)) {
|
||||
setableTypes[key] = false;
|
||||
} else {
|
||||
setableTypes[key] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// const typesAndAttributes = [...customerTypes, ...customerAttributes];
|
||||
// if (typesAndAttributes.includes('webshop') && !typesAndAttributes.includes('!guest')) {
|
||||
// typesAndAttributes.push('guest');
|
||||
// }
|
||||
|
||||
// for (const key in setableTypes) {
|
||||
// if (Object.prototype.hasOwnProperty.call(setableTypes, key)) {
|
||||
// if (typesAndAttributes.includes(key)) {
|
||||
// setableTypes[key] = true;
|
||||
// } else if (typesAndAttributes.includes(`!${key}`)) {
|
||||
// setableTypes[key] = false;
|
||||
// } else {
|
||||
// setableTypes[key] = false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
return setableTypes;
|
||||
})
|
||||
@@ -808,8 +823,8 @@ export class DomainCheckoutService {
|
||||
|
||||
@memorize()
|
||||
getBranches(): Observable<BranchDTO[]> {
|
||||
return this.storeCheckoutService
|
||||
.StoreCheckoutGetBranches({
|
||||
return this._branchService
|
||||
.StoreCheckoutBranchGetBranches({
|
||||
take: 999,
|
||||
})
|
||||
.pipe(
|
||||
@@ -828,10 +843,6 @@ export class DomainCheckoutService {
|
||||
.pipe(map((response) => response.result));
|
||||
}
|
||||
|
||||
setCustomerFeatures({ processId, customerFeatures }: { processId: number; customerFeatures: { [key: string]: string } }) {
|
||||
this.store.dispatch(DomainCheckoutActions.setCustomerFeatures({ processId, customerFeatures }));
|
||||
}
|
||||
|
||||
setOlaErrors({ processId, errorIds }: { processId: number; errorIds: number[] }) {
|
||||
this.store.dispatch(
|
||||
DomainCheckoutActions.setOlaError({
|
||||
@@ -857,6 +868,14 @@ export class DomainCheckoutService {
|
||||
this.store.dispatch(DomainCheckoutActions.removeProcess({ processId }));
|
||||
}
|
||||
|
||||
setCustomer({ processId, customerDto }: { processId: number; customerDto: CustomerDTO }) {
|
||||
this.store.dispatch(DomainCheckoutActions.setCustomer({ processId, customer: customerDto }));
|
||||
}
|
||||
|
||||
getCustomer({ processId }: { processId: number }): Observable<CustomerDTO> {
|
||||
return this.store.select(DomainCheckoutSelectors.selectCustomerByProcessId, { processId });
|
||||
}
|
||||
|
||||
setPayer({ processId, payer }: { processId: number; payer: PayerDTO }) {
|
||||
this.store.dispatch(DomainCheckoutActions.setPayer({ processId, payer }));
|
||||
}
|
||||
@@ -877,6 +896,14 @@ export class DomainCheckoutService {
|
||||
return this.store.select(DomainCheckoutSelectors.selectOrders);
|
||||
}
|
||||
|
||||
updateOrderItem(item: DisplayOrderItemDTO) {
|
||||
this.store.dispatch(DomainCheckoutActions.updateOrderItem({ item }));
|
||||
}
|
||||
|
||||
removeAllOrders() {
|
||||
this.store.dispatch(DomainCheckoutActions.removeAllOrders());
|
||||
}
|
||||
|
||||
setSpecialComment({ processId, agentComment }: { processId: number; agentComment: string }) {
|
||||
this.store.dispatch(DomainCheckoutActions.setSpecialComment({ processId, agentComment }));
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { BuyerDTO, CheckoutDTO, NotificationChannel, PayerDTO, ShippingAddressDTO, ShoppingCartDTO } from '@swagger/checkout';
|
||||
import { CustomerDTO } from '@swagger/crm';
|
||||
import { DisplayOrderDTO } from '@swagger/oms';
|
||||
|
||||
export interface CheckoutEntity {
|
||||
processId: number;
|
||||
checkout: CheckoutDTO;
|
||||
shoppingCart: ShoppingCartDTO;
|
||||
customerFeatures: { [key: string]: string };
|
||||
customer: CustomerDTO;
|
||||
payer: PayerDTO;
|
||||
buyer: BuyerDTO;
|
||||
shippingAddress: ShippingAddressDTO;
|
||||
|
||||
@@ -8,7 +8,8 @@ import {
|
||||
BuyerDTO,
|
||||
PayerDTO,
|
||||
} from '@swagger/checkout';
|
||||
import { DisplayOrderDTO } from '@swagger/oms';
|
||||
import { CustomerDTO } from '@swagger/crm';
|
||||
import { DisplayOrderDTO, DisplayOrderItemDTO } from '@swagger/oms';
|
||||
|
||||
const prefix = '[DOMAIN-CHECKOUT]';
|
||||
|
||||
@@ -38,11 +39,6 @@ export const setCheckoutDestination = createAction(
|
||||
props<{ processId: number; destination: DestinationDTO }>()
|
||||
);
|
||||
|
||||
export const setCustomerFeatures = createAction(
|
||||
`${prefix} Set Customer Features`,
|
||||
props<{ processId: number; customerFeatures: { [key: string]: string } }>()
|
||||
);
|
||||
|
||||
export const setShippingAddress = createAction(
|
||||
`${prefix} Set Shipping Address`,
|
||||
props<{ processId: number; shippingAddress: ShippingAddressDTO }>()
|
||||
@@ -52,6 +48,10 @@ export const removeProcess = createAction(`${prefix} Remove Process`, props<{ pr
|
||||
|
||||
export const setOrders = createAction(`${prefix} Add Orders`, props<{ orders: DisplayOrderDTO[] }>());
|
||||
|
||||
export const updateOrderItem = createAction(`${prefix} Update Orders`, props<{ item: DisplayOrderItemDTO }>());
|
||||
|
||||
export const removeAllOrders = createAction(`${prefix} Remove All Orders`);
|
||||
|
||||
export const setBuyer = createAction(`${prefix} Set Buyer`, props<{ processId: number; buyer: BuyerDTO }>());
|
||||
|
||||
export const setPayer = createAction(`${prefix} Set Payer`, props<{ processId: number; payer: PayerDTO }>());
|
||||
@@ -59,3 +59,5 @@ export const setPayer = createAction(`${prefix} Set Payer`, props<{ processId: n
|
||||
export const setSpecialComment = createAction(`${prefix} Set Agent Comment`, props<{ processId: number; agentComment: string }>());
|
||||
|
||||
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 }>());
|
||||
|
||||
@@ -46,11 +46,6 @@ const _domainCheckoutReducer = createReducer(
|
||||
};
|
||||
return storeCheckoutAdapter.setOne(entity, s);
|
||||
}),
|
||||
on(DomainCheckoutActions.setCustomerFeatures, (s, { processId, customerFeatures }) => {
|
||||
const entity = getOrCreateCheckoutEntity({ processId, entities: s.entities });
|
||||
entity.customerFeatures = customerFeatures;
|
||||
return storeCheckoutAdapter.setOne(entity, s);
|
||||
}),
|
||||
on(DomainCheckoutActions.setShippingAddress, (s, { processId, shippingAddress }) => {
|
||||
const entity = getOrCreateCheckoutEntity({ processId, entities: s.entities });
|
||||
entity.shippingAddress = shippingAddress;
|
||||
@@ -72,11 +67,39 @@ const _domainCheckoutReducer = createReducer(
|
||||
return storeCheckoutAdapter.setOne(entity, s);
|
||||
}),
|
||||
on(DomainCheckoutActions.removeProcess, (s, { processId }) => storeCheckoutAdapter.removeOne(processId, s)),
|
||||
on(DomainCheckoutActions.setOrders, (s, { orders }) => ({ ...s, orders })),
|
||||
on(DomainCheckoutActions.setOrders, (s, { orders }) => ({ ...s, orders: [...s.orders, ...orders] })),
|
||||
on(DomainCheckoutActions.updateOrderItem, (s, { item }) => {
|
||||
const orders = [...s.orders];
|
||||
|
||||
const orderToUpdate = orders?.find((order) => order.items?.find((i) => i.id === item?.id));
|
||||
const orderToUpdateIndex = orders?.indexOf(orderToUpdate);
|
||||
|
||||
const orderItemToUpdate = orderToUpdate?.items?.find((i) => i.id === item?.id);
|
||||
const orderItemToUpdateIndex = orderToUpdate?.items?.indexOf(orderItemToUpdate);
|
||||
|
||||
const items = [...orderToUpdate?.items];
|
||||
items[orderItemToUpdateIndex] = item;
|
||||
|
||||
orders[orderToUpdateIndex] = {
|
||||
...orderToUpdate,
|
||||
items: [...items],
|
||||
};
|
||||
|
||||
return { ...s, orders: [...orders] };
|
||||
}),
|
||||
on(DomainCheckoutActions.removeAllOrders, (s) => ({
|
||||
...s,
|
||||
orders: [],
|
||||
})),
|
||||
on(DomainCheckoutActions.setOlaError, (s, { processId, olaErrorIds }) => {
|
||||
const entity = getOrCreateCheckoutEntity({ processId, entities: s.entities });
|
||||
entity.olaErrorIds = olaErrorIds;
|
||||
return storeCheckoutAdapter.setOne(entity, s);
|
||||
}),
|
||||
on(DomainCheckoutActions.setCustomer, (s, { processId, customer }) => {
|
||||
const entity = getOrCreateCheckoutEntity({ processId, entities: s.entities });
|
||||
entity.customer = customer;
|
||||
return storeCheckoutAdapter.setOne(entity, s);
|
||||
})
|
||||
);
|
||||
|
||||
@@ -92,7 +115,6 @@ function getOrCreateCheckoutEntity({ entities, processId }: { entities: Dictiona
|
||||
processId,
|
||||
checkout: undefined,
|
||||
shoppingCart: undefined,
|
||||
customerFeatures: undefined,
|
||||
shippingAddress: undefined,
|
||||
orders: [],
|
||||
payer: undefined,
|
||||
@@ -100,6 +122,7 @@ function getOrCreateCheckoutEntity({ entities, processId }: { entities: Dictiona
|
||||
specialComment: '',
|
||||
notificationChannels: 0,
|
||||
olaErrorIds: [],
|
||||
customer: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Dictionary } from '@ngrx/entity';
|
||||
import { createSelector } from '@ngrx/store';
|
||||
import { CustomerDTO } from '@swagger/crm';
|
||||
import { CheckoutEntity } from './defs/checkout.entity';
|
||||
import { storeCheckoutAdapter, storeFeatureSelector } from './domain-checkout.state';
|
||||
|
||||
@@ -22,7 +23,7 @@ export const selectCheckoutByProcessId = createSelector(
|
||||
|
||||
export const selectCustomerFeaturesByProcessId = createSelector(
|
||||
selectEntities,
|
||||
(entities: Dictionary<CheckoutEntity>, { processId }: { processId: number }) => entities[processId]?.customerFeatures
|
||||
(entities: Dictionary<CheckoutEntity>, { processId }: { processId: number }) => getCusomterFeatures(entities[processId]?.customer)
|
||||
);
|
||||
|
||||
export const selectShippingAddressByProcessId = createSelector(
|
||||
@@ -61,3 +62,19 @@ export const selectOlaErrorsByProcessId = createSelector(
|
||||
selectEntities,
|
||||
(entities: Dictionary<CheckoutEntity>, { processId }: { processId: number }) => entities[processId]?.olaErrorIds
|
||||
);
|
||||
|
||||
export const selectCustomerByProcessId = createSelector(
|
||||
selectEntities,
|
||||
(entities: Dictionary<CheckoutEntity>, { processId }: { processId: number }) => entities[processId]?.customer
|
||||
);
|
||||
|
||||
function getCusomterFeatures(custoemr: CustomerDTO): { [key: string]: string } {
|
||||
const customerFeatures = custoemr?.features ?? [];
|
||||
const features: { [key: string]: string } = {};
|
||||
|
||||
for (const feature of customerFeatures) {
|
||||
features[feature.key] = feature.key;
|
||||
}
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
@@ -5,11 +5,7 @@ import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: any;
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
|
||||
teardown: { destroyAfterEach: false },
|
||||
});
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"declarationMap": true,
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"inlineSources": true,
|
||||
"types": [],
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,26 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
AddressDTO,
|
||||
AddressService,
|
||||
AssignedPayerDTO,
|
||||
AutocompleteDTO,
|
||||
CommunicationDetailsDTO,
|
||||
CountryDTO,
|
||||
CountryService,
|
||||
CustomerDTO,
|
||||
CustomerInfoDTO,
|
||||
CustomerService,
|
||||
HistoryDTO,
|
||||
InputDTO,
|
||||
KeyValueDTOOfStringAndString,
|
||||
ListResponseArgsOfCustomerInfoDTO,
|
||||
LoyaltyCardService,
|
||||
NotificationChannel,
|
||||
PayerDTO,
|
||||
PayerService,
|
||||
ResponseArgsOfHistoryDTO,
|
||||
ResponseArgsOfIEnumerableOfBonusCardInfoDTO,
|
||||
ShippingAddressDTO,
|
||||
ShippingAddressService,
|
||||
} from '@swagger/crm';
|
||||
import { isArray } from '@utils/common';
|
||||
import { PagedResult, Result } from 'apps/domain/defs/src/public-api';
|
||||
@@ -24,7 +29,14 @@ import { catchError, map, mergeMap, retry } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CrmCustomerService {
|
||||
constructor(private customerService: CustomerService, private payerService: PayerService) {}
|
||||
constructor(
|
||||
private customerService: CustomerService,
|
||||
private payerService: PayerService,
|
||||
private addressService: AddressService,
|
||||
private countryService: CountryService,
|
||||
private shippingAddressService: ShippingAddressService,
|
||||
private loyaltyCardService: LoyaltyCardService
|
||||
) {}
|
||||
|
||||
complete(queryString: string, filter?: { [key: string]: string }): Observable<Result<AutocompleteDTO[]>> {
|
||||
return this.customerService.CustomerCustomerAutocomplete({
|
||||
@@ -66,10 +78,6 @@ export class CrmCustomerService {
|
||||
return this.customerService.CustomerGetAssignedPayersByCustomerId(params);
|
||||
}
|
||||
|
||||
getFilters(): Observable<Result<InputDTO[]>> {
|
||||
return this.customerService.CustomerQueryCustomerFilter();
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
getNotificationChannelForCommunicationDetails({
|
||||
communicationDetails,
|
||||
@@ -96,12 +104,23 @@ export class CrmCustomerService {
|
||||
return this.customerService.CustomerPatchCustomer({ customerId, customer: { ...customer, notificationChannels } });
|
||||
}
|
||||
|
||||
createB2BCustomer(customer: CustomerDTO) {
|
||||
createB2BCustomer(customer: CustomerDTO): Promise<Result<CustomerDTO>> {
|
||||
const notificationChannels = this.getNotificationChannelForCommunicationDetails({
|
||||
communicationDetails: customer?.communicationDetails,
|
||||
});
|
||||
|
||||
return this.customerService.CustomerCreateCustomer({ ...customer, customerType: 16, notificationChannels });
|
||||
const payload: CustomerDTO = { ...customer, customerType: 16, notificationChannels };
|
||||
|
||||
payload.shippingAddresses = payload.shippingAddresses ?? [];
|
||||
|
||||
payload.payers = payload.payers ?? [];
|
||||
|
||||
return this.customerService
|
||||
.CustomerCreateCustomer({
|
||||
customer: payload,
|
||||
modifiers: [{ key: 'b2b', group: 'customertype' }],
|
||||
})
|
||||
.toPromise();
|
||||
}
|
||||
|
||||
createOnlineCustomer(customer: CustomerDTO): Observable<Result<CustomerDTO>> {
|
||||
@@ -148,63 +167,253 @@ export class CrmCustomerService {
|
||||
];
|
||||
}
|
||||
|
||||
return this.customerService.CustomerCreateOnlineCustomer({ ...payload, notificationChannels });
|
||||
const p4mUser = customer.features.find((f) => f.key === 'p4mUser')?.value;
|
||||
|
||||
const modifiers: KeyValueDTOOfStringAndString[] = [{ key: 'webshop', group: 'customertype' }];
|
||||
|
||||
if (p4mUser) {
|
||||
modifiers.push({ key: 'add-loyalty-card', value: p4mUser });
|
||||
}
|
||||
|
||||
return this.customerService.CustomerCreateCustomer({
|
||||
customer: { ...payload, notificationChannels },
|
||||
modifiers,
|
||||
});
|
||||
}
|
||||
|
||||
createGuestCustomer(customer: CustomerDTO): Observable<Result<CustomerDTO>> {
|
||||
mapCustomerToPayer(customer: CustomerDTO): PayerDTO {
|
||||
return {
|
||||
address: customer.address,
|
||||
communicationDetails: customer.communicationDetails,
|
||||
firstName: customer.firstName,
|
||||
lastName: customer.lastName,
|
||||
organisation: customer.organisation,
|
||||
title: customer.title,
|
||||
payerType: 1,
|
||||
gender: customer.gender,
|
||||
};
|
||||
}
|
||||
|
||||
mapCustomerToShippingAddress(customer: CustomerDTO): ShippingAddressDTO {
|
||||
return {
|
||||
address: customer.address,
|
||||
communicationDetails: customer.communicationDetails,
|
||||
firstName: customer.firstName,
|
||||
gender: customer.gender,
|
||||
lastName: customer.lastName,
|
||||
organisation: customer.organisation,
|
||||
title: customer.title,
|
||||
type: 1,
|
||||
};
|
||||
}
|
||||
|
||||
async updateToOnlineCustomer(customer: CustomerDTO): Promise<Result<CustomerDTO>> {
|
||||
const payload: CustomerDTO = { shippingAddresses: [], payers: [], ...customer, customerType: 8, hasOnlineAccount: true };
|
||||
|
||||
const notificationChannels = this.getNotificationChannelForCommunicationDetails({
|
||||
communicationDetails: payload?.communicationDetails,
|
||||
});
|
||||
|
||||
const shippingAddressesToAdd = payload.shippingAddresses?.filter((sa) => !sa.id)?.map((m) => m.data) ?? [];
|
||||
payload.shippingAddresses = payload.shippingAddresses?.filter((sa) => !!sa.id) ?? [];
|
||||
|
||||
if (payload.shippingAddresses.length === 0) {
|
||||
shippingAddressesToAdd.unshift(this.mapCustomerToShippingAddress(payload));
|
||||
}
|
||||
|
||||
const payersToAdd = payload.payers?.filter((p) => !p.assignedToCustomer)?.map((p) => p.payer?.data) ?? [];
|
||||
payload.payers = payload.payers?.filter((p) => !!p.assignedToCustomer) ?? [];
|
||||
|
||||
if (payload.payers.length === 0) {
|
||||
payersToAdd.unshift({
|
||||
...this.mapCustomerToPayer(payload),
|
||||
payerType: payload.customerType,
|
||||
});
|
||||
}
|
||||
|
||||
const modifiers: KeyValueDTOOfStringAndString[] = [{ key: 'webshop', group: 'customertype' }];
|
||||
|
||||
const res = await this.customerService
|
||||
.CustomerUpdateCustomer({
|
||||
customerId: customer.id,
|
||||
payload: {
|
||||
modifiers,
|
||||
customer: { ...payload, notificationChannels },
|
||||
},
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
for (let shippingAddress of shippingAddressesToAdd) {
|
||||
await this.createShippingAddress(res.result.id, shippingAddress, true);
|
||||
}
|
||||
|
||||
for (let payer of payersToAdd) {
|
||||
await this.createPayer(res.result.id, payer, true);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
async updateToP4MOnlineCustomer(customer: CustomerDTO): Promise<Result<CustomerDTO>> {
|
||||
const shippingAddressesToAdd = customer.shippingAddresses?.filter((sa) => !sa.id)?.map((m) => m.data) ?? [];
|
||||
customer.shippingAddresses = customer.shippingAddresses?.filter((sa) => !!sa.id) ?? [];
|
||||
|
||||
if (customer.shippingAddresses.length === 0) {
|
||||
shippingAddressesToAdd.unshift(this.mapCustomerToShippingAddress(customer));
|
||||
}
|
||||
|
||||
const payersToAdd = customer.payers?.filter((p) => !p.assignedToCustomer)?.map((p) => p.payer?.data) ?? [];
|
||||
customer.payers = customer.payers?.filter((p) => !!p.assignedToCustomer) ?? [];
|
||||
|
||||
if (customer.payers.length === 0) {
|
||||
payersToAdd.unshift({
|
||||
...this.mapCustomerToPayer(customer),
|
||||
payerType: customer.customerType,
|
||||
});
|
||||
}
|
||||
|
||||
const p4mUser = customer.features.find((f) => f.key === 'p4mUser')?.value;
|
||||
|
||||
const modifiers: KeyValueDTOOfStringAndString[] = [{ key: 'webshop', group: 'customertype' }];
|
||||
|
||||
if (p4mUser) {
|
||||
modifiers.push({ key: 'add-loyalty-card', value: p4mUser });
|
||||
}
|
||||
|
||||
const res = await this.customerService
|
||||
.CustomerUpdateCustomer({
|
||||
customerId: customer.id,
|
||||
payload: {
|
||||
customer,
|
||||
modifiers,
|
||||
},
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
for (let shippingAddress of shippingAddressesToAdd) {
|
||||
await this.createShippingAddress(res.result.id, shippingAddress, true);
|
||||
}
|
||||
|
||||
for (let payer of payersToAdd) {
|
||||
await this.createPayer(res.result.id, payer, true);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
async updateStoreP4MToWebshopP4M(customer: CustomerDTO): Promise<Result<CustomerDTO>> {
|
||||
const shippingAddressesToAdd = customer.shippingAddresses?.filter((sa) => !sa.id)?.map((m) => m.data) ?? [];
|
||||
customer.shippingAddresses = customer.shippingAddresses?.filter((sa) => !!sa.id) ?? [];
|
||||
|
||||
if (customer.shippingAddresses.length === 0) {
|
||||
shippingAddressesToAdd.unshift(this.mapCustomerToShippingAddress(customer));
|
||||
}
|
||||
|
||||
const payersToAdd = customer.payers?.filter((p) => !p.assignedToCustomer)?.map((p) => p.payer?.data) ?? [];
|
||||
customer.payers = customer.payers?.filter((p) => !!p.assignedToCustomer) ?? [];
|
||||
|
||||
if (customer.payers.length === 0) {
|
||||
payersToAdd.unshift({
|
||||
...this.mapCustomerToPayer(customer),
|
||||
payerType: customer.customerType,
|
||||
});
|
||||
}
|
||||
|
||||
const modifiers: KeyValueDTOOfStringAndString[] = [{ key: 'webshop', group: 'customertype' }];
|
||||
|
||||
const res = await this.customerService
|
||||
.CustomerUpdateCustomer({
|
||||
customerId: customer.id,
|
||||
payload: {
|
||||
customer,
|
||||
modifiers,
|
||||
},
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
for (let shippingAddress of shippingAddressesToAdd) {
|
||||
await this.createShippingAddress(res.result.id, shippingAddress, true);
|
||||
}
|
||||
|
||||
for (let payer of payersToAdd) {
|
||||
await this.createPayer(res.result.id, payer, true);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
async createGuestCustomer(customer: CustomerDTO): Promise<Result<CustomerDTO>> {
|
||||
const notificationChannels = this.getNotificationChannelForCommunicationDetails({
|
||||
communicationDetails: customer?.communicationDetails,
|
||||
});
|
||||
const payload: CustomerDTO = { ...customer, customerType: 8, isGuestAccount: true, notificationChannels };
|
||||
|
||||
if (!(isArray(payload.shippingAddresses) && payload.shippingAddresses.length > 0)) {
|
||||
payload.shippingAddresses = [
|
||||
{
|
||||
data: {
|
||||
address: payload.address,
|
||||
communicationDetails: payload.communicationDetails,
|
||||
firstName: payload.firstName,
|
||||
gender: payload.gender,
|
||||
lastName: payload.lastName,
|
||||
organisation: payload.organisation,
|
||||
title: payload.title,
|
||||
type: 1,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
payload.shippingAddresses = customer.shippingAddresses ?? [];
|
||||
|
||||
if (!(isArray(payload.payers) && payload.payers.length > 0)) {
|
||||
payload.payers = [
|
||||
{
|
||||
payer: {
|
||||
data: {
|
||||
address: payload.address,
|
||||
communicationDetails: payload.communicationDetails,
|
||||
firstName: payload.firstName,
|
||||
gender: payload.gender,
|
||||
lastName: payload.lastName,
|
||||
organisation: payload.organisation,
|
||||
title: payload.title,
|
||||
payerType: payload.customerType,
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
payload.shippingAddresses.push({
|
||||
data: this.mapCustomerToShippingAddress(customer),
|
||||
});
|
||||
|
||||
return this.customerService.CustomerCreateOnlineCustomer(payload);
|
||||
payload.payers = customer.payers ?? [];
|
||||
|
||||
payload.payers.push({
|
||||
payer: {
|
||||
data: {
|
||||
...this.mapCustomerToPayer(customer),
|
||||
payerType: payload.customerType,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const res = await this.customerService
|
||||
.CustomerCreateCustomer({
|
||||
customer: payload,
|
||||
modifiers: [{ key: 'webshop', group: 'customertype' }],
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
createBranchCustomer(customer: CustomerDTO): Observable<Result<CustomerDTO>> {
|
||||
createStoreCustomer(customer: CustomerDTO): Observable<Result<CustomerDTO>> {
|
||||
const notificationChannels = this.getNotificationChannelForCommunicationDetails({
|
||||
communicationDetails: customer?.communicationDetails,
|
||||
});
|
||||
return this.customerService.CustomerCreateCustomer({ ...customer, customerType: 8, notificationChannels });
|
||||
|
||||
const p4mUser = customer.features.find((f) => f.key === 'p4mUser')?.value;
|
||||
|
||||
const modifiers: KeyValueDTOOfStringAndString[] = [{ key: 'store', group: 'customertype' }];
|
||||
|
||||
if (p4mUser) {
|
||||
modifiers.push({ key: 'add-loyalty-card', value: p4mUser });
|
||||
}
|
||||
|
||||
return this.customerService.CustomerCreateCustomer({
|
||||
customer: { ...customer, customerType: 8, notificationChannels },
|
||||
modifiers,
|
||||
});
|
||||
}
|
||||
|
||||
validateAddress(address: AddressDTO): Observable<Result<AddressDTO[]>> {
|
||||
return this.customerService.CustomerValidateAddress(address);
|
||||
return this.addressService.AddressValidateAddress(address);
|
||||
}
|
||||
|
||||
getOnlineCustomerByEmail(email: string): Observable<CustomerInfoDTO | null> {
|
||||
return this.getCustomers(email, {
|
||||
take: 1,
|
||||
filter: {
|
||||
customertype: 'webshop',
|
||||
},
|
||||
}).pipe(
|
||||
map((r) => {
|
||||
if (r.hits === 1) {
|
||||
return r.result[0];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}),
|
||||
catchError((err) => [null])
|
||||
);
|
||||
}
|
||||
|
||||
private cachedCountriesFailed = false;
|
||||
@@ -213,8 +422,8 @@ export class CrmCustomerService {
|
||||
if (!this.cachedCountries || this.cachedCountriesFailed) {
|
||||
this.cachedCountriesFailed = false;
|
||||
this.cachedCountries = new ReplaySubject();
|
||||
this.customerService
|
||||
.CustomerGetCountries({})
|
||||
this.countryService
|
||||
.CountryGetCountries({})
|
||||
.pipe(
|
||||
retry(3),
|
||||
catchError((err) => {
|
||||
@@ -235,22 +444,28 @@ export class CrmCustomerService {
|
||||
return this.customerService.CustomerEmailExists(email);
|
||||
}
|
||||
|
||||
createPayer(customerId: number, payer: PayerDTO, isDefault?: boolean): Observable<[Result<PayerDTO>, Result<AssignedPayerDTO>]> {
|
||||
return this.getCustomer(customerId).pipe(
|
||||
mergeMap((customerResponse) =>
|
||||
this.payerService
|
||||
.PayerCreatePayer({ ...payer, payerType: customerResponse.result.customerType })
|
||||
.pipe(
|
||||
mergeMap((payerResponse) =>
|
||||
this.customerService
|
||||
.CustomerAddPayerReference({ customerId: customerId, payerId: payerResponse.result.id, isDefault: isDefault })
|
||||
.pipe(
|
||||
map((assigendPayerResponse) => [payerResponse, assigendPayerResponse] as [Result<PayerDTO>, Result<AssignedPayerDTO>])
|
||||
)
|
||||
checkLoyaltyCard({ loyaltyCardNumber, customerId }: { loyaltyCardNumber: string; customerId?: number }) {
|
||||
return this.loyaltyCardService.LoyaltyCardCheckLoyaltyCard({ loyaltyCardNumber, customerId });
|
||||
}
|
||||
|
||||
createPayer(customerId: number, payer: PayerDTO, isDefault?: boolean): Promise<[Result<PayerDTO>, Result<AssignedPayerDTO>]> {
|
||||
return this.getCustomer(customerId)
|
||||
.pipe(
|
||||
mergeMap((customerResponse) =>
|
||||
this.payerService
|
||||
.PayerCreatePayer({ ...payer, payerType: customerResponse.result.customerType })
|
||||
.pipe(
|
||||
mergeMap((payerResponse) =>
|
||||
this.customerService
|
||||
.CustomerAddPayerReference({ customerId: customerId, payerId: payerResponse.result.id, isDefault: isDefault })
|
||||
.pipe(
|
||||
map((assigendPayerResponse) => [payerResponse, assigendPayerResponse] as [Result<PayerDTO>, Result<AssignedPayerDTO>])
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
.toPromise();
|
||||
}
|
||||
|
||||
updatePayer(customerId: number, payerId: number, payer: PayerDTO, isDefault?: boolean): Observable<Result<PayerDTO>> {
|
||||
@@ -263,11 +478,7 @@ export class CrmCustomerService {
|
||||
return this.customerService.CustomerModifyPayerReference({ payerId, customerId, isDefault });
|
||||
}
|
||||
|
||||
createShippingAddress(
|
||||
customerId: number,
|
||||
shippingAddress: ShippingAddressDTO,
|
||||
isDefault?: boolean
|
||||
): Observable<Result<ShippingAddressDTO>> {
|
||||
createShippingAddress(customerId: number, shippingAddress: ShippingAddressDTO, isDefault?: boolean): Promise<Result<ShippingAddressDTO>> {
|
||||
const data: ShippingAddressDTO = { ...shippingAddress };
|
||||
if (isDefault) {
|
||||
data.isDefault = new Date().toJSON();
|
||||
@@ -275,7 +486,7 @@ export class CrmCustomerService {
|
||||
delete data.isDefault;
|
||||
}
|
||||
|
||||
return this.customerService.CustomerCreateShippingAddress({ customerId, shippingAddress: data });
|
||||
return this.shippingAddressService.ShippingAddressCreateShippingAddress({ customerId, shippingAddress: data }).toPromise();
|
||||
}
|
||||
|
||||
updateShippingAddress(
|
||||
@@ -283,7 +494,7 @@ export class CrmCustomerService {
|
||||
shippingAddressId: number,
|
||||
shippingAddress: ShippingAddressDTO,
|
||||
isDefault?: boolean
|
||||
): Observable<Result<ShippingAddressDTO>> {
|
||||
): Promise<Result<ShippingAddressDTO>> {
|
||||
const data: ShippingAddressDTO = { ...shippingAddress };
|
||||
|
||||
if (isDefault) {
|
||||
@@ -292,15 +503,17 @@ export class CrmCustomerService {
|
||||
delete data.isDefault;
|
||||
}
|
||||
|
||||
return this.customerService.CustomerUpdateShippingAddress({ shippingAddressId, shippingAddress: data, customerId });
|
||||
return this.shippingAddressService
|
||||
.ShippingAddressUpdateShippingAddress({ shippingAddressId, shippingAddress: data, customerId })
|
||||
.toPromise();
|
||||
}
|
||||
|
||||
getShippingAddress(shippingAddressId: number): Observable<Result<ShippingAddressDTO>> {
|
||||
return this.customerService.CustomerGetShippingaddress(shippingAddressId);
|
||||
return this.shippingAddressService.ShippingAddressGetShippingaddress(shippingAddressId);
|
||||
}
|
||||
|
||||
getShippingAddresses(params: CustomerService.CustomerGetShippingAddressesParams): Observable<Result<ShippingAddressDTO[]>> {
|
||||
return this.customerService.CustomerGetShippingAddresses(params);
|
||||
getShippingAddresses(params: ShippingAddressService.ShippingAddressGetShippingAddressesParams): Observable<Result<ShippingAddressDTO[]>> {
|
||||
return this.shippingAddressService.ShippingAddressGetShippingAddresses(params);
|
||||
}
|
||||
|
||||
getPayer(payerId: number): Observable<Result<PayerDTO>> {
|
||||
@@ -311,7 +524,7 @@ export class CrmCustomerService {
|
||||
return this.customerService.CustomerGetBonuscards(customerId);
|
||||
}
|
||||
|
||||
getCustomerHistory(customerId: number): Observable<ResponseArgsOfHistoryDTO> {
|
||||
return this.customerService.CustomerGetCustomerHistory({ customerId });
|
||||
getCustomerHistory(customerId: number): Observable<HistoryDTO[]> {
|
||||
return this.customerService.CustomerGetCustomerHistory({ customerId }).pipe(map((response) => response?.result));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,7 @@ import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: any;
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
|
||||
teardown: { destroyAfterEach: false },
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user