mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
33
angular.json
33
angular.json
@@ -2746,6 +2746,39 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"@shared/history": {
|
||||||
|
"projectType": "library",
|
||||||
|
"root": "apps/shared/history",
|
||||||
|
"sourceRoot": "apps/shared/history/src",
|
||||||
|
"prefix": "lib",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||||
|
"options": {
|
||||||
|
"project": "apps/shared/history/ng-package.json"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"tsConfig": "apps/shared/history/tsconfig.lib.prod.json"
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"tsConfig": "apps/shared/history/tsconfig.lib.json"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultConfiguration": "production"
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": "apps/shared/history/tsconfig.spec.json",
|
||||||
|
"polyfills": [
|
||||||
|
"zone.js",
|
||||||
|
"zone.js/testing"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
CustomerDTO,
|
CustomerDTO,
|
||||||
CustomerInfoDTO,
|
CustomerInfoDTO,
|
||||||
CustomerService,
|
CustomerService,
|
||||||
|
HistoryDTO,
|
||||||
InputDTO,
|
InputDTO,
|
||||||
KeyValueDTOOfStringAndString,
|
KeyValueDTOOfStringAndString,
|
||||||
ListResponseArgsOfCustomerInfoDTO,
|
ListResponseArgsOfCustomerInfoDTO,
|
||||||
@@ -18,7 +19,6 @@ import {
|
|||||||
PayerDTO,
|
PayerDTO,
|
||||||
PayerService,
|
PayerService,
|
||||||
ResponseArgsOfIEnumerableOfBonusCardInfoDTO,
|
ResponseArgsOfIEnumerableOfBonusCardInfoDTO,
|
||||||
ResponseArgsOfIEnumerableOfHistoryDTO,
|
|
||||||
ShippingAddressDTO,
|
ShippingAddressDTO,
|
||||||
ShippingAddressService,
|
ShippingAddressService,
|
||||||
} from '@swagger/crm';
|
} from '@swagger/crm';
|
||||||
@@ -524,7 +524,7 @@ export class CrmCustomerService {
|
|||||||
return this.customerService.CustomerGetBonuscards(customerId);
|
return this.customerService.CustomerGetBonuscards(customerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCustomerHistory(customerId: number): Observable<ResponseArgsOfIEnumerableOfHistoryDTO> {
|
getCustomerHistory(customerId: number): Observable<HistoryDTO[]> {
|
||||||
return this.customerService.CustomerGetCustomerHistory({ customerId });
|
return this.customerService.CustomerGetCustomerHistory({ customerId }).pipe(map((response) => response?.result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,29 +19,29 @@ body {
|
|||||||
background: var(--bg-color);
|
background: var(--bg-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
@layer base {
|
||||||
width: 0; // remove scrollbar space
|
::-webkit-scrollbar {
|
||||||
background: transparent; // optional: just make scrollbar invisible */
|
width: 0; // remove scrollbar space
|
||||||
}
|
background: transparent; // optional: just make scrollbar invisible */
|
||||||
|
}
|
||||||
|
|
||||||
.desktop .scroll-bar::-webkit-scrollbar,
|
.desktop .scroll-bar::-webkit-scrollbar {
|
||||||
.desktop pdf-viewer ::-webkit-scrollbar {
|
@apply w-3;
|
||||||
width: 12px;
|
background-color: transparent;
|
||||||
background-color: transparent;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.desktop .scroll-bar::-webkit-scrollbar-thumb,
|
.desktop .scroll-bar::-webkit-scrollbar-track {
|
||||||
.desktop pdf-viewer ::-webkit-scrollbar-thumb {
|
@apply my-4;
|
||||||
border-radius: 10px;
|
-webkit-box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.1);
|
||||||
-webkit-box-shadow: inset 0 0 6px rgb(0 0 0 / 10%);
|
border-radius: 10px;
|
||||||
background-color: var(--scrollbar-color);
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.desktop .scroll-bar::-webkit-scrollbar-track,
|
.desktop .scroll-bar::-webkit-scrollbar-thumb {
|
||||||
.desktop pdf-viewer ::-webkit-scrollbar-track {
|
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
|
||||||
-webkit-box-shadow: inset 0 0 4px rgb(0 0 0 / 10%);
|
border-radius: 10px;
|
||||||
border-radius: 10px;
|
background-color: var(--scrollbar-color);
|
||||||
background-color: white;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes load {
|
@keyframes load {
|
||||||
|
|||||||
8
apps/modal/history/src/lib/history-data.ts
Normal file
8
apps/modal/history/src/lib/history-data.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { HistoryDTO as CrmHistoryDTO } from '@swagger/crm';
|
||||||
|
import { HistoryDTO as OmsHistoryDTO } from '@swagger/oms';
|
||||||
|
|
||||||
|
export interface HistoryData {
|
||||||
|
customerNumber: string;
|
||||||
|
customerName: string;
|
||||||
|
history: CrmHistoryDTO[] | OmsHistoryDTO[];
|
||||||
|
}
|
||||||
@@ -1,58 +1,13 @@
|
|||||||
<div class="wrapper">
|
<div class="wrapper -mx-4 px-4">
|
||||||
<div class="customer">
|
<div class="bg-white -mx-4 px-7 flex flex-row py-5">
|
||||||
<div class="row">
|
<div class="flex flex-row flex-grow">
|
||||||
<span class="label">Kundenname</span>
|
<span class="mr-3">Kundenname</span>
|
||||||
<strong>{{ customerName }}</strong>
|
<strong>{{ customerName }}</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="flex flex-row flex-grow">
|
||||||
<span class="label">Kundennummer</span>
|
<span class="mr-3">Kundennummer</span>
|
||||||
<strong *ngIf="ref.data.mode === 'customer'">{{ customer?.customerNumber }}</strong>
|
<strong>{{ customerNumber }}</strong>
|
||||||
<strong *ngIf="ref.data.mode === 'goods'">{{ orderItemListItem?.buyerNumber }}</strong>
|
|
||||||
<strong *ngIf="ref.data.mode === 'order'">{{ order?.buyer.buyerNumber }}</strong>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr />
|
|
||||||
<div class="scroll-container">
|
|
||||||
<div *ngFor="let history of history$ | async; first as isFirst; last as isLast" class="content-wrapper">
|
|
||||||
<div class="log-entry" [class.last]="isLast" [class.first]="isFirst">
|
|
||||||
<span class="timeline-dot"></span>
|
|
||||||
<div class="row details header">
|
|
||||||
<div *ngIf="history.changed">{{ history.changed | date }} | {{ history.changed | date: 'shortTime' }} Uhr</div>
|
|
||||||
<div *ngIf="history.location">| {{ history.location }}</div>
|
|
||||||
<div *ngIf="history.changedBy">| {{ history.changedBy }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="row details title">
|
|
||||||
<ng-container *ngIf="ref?.data?.mode === 'goods' || ref?.data?.mode === 'order'; else customer">
|
|
||||||
Status der Bestellung wurde geändert
|
|
||||||
</ng-container>
|
|
||||||
<ng-template #customer>
|
|
||||||
Kundendaten wurden geändert
|
|
||||||
</ng-template>
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
<div *ngFor="let values of history?.values" class="row details changes">
|
|
||||||
<p>{{ values.caption }}:</p>
|
|
||||||
<p class="changes-gap">
|
|
||||||
<strong>{{ values.value }} </strong>(neu)
|
|
||||||
</p>
|
|
||||||
<p *ngIf="values.previousValue">
|
|
||||||
<strong>{{ values.previousValue }} </strong>(alt)
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="spinner$ | async" class="loading-spinner">
|
|
||||||
<ui-spinner [show]="true"></ui-spinner>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="historyError$ | async">
|
|
||||||
<h3 class="error">
|
|
||||||
Abruf der Historie fehlgeschlagen.
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="historyEmpty$ | async">
|
|
||||||
<h3 class="error">
|
|
||||||
Keine Einträge in der Historie gefunden.
|
|
||||||
</h3>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<shared-history-list [history]="history"> </shared-history-list>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,133 +1,7 @@
|
|||||||
$offset: 10px;
|
|
||||||
$line-top-offset: 3px;
|
|
||||||
$dot-size: 16px;
|
|
||||||
$dot-size-lg: 20px;
|
|
||||||
$border-size: 1px;
|
|
||||||
$border-size-cover: 2px;
|
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
@apply bg-white;
|
|
||||||
min-height: 500px;
|
min-height: 500px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.row {
|
.wrapper {
|
||||||
@apply w-full flex flex-row flex-grow items-center px-2 my-2;
|
background-color: #f5f7fa;
|
||||||
|
|
||||||
.label {
|
|
||||||
width: 150px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
height: 2px;
|
|
||||||
@apply bg-disabled-customer my-6;
|
|
||||||
margin-left: -1rem;
|
|
||||||
width: calc(100% + 2rem);
|
|
||||||
}
|
|
||||||
|
|
||||||
.error {
|
|
||||||
@apply text-warning text-center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-spinner {
|
|
||||||
@apply p-8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scroll-container {
|
|
||||||
@apply overflow-y-scroll overflow-x-hidden mr-10 mb-8;
|
|
||||||
max-height: 800px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scroll-container::-webkit-scrollbar-track {
|
|
||||||
-webkit-box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.1);
|
|
||||||
border-radius: 10px;
|
|
||||||
background-color: #e1ebf5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scroll-container::-webkit-scrollbar {
|
|
||||||
width: 12px;
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scroll-container::-webkit-scrollbar-thumb {
|
|
||||||
border-radius: 10px;
|
|
||||||
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
|
|
||||||
background-color: #0f2942;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-wrapper {
|
|
||||||
@apply flex flex-col pl-2 pr-9 mb-10;
|
|
||||||
}
|
|
||||||
|
|
||||||
.details {
|
|
||||||
@apply my-0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
@apply font-bold text-lg;
|
|
||||||
}
|
|
||||||
|
|
||||||
.changes {
|
|
||||||
@apply flex flex-row my-0;
|
|
||||||
|
|
||||||
p {
|
|
||||||
@apply m-0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.changes-gap {
|
|
||||||
@apply mx-1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.log-entry {
|
|
||||||
position: relative;
|
|
||||||
// calculate offset relative to container offset (22px)
|
|
||||||
padding-left: calc(70px - 22px);
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
height: calc(100% + 40px);
|
|
||||||
width: 1px;
|
|
||||||
top: $line-top-offset;
|
|
||||||
left: $offset;
|
|
||||||
border: $border-size solid #e1ebf5;
|
|
||||||
background: #e1ebf5;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.last:before {
|
|
||||||
height: 30%;
|
|
||||||
border: $border-size-cover solid #fff;
|
|
||||||
background: #fff;
|
|
||||||
left: calc(#{$offset} - #{$border-size-cover});
|
|
||||||
}
|
|
||||||
|
|
||||||
.timeline-dot {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: $offset;
|
|
||||||
background: #fff;
|
|
||||||
width: 2px;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
background: #e1ebf5;
|
|
||||||
|
|
||||||
top: $line-top-offset;
|
|
||||||
left: calc((#{$dot-size} - #{$line-top-offset}) / -2);
|
|
||||||
border-radius: 50%;
|
|
||||||
width: $dot-size;
|
|
||||||
height: $dot-size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.first {
|
|
||||||
.timeline-dot:before {
|
|
||||||
width: $dot-size-lg;
|
|
||||||
height: $dot-size-lg;
|
|
||||||
background: #be8100;
|
|
||||||
left: calc(#{$dot-size} / -2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { createComponentFactory, mockProvider, Spectator } from '@ngneat/spectator';
|
||||||
|
import { SharedHistoryListComponent, SharedHistoryListModule } from '@shared/history';
|
||||||
|
import { HistoryDTO } from '@swagger/crm';
|
||||||
|
import { UiModalRef } from '@ui/modal';
|
||||||
|
import { HistoryData } from './history-data';
|
||||||
|
import { HistoryModalComponent } from './history.component';
|
||||||
|
|
||||||
|
describe('HistoryModalComponent', () => {
|
||||||
|
let spectator: Spectator<HistoryModalComponent>;
|
||||||
|
let modalRefMock: jasmine.SpyObj<UiModalRef<void, HistoryData>>;
|
||||||
|
|
||||||
|
const createComponent = createComponentFactory({
|
||||||
|
component: HistoryModalComponent,
|
||||||
|
imports: [SharedHistoryListModule],
|
||||||
|
declarations: [],
|
||||||
|
providers: [mockProvider(UiModalRef, { data: {} as HistoryData })],
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
spectator = createComponent();
|
||||||
|
modalRefMock = spectator.inject(UiModalRef);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(spectator.component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('customerName', () => {
|
||||||
|
it('should get the customer name from ref.data', () => {
|
||||||
|
const customerName = 'Test';
|
||||||
|
spectator.component.ref.data.customerName = customerName;
|
||||||
|
expect(spectator.component.customerName).toBe(customerName);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('customerNumber', () => {
|
||||||
|
it('should get the customer number from ref.data', () => {
|
||||||
|
const customerNumber = '12345';
|
||||||
|
spectator.component.ref.data.customerNumber = customerNumber;
|
||||||
|
expect(spectator.component.customerNumber).toBe(customerNumber);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('history', () => {
|
||||||
|
it('should get the history from ref.data', () => {
|
||||||
|
const history: HistoryDTO[] = [{ id: 1 }];
|
||||||
|
spectator.component.ref.data.history = history;
|
||||||
|
expect(spectator.component.history).toBe(history);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('template', () => {
|
||||||
|
it('should render shared-history-list and set Input History', () => {
|
||||||
|
const history: HistoryDTO[] = [{ id: 1 }, { id: 2 }];
|
||||||
|
spyOnProperty(spectator.component, 'history', 'get').and.returnValue(history);
|
||||||
|
spectator.detectComponentChanges();
|
||||||
|
expect(spectator.query(SharedHistoryListComponent).history).toEqual(history);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,13 +1,6 @@
|
|||||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||||
import { CrmCustomerService } from '@domain/crm';
|
|
||||||
import { DomainOmsService } from '@domain/oms';
|
|
||||||
import { CustomerDTO } from '@swagger/crm';
|
|
||||||
import { HistoryDTO as CrmHistoryDTO } from '@swagger/crm';
|
|
||||||
import { HistoryDTO as OmsHistoryDTO, OrderDTO } from '@swagger/oms';
|
|
||||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
|
||||||
import { UiModalRef } from '@ui/modal';
|
import { UiModalRef } from '@ui/modal';
|
||||||
import { BehaviorSubject, Observable, of } from 'rxjs';
|
import { HistoryData } from './history-data';
|
||||||
import { catchError, map } from 'rxjs/operators';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'lib-history',
|
selector: 'lib-history',
|
||||||
@@ -15,100 +8,18 @@ import { catchError, map } from 'rxjs/operators';
|
|||||||
styleUrls: ['history.component.scss'],
|
styleUrls: ['history.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class HistoryComponent implements OnInit {
|
export class HistoryModalComponent {
|
||||||
historyError$ = new BehaviorSubject<boolean>(false);
|
|
||||||
historyEmpty$ = new BehaviorSubject<boolean>(false);
|
|
||||||
spinner$ = new BehaviorSubject<boolean>(true);
|
|
||||||
|
|
||||||
history$: Observable<Array<CrmHistoryDTO | OmsHistoryDTO>>;
|
|
||||||
|
|
||||||
get customerName() {
|
get customerName() {
|
||||||
if (this.ref.data.mode === 'customer' || this.ref.data.mode === 'goods') {
|
return this.ref.data.customerName;
|
||||||
const data = this.ref.data.item as CustomerDTO;
|
|
||||||
return [data?.organisation?.name ?? data?.organisation, data?.lastName, data?.firstName].filter((i) => !!i).join(', ');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.ref.data.mode === 'order') {
|
|
||||||
const data = this.ref.data.item as { order: OrderDTO; orderItemSubsetId: number };
|
|
||||||
return [data?.order?.buyer?.organisation, data?.order?.buyer?.lastName, data?.order?.buyer?.firstName].filter((i) => !!i).join(', ');
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
get customerNumber() {
|
||||||
public ref: UiModalRef<
|
return this.ref.data.customerNumber;
|
||||||
void,
|
|
||||||
{ mode: 'goods' | 'customer' | 'order'; item: CustomerDTO | OrderItemListItemDTO | { order: OrderDTO; orderItemSubsetId: number } }
|
|
||||||
>,
|
|
||||||
private customerService: CrmCustomerService,
|
|
||||||
private omsService: DomainOmsService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
get customer() {
|
|
||||||
return this.ref.data.item as CustomerDTO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get orderItemListItem() {
|
get history() {
|
||||||
return this.ref.data.item as OrderItemListItemDTO;
|
return this.ref.data.history;
|
||||||
}
|
}
|
||||||
|
|
||||||
get order() {
|
constructor(public ref: UiModalRef<void, HistoryData>) {}
|
||||||
return (this.ref.data.item as any)?.order as OrderDTO;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
switch (this.ref.data.mode) {
|
|
||||||
case 'customer':
|
|
||||||
this.history$ = this.customerService.getCustomerHistory((this.ref.data.item as CustomerDTO).id).pipe(
|
|
||||||
map((response) => {
|
|
||||||
this.spinner$.next(false);
|
|
||||||
if (response.result.length === 0) {
|
|
||||||
this.historyEmpty$.next(true);
|
|
||||||
}
|
|
||||||
return response.result;
|
|
||||||
}),
|
|
||||||
catchError(() => {
|
|
||||||
this.historyError$.next(true);
|
|
||||||
this.spinner$.next(false);
|
|
||||||
return of<CrmHistoryDTO[]>([]);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 'goods':
|
|
||||||
this.history$ = this.omsService.getHistory((this.ref.data.item as OrderItemListItemDTO).orderItemSubsetId).pipe(
|
|
||||||
map((history) => {
|
|
||||||
this.spinner$.next(false);
|
|
||||||
if (history.length === 0) {
|
|
||||||
this.historyEmpty$.next(true);
|
|
||||||
}
|
|
||||||
return history;
|
|
||||||
}),
|
|
||||||
catchError(() => {
|
|
||||||
this.historyError$.next(true);
|
|
||||||
this.spinner$.next(false);
|
|
||||||
return of([]);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 'order':
|
|
||||||
this.history$ = this.omsService
|
|
||||||
.getHistory((this.ref.data.item as { order: OrderDTO; orderItemSubsetId: number }).orderItemSubsetId)
|
|
||||||
.pipe(
|
|
||||||
map((history) => {
|
|
||||||
this.spinner$.next(false);
|
|
||||||
if (history.length === 0) {
|
|
||||||
this.historyEmpty$.next(true);
|
|
||||||
}
|
|
||||||
return history;
|
|
||||||
}),
|
|
||||||
catchError(() => {
|
|
||||||
this.historyError$.next(true);
|
|
||||||
this.spinner$.next(false);
|
|
||||||
return of([]);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { UiIconModule } from '@ui/icon';
|
import { SharedHistoryListModule } from '@shared/history';
|
||||||
import { UiModalModule } from '@ui/modal';
|
import { UiModalModule } from '@ui/modal';
|
||||||
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
|
import { HistoryModalComponent } from './history.component';
|
||||||
import { HistoryComponent } from './history.component';
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [HistoryComponent],
|
declarations: [HistoryModalComponent],
|
||||||
imports: [CommonModule, UiModalModule, UiIconModule, UiSpinnerModule],
|
imports: [CommonModule, UiModalModule, SharedHistoryListModule],
|
||||||
exports: [HistoryComponent],
|
exports: [HistoryModalComponent],
|
||||||
})
|
})
|
||||||
export class HistoryModule {}
|
export class HistoryModule {}
|
||||||
|
|||||||
@@ -3,4 +3,5 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export * from './lib/history.module';
|
export * from './lib/history.module';
|
||||||
|
export * from './lib/history-data';
|
||||||
export * from './lib/history.component';
|
export * from './lib/history.component';
|
||||||
|
|||||||
@@ -44,9 +44,3 @@
|
|||||||
@apply bg-brand text-white;
|
@apply bg-brand text-white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
::ng-deep .desktop page-search-results {
|
|
||||||
.scroll-bar-margin::-webkit-scrollbar-track {
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -12,8 +12,10 @@
|
|||||||
<div class="card-customer-details">
|
<div class="card-customer-details">
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
<h1 class="title">{{ (customerType$ | async) === 'b2b' ? 'Firmendetails' : 'Kundendetails' }}</h1>
|
<h1 class="title">{{ (customerType$ | async) === 'b2b' ? 'Firmendetails' : 'Kundendetails' }}</h1>
|
||||||
<button (click)="openHistory()" class="button-customer-history">
|
<button [disabled]="fetchHistory$ | async" (click)="openHistory()" class="button-customer-history">
|
||||||
Historie
|
<ui-spinner [show]="fetchHistory$ | async">
|
||||||
|
Historie
|
||||||
|
</ui-spinner>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="info">Sind Ihre {{ (customerType$ | async) === 'b2b' ? 'Firmendaten' : 'Kundendaten' }} korrekt?</p>
|
<p class="info">Sind Ihre {{ (customerType$ | async) === 'b2b' ? 'Firmendaten' : 'Kundendaten' }} korrekt?</p>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { HttpErrorResponse } from '@angular/common/http';
|
import { HttpErrorResponse } from '@angular/common/http';
|
||||||
import { Component, ChangeDetectionStrategy, OnInit, ChangeDetectorRef } from '@angular/core';
|
import { Component, ChangeDetectionStrategy, OnInit, ChangeDetectorRef, OnDestroy } from '@angular/core';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { ApplicationService } from '@core/application';
|
import { ApplicationService } from '@core/application';
|
||||||
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
|
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
|
||||||
import { DomainCheckoutService } from '@domain/checkout';
|
import { DomainCheckoutService } from '@domain/checkout';
|
||||||
import { AddressHelper, AssignedPayerHelper, CrmCustomerService, ShippingAddressHelper } from '@domain/crm';
|
import { AddressHelper, AssignedPayerHelper, CrmCustomerService, ShippingAddressHelper } from '@domain/crm';
|
||||||
import { HistoryComponent } from '@modal/history';
|
import { HistoryModalComponent, HistoryData } from '@modal/history';
|
||||||
import {
|
import {
|
||||||
BuyerDTO,
|
BuyerDTO,
|
||||||
NotificationChannel,
|
NotificationChannel,
|
||||||
@@ -20,11 +20,11 @@ import {
|
|||||||
ShippingAddressDTO as CrmShippingAddressDTO,
|
ShippingAddressDTO as CrmShippingAddressDTO,
|
||||||
ShippingAddressDTO,
|
ShippingAddressDTO,
|
||||||
} from '@swagger/crm';
|
} from '@swagger/crm';
|
||||||
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
|
import { UiErrorModalComponent, UiMessageModalComponent, UiModalService } from '@ui/modal';
|
||||||
import { isResponseArgs } from '@utils/object';
|
import { isResponseArgs } from '@utils/object';
|
||||||
import { isBoolean } from 'lodash';
|
import { isBoolean } from 'lodash';
|
||||||
import { BehaviorSubject, combineLatest, Observable, of } from 'rxjs';
|
import { BehaviorSubject, combineLatest, Observable, of, Subject } from 'rxjs';
|
||||||
import { catchError, first, map, shareReplay, switchMap, tap } from 'rxjs/operators';
|
import { catchError, first, take, map, shareReplay, switchMap, tap, takeUntil } from 'rxjs/operators';
|
||||||
import { CantAddCustomerToCartModalComponent } from '../modals/cant-add-customer-to-cart-modal/cant-add-customer-to-cart.component';
|
import { CantAddCustomerToCartModalComponent } from '../modals/cant-add-customer-to-cart-modal/cant-add-customer-to-cart.component';
|
||||||
import { CantAddCustomerToCartData } from '../modals/cant-add-customer-to-cart-modal/cant-add-customer-to-cart.data';
|
import { CantAddCustomerToCartData } from '../modals/cant-add-customer-to-cart-modal/cant-add-customer-to-cart.data';
|
||||||
import { CantSelectGuestModalComponent } from '../modals/cant-select-guest/cant-select-guest-modal.component';
|
import { CantSelectGuestModalComponent } from '../modals/cant-select-guest/cant-select-guest-modal.component';
|
||||||
@@ -35,7 +35,7 @@ import { CantSelectGuestModalComponent } from '../modals/cant-select-guest/cant-
|
|||||||
styleUrls: ['customer-details.component.scss'],
|
styleUrls: ['customer-details.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class CustomerDetailsComponent implements OnInit {
|
export class CustomerDetailsComponent implements OnInit, OnDestroy {
|
||||||
customerId$: Observable<number>;
|
customerId$: Observable<number>;
|
||||||
customer$: Observable<CustomerDTO>;
|
customer$: Observable<CustomerDTO>;
|
||||||
|
|
||||||
@@ -62,6 +62,7 @@ export class CustomerDetailsComponent implements OnInit {
|
|||||||
|
|
||||||
fetchShippingAdresses$ = new BehaviorSubject<boolean>(false);
|
fetchShippingAdresses$ = new BehaviorSubject<boolean>(false);
|
||||||
fetchAssignedPayers$ = new BehaviorSubject<boolean>(false);
|
fetchAssignedPayers$ = new BehaviorSubject<boolean>(false);
|
||||||
|
fetchHistory$ = new BehaviorSubject<boolean>(false);
|
||||||
showSpinner: boolean;
|
showSpinner: boolean;
|
||||||
|
|
||||||
continueDisabled$ = combineLatest([this.fetchShippingAdresses$, this.fetchAssignedPayers$]).pipe(
|
continueDisabled$ = combineLatest([this.fetchShippingAdresses$, this.fetchAssignedPayers$]).pipe(
|
||||||
@@ -70,6 +71,8 @@ export class CustomerDetailsComponent implements OnInit {
|
|||||||
|
|
||||||
private currentBreadcrumb: Breadcrumb;
|
private currentBreadcrumb: Breadcrumb;
|
||||||
|
|
||||||
|
private _onDestroy$ = new Subject();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private activatedRoute: ActivatedRoute,
|
private activatedRoute: ActivatedRoute,
|
||||||
private customerDetailsService: CrmCustomerService,
|
private customerDetailsService: CrmCustomerService,
|
||||||
@@ -182,6 +185,11 @@ export class CustomerDetailsComponent implements OnInit {
|
|||||||
this.createBreadcrumb();
|
this.createBreadcrumb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this._onDestroy$.next();
|
||||||
|
this._onDestroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
async createBreadcrumb() {
|
async createBreadcrumb() {
|
||||||
const customerId = await this.customerId$.pipe(first()).toPromise();
|
const customerId = await this.customerId$.pipe(first()).toPromise();
|
||||||
|
|
||||||
@@ -214,16 +222,50 @@ export class CustomerDetailsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async openHistory() {
|
async openHistory() {
|
||||||
const customer = await this.customer$.pipe(first()).toPromise();
|
this.fetchHistory$.next(true);
|
||||||
this.modal.open({
|
try {
|
||||||
content: HistoryComponent,
|
const customer = await this.customer$.pipe(first()).toPromise();
|
||||||
title: 'Historie',
|
const customerName = [customer.organisation?.name ?? customer.organisation?.name, customer.lastName, customer.firstName]
|
||||||
config: { showScrollbarY: false },
|
.filter((i) => !!i)
|
||||||
data: {
|
.join(', ');
|
||||||
mode: 'customer',
|
const customerNumber = customer.customerNumber;
|
||||||
item: customer,
|
const history = await this.customerDetailsService
|
||||||
},
|
.getCustomerHistory(customer.id)
|
||||||
});
|
.pipe(takeUntil(this._onDestroy$), take(1))
|
||||||
|
.toPromise();
|
||||||
|
|
||||||
|
const data: HistoryData = {
|
||||||
|
customerName,
|
||||||
|
customerNumber,
|
||||||
|
history: history,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!!history) {
|
||||||
|
if (history.length > 0) {
|
||||||
|
this.modal.open<void, HistoryData>({
|
||||||
|
content: HistoryModalComponent,
|
||||||
|
title: 'Historie',
|
||||||
|
config: { showScrollbarY: false, padding: false },
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
} else if (history.length === 0) {
|
||||||
|
this.modal.open({
|
||||||
|
content: UiMessageModalComponent,
|
||||||
|
title: 'Keine Einträge in der Historie gefunden',
|
||||||
|
data: { message: `Es konnten keine Einträge für ${customerName} mit der Kundennummer ${customerNumber} gefunden werden.` },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const errorModalRef = this.modal.open({
|
||||||
|
content: UiErrorModalComponent,
|
||||||
|
title: 'Abruf der Historie fehlgeschlagen',
|
||||||
|
data: error,
|
||||||
|
});
|
||||||
|
await errorModalRef.afterClosed$.toPromise();
|
||||||
|
} finally {
|
||||||
|
this.fetchHistory$.next(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async continue() {
|
async continue() {
|
||||||
|
|||||||
@@ -138,7 +138,11 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<div class="history-wrapper">
|
<div class="history-wrapper">
|
||||||
<button class="cta-history" (click)="openHistory(subsetItem.id)">Historie</button>
|
<button [disabled]="fetchHistory$ | async" class="cta-history" (click)="openHistory(subsetItem.id)">
|
||||||
|
<ui-spinner [show]="fetchHistory$ | async">
|
||||||
|
Historie
|
||||||
|
</ui-spinner>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnInit, OnDestroy } from '@angular/core';
|
||||||
import { ProductImageService } from '@cdn/product-image';
|
import { ProductImageService } from '@cdn/product-image';
|
||||||
import { HistoryComponent } from '@modal/history';
|
import { DomainOmsService } from '@domain/oms';
|
||||||
|
import { HistoryModalComponent, HistoryData } from '@modal/history';
|
||||||
import { OrderDTO, OrderItemDTO, OrderItemSubsetDTO } from '@swagger/oms';
|
import { OrderDTO, OrderItemDTO, OrderItemSubsetDTO } from '@swagger/oms';
|
||||||
import { UiModalService } from '@ui/modal';
|
import { UiErrorModalComponent, UiMessageModalComponent, UiModalService } from '@ui/modal';
|
||||||
import { Observable, of } from 'rxjs';
|
import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
|
||||||
|
import { takeUntil, take } from 'rxjs/operators';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'page-customer-order-item-card',
|
selector: 'page-customer-order-item-card',
|
||||||
templateUrl: 'customer-order-item-card.component.html',
|
templateUrl: 'customer-order-item-card.component.html',
|
||||||
styleUrls: ['./customer-order-item-card.component.scss'],
|
styleUrls: ['./customer-order-item-card.component.scss'],
|
||||||
})
|
})
|
||||||
export class CustomerOrderItemCardComponent implements OnInit {
|
export class CustomerOrderItemCardComponent implements OnInit, OnDestroy {
|
||||||
@Input()
|
@Input()
|
||||||
order: OrderDTO;
|
order: OrderDTO;
|
||||||
|
|
||||||
@@ -25,7 +27,10 @@ export class CustomerOrderItemCardComponent implements OnInit {
|
|||||||
return this.orderItem.subsetItems.map((subsetItem) => subsetItem.data);
|
return this.orderItem.subsetItems.map((subsetItem) => subsetItem.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(private imageService: ProductImageService, private _modal: UiModalService) {}
|
fetchHistory$ = new BehaviorSubject<boolean>(false);
|
||||||
|
private _onDestroy$ = new Subject();
|
||||||
|
|
||||||
|
constructor(private imageService: ProductImageService, private _modal: UiModalService, private _omsService: DomainOmsService) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.expand = new Array(this.subsetItems.length);
|
this.expand = new Array(this.subsetItems.length);
|
||||||
@@ -38,6 +43,11 @@ export class CustomerOrderItemCardComponent implements OnInit {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this._onDestroy$.next();
|
||||||
|
this._onDestroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
ssc(subsetItem: OrderItemSubsetDTO) {
|
ssc(subsetItem: OrderItemSubsetDTO) {
|
||||||
if (subsetItem.ssc) {
|
if (subsetItem.ssc) {
|
||||||
return `${subsetItem.ssc} - ${subsetItem.sscText}`;
|
return `${subsetItem.ssc} - ${subsetItem.sscText}`;
|
||||||
@@ -46,18 +56,48 @@ export class CustomerOrderItemCardComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
openHistory(orderItemSubsetId: number) {
|
async openHistory(orderItemSubsetId: number) {
|
||||||
this._modal.open({
|
this.fetchHistory$.next(true);
|
||||||
content: HistoryComponent,
|
try {
|
||||||
title: 'Historie',
|
const customerName = [
|
||||||
config: { showScrollbarY: false },
|
this.order.buyer?.organisation?.name ?? this.order.buyer?.organisation?.name,
|
||||||
data: {
|
this.order.buyer?.lastName,
|
||||||
mode: 'order',
|
this.order.buyer?.firstName,
|
||||||
item: {
|
]
|
||||||
order: this.order,
|
.filter((i) => !!i)
|
||||||
orderItemSubsetId,
|
.join(', ');
|
||||||
},
|
const history = await this._omsService.getHistory(orderItemSubsetId).pipe(takeUntil(this._onDestroy$), take(1)).toPromise();
|
||||||
},
|
if (!!history) {
|
||||||
});
|
if (history.length > 0) {
|
||||||
|
const data: HistoryData = {
|
||||||
|
customerName,
|
||||||
|
customerNumber: String(orderItemSubsetId),
|
||||||
|
history: history,
|
||||||
|
};
|
||||||
|
|
||||||
|
this._modal.open({
|
||||||
|
content: HistoryModalComponent,
|
||||||
|
title: 'Historie',
|
||||||
|
config: { showScrollbarY: false, padding: false },
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
} else if (history.length === 0) {
|
||||||
|
this._modal.open({
|
||||||
|
content: UiMessageModalComponent,
|
||||||
|
title: 'Keine Einträge in der Historie gefunden',
|
||||||
|
data: { message: `Es konnten keine Einträge für ${customerName} mit der Bestellnummer ${orderItemSubsetId} gefunden werden.` },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const errorModalRef = this._modal.open({
|
||||||
|
content: UiErrorModalComponent,
|
||||||
|
title: 'Abruf der Historie fehlgeschlagen',
|
||||||
|
data: error,
|
||||||
|
});
|
||||||
|
await errorModalRef.afterClosed$.toPromise();
|
||||||
|
} finally {
|
||||||
|
this.fetchHistory$.next(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<h5>Seite {{ page }} / {{ totalPages }}</h5>
|
<h5>Seite {{ page }} / {{ totalPages }}</h5>
|
||||||
|
|
||||||
<pdf-viewer
|
<pdf-viewer
|
||||||
|
class="scroll-bar"
|
||||||
[src]="objectURL"
|
[src]="objectURL"
|
||||||
[render-text]="true"
|
[render-text]="true"
|
||||||
[(page)]="page"
|
[(page)]="page"
|
||||||
|
|||||||
@@ -151,7 +151,11 @@
|
|||||||
</button>
|
</button>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<div class="history-wrapper">
|
<div class="history-wrapper">
|
||||||
<button class="cta-history" (click)="openHistory()">Historie</button>
|
<button [disabled]="fetchHistory$ | async" class="cta-history" (click)="openHistory()">
|
||||||
|
<ui-spinner [show]="fetchHistory$ | async">
|
||||||
|
Historie
|
||||||
|
</ui-spinner>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ui-select-bullet *ngIf="selectable$ | async" [ngModel]="selected$ | async" (ngModelChange)="setSelected($event)"> </ui-select-bullet>
|
<ui-select-bullet *ngIf="selectable$ | async" [ngModel]="selected$ | async" (ngModelChange)="setSelected($event)"> </ui-select-bullet>
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ import {
|
|||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { UntypedFormControl } from '@angular/forms';
|
import { UntypedFormControl } from '@angular/forms';
|
||||||
import { DomainOmsService, DomainReceiptService } from '@domain/oms';
|
import { DomainOmsService, DomainReceiptService } from '@domain/oms';
|
||||||
import { HistoryComponent } from '@modal/history';
|
import { HistoryModalComponent, HistoryData } from '@modal/history';
|
||||||
import { ComponentStore, tapResponse } from '@ngrx/component-store';
|
import { ComponentStore, tapResponse } from '@ngrx/component-store';
|
||||||
import { OrderDTO, OrderItemListItemDTO, ReceiptDTO, ReceiptType } from '@swagger/oms';
|
import { OrderDTO, OrderItemListItemDTO, ReceiptDTO, ReceiptType } from '@swagger/oms';
|
||||||
import { UiModalService } from '@ui/modal';
|
import { UiErrorModalComponent, UiMessageModalComponent, UiModalService } from '@ui/modal';
|
||||||
import { isEqual } from 'lodash';
|
import { isEqual } from 'lodash';
|
||||||
import { combineLatest, NEVER } from 'rxjs';
|
import { BehaviorSubject, combineLatest, NEVER, Subject } from 'rxjs';
|
||||||
import { catchError, filter, first, map, switchMap, withLatestFrom } from 'rxjs/operators';
|
import { catchError, filter, first, map, switchMap, withLatestFrom, takeUntil, take } from 'rxjs/operators';
|
||||||
import { SharedGoodsInOutOrderDetailsStore } from '../goods-in-out-order-details.store';
|
import { SharedGoodsInOutOrderDetailsStore } from '../goods-in-out-order-details.store';
|
||||||
|
|
||||||
export interface SharedGoodsInOutOrderDetailsItemComponentState {
|
export interface SharedGoodsInOutOrderDetailsItemComponentState {
|
||||||
@@ -141,6 +141,9 @@ export class SharedGoodsInOutOrderDetailsItemComponent extends ComponentStore<Sh
|
|||||||
|
|
||||||
more$ = this.select((s) => s.more);
|
more$ = this.select((s) => s.more);
|
||||||
|
|
||||||
|
fetchHistory$ = new BehaviorSubject<boolean>(false);
|
||||||
|
private _onDestroy$ = new Subject();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _host: SharedGoodsInOutOrderDetailsStore,
|
private _host: SharedGoodsInOutOrderDetailsStore,
|
||||||
private _domainReceiptService: DomainReceiptService,
|
private _domainReceiptService: DomainReceiptService,
|
||||||
@@ -158,6 +161,8 @@ export class SharedGoodsInOutOrderDetailsItemComponent extends ComponentStore<Sh
|
|||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
// Remove Prev OrderItem from selected list
|
// Remove Prev OrderItem from selected list
|
||||||
this._host.selectOrderItem(this.orderItem, false);
|
this._host.selectOrderItem(this.orderItem, false);
|
||||||
|
this._onDestroy$.next();
|
||||||
|
this._onDestroy$.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadReceipts = this.effect(($) =>
|
loadReceipts = this.effect(($) =>
|
||||||
@@ -206,16 +211,49 @@ export class SharedGoodsInOutOrderDetailsItemComponent extends ComponentStore<Sh
|
|||||||
this.patchState({ more });
|
this.patchState({ more });
|
||||||
}
|
}
|
||||||
|
|
||||||
openHistory() {
|
async openHistory() {
|
||||||
this._modal.open({
|
this.fetchHistory$.next(true);
|
||||||
content: HistoryComponent,
|
try {
|
||||||
title: 'Historie',
|
const customerName = [this.orderItem?.organisation ?? this.orderItem.organisation, this.orderItem.lastName, this.orderItem.firstName]
|
||||||
config: { showScrollbarY: false },
|
.filter((i) => !!i)
|
||||||
data: {
|
.join(', ');
|
||||||
mode: 'goods',
|
const customerNumber = this.orderItem.buyerNumber;
|
||||||
item: this.orderItem,
|
const history = await this._omsService
|
||||||
},
|
.getHistory(this.orderItem.orderItemSubsetId)
|
||||||
});
|
.pipe(takeUntil(this._onDestroy$), take(1))
|
||||||
|
.toPromise();
|
||||||
|
|
||||||
|
if (!!history) {
|
||||||
|
if (history.length > 0) {
|
||||||
|
const data: HistoryData = {
|
||||||
|
customerName,
|
||||||
|
customerNumber,
|
||||||
|
history: history,
|
||||||
|
};
|
||||||
|
this._modal.open({
|
||||||
|
content: HistoryModalComponent,
|
||||||
|
title: 'Historie',
|
||||||
|
config: { showScrollbarY: false, padding: false },
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
} else if (history.length === 0) {
|
||||||
|
this._modal.open({
|
||||||
|
content: UiMessageModalComponent,
|
||||||
|
title: 'Keine Einträge in der Historie gefunden',
|
||||||
|
data: { message: `Es konnten keine Einträge für ${customerName} mit der Kundennummer ${customerNumber} gefunden werden.` },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const errorModalRef = this._modal.open({
|
||||||
|
content: UiErrorModalComponent,
|
||||||
|
title: 'Abruf der Historie fehlgeschlagen',
|
||||||
|
data: error,
|
||||||
|
});
|
||||||
|
await errorModalRef.afterClosed$.toPromise();
|
||||||
|
} finally {
|
||||||
|
this.fetchHistory$.next(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setSelected(selected: boolean) {
|
setSelected(selected: boolean) {
|
||||||
|
|||||||
25
apps/shared/history/README.md
Normal file
25
apps/shared/history/README.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# History
|
||||||
|
|
||||||
|
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.0.0.
|
||||||
|
|
||||||
|
## Code scaffolding
|
||||||
|
|
||||||
|
Run `ng generate component component-name --project history` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project history`.
|
||||||
|
|
||||||
|
> Note: Don't forget to add `--project history` or else it will be added to the default project in your `angular.json` file.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Run `ng build history` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||||
|
|
||||||
|
## Publishing
|
||||||
|
|
||||||
|
After building your library with `ng build history`, go to the dist folder `cd dist/history` and run `npm publish`.
|
||||||
|
|
||||||
|
## Running unit tests
|
||||||
|
|
||||||
|
Run `ng test history` 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.
|
||||||
7
apps/shared/history/ng-package.json
Normal file
7
apps/shared/history/ng-package.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||||
|
"dest": "../../../dist/shared/history",
|
||||||
|
"lib": {
|
||||||
|
"entryFile": "src/public-api.ts"
|
||||||
|
}
|
||||||
|
}
|
||||||
11
apps/shared/history/package.json
Normal file
11
apps/shared/history/package.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "@shared/history",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@angular/common": "^15.0.0",
|
||||||
|
"@angular/core": "^15.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.3.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
10
apps/shared/history/src/lib/history-list.component.html
Normal file
10
apps/shared/history/src/lib/history-list.component.html
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<div class="scroll-container scroll-bar pt-5 overflow-y-scroll overflow-x-hidden mr-2">
|
||||||
|
<div *ngFor="let logEntry of history; first as isFirst; last as isLast" class="flex flex-col pl-2 pr-7 mb-10">
|
||||||
|
<div class="log-entry relative pl-7" [class.last]="isLast" [class.first]="isFirst">
|
||||||
|
<span class="timeline-dot" [class.last]="isLast && !isFirst"></span>
|
||||||
|
<span class="timeline-dot" [class.bottom-square]="isLast && isFirst"></span>
|
||||||
|
|
||||||
|
<shared-history-log-entry [historyLogEntryData]="logEntry"></shared-history-log-entry>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
84
apps/shared/history/src/lib/history-list.component.scss
Normal file
84
apps/shared/history/src/lib/history-list.component.scss
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
:host {
|
||||||
|
// Dot Timeline
|
||||||
|
--timeline-bar-left-offset: 6px;
|
||||||
|
--timeline-bar-dots-top-offset: 5px;
|
||||||
|
--timeline-bar-dot-size: 14px;
|
||||||
|
--timeline-bar-line-width: 1px;
|
||||||
|
|
||||||
|
min-height: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-container {
|
||||||
|
max-height: 800px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-entry {
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
height: calc(100% + 40px);
|
||||||
|
width: 1px;
|
||||||
|
top: var(--timeline-bar-dots-top-offset);
|
||||||
|
left: var(--timeline-bar-left-offset);
|
||||||
|
border: var(--timeline-bar-line-width) solid #aeb7c1;
|
||||||
|
background: #aeb7c1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.last:before {
|
||||||
|
@apply bg-white;
|
||||||
|
height: 100%;
|
||||||
|
border: var(--timeline-bar-line-width) solid #aeb7c1;
|
||||||
|
left: var(--timeline-bar-left-offset);
|
||||||
|
top: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.last.first:before {
|
||||||
|
top: var(--timeline-bar-dots-top-offset);
|
||||||
|
height: 97%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-dot {
|
||||||
|
@apply absolute top-0 bg-white;
|
||||||
|
left: var(--timeline-bar-left-offset);
|
||||||
|
width: 2px;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
@apply absolute;
|
||||||
|
content: '';
|
||||||
|
background: #aeb7c1;
|
||||||
|
top: var(--timeline-bar-dots-top-offset);
|
||||||
|
left: calc((-1 * var(--timeline-bar-dots-top-offset)) - 1px);
|
||||||
|
border-radius: 50%;
|
||||||
|
width: var(--timeline-bar-dot-size);
|
||||||
|
height: var(--timeline-bar-dot-size);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.last:before,
|
||||||
|
&.bottom-square:before {
|
||||||
|
@apply rounded-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.last,
|
||||||
|
&.bottom-square {
|
||||||
|
top: unset;
|
||||||
|
bottom: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.first {
|
||||||
|
.timeline-dot:before {
|
||||||
|
@apply bg-black;
|
||||||
|
width: var(--timeline-bar-dot-size);
|
||||||
|
height: var(--timeline-bar-dot-size);
|
||||||
|
left: calc((var(--timeline-bar-dot-size) / -2) + 1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-dot.bottom-square:before {
|
||||||
|
background: #aeb7c1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
70
apps/shared/history/src/lib/history-list.component.spec.ts
Normal file
70
apps/shared/history/src/lib/history-list.component.spec.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import { createComponentFactory, Spectator } from '@ngneat/spectator';
|
||||||
|
import { SharedHistoryListComponent, SharedHistoryLogEntryComponent, SharedHistoryLogEntryModule } from '@shared/history';
|
||||||
|
import { HistoryDTO } from '@swagger/crm';
|
||||||
|
|
||||||
|
describe('SharedHistoryListComponent', () => {
|
||||||
|
let spectator: Spectator<SharedHistoryListComponent>;
|
||||||
|
|
||||||
|
const createComponent = createComponentFactory({
|
||||||
|
component: SharedHistoryListComponent,
|
||||||
|
imports: [SharedHistoryLogEntryModule],
|
||||||
|
declarations: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
spectator = createComponent();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(spectator.component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('history', () => {
|
||||||
|
it('should render log-entry if history length <= 0', () => {
|
||||||
|
const history = [];
|
||||||
|
spectator.setInput('history', history);
|
||||||
|
expect(spectator.query('.log-entry')).not.toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render log-entry if history length > 0', () => {
|
||||||
|
const history = [{}, {}];
|
||||||
|
spectator.setInput('history', history);
|
||||||
|
expect(spectator.query('.log-entry')).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add class last to last log-entry', () => {
|
||||||
|
const history = [{}, {}];
|
||||||
|
spectator.setInput('history', history);
|
||||||
|
expect(spectator.queryLast('.log-entry')).toHaveClass('last');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add class first to first log-entry', () => {
|
||||||
|
const history = [{}, {}];
|
||||||
|
spectator.setInput('history', history);
|
||||||
|
expect(spectator.queryAll('.log-entry')[0]).toHaveClass('first');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add class last to timeline-dot if it is the last log-entry and not the first', () => {
|
||||||
|
const history = [{}, {}];
|
||||||
|
spectator.setInput('history', history);
|
||||||
|
expect(spectator.queryLast('.log-entry').querySelector('.timeline-dot')).toHaveClass('last');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add class bottom-square if it is the last and first log-entry at the same time', () => {
|
||||||
|
const history = [{}];
|
||||||
|
spectator.setInput('history', history);
|
||||||
|
expect(spectator.queryLast('.timeline-dot')).toHaveClass('bottom-square');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('template', () => {
|
||||||
|
it('should render shared-history-log-entry and set Input historyLogEntryData', () => {
|
||||||
|
const history: HistoryDTO[] = [];
|
||||||
|
const historyLogEntryData: HistoryDTO = { id: 1 };
|
||||||
|
history.push(historyLogEntryData);
|
||||||
|
spectator.setInput('history', history);
|
||||||
|
spectator.detectComponentChanges();
|
||||||
|
expect(spectator.query(SharedHistoryLogEntryComponent).historyLogEntryData).toEqual(historyLogEntryData);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
14
apps/shared/history/src/lib/history-list.component.ts
Normal file
14
apps/shared/history/src/lib/history-list.component.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||||
|
import { HistoryDTO as CrmHistoryDTO } from '@swagger/crm';
|
||||||
|
import { HistoryDTO as OmsHistoryDTO } from '@swagger/oms';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'shared-history-list',
|
||||||
|
templateUrl: 'history-list.component.html',
|
||||||
|
styleUrls: ['history-list.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
})
|
||||||
|
export class SharedHistoryListComponent {
|
||||||
|
@Input() history: CrmHistoryDTO[] | OmsHistoryDTO[];
|
||||||
|
constructor() {}
|
||||||
|
}
|
||||||
13
apps/shared/history/src/lib/history-list.module.ts
Normal file
13
apps/shared/history/src/lib/history-list.module.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
|
import { SharedHistoryListComponent } from './history-list.component';
|
||||||
|
import { SharedHistoryLogEntryModule } from './history-log-entry';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [CommonModule, SharedHistoryLogEntryModule],
|
||||||
|
exports: [SharedHistoryListComponent],
|
||||||
|
declarations: [SharedHistoryListComponent],
|
||||||
|
providers: [],
|
||||||
|
})
|
||||||
|
export class SharedHistoryListModule {}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<p class="px-6 caption">{{ historyLogEntryValues?.caption }}</p>
|
||||||
|
<p class="pr-6 previous-value">
|
||||||
|
{{ historyLogEntryValues?.previousValue }}
|
||||||
|
</p>
|
||||||
|
<p class="pr-6 value">
|
||||||
|
{{ historyLogEntryValues?.value }}
|
||||||
|
</p>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
:host {
|
||||||
|
@apply grid grid-flow-col py-2;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import { createComponentFactory, Spectator } from '@ngneat/spectator';
|
||||||
|
import { SharedHistoryLogEntryValuesComponent } from '@shared/history';
|
||||||
|
import { DiffDTO as CrmDiffDTO } from '@swagger/crm';
|
||||||
|
import { DiffDTO as OmsDiffDTO } from '@swagger/oms';
|
||||||
|
|
||||||
|
describe('SharedHistoryLogEntryValuesComponent', () => {
|
||||||
|
let spectator: Spectator<SharedHistoryLogEntryValuesComponent>;
|
||||||
|
let historyValuesMock: CrmDiffDTO | OmsDiffDTO;
|
||||||
|
|
||||||
|
const createComponent = createComponentFactory({
|
||||||
|
component: SharedHistoryLogEntryValuesComponent,
|
||||||
|
imports: [],
|
||||||
|
declarations: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
spectator = createComponent();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(spectator.component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('values', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
historyValuesMock = {
|
||||||
|
caption: 'test',
|
||||||
|
previousValue: 'previous',
|
||||||
|
value: 'next',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render caption if caption exist', () => {
|
||||||
|
spectator.setInput('historyLogEntryValues', historyValuesMock);
|
||||||
|
expect(spectator.query('.caption')).toHaveText(historyValuesMock.caption);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render previousValue if previousValue exist', () => {
|
||||||
|
spectator.setInput('historyLogEntryValues', historyValuesMock);
|
||||||
|
expect(spectator.query('.previous-value')).toHaveText(historyValuesMock.previousValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render value if value exist', () => {
|
||||||
|
spectator.setInput('historyLogEntryValues', historyValuesMock);
|
||||||
|
expect(spectator.query('.value')).toHaveText(historyValuesMock.value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||||
|
import { DiffDTO as CrmDiffDTO } from '@swagger/crm';
|
||||||
|
import { DiffDTO as OmsDiffDTO } from '@swagger/oms';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'shared-history-log-entry-values',
|
||||||
|
templateUrl: 'history-log-entry-values.component.html',
|
||||||
|
styleUrls: ['history-log-entry-values.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
})
|
||||||
|
export class SharedHistoryLogEntryValuesComponent {
|
||||||
|
@Input() historyLogEntryValues: CrmDiffDTO | OmsDiffDTO;
|
||||||
|
constructor() {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
// start:ng42.barrel
|
||||||
|
export * from './history-log-entry-values.component';
|
||||||
|
// end:ng42.barrel
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<div class="w-full flex flex-row flex-grow mb-2">
|
||||||
|
<ng-container *ngIf="historyLogEntryData?.changed; else created">
|
||||||
|
<div class="flex flex-row font-bold mr-6">
|
||||||
|
<div class="flex flex-row whitespace-nowrap changed-timestamp">
|
||||||
|
{{ historyLogEntryData.changed | date }} <span class="separator font-normal">|</span>
|
||||||
|
{{ historyLogEntryData.changed | date: 'shortTime' }} Uhr
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-row">
|
||||||
|
<div class="flex flex-row changed-by" *ngIf="historyLogEntryData.changedBy">
|
||||||
|
Geändert von {{ historyLogEntryData.changedBy }}
|
||||||
|
<span *ngIf="historyLogEntryData.changedAt" class="separator">|</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-row changed-at" *ngIf="historyLogEntryData.changedAt">{{ historyLogEntryData.changedAt }}</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="details-container">
|
||||||
|
<div class="details-header">
|
||||||
|
<strong class="px-6 log-entry-name">{{ historyLogEntryData?.name ?? 'Geändertes Feld'}}</strong>
|
||||||
|
<div *ngIf="historyLogEntryData?.values?.length > 0" class="pr-6"><strong class="old-value">Alter Wert</strong></div>
|
||||||
|
<div *ngIf="historyLogEntryData?.values?.length > 0" class="pr-6"><strong class="new-value">Neuer Wert</strong></div>
|
||||||
|
</div>
|
||||||
|
<div class="details-values" [class.first]="isFirst" *ngFor="let values of historyLogEntryData?.values; first as isFirst">
|
||||||
|
<shared-history-log-entry-values [historyLogEntryValues]="values"></shared-history-log-entry-values>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-template #created>
|
||||||
|
<ng-container *ngIf="historyLogEntryData?.created">
|
||||||
|
<div class="flex flex-row font-bold mr-6">
|
||||||
|
<div class="flex flex-row whitespace-nowrap created-timestamp">
|
||||||
|
{{ historyLogEntryData.created | date }} <span class="separator font-normal">|</span>
|
||||||
|
{{ historyLogEntryData.created | date: 'shortTime' }} Uhr
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-row">
|
||||||
|
<div class="flex flex-row created-by" *ngIf="historyLogEntryData.createdBy">
|
||||||
|
Angelegt von {{ historyLogEntryData.createdBy }}
|
||||||
|
<span *ngIf="historyLogEntryData.createdAt" class="separator">|</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-row created-at" *ngIf="historyLogEntryData.createdAt">{{ historyLogEntryData.createdAt }}</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</ng-template>
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
.separator {
|
||||||
|
@apply -mt-px-2;
|
||||||
|
color: #aeb7c1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.details-container {
|
||||||
|
@apply bg-white flex flex-col break-all;
|
||||||
|
box-shadow: 0px 6px 24px rgba(206, 212, 219, 0.8);
|
||||||
|
border-radius: 0px 5px 5px 5px;
|
||||||
|
|
||||||
|
.details-header {
|
||||||
|
@apply grid grid-flow-col py-3;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
|
|
||||||
|
.old-value {
|
||||||
|
@apply rounded-card text-white py-1 px-4;
|
||||||
|
background-color: #89949e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-value {
|
||||||
|
@apply rounded-card text-white py-1 px-4;
|
||||||
|
background-color: #134563;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.details-values {
|
||||||
|
&:nth-child(even) {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.first {
|
||||||
|
@apply border-t-2 border-solid;
|
||||||
|
border-color: #d8dfe5;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
import { createComponentFactory, Spectator } from '@ngneat/spectator';
|
||||||
|
import { SharedHistoryLogEntryComponent, SharedHistoryLogEntryValuesComponent } from '@shared/history';
|
||||||
|
import { DiffDTO, HistoryDTO as CrmHistoryDTO, HistoryDTO } from '@swagger/crm';
|
||||||
|
import { HistoryDTO as OmsHistoryDTO } from '@swagger/oms';
|
||||||
|
import { DatePipe } from '@angular/common';
|
||||||
|
import { registerLocaleData } from '@angular/common';
|
||||||
|
import localeDe from '@angular/common/locales/de';
|
||||||
|
import localeDeExtra from '@angular/common/locales/extra/de';
|
||||||
|
import { LOCALE_ID } from '@angular/core';
|
||||||
|
|
||||||
|
registerLocaleData(localeDe, 'de-DE', localeDeExtra);
|
||||||
|
|
||||||
|
describe('SharedHistoryLogEntryComponent', () => {
|
||||||
|
let spectator: Spectator<SharedHistoryLogEntryComponent>;
|
||||||
|
let historyMock: CrmHistoryDTO | OmsHistoryDTO;
|
||||||
|
const datePipe = new DatePipe('de-DE');
|
||||||
|
|
||||||
|
const createComponent = createComponentFactory({
|
||||||
|
component: SharedHistoryLogEntryComponent,
|
||||||
|
imports: [],
|
||||||
|
declarations: [SharedHistoryLogEntryValuesComponent],
|
||||||
|
providers: [{ provide: LOCALE_ID, useValue: 'de-DE' }],
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
spectator = createComponent();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(spectator.component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('log-entry', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
historyMock = {};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('type changed', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
historyMock = {
|
||||||
|
changed: '2022-11-16T14:49:35.6895',
|
||||||
|
changedAt: 'test-system',
|
||||||
|
changedBy: 'test-user',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not render created log-entry', () => {
|
||||||
|
expect(spectator.query('.created-timestamp')).not.toBeVisible();
|
||||||
|
expect(spectator.query('.created-by')).not.toBeVisible();
|
||||||
|
expect(spectator.query('.created-at')).not.toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render changed-timestamp', () => {
|
||||||
|
const date = datePipe.transform(historyMock.changed);
|
||||||
|
const time = datePipe.transform(historyMock.changed, 'shortTime');
|
||||||
|
const changedTimestamp = date + ' | ' + time + ' Uhr';
|
||||||
|
spectator.setInput('historyLogEntryData', historyMock);
|
||||||
|
expect(spectator.query('.changed-timestamp')).toHaveText(changedTimestamp);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render changed-by', () => {
|
||||||
|
const changedBy = historyMock.changedBy + ' |';
|
||||||
|
spectator.setInput('historyLogEntryData', historyMock);
|
||||||
|
expect(spectator.query('.changed-by')).toHaveText(changedBy);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render changed-at', () => {
|
||||||
|
const changedAt = historyMock.changedAt;
|
||||||
|
spectator.setInput('historyLogEntryData', historyMock);
|
||||||
|
expect(spectator.query('.changed-at')).toHaveText(changedAt);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('type created', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
historyMock = {
|
||||||
|
created: '2022-11-16T14:49:35.6895',
|
||||||
|
createdAt: 'test-system',
|
||||||
|
createdBy: 'test-user',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not render changed log-entry', () => {
|
||||||
|
expect(spectator.query('.changed-timestamp')).not.toBeVisible();
|
||||||
|
expect(spectator.query('.changed-by')).not.toBeVisible();
|
||||||
|
expect(spectator.query('.changed-at')).not.toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render created-timestamp', () => {
|
||||||
|
const date = datePipe.transform(historyMock.created);
|
||||||
|
const time = datePipe.transform(historyMock.created, 'shortTime');
|
||||||
|
const createdTimestamp = date + ' | ' + time + ' Uhr';
|
||||||
|
spectator.setInput('historyLogEntryData', historyMock);
|
||||||
|
expect(spectator.query('.created-timestamp')).toHaveText(createdTimestamp);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render created-by', () => {
|
||||||
|
const createdBy = historyMock.createdBy + ' |';
|
||||||
|
spectator.setInput('historyLogEntryData', historyMock);
|
||||||
|
expect(spectator.query('.created-by')).toHaveText(createdBy);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render created-at', () => {
|
||||||
|
const createdAt = historyMock.createdAt;
|
||||||
|
spectator.setInput('historyLogEntryData', historyMock);
|
||||||
|
expect(spectator.query('.created-at')).toHaveText(createdAt);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render log-entry-name if available', () => {
|
||||||
|
historyMock = {
|
||||||
|
name: 'test-name',
|
||||||
|
};
|
||||||
|
spectator.setInput('historyLogEntryData', historyMock);
|
||||||
|
expect(spectator.query('.log-entry-name')).toHaveText('test-name');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should instead render Geändertes Feld if log-entry-name is not available', () => {
|
||||||
|
spectator.setInput('historyLogEntryData', historyMock);
|
||||||
|
expect(spectator.query('.log-entry-name')).toHaveText('Geändertes Feld');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not render old and new value if no log-entry-values are available', () => {
|
||||||
|
spectator.setInput('historyLogEntryData', historyMock);
|
||||||
|
expect(spectator.query('.old-value')).not.toBeVisible();
|
||||||
|
expect(spectator.query('.new-value')).not.toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render shared-history-log-entry-values if log-entry-values are available', () => {
|
||||||
|
historyMock = {
|
||||||
|
values: [{}, {}],
|
||||||
|
};
|
||||||
|
spectator.setInput('historyLogEntryData', historyMock);
|
||||||
|
expect(spectator.query('shared-history-log-entry-values')).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render shared-history-log-entry-values and set Input historyLogEntryValues', () => {
|
||||||
|
const historyLogEntryValues: DiffDTO = { value: 'Test' };
|
||||||
|
const history: HistoryDTO = { id: 1, values: [historyLogEntryValues] };
|
||||||
|
spectator.setInput('historyLogEntryData', history);
|
||||||
|
spectator.detectComponentChanges();
|
||||||
|
expect(spectator.query(SharedHistoryLogEntryValuesComponent).historyLogEntryValues).toEqual(historyLogEntryValues);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
|
||||||
|
import { HistoryDTO as CrmHistoryDTO } from '@swagger/crm';
|
||||||
|
import { HistoryDTO as OmsHistoryDTO } from '@swagger/oms';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'shared-history-log-entry',
|
||||||
|
templateUrl: 'history-log-entry.component.html',
|
||||||
|
styleUrls: ['history-log-entry.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
})
|
||||||
|
export class SharedHistoryLogEntryComponent {
|
||||||
|
@Input() historyLogEntryData: CrmHistoryDTO | OmsHistoryDTO;
|
||||||
|
constructor() {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { SharedHistoryLogEntryValuesComponent } from './history-log-entry-values';
|
||||||
|
import { SharedHistoryLogEntryComponent } from './history-log-entry.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [CommonModule],
|
||||||
|
exports: [SharedHistoryLogEntryComponent, SharedHistoryLogEntryValuesComponent],
|
||||||
|
declarations: [SharedHistoryLogEntryComponent, SharedHistoryLogEntryValuesComponent],
|
||||||
|
providers: [],
|
||||||
|
})
|
||||||
|
export class SharedHistoryLogEntryModule {}
|
||||||
5
apps/shared/history/src/lib/history-log-entry/index.ts
Normal file
5
apps/shared/history/src/lib/history-log-entry/index.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
// start:ng42.barrel
|
||||||
|
export * from './history-log-entry.component';
|
||||||
|
export * from './history-log-entry.module';
|
||||||
|
export * from './history-log-entry-values';
|
||||||
|
// end:ng42.barrel
|
||||||
5
apps/shared/history/src/lib/index.ts
Normal file
5
apps/shared/history/src/lib/index.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
// start:ng42.barrel
|
||||||
|
export * from './history-list.component';
|
||||||
|
export * from './history-list.module';
|
||||||
|
export * from './history-log-entry';
|
||||||
|
// end:ng42.barrel
|
||||||
5
apps/shared/history/src/public-api.ts
Normal file
5
apps/shared/history/src/public-api.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
/*
|
||||||
|
* Public API Surface of history
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './lib';
|
||||||
14
apps/shared/history/tsconfig.lib.json
Normal file
14
apps/shared/history/tsconfig.lib.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/* 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": []
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"**/*.spec.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
10
apps/shared/history/tsconfig.lib.prod.json
Normal file
10
apps/shared/history/tsconfig.lib.prod.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.lib.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"declarationMap": false
|
||||||
|
},
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
"compilationMode": "partial"
|
||||||
|
}
|
||||||
|
}
|
||||||
14
apps/shared/history/tsconfig.spec.json
Normal file
14
apps/shared/history/tsconfig.spec.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||||
|
{
|
||||||
|
"extends": "../../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../../out-tsc/spec",
|
||||||
|
"types": [
|
||||||
|
"jasmine"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"**/*.spec.ts",
|
||||||
|
"**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -2,8 +2,12 @@
|
|||||||
import { DiffDTO } from './diff-dto';
|
import { DiffDTO } from './diff-dto';
|
||||||
export interface HistoryDTO {
|
export interface HistoryDTO {
|
||||||
changed?: string;
|
changed?: string;
|
||||||
|
changedAt?: string;
|
||||||
changedBy?: string;
|
changedBy?: string;
|
||||||
changeset?: number;
|
changeset?: number;
|
||||||
|
created?: string;
|
||||||
|
createdAt?: string;
|
||||||
|
createdBy?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
histDate?: string;
|
histDate?: string;
|
||||||
historyset?: number;
|
historyset?: number;
|
||||||
|
|||||||
@@ -2,8 +2,12 @@
|
|||||||
import { DiffDTO } from './diff-dto';
|
import { DiffDTO } from './diff-dto';
|
||||||
export interface HistoryDTO {
|
export interface HistoryDTO {
|
||||||
changed?: string;
|
changed?: string;
|
||||||
|
changedAt?: string;
|
||||||
changedBy?: string;
|
changedBy?: string;
|
||||||
changeset?: number;
|
changeset?: number;
|
||||||
|
created?: string;
|
||||||
|
createdAt?: string;
|
||||||
|
createdBy?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
histDate?: string;
|
histDate?: string;
|
||||||
historyset?: number;
|
historyset?: number;
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ export class UiModalConfig extends OverlayConfig {
|
|||||||
backdropClose?: boolean;
|
backdropClose?: boolean;
|
||||||
showScrollbarX?: boolean;
|
showScrollbarX?: boolean;
|
||||||
showScrollbarY?: boolean;
|
showScrollbarY?: boolean;
|
||||||
|
padding?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Component, ChangeDetectionStrategy, OnInit, TemplateRef, Type, ChangeDetectorRef, OnDestroy } from '@angular/core';
|
import { Component, ChangeDetectionStrategy, OnInit, TemplateRef, Type, ChangeDetectorRef, OnDestroy, HostBinding } from '@angular/core';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { UiModalRef } from './defs/modal-ref';
|
import { UiModalRef } from './defs/modal-ref';
|
||||||
|
|
||||||
@@ -55,4 +55,8 @@ export class UiModalComponent implements OnInit, OnDestroy {
|
|||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.subscription.unsubscribe();
|
this.subscription.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@HostBinding('style') get class() {
|
||||||
|
return !this.ref?.config?.padding ? 'padding: 0px' : '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export class UiModalService {
|
|||||||
showScrollbarX: false,
|
showScrollbarX: false,
|
||||||
showScrollbarY: true,
|
showScrollbarY: true,
|
||||||
canClose: true,
|
canClose: true,
|
||||||
|
padding: true,
|
||||||
...config,
|
...config,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
20282
package-lock.json
generated
20282
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -147,6 +147,9 @@
|
|||||||
"@shell/process": [
|
"@shell/process": [
|
||||||
"apps/shell/process/src/public-api.ts"
|
"apps/shell/process/src/public-api.ts"
|
||||||
],
|
],
|
||||||
|
"@shared/history": [
|
||||||
|
"apps/shared/history/src/public-api.ts"
|
||||||
|
],
|
||||||
"@ui/toggle": [
|
"@ui/toggle": [
|
||||||
"apps/ui/toggle/src/public-api.ts"
|
"apps/ui/toggle/src/public-api.ts"
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user