mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Merge branch 'develop' into release/1.5
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { fromEvent } from 'rxjs';
|
||||
import { map, take } from 'rxjs/operators';
|
||||
import { map, take, tap } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@@ -8,16 +8,17 @@ import { map, take } from 'rxjs/operators';
|
||||
export class EnvironmentService {
|
||||
constructor() {}
|
||||
|
||||
/** Returns whether app is used within native container*/
|
||||
isNative(): Promise<boolean> {
|
||||
return fromEvent(window, 'message')
|
||||
.pipe(
|
||||
map((evt: MessageEvent) => evt.data),
|
||||
map((data) => data.status === 'INIT'),
|
||||
take(1)
|
||||
)
|
||||
.toPromise();
|
||||
}
|
||||
// /** Returns whether app is used within native container*/
|
||||
// isNative(): Promise<boolean> {
|
||||
// return fromEvent(window, 'message')
|
||||
// .pipe(
|
||||
// map((evt: MessageEvent) => evt.data),
|
||||
// tap(console.log.bind(window)),
|
||||
// map((data) => data.status === 'INIT'),
|
||||
// take(1)
|
||||
// )
|
||||
// .toPromise();
|
||||
// }
|
||||
|
||||
/** Returns whether current device is mobile phone or tablet */
|
||||
async isMobile(): Promise<boolean> {
|
||||
|
||||
@@ -45,6 +45,8 @@ export class ReOrderActionHandler extends ActionHandler<OrderItemsContext> {
|
||||
context = await this._command.handleCommand('NOTAVAILABLE', context);
|
||||
updatedItems.push(...context.items);
|
||||
}
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export type ProcessingStatusType = 'Approved' | 'InProcess' | 'Completed' | 'Overdue' | 'Archived' | 'Uncompleted';
|
||||
export type ProcessingStatusType = 'Approved' | 'InProcess' | 'Completed' | 'Overdue' | 'Archived' | 'Uncompleted' | 'Removed';
|
||||
|
||||
export type ProcessingStatusList = ProcessingStatusType[];
|
||||
|
||||
@@ -168,6 +168,10 @@ export class DomainTaskCalendarService {
|
||||
processingStatusList.push('Archived');
|
||||
}
|
||||
|
||||
if (!!(processingStatus & 32)) {
|
||||
processingStatusList.push('Removed');
|
||||
}
|
||||
|
||||
if (!!(processingStatus & 64)) {
|
||||
processingStatusList.push('Uncompleted');
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { CommandService } from '@core/command';
|
||||
import { OrderItemsContext } from '@domain/oms';
|
||||
@@ -64,12 +63,7 @@ export class GoodsInCleanupListComponent implements OnInit, OnDestroy {
|
||||
|
||||
private _onDestroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
private _store: GoodsInCleanupListStore,
|
||||
private _commandService: CommandService,
|
||||
private _router: Router
|
||||
) {}
|
||||
constructor(private _breadcrumb: BreadcrumbService, private _store: GoodsInCleanupListStore, private _commandService: CommandService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.initInitialSearch();
|
||||
@@ -94,11 +88,7 @@ export class GoodsInCleanupListComponent implements OnInit, OnDestroy {
|
||||
initInitialSearch() {
|
||||
if (this._store.hits === 0) {
|
||||
this._store.searchResult$.pipe(takeUntil(this._onDestroy$)).subscribe(async (result) => {
|
||||
if (result.hits === 0) {
|
||||
await this._router.navigate(['/goods/in']);
|
||||
} else {
|
||||
await this.updateBreadcrumb();
|
||||
}
|
||||
await this.updateBreadcrumb();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,10 @@ import { CommandService } from '@core/command';
|
||||
import { DomainOmsService } from '@domain/oms';
|
||||
import { ComponentStore } from '@ngrx/component-store';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
||||
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
|
||||
import { isEqual } from 'lodash';
|
||||
import { Subject } from 'rxjs';
|
||||
import { catchError, first, shareReplay, switchMap, takeUntil } from 'rxjs/operators';
|
||||
import { catchError, first, shareReplay, switchMap } from 'rxjs/operators';
|
||||
|
||||
interface GoodsInListItemComponentState {
|
||||
item: OrderItemListItemDTO;
|
||||
@@ -114,7 +115,7 @@ export class GoodsInListItemComponent extends ComponentStore<GoodsInListItemComp
|
||||
|
||||
private _onDestroy$ = new Subject();
|
||||
|
||||
constructor(private _omsService: DomainOmsService, private _command: CommandService) {
|
||||
constructor(private _omsService: DomainOmsService, private _command: CommandService, private _modal: UiModalService) {
|
||||
super({
|
||||
item: undefined,
|
||||
editSsc: false,
|
||||
@@ -153,7 +154,14 @@ export class GoodsInListItemComponent extends ComponentStore<GoodsInListItemComp
|
||||
}
|
||||
|
||||
async showReorderModal() {
|
||||
await this._command.handleCommand('REORDER', { items: [this.item] });
|
||||
this.refresh.emit();
|
||||
try {
|
||||
await this._command.handleCommand('REORDER', { items: [this.item] });
|
||||
this.refresh.emit();
|
||||
} catch (e) {
|
||||
this._modal.open({
|
||||
content: UiErrorModalComponent,
|
||||
data: e,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,26 @@
|
||||
<div class="list-count">{{ hits$ | async }} Titel</div>
|
||||
|
||||
<ui-scroll-container [loading]="loading$ | async" (reachEnd)="loadMore()" [deltaEnd]="150" [itemLength]="itemLength$ | async">
|
||||
<ui-scroll-container
|
||||
*ngIf="!(listEmpty$ | async); else emptyMessage"
|
||||
[loading]="loading$ | async"
|
||||
(reachEnd)="loadMore()"
|
||||
[deltaEnd]="150"
|
||||
[itemLength]="itemLength$ | async"
|
||||
>
|
||||
<ng-container *ngFor="let item of items$ | async">
|
||||
<goods-in-list-item [item]="item" [editSsc]="editSsc" (refresh)="refreshList()"></goods-in-list-item>
|
||||
<hr />
|
||||
</ng-container>
|
||||
</ui-scroll-container>
|
||||
|
||||
<div class="actions">
|
||||
<ng-template #emptyMessage>
|
||||
<div class="empty-message">
|
||||
Momentan steht kein Bestellposten zur Nachbearbeitung aus.<br />
|
||||
Alle Bestellposten sind ordnungsgemäß bearbeitet.
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<div *ngIf="!(listEmpty$ | async)" class="actions">
|
||||
<button *ngIf="!editSsc" class="cta-edit-ssc cta-action-primary" (click)="editSsc = true">
|
||||
Meldenummern vergeben
|
||||
</button>
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
@apply bg-white;
|
||||
}
|
||||
|
||||
.empty-message {
|
||||
@apply bg-white text-center font-semibold text-inactive-branch py-10 rounded-card;
|
||||
}
|
||||
|
||||
hr {
|
||||
@apply bg-branch;
|
||||
height: 2px;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { AfterViewInit, ChangeDetectionStrategy, Component, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { DomainOmsService } from '@domain/oms';
|
||||
import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs';
|
||||
@@ -25,6 +24,11 @@ export class GoodsInListComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
loading$ = this._store.loading$.pipe(shareReplay());
|
||||
|
||||
listEmpty$ = combineLatest([this.loading$, this.hits$]).pipe(
|
||||
map(([loading, hits]) => !loading && hits === 0),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
editSsc: boolean;
|
||||
|
||||
editSscDisabled$: Observable<boolean>;
|
||||
@@ -33,12 +37,7 @@ export class GoodsInListComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
private _onDestroy$ = new Subject();
|
||||
|
||||
constructor(
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
private _domainOmsService: DomainOmsService,
|
||||
private _store: GoodsInListStore,
|
||||
private _router: Router
|
||||
) {}
|
||||
constructor(private _breadcrumb: BreadcrumbService, private _domainOmsService: DomainOmsService, private _store: GoodsInListStore) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.initInitialSearch();
|
||||
@@ -67,19 +66,16 @@ export class GoodsInListComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
registerEditSscDisabled() {
|
||||
this.editSscDisabled$ = combineLatest(this.listItems.map((item) => item.sscInvalid$)).pipe(
|
||||
map((items) => items.includes(true) || this.listItems.filter((i) => i.sscChanged).length === 0)
|
||||
);
|
||||
this.editSscDisabled$ = combineLatest([
|
||||
combineLatest(this.listItems.map((item) => item.sscInvalid$)),
|
||||
combineLatest(this.listItems.map((item) => item.sscChanged$)),
|
||||
]).pipe(map(([sscInvalid, sscChanged]) => sscInvalid.includes(true) || sscChanged.every((item) => !item)));
|
||||
}
|
||||
|
||||
initInitialSearch() {
|
||||
if (this._store.hits === 0) {
|
||||
this._store.searchResult$.pipe(takeUntil(this._onDestroy$)).subscribe(async (result) => {
|
||||
if (result.hits === 0) {
|
||||
await this._router.navigate(['/goods/in']);
|
||||
} else {
|
||||
await this.updateBreadcrumb();
|
||||
}
|
||||
await this.updateBreadcrumb();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -118,13 +118,9 @@ export class GoodsInReservationComponent implements OnInit, OnDestroy {
|
||||
initInitialSearch() {
|
||||
if (this._store.hits === 0) {
|
||||
this._store.searchResult$.pipe(takeUntil(this._onDestroy$)).subscribe(async (result) => {
|
||||
if (result.hits === 0) {
|
||||
await this._router.navigate(['/goods/in']);
|
||||
} else {
|
||||
await this.updateBreadcrumb();
|
||||
if (result.hits === 1) {
|
||||
this.navigateToDetails(result.result[0]);
|
||||
}
|
||||
await this.updateBreadcrumb();
|
||||
if (result.hits === 1) {
|
||||
this.navigateToDetails(result.result[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
.search-main {
|
||||
@apply bg-white text-center rounded-t-card py-5 shadow-card;
|
||||
height: calc(100vh - 500px);
|
||||
height: calc(100vh - 495px);
|
||||
|
||||
.search-main-title {
|
||||
@apply text-2xl font-bold;
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
<div class="hits">{{ hits$ | async }} Titel</div>
|
||||
<ui-scroll-container [loading]="loading$ | async" (reachEnd)="loadMore()" [deltaEnd]="150" [itemLength]="(items$ | async).length">
|
||||
<ui-scroll-container
|
||||
*ngIf="!(listEmpty$ | async); else emptyMessage"
|
||||
[loading]="loading$ | async"
|
||||
(reachEnd)="loadMore()"
|
||||
[deltaEnd]="150"
|
||||
[itemLength]="(items$ | async).length"
|
||||
>
|
||||
<shared-goods-in-out-order-group *ngFor="let bueryNumberGroup of items$ | async | groupBy: byBuyerNumberFn">
|
||||
<ng-container *ngFor="let orderNumberGroup of bueryNumberGroup.items | groupBy: byOrderNumberFn; let lastOrderNumber = last">
|
||||
<ng-container
|
||||
@@ -23,3 +29,10 @@
|
||||
</ng-container>
|
||||
</shared-goods-in-out-order-group>
|
||||
</ui-scroll-container>
|
||||
|
||||
<ng-template #emptyMessage>
|
||||
<div class="empty-message">
|
||||
Es sind im Moment keine Bestellposten vorhanden,<br />
|
||||
die bearbeitet werden können.
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
@apply text-active-branch text-right mb-3 font-semibold text-base;
|
||||
}
|
||||
|
||||
.empty-message {
|
||||
@apply bg-white text-center font-semibold text-inactive-branch py-10 rounded-card;
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy } from '@angular/core';
|
||||
import { first, shareReplay, takeUntil } from 'rxjs/operators';
|
||||
import { first, map, shareReplay, takeUntil } from 'rxjs/operators';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { GoodsInSearchStore } from '../goods-in-search.store';
|
||||
import { Subject } from 'rxjs';
|
||||
import { combineLatest, Subject } from 'rxjs';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
|
||||
@Component({
|
||||
@@ -19,6 +19,11 @@ export class GoodsInSearchResultsComponent implements OnInit, OnDestroy {
|
||||
|
||||
loading$ = this._goodsInSearchStore.fetching$.pipe(shareReplay());
|
||||
|
||||
listEmpty$ = combineLatest([this.loading$, this.hits$]).pipe(
|
||||
map(([loading, hits]) => !loading && hits === 0),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
byBuyerNumberFn = (item: OrderItemListItemDTO) => item.buyerNumber;
|
||||
|
||||
byOrderNumberFn = (item: OrderItemListItemDTO) => item.orderNumber;
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
<div class="hits">{{ hits$ | async }} Titel</div>
|
||||
<ui-scroll-container [loading]="loading$ | async" (reachEnd)="loadMore()" [deltaEnd]="150" [itemLength]="itemLength$ | async">
|
||||
<ui-scroll-container
|
||||
*ngIf="!(listEmpty$ | async); else emptyMessage"
|
||||
[loading]="loading$ | async"
|
||||
(reachEnd)="loadMore()"
|
||||
[deltaEnd]="150"
|
||||
[itemLength]="itemLength$ | async"
|
||||
>
|
||||
<shared-goods-in-out-order-group *ngFor="let bueryNumberGroup of items$ | async | groupBy: byBuyerNumberFn">
|
||||
<ng-container *ngFor="let orderNumberGroup of bueryNumberGroup.items | groupBy: byOrderNumberFn; let lastOrderNumber = last">
|
||||
<ng-container
|
||||
@@ -26,6 +32,13 @@
|
||||
</shared-goods-in-out-order-group>
|
||||
</ui-scroll-container>
|
||||
|
||||
<ng-template #emptyMessage>
|
||||
<div class="empty-message">
|
||||
Es sind im Moment keine Bestellposten vorhanden,<br />
|
||||
die bearbeitet werden können.
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<div class="actions" *ngIf="actions$ | async; let actions">
|
||||
<button
|
||||
[disabled]="(loadingFetchedActionButton$ | async) || (loading$ | async)"
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
@apply text-active-customer text-right mb-3 font-semibold text-base;
|
||||
}
|
||||
|
||||
.empty-message {
|
||||
@apply bg-white text-center font-semibold text-inactive-customer py-10 rounded-card;
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,11 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
|
||||
loading$ = this._goodsOutSearchStore.fetching$.pipe(shareReplay());
|
||||
loadingFetchedActionButton$ = new BehaviorSubject<boolean>(false);
|
||||
|
||||
listEmpty$ = combineLatest([this.loading$, this.hits$]).pipe(
|
||||
map(([loading, hits]) => !loading && hits === 0),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
selectedOrderItemSubsetIds$ = this.select((s) => s.selectedOrderItemSubsetIds);
|
||||
|
||||
get selectedOrderItemSubsetIds() {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
:host {
|
||||
@apply flex flex-col;
|
||||
|
||||
&.Removed {
|
||||
@apply opacity-30;
|
||||
}
|
||||
}
|
||||
|
||||
.info-header {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Clipboard } from '@angular/cdk/clipboard';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { Component, ChangeDetectionStrategy, Input, OnChanges, SimpleChanges, Optional } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, Input, OnChanges, SimpleChanges, Optional, HostBinding } from '@angular/core';
|
||||
import { DomainTaskCalendarService } from '@domain/task-calendar';
|
||||
import { FileDTO } from '@swagger/checkout';
|
||||
import { DisplayInfoDTO } from '@swagger/eis';
|
||||
@@ -108,6 +108,11 @@ export class TaskInfoComponent implements OnChanges {
|
||||
)
|
||||
);
|
||||
|
||||
@HostBinding('class')
|
||||
get statusClass() {
|
||||
return this.domainTaskCalendarService.getProcessingStatusList(this.info);
|
||||
}
|
||||
|
||||
constructor(
|
||||
private dateAdapter: DateAdapter,
|
||||
private datePipe: DatePipe,
|
||||
|
||||
@@ -32,3 +32,21 @@
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="isToday$ | async">
|
||||
<div class="task-list ongoing-list" *ngIf="ongoingItems$ | async; let ongoingItems">
|
||||
<div class="head-row">
|
||||
<div class="head-row-title">
|
||||
<h4>Laufende Aufgaben</h4>
|
||||
</div>
|
||||
<div class="head-row-info">
|
||||
<span class="muted"> {{ ongoingItems?.length }} Aufgaben </span>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<ng-container *ngFor="let item of ongoingItems">
|
||||
<page-task-list-item [item]="item" (click)="select.emit(item)"></page-task-list-item>
|
||||
<hr />
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
@@ -42,3 +42,11 @@
|
||||
@apply opacity-30;
|
||||
}
|
||||
}
|
||||
|
||||
.task-list ::ng-deep page-task-list-item.Removed {
|
||||
.date,
|
||||
.shirt-size,
|
||||
.task-content {
|
||||
@apply opacity-30 line-through;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,13 +55,35 @@ export class TaskListComponent {
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}),
|
||||
map((list) => list.sort(this.moveRemovedToEnd.bind(this)))
|
||||
);
|
||||
|
||||
ongoingItems$ = combineLatest([this.items$, this.selected$]).pipe(
|
||||
map(([items, selectedDate]) => {
|
||||
// Filter Aufgaben die vor dem aktuellen Tag gestartet sind und nicht überfällig oder abgeschlossen sind
|
||||
const list = items.filter((item) => {
|
||||
const type = this.domainTaskCalendarService.getInfoType(item);
|
||||
const processingStatus = this.domainTaskCalendarService.getProcessingStatusList(item);
|
||||
if (
|
||||
type === 'Task' &&
|
||||
processingStatus.includes('InProcess') &&
|
||||
!processingStatus.includes('Overdue') &&
|
||||
!processingStatus.includes('Completed')
|
||||
) {
|
||||
return new Date(item.taskDate) < this.today;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return this.sort(list, ['Overdue', 'InProcess', 'Approved', 'Completed']);
|
||||
})
|
||||
);
|
||||
|
||||
selectedItems$ = combineLatest([this.items$, this.selected$]).pipe(
|
||||
map(([items, date]) => items.filter((item) => this.dateAdapter.equals(this.domainTaskCalendarService.getDisplayInfoDate(item), date))),
|
||||
// Sortierung der aufgaben nach Rot => Gelb => Grau => Grün
|
||||
map((list) => this.sort(list, ['Overdue', 'InProcess', 'Approved', 'Completed']))
|
||||
map((list) => this.sort(list, ['Overdue', 'InProcess', 'Approved', 'Completed', 'Removed'])),
|
||||
map((list) => list.sort(this.moveRemovedToEnd.bind(this)))
|
||||
);
|
||||
|
||||
@Output()
|
||||
@@ -75,6 +97,21 @@ export class TaskListComponent {
|
||||
private domainPrinterService: DomainPrinterService
|
||||
) {}
|
||||
|
||||
moveRemovedToEnd(a: DisplayInfoDTO, b: DisplayInfoDTO) {
|
||||
const statusA = this.domainTaskCalendarService.getProcessingStatusList(a)?.includes('Removed');
|
||||
const statusB = this.domainTaskCalendarService.getProcessingStatusList(b)?.includes('Removed');
|
||||
|
||||
if (statusA && statusB) {
|
||||
return 0;
|
||||
} else if (statusA && !statusB) {
|
||||
return 1;
|
||||
} else if (!statusA && statusB) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Array of DisplayInfoDTO, sorted by ProcessingStatus
|
||||
* Ignores Overdue if Task is already Completed
|
||||
@@ -85,8 +122,9 @@ export class TaskListComponent {
|
||||
*/
|
||||
sort(items: DisplayInfoDTO[], order: ProcessingStatusList) {
|
||||
let result = [...items];
|
||||
const reversedOrder = [...order].reverse();
|
||||
|
||||
for (const status of [...order].reverse()) {
|
||||
for (const status of reversedOrder) {
|
||||
result = result?.sort((a, b) => {
|
||||
const statusA = this.domainTaskCalendarService.getProcessingStatusList(a);
|
||||
const statusB = this.domainTaskCalendarService.getProcessingStatusList(b);
|
||||
|
||||
@@ -4,4 +4,10 @@
|
||||
<ui-icon *ngIf="info?.updateComment" icon="refresh" size="22px"></ui-icon>
|
||||
</div>
|
||||
<page-task-info [info]="info"></page-task-info>
|
||||
<button type="button" (click)="close()"><ui-icon icon="close" size="16px"></ui-icon></button>
|
||||
<button class="btn-close" type="button" (click)="close()"><ui-icon icon="close" size="16px"></ui-icon></button>
|
||||
|
||||
<div class="actions">
|
||||
<button *ngIf="showOpenSuccessorCta$ | async" class="btn-cta" type="button" (click)="close(info.successor?.id)">
|
||||
Zur neuen Aufgabe
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
:host {
|
||||
@apply flex flex-col relative;
|
||||
|
||||
&.Removed {
|
||||
h1 {
|
||||
@apply opacity-30 line-through;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -18,10 +24,18 @@ h3 {
|
||||
@apply absolute m-0 -top-4 p-4 pl-0 text-regular text-active-branch uppercase;
|
||||
}
|
||||
|
||||
button {
|
||||
.btn-close {
|
||||
@apply absolute -top-4 -right-4 p-4 outline-none border-none bg-transparent;
|
||||
|
||||
ui-icon {
|
||||
@apply text-inactive-branch;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
@apply text-center mb-5 mt-6 sticky bottom-1;
|
||||
|
||||
.btn-cta {
|
||||
@apply bg-brand text-white font-bold text-lg outline-none border-none rounded-full px-6 py-3;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, HostBinding } from '@angular/core';
|
||||
import { DomainTaskCalendarService } from '@domain/task-calendar';
|
||||
import { DisplayInfoDTO } from '@swagger/eis';
|
||||
import { UiModalRef } from '@ui/modal';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { combineLatest, ReplaySubject } from 'rxjs';
|
||||
import { map, shareReplay } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'page-info-modal',
|
||||
@@ -12,11 +14,31 @@ import { Subscription } from 'rxjs';
|
||||
export class InfoModalComponent {
|
||||
info: DisplayInfoDTO;
|
||||
|
||||
constructor(private modalRef: UiModalRef<DisplayInfoDTO>) {
|
||||
this.info = this.modalRef.data;
|
||||
info$ = new ReplaySubject<DisplayInfoDTO>();
|
||||
|
||||
processingStatus$ = this.info$.pipe(
|
||||
map((info) => this.domainTaskCalendarService.getProcessingStatusList(info)),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
showOpenSuccessorCta$ = combineLatest([this.processingStatus$, this.info$]).pipe(
|
||||
map(([processingStatus, info]) => processingStatus.includes('Removed') && !!info.successor?.id)
|
||||
);
|
||||
|
||||
@HostBinding('class')
|
||||
get statusClass() {
|
||||
return this.domainTaskCalendarService.getProcessingStatusList(this.info);
|
||||
}
|
||||
|
||||
close() {
|
||||
this.modalRef.close();
|
||||
constructor(
|
||||
private modalRef: UiModalRef<{ successorId: number }, DisplayInfoDTO>,
|
||||
private domainTaskCalendarService: DomainTaskCalendarService
|
||||
) {
|
||||
this.info = this.modalRef.data;
|
||||
this.info$.next(this.info);
|
||||
}
|
||||
|
||||
close(successorId: number = undefined) {
|
||||
this.modalRef.close({ successorId });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,4 +4,10 @@
|
||||
<ui-icon *ngIf="info?.updateComment" icon="refresh" size="22px"></ui-icon>
|
||||
</div>
|
||||
<page-task-info [info]="info" showTaskDate="true"></page-task-info>
|
||||
<button type="button" (click)="close()"><ui-icon icon="close" size="16px"></ui-icon></button>
|
||||
<button class="btn-close" type="button" (click)="close()"><ui-icon icon="close" size="16px"></ui-icon></button>
|
||||
|
||||
<div class="actions">
|
||||
<button *ngIf="showOpenSuccessorCta$ | async" class="btn-cta" type="button" (click)="close(info.successor?.id)">
|
||||
Zur neuen Aufgabe
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
:host {
|
||||
@apply flex flex-col relative;
|
||||
|
||||
&.Removed {
|
||||
h1 {
|
||||
@apply opacity-30 line-through;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -18,10 +24,18 @@ h3 {
|
||||
@apply absolute m-0 -top-4 p-4 pl-0 text-regular text-active-branch uppercase;
|
||||
}
|
||||
|
||||
button {
|
||||
.btn-close {
|
||||
@apply absolute top-0 right-0 outline-none border-none bg-transparent;
|
||||
|
||||
ui-icon {
|
||||
@apply text-inactive-branch;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
@apply text-center mb-5 mt-6 sticky bottom-1;
|
||||
|
||||
.btn-cta {
|
||||
@apply bg-brand text-white font-bold text-lg outline-none border-none rounded-full px-6 py-3;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, HostBinding } from '@angular/core';
|
||||
import { DomainTaskCalendarService } from '@domain/task-calendar';
|
||||
import { DisplayInfoDTO } from '@swagger/eis';
|
||||
import { UiModalRef } from '@ui/modal';
|
||||
import { combineLatest, ReplaySubject } from 'rxjs';
|
||||
import { map, shareReplay } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'page-preinfo-modal',
|
||||
@@ -11,11 +14,31 @@ import { UiModalRef } from '@ui/modal';
|
||||
export class PreInfoModalComponent {
|
||||
info: DisplayInfoDTO;
|
||||
|
||||
constructor(private modalRef: UiModalRef<DisplayInfoDTO>) {
|
||||
this.info = this.modalRef.data;
|
||||
info$ = new ReplaySubject<DisplayInfoDTO>();
|
||||
|
||||
processingStatus$ = this.info$.pipe(
|
||||
map((info) => this.domainTaskCalendarService.getProcessingStatusList(info)),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
showOpenSuccessorCta$ = combineLatest([this.processingStatus$, this.info$]).pipe(
|
||||
map(([processingStatus, info]) => processingStatus.includes('Removed') && !!info.successor?.id)
|
||||
);
|
||||
|
||||
@HostBinding('class')
|
||||
get statusClass() {
|
||||
return this.domainTaskCalendarService.getProcessingStatusList(this.info);
|
||||
}
|
||||
|
||||
close() {
|
||||
this.modalRef.close();
|
||||
constructor(
|
||||
private modalRef: UiModalRef<{ successorId: number }, DisplayInfoDTO>,
|
||||
private domainTaskCalendarService: DomainTaskCalendarService
|
||||
) {
|
||||
this.info = this.modalRef.data;
|
||||
this.info$.next(this.info);
|
||||
}
|
||||
|
||||
close(successorId: number = undefined) {
|
||||
this.modalRef.close({ successorId });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
<button *ngIf="showCompleteEditCta$ | async" class="btn-cta" type="button" (click)="completeEdit()" [disabled]="editDisabled$ | async">
|
||||
Bearbeitung abschließen
|
||||
</button>
|
||||
<button *ngIf="showOpenSuccessorCta$ | async" class="btn-cta" type="button" (click)="close(info.successor?.id)">
|
||||
Zur neuen Aufgabe
|
||||
</button>
|
||||
<div *ngIf="showCameraCta$ | async" [disabled]="editDisabled$ | async">
|
||||
<ng-container>
|
||||
<div class="camera-hint">Bitte fotografieren Sie die Präsentation, um die<br />Aufgabe abschließen zu können</div>
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
:host {
|
||||
@apply flex flex-col relative;
|
||||
|
||||
&.Removed {
|
||||
.header {
|
||||
@apply opacity-30 line-through;
|
||||
}
|
||||
.status {
|
||||
@apply opacity-30;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ChangeDetectionStrategy, Component, ElementRef, ViewChild } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, ElementRef, HostBinding, ViewChild } from '@angular/core';
|
||||
import { DomainTaskCalendarService } from '@domain/task-calendar';
|
||||
import { DisplayInfoDTO } from '@swagger/eis';
|
||||
import { DateAdapter } from '@ui/common';
|
||||
@@ -6,7 +6,7 @@ import { UiMessageModalComponent, UiModalRef, UiModalService } from '@ui/modal';
|
||||
import { isNullOrUndefined } from '@utils/common';
|
||||
import { NativeContainerService } from 'native-container';
|
||||
import { combineLatest, ReplaySubject } from 'rxjs';
|
||||
import { map, tap, shareReplay, switchMap } from 'rxjs/operators';
|
||||
import { map, shareReplay, switchMap } from 'rxjs/operators';
|
||||
import { CameraCaptureModalComponent } from '../camera/camera-capture-modal.component';
|
||||
|
||||
@Component({
|
||||
@@ -44,6 +44,11 @@ export class TaskModalComponent {
|
||||
})
|
||||
);
|
||||
|
||||
@HostBinding('class')
|
||||
get statusClass() {
|
||||
return this.domainTaskCalendarService.getProcessingStatusList(this.info);
|
||||
}
|
||||
|
||||
editDisabled$ = this.info$.pipe(
|
||||
map((info) => {
|
||||
if (info.publicationDate && info.taskDate && info.taskOverdueDate) {
|
||||
@@ -65,22 +70,37 @@ export class TaskModalComponent {
|
||||
showStartEditCta$ = this.processingStatus$.pipe(
|
||||
map(
|
||||
(processingStatus) =>
|
||||
!processingStatus.includes('Uncompleted') && !processingStatus.includes('InProcess') && !processingStatus.includes('Completed')
|
||||
!processingStatus.includes('Uncompleted') &&
|
||||
!processingStatus.includes('InProcess') &&
|
||||
!processingStatus.includes('Completed') &&
|
||||
!processingStatus.includes('Removed')
|
||||
)
|
||||
);
|
||||
|
||||
showCompleteEditCta$ = combineLatest([this.processingStatus$, this.info$]).pipe(
|
||||
map(([processingStatus, info]) => processingStatus.includes('InProcess') && !info.requiresImageOnConfirmation)
|
||||
map(
|
||||
([processingStatus, info]) =>
|
||||
processingStatus.includes('InProcess') && !info.requiresImageOnConfirmation && !processingStatus.includes('Removed')
|
||||
)
|
||||
);
|
||||
|
||||
showCameraCta$ = combineLatest([this.processingStatus$, this.info$]).pipe(
|
||||
map(([processingStatus, info]) => processingStatus.includes('InProcess') && info.requiresImageOnConfirmation)
|
||||
map(
|
||||
([processingStatus, info]) =>
|
||||
processingStatus.includes('InProcess') && info.requiresImageOnConfirmation && !processingStatus.includes('Removed')
|
||||
)
|
||||
);
|
||||
|
||||
showResetEditCta$ = this.processingStatus$.pipe(map((processingStatus) => processingStatus.includes('Completed')));
|
||||
showResetEditCta$ = this.processingStatus$.pipe(
|
||||
map((processingStatus) => processingStatus.includes('Completed') && !processingStatus.includes('Removed'))
|
||||
);
|
||||
|
||||
showOpenSuccessorCta$ = combineLatest([this.processingStatus$, this.info$]).pipe(
|
||||
map(([processingStatus, info]) => processingStatus.includes('Removed') && !!info.successor?.id)
|
||||
);
|
||||
|
||||
constructor(
|
||||
private modalRef: UiModalRef<DisplayInfoDTO>,
|
||||
private modalRef: UiModalRef<{ successorId: number }, DisplayInfoDTO>,
|
||||
private domainTaskCalendarService: DomainTaskCalendarService,
|
||||
private uiModal: UiModalService,
|
||||
private nativeContainer: NativeContainerService,
|
||||
@@ -90,8 +110,8 @@ export class TaskModalComponent {
|
||||
this.info$.next(this.info);
|
||||
}
|
||||
|
||||
close() {
|
||||
this.modalRef.close();
|
||||
close(successorId: number = undefined) {
|
||||
this.modalRef.close({ successorId });
|
||||
}
|
||||
|
||||
async startEdit() {
|
||||
|
||||
@@ -5,10 +5,10 @@ import { DisplayInfoDTO, InputDTO, ResponseArgsOfIEnumerableOfInputDTO } from '@
|
||||
import { CalendarIndicator } from '@ui/calendar';
|
||||
import { DateAdapter } from '@ui/common';
|
||||
import { Filter, FilterOption, SelectFilter, UiFilterMappingService } from '@ui/filter';
|
||||
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
|
||||
import { UiMessageModalComponent, UiModalRef, UiModalResult, UiModalService } from '@ui/modal';
|
||||
import { clone } from 'lodash';
|
||||
import { combineLatest, Observable } from 'rxjs';
|
||||
import { debounceTime, distinctUntilChanged, switchMap, withLatestFrom } from 'rxjs/operators';
|
||||
import { Observable } from 'rxjs';
|
||||
import { debounceTime, map, switchMap, withLatestFrom } from 'rxjs/operators';
|
||||
import { InfoModalComponent } from './modals/info/info-modal.component';
|
||||
import { PreInfoModalComponent } from './modals/preinfo/preinfo-modal.component';
|
||||
import { TaskModalComponent } from './modals/task/task-modal.component';
|
||||
@@ -172,36 +172,45 @@ export class TaskCalendarStore extends ComponentStore<TaskCalendarState> {
|
||||
|
||||
open(displayInfoDTO: DisplayInfoDTO) {
|
||||
const type = this.domainTaskCalendarService.getInfoType(displayInfoDTO);
|
||||
let taskModalRef: UiModalRef<{ successorId: number }, DisplayInfoDTO>;
|
||||
|
||||
switch (type) {
|
||||
case 'Info':
|
||||
this.uiModal.open({
|
||||
taskModalRef = this.uiModal.open({
|
||||
content: InfoModalComponent,
|
||||
data: displayInfoDTO,
|
||||
});
|
||||
break;
|
||||
|
||||
case 'PreInfo':
|
||||
this.uiModal.open({
|
||||
taskModalRef = this.uiModal.open({
|
||||
content: PreInfoModalComponent,
|
||||
data: displayInfoDTO,
|
||||
});
|
||||
break;
|
||||
|
||||
case 'Task':
|
||||
const taskModalRef = this.uiModal.open<string, DisplayInfoDTO>({
|
||||
taskModalRef = this.uiModal.open({
|
||||
content: TaskModalComponent,
|
||||
data: displayInfoDTO,
|
||||
});
|
||||
|
||||
taskModalRef.afterClosed$.subscribe({
|
||||
complete: () => this.loadItems(),
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// Logik welcher Dialog soll angezeigt werden
|
||||
taskModalRef?.afterClosed$.subscribe({
|
||||
next: async (result: UiModalResult<{ successorId: number }>) => {
|
||||
if (result.data?.successorId) {
|
||||
const info = await this.domainTaskCalendarService
|
||||
.getInfoById({ infoId: result.data.successorId })
|
||||
.pipe(map((res) => res.result))
|
||||
.toPromise();
|
||||
if (info) {
|
||||
this.open(info);
|
||||
}
|
||||
}
|
||||
},
|
||||
complete: () => this.loadItems(),
|
||||
});
|
||||
}
|
||||
|
||||
mapInputArrayToFilterArray(source: InputDTO[]): SelectFilter[] {
|
||||
|
||||
@@ -32,7 +32,7 @@ import { ReloadFormState } from '../actions/forms.actions';
|
||||
import { FILIALE_LANDING_PAGE } from '../../utils/app.constants';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
export const SYNC_DATA_VERSION = 220;
|
||||
export const SYNC_DATA_VERSION = 222;
|
||||
|
||||
export class AppStateModel {
|
||||
currentProcesssId: number;
|
||||
|
||||
@@ -33,5 +33,9 @@
|
||||
></app-remission-to-top-to-bottom-actions>
|
||||
</div>
|
||||
</ng-container>
|
||||
<div class="empty-hits" *ngIf="data.productsData && data.productsData.hits === 0">
|
||||
Es gibt im Moment keine Artikel, die <br />
|
||||
remittiert werden müssen.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -34,3 +34,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty-hits {
|
||||
@apply mt-16 text-center text-active-branch text-lg;
|
||||
}
|
||||
|
||||
@@ -279,11 +279,6 @@ export class RemissionListCreateComponent implements OnInit, OnDestroy {
|
||||
};
|
||||
|
||||
startRemission() {
|
||||
try {
|
||||
throw new Error('[Remission Create] Start Remission');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
this.currentRemissionProcess$
|
||||
.pipe(
|
||||
switchMap((process) =>
|
||||
@@ -299,11 +294,7 @@ export class RemissionListCreateComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
openStartRemissionDialog() {
|
||||
if (this.isIPad) {
|
||||
this.startRemission();
|
||||
} else {
|
||||
this.remissionStartDialog.openDialog();
|
||||
}
|
||||
this.startRemission();
|
||||
}
|
||||
|
||||
navigateToStartedRemission() {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<button class="close-btn" (click)="ref.close()">
|
||||
<ui-icon icon="close" size="21px"></ui-icon>
|
||||
</button>
|
||||
|
||||
<h1>
|
||||
Ist Ihre
|
||||
{{ isNative ? 'Wannennummer' : 'Packstück-ID' }}
|
||||
korrekt oder möchten <br />
|
||||
Sie diese erneut scannen?
|
||||
</h1>
|
||||
<h3>
|
||||
{{ ref.data }}
|
||||
</h3>
|
||||
|
||||
<div class="actions-wrapper">
|
||||
<button type="button">
|
||||
Erneut Scannen
|
||||
</button>
|
||||
<button type="button" class="primary">
|
||||
Nummer korrekt
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1,28 @@
|
||||
:host {
|
||||
@apply block box-content relative;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
@apply absolute -top-2 right-0 text-ucla-blue border-none bg-transparent;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply text-xl font-bold text-center;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@apply text-3xl font-bold text-center;
|
||||
}
|
||||
|
||||
.actions-wrapper {
|
||||
@apply grid grid-flow-col items-center content-center gap-4 mx-auto mb-4;
|
||||
width: fit-content;
|
||||
|
||||
button {
|
||||
@apply border-solid border-brand border-2 rounded-full px-6 py-3 bg-white text-brand text-cta-l font-bold;
|
||||
|
||||
&.primary {
|
||||
@apply bg-brand text-white;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { UiModalRef } from '@ui/modal';
|
||||
import { NativeContainerService } from 'native-container';
|
||||
|
||||
@Component({
|
||||
selector: 'app-confirm.receipt-number-modal',
|
||||
templateUrl: 'confirm-receipt-number-modal.component.html',
|
||||
styleUrls: ['confirm-receipt-number-modal.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ConfirmReceiptNumberModalComponent {
|
||||
get isNative() {
|
||||
return this._nativeContainer.isUiWebview().isNative;
|
||||
}
|
||||
|
||||
constructor(public ref: UiModalRef<boolean, string>, private _nativeContainer: NativeContainerService) {}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { ConfirmReceiptNumberModalComponent } from './confirm-receipt-number-modal.component';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiIconModule],
|
||||
exports: [ConfirmReceiptNumberModalComponent],
|
||||
declarations: [ConfirmReceiptNumberModalComponent],
|
||||
})
|
||||
export class ConfirmReceiptNumberModalModule {}
|
||||
@@ -0,0 +1,4 @@
|
||||
// start:ng42.barrel
|
||||
export * from './confirm-receipt-number-modal.component';
|
||||
export * from './confirm-receipt-number-modal.module';
|
||||
// end:ng42.barrel
|
||||
@@ -14,6 +14,11 @@
|
||||
*ngIf="showScanningButton$ | async"
|
||||
(scan)="shippingDocumentScanned($event)"
|
||||
></lib-remission-shipping-document-scanner>
|
||||
<ui-searchbox
|
||||
*ngIf="showSearchbox$ | async"
|
||||
placeholder="Packstück-ID scannen"
|
||||
(search)="shippingDocumentScanned($event)"
|
||||
></ui-searchbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -41,3 +41,8 @@
|
||||
margin-top: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
ui-searchbox {
|
||||
@apply ml-4;
|
||||
width: 425px;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { SetRemissionShippingDocument } from 'apps/sales/src/app/core/store/acti
|
||||
import { NativeContainerService } from 'shared/public_api';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
|
||||
import { ConfirmReceiptNumberModalComponent } from './confirm-receipt-number-modal/confirm-receipt-number-modal.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-shipping-document-creation',
|
||||
@@ -22,6 +23,8 @@ import { UiMessageModalComponent, UiModalService } from '@ui/modal';
|
||||
export class ShippingDocumentCreationComponent implements OnInit {
|
||||
showScanningButton$: Observable<boolean>;
|
||||
|
||||
showSearchbox$: Observable<boolean>;
|
||||
|
||||
@Select(RemissionSelectors.getRemissionShippingDocument)
|
||||
shippingDocument$: Observable<ShippingDocument>;
|
||||
@Select(RemissionSelectors.getRemissionShippingDocumentstatus)
|
||||
@@ -47,15 +50,21 @@ export class ShippingDocumentCreationComponent implements OnInit {
|
||||
this.showScanningButton$ = this.enableScan$.pipe(
|
||||
map((allowScan) => !!allowScan && this.appService.isIPadEnv() && this.nativeService.isUiWebview())
|
||||
);
|
||||
|
||||
this.showSearchbox$ = this.showScanningButton$.pipe(map((s) => !s));
|
||||
}
|
||||
|
||||
shippingDocumentWithGeneratedId() {
|
||||
this.createShippingDocument();
|
||||
}
|
||||
|
||||
shippingDocumentScanned(receiptNumber: string) {
|
||||
if (receiptNumber) {
|
||||
this.createShippingDocument(receiptNumber);
|
||||
async shippingDocumentScanned(receiptNumber: string) {
|
||||
if (receiptNumber && receiptNumber.length > 3) {
|
||||
const result = await this.modal.open({ content: ConfirmReceiptNumberModalComponent, data: receiptNumber }).afterClosed$.toPromise();
|
||||
|
||||
if (result.data) {
|
||||
this.createShippingDocument(receiptNumber);
|
||||
}
|
||||
} else {
|
||||
this.invalidBarcodeDialog.openDialog();
|
||||
}
|
||||
|
||||
@@ -83,6 +83,8 @@ import { RemissionShippingDocumentContainerComponent } from './pages/remission-l
|
||||
import { RemissionScrollButtonComponent } from './components/remission-scroll-button';
|
||||
import { ShippingDocumentActionsComponent } from './pages/remission-list-started/shipping-document-container/shipping-document-actions';
|
||||
import { RemissionListStartActionComponent } from './components/remission-list-actions/remission-list-start';
|
||||
import { UiSearchboxNextModule } from '@ui/searchbox';
|
||||
import { ConfirmReceiptNumberModalModule } from './pages/remission-list-started/shipping-document-creation/confirm-receipt-number-modal/confirm-receipt-number-modal.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@@ -154,6 +156,8 @@ import { RemissionListStartActionComponent } from './components/remission-list-a
|
||||
TabSelectionModule,
|
||||
FilterLoaderModule,
|
||||
RemissionUeberlaufCapacitiesModule,
|
||||
UiSearchboxNextModule,
|
||||
ConfirmReceiptNumberModalModule,
|
||||
],
|
||||
})
|
||||
export class RemissionClientModule {}
|
||||
|
||||
@@ -27,5 +27,5 @@ export const ProcessingStatusNameMap = new Map<number, { value: string; disabled
|
||||
[33554432, { value: 'reserviert', disabled: true }],
|
||||
[67108864, { value: 'zusammengestellt', disabled: true }],
|
||||
[134217728, { value: 'verpackt', disabled: true }],
|
||||
[268435456, { value: 'Lieferantenbestellung ausführen', disabled: true }],
|
||||
[268435456, { value: 'Lieferschein', disabled: true }],
|
||||
]);
|
||||
|
||||
@@ -71,7 +71,7 @@ export class SharedGoodsInOutOrderDetailsCoversComponent extends ComponentStore<
|
||||
map(
|
||||
(orderItems) =>
|
||||
orderItems
|
||||
?.filter((a) => !!a.readyForPickUp)
|
||||
?.filter((a) => !!a.readyForPickUp && a.processingStatus === 128)
|
||||
?.sort((a, b) => new Date(b.readyForPickUp).getTime() - new Date(a.readyForPickUp).getTime())
|
||||
?.find((_) => true)?.compartmentCode
|
||||
)
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
{{ orderItem?.processingStatus | processingStatus }}
|
||||
<ui-icon [rotate]="dropdown.opened ? '270deg' : '90deg'" icon="arrow_head"></ui-icon>
|
||||
</button>
|
||||
<ui-dropdown #statusDropdown yPosition="below" xPosition="after">
|
||||
<ui-dropdown #statusDropdown yPosition="below" xPosition="after" [xOffset]="8">
|
||||
<button uiDropdownItem *ngFor="let action of statusActions$ | async" (click)="handleAction(action)">
|
||||
{{ action.label }}
|
||||
</button>
|
||||
@@ -126,7 +126,7 @@
|
||||
</strong>
|
||||
<ui-icon [rotate]="deadlineDropdownTrigger.opened ? '270deg' : '90deg'" icon="arrow_head"></ui-icon>
|
||||
</button>
|
||||
<ui-dropdown #deadlineDropdown yPosition="below" xPosition="after" class="deadline-select">
|
||||
<ui-dropdown #deadlineDropdown yPosition="below" xPosition="after" class="deadline-select" [xOffset]="8">
|
||||
<button uiDropdownItem *ngFor="let dl of pickupDeadlines$ | async | keyvalue" (click)="updatePickupDeadline(dl.value)">
|
||||
{{ dl.key }}
|
||||
</button>
|
||||
@@ -153,6 +153,7 @@
|
||||
#uiDatepicker
|
||||
yPosition="below"
|
||||
xPosition="after"
|
||||
[xOffset]="8"
|
||||
[min]="minDateDatepicker"
|
||||
[disabledDaysOfWeek]="[0]"
|
||||
[selected]="orderItem?.estimatedShippingDate"
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
.cta-status-dropdown,
|
||||
.cta-datepicker,
|
||||
.cta-pickup-deadline {
|
||||
@apply flex flex-row border-none outline-none text-base font-bold bg-transparent items-center;
|
||||
@apply flex flex-row border-none outline-none text-base font-bold bg-transparent items-center px-0 mx-0;
|
||||
|
||||
ui-icon {
|
||||
@apply text-inactive-customer ml-2;
|
||||
|
||||
@@ -61,6 +61,9 @@ button {
|
||||
|
||||
input:disabled {
|
||||
@apply text-warning font-bold;
|
||||
// ipad color fix
|
||||
-webkit-text-fill-color: rgb(190, 129, 0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
button {
|
||||
|
||||
@@ -1,37 +1,6 @@
|
||||
import { Injectable, Pipe, PipeTransform } from '@angular/core';
|
||||
import { OrderItemProcessingStatusValue } from '@swagger/oms';
|
||||
|
||||
const ProcessingStatusNameMap = new Map<number, { value: string; disabled: boolean }>([
|
||||
[1, { value: 'neu', disabled: true }],
|
||||
[2, { value: '', disabled: true }],
|
||||
[4, { value: '', disabled: true }],
|
||||
[8, { value: 'geparkt', disabled: true }],
|
||||
[16, { value: 'bestellt', disabled: false }],
|
||||
[32, { value: 'Vorbereitung Versand', disabled: true }],
|
||||
[64, { value: 'versendet', disabled: false }],
|
||||
[128, { value: 'eingetroffen', disabled: false }],
|
||||
[256, { value: 'abgeholt', disabled: false }],
|
||||
[512, { value: 'storniert (Kunde)', disabled: false }],
|
||||
[1024, { value: 'storniert', disabled: false }],
|
||||
[2048, { value: 'storniert (Lieferant)', disabled: false }],
|
||||
[4096, { value: 'nicht lieferbar', disabled: false }],
|
||||
[8192, { value: 'nachbestellt', disabled: true }],
|
||||
[16384, { value: 'zurückgegeben', disabled: true }],
|
||||
[32768, { value: 'steht zum Download zur Verfügung', disabled: true }],
|
||||
[65536, { value: 'downloaded', disabled: true }],
|
||||
[131072, { value: 'nicht abgeholt', disabled: true }],
|
||||
[262144, { value: 'ans Lager (nicht abgeholt)', disabled: false }],
|
||||
[524288, { value: 'angefragt', disabled: false }],
|
||||
[1048576, { value: 'weitergeleitet intern', disabled: false }],
|
||||
[2097152, { value: 'überfällig', disabled: true }],
|
||||
[4194304, { value: 'zugestellt', disabled: false }],
|
||||
[8388608, { value: 'Lieferant ermittelt', disabled: false }],
|
||||
[16777216, { value: 'derzeit nicht lieferbar', disabled: false }],
|
||||
[33554432, { value: 'reserviert', disabled: true }],
|
||||
[67108864, { value: 'zusammengestellt', disabled: true }],
|
||||
[134217728, { value: 'verpackt', disabled: true }],
|
||||
[268435456, { value: 'Lieferantenbestellung ausführen', disabled: true }],
|
||||
]);
|
||||
import { ProcessingStatusNameMap } from '../constants/processing-status-name.map';
|
||||
|
||||
@Pipe({
|
||||
name: 'processingStatus',
|
||||
|
||||
@@ -5,6 +5,6 @@ import { Pipe, PipeTransform } from '@angular/core';
|
||||
})
|
||||
export class ReplacePipe implements PipeTransform {
|
||||
transform(value: string, replaceStr: string = '', replaceWith: string = ''): string {
|
||||
return value?.replace(replaceStr, replaceWith);
|
||||
return value?.replace(new RegExp(replaceStr, 'gi'), replaceWith);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,8 @@ export class UiDatepickerTriggerDirective implements OnInit, OnDestroy, OnChange
|
||||
this.close();
|
||||
}
|
||||
|
||||
this.updatePositionStrategy();
|
||||
|
||||
this.datepickerRef = this.overlayRef.attach(dropdownPortal);
|
||||
this.datepicker.close = () => this.close();
|
||||
|
||||
@@ -104,6 +106,10 @@ export class UiDatepickerTriggerDirective implements OnInit, OnDestroy, OnChange
|
||||
this.subscription.add(this.overlayRef.backdropClick().subscribe(() => this.close()));
|
||||
}
|
||||
|
||||
updatePositionStrategy() {
|
||||
this.overlayRef.updatePositionStrategy(this.getPositionStrategy());
|
||||
}
|
||||
|
||||
getPositionStrategy() {
|
||||
let [originX, originFallbackX]: HorizontalConnectionPos[] = [this.datepicker.xPosition === 'before' ? 'start' : 'end', 'start'];
|
||||
|
||||
@@ -111,17 +117,19 @@ export class UiDatepickerTriggerDirective implements OnInit, OnDestroy, OnChange
|
||||
|
||||
let [overlayY, originFallbackY]: VerticalConnectionPos[] = [originY === 'bottom' ? 'top' : 'bottom', overlayFallbackY];
|
||||
let [overlayX, overlayFallbackX] = [originX, originFallbackX];
|
||||
let offsetY = 0;
|
||||
let offsetY = this.datepicker.yOffset ?? 0;
|
||||
let offsetX = this.datepicker.xOffset ?? 0;
|
||||
|
||||
return this.overlayPositionBuilder.flexibleConnectedTo(this.elementRef).withPositions([
|
||||
{ originX, originY, overlayX, overlayY, offsetY },
|
||||
{ originX: originFallbackX, originY, overlayX: overlayFallbackX, overlayY, offsetY },
|
||||
{ originX, originY, overlayX, overlayY, offsetY, offsetX },
|
||||
{ originX: originFallbackX, originY, overlayX: overlayFallbackX, overlayY, offsetY, offsetX },
|
||||
{
|
||||
originX,
|
||||
originY: originFallbackY,
|
||||
overlayX,
|
||||
overlayY: overlayFallbackY,
|
||||
offsetY: -offsetY,
|
||||
offsetX: -offsetX,
|
||||
},
|
||||
{
|
||||
originX: originFallbackX,
|
||||
@@ -129,6 +137,7 @@ export class UiDatepickerTriggerDirective implements OnInit, OnDestroy, OnChange
|
||||
overlayX: overlayFallbackX,
|
||||
overlayY: overlayFallbackY,
|
||||
offsetY: -offsetY,
|
||||
offsetX: -offsetX,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,12 @@ export class UiDatepickerComponent<TDate = any> extends Datepicker<TDate> implem
|
||||
@Input()
|
||||
yPosition: DatepickerPositionY;
|
||||
|
||||
@Input()
|
||||
xOffset = 0;
|
||||
|
||||
@Input()
|
||||
yOffset = 0;
|
||||
|
||||
get classList() {
|
||||
return ['dp', `x-position-${this.xPosition}`, `y-position-${this.yPosition}`];
|
||||
}
|
||||
|
||||
@@ -76,6 +76,8 @@ export class UiDropdownTriggerDirective implements OnInit, OnDestroy, OnChanges
|
||||
this.close();
|
||||
}
|
||||
|
||||
this.updatePositionStrategy();
|
||||
|
||||
this.dropdownRef = this.overlayRef.attach(dropdownPortal);
|
||||
|
||||
this.dropdown.close = () => {
|
||||
@@ -104,6 +106,10 @@ export class UiDropdownTriggerDirective implements OnInit, OnDestroy, OnChanges
|
||||
.subscribe(() => this.close());
|
||||
}
|
||||
|
||||
updatePositionStrategy() {
|
||||
this.overlayRef.updatePositionStrategy(this.getPositionStrategy());
|
||||
}
|
||||
|
||||
getPositionStrategy() {
|
||||
let [originX, originFallbackX]: HorizontalConnectionPos[] = [this.dropdown.xPosition === 'before' ? 'start' : 'end', 'start'];
|
||||
|
||||
@@ -111,17 +117,20 @@ export class UiDropdownTriggerDirective implements OnInit, OnDestroy, OnChanges
|
||||
|
||||
let [overlayY, originFallbackY]: VerticalConnectionPos[] = [originY === 'bottom' ? 'top' : 'bottom', overlayFallbackY];
|
||||
let [overlayX, overlayFallbackX] = [originX, originFallbackX];
|
||||
let offsetY = 0;
|
||||
|
||||
let offsetY = this.dropdown.yOffset ?? 0;
|
||||
let offsetX = this.dropdown.xOffset ?? 0;
|
||||
|
||||
return this.overlayPositionBuilder.flexibleConnectedTo(this.elementRef).withPositions([
|
||||
{ originX, originY, overlayX, overlayY, offsetY },
|
||||
{ originX: originFallbackX, originY, overlayX: overlayFallbackX, overlayY, offsetY },
|
||||
{ originX, originY, overlayX, overlayY, offsetY, offsetX },
|
||||
{ originX: originFallbackX, originY, overlayX: overlayFallbackX, overlayY, offsetY, offsetX },
|
||||
{
|
||||
originX,
|
||||
originY: originFallbackY,
|
||||
overlayX,
|
||||
overlayY: overlayFallbackY,
|
||||
offsetY: -offsetY,
|
||||
offsetX: -offsetX,
|
||||
},
|
||||
{
|
||||
originX: originFallbackX,
|
||||
@@ -129,6 +138,7 @@ export class UiDropdownTriggerDirective implements OnInit, OnDestroy, OnChanges
|
||||
overlayX: overlayFallbackX,
|
||||
overlayY: overlayFallbackY,
|
||||
offsetY: -offsetY,
|
||||
offsetX: -offsetX,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,12 @@ export class UiDropdownComponent implements OnInit {
|
||||
@Input()
|
||||
yPosition: DropdownPositionY;
|
||||
|
||||
@Input()
|
||||
xOffset = 0;
|
||||
|
||||
@Input()
|
||||
yOffset = 0;
|
||||
|
||||
close = () => {};
|
||||
|
||||
get classList() {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
[ngModel]="uiStartOption?.value"
|
||||
(save)="uiStartOption?.setValue($event)"
|
||||
>
|
||||
<ng-container #content>Übernehmen</ng-container>
|
||||
</ui-datepicker>
|
||||
</div>
|
||||
<div *ngIf="uiStopOption" class="option">
|
||||
@@ -49,6 +50,7 @@
|
||||
[ngModel]="uiStopOption?.value"
|
||||
(save)="uiStopOption?.setValue($event)"
|
||||
>
|
||||
<ng-container #content>Übernehmen</ng-container>
|
||||
</ui-datepicker>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -167,6 +167,7 @@ export class UiOption implements IUiOption {
|
||||
|
||||
trySetFromValue(value: string) {
|
||||
const type = this.getParentInput()?.type;
|
||||
|
||||
switch (type) {
|
||||
case UiInputType.Bool:
|
||||
case UiInputType.InputSelector:
|
||||
@@ -179,6 +180,9 @@ export class UiOption implements IUiOption {
|
||||
case UiInputType.IntegerRange:
|
||||
this.trySetFromNumberRange(value);
|
||||
break;
|
||||
case UiInputType.DateRange:
|
||||
this.trySetFromDateRange(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,6 +195,32 @@ export class UiOption implements IUiOption {
|
||||
}
|
||||
}
|
||||
|
||||
trySetFromDateRange(value: string) {
|
||||
let split: string[] = [];
|
||||
|
||||
if (value) {
|
||||
if (value?.includes('"-"')) {
|
||||
split = value.split('"-"');
|
||||
} else if (value?.includes('-"')) {
|
||||
split = value.split('-"');
|
||||
} else if (value?.includes('"-')) {
|
||||
split = value.split('"-');
|
||||
}
|
||||
}
|
||||
|
||||
if (this.key === 'start') {
|
||||
if (split[0]) {
|
||||
split[0] = split[0].replace(new RegExp('"', 'g'), '');
|
||||
}
|
||||
this.setValue(split[0]);
|
||||
} else if (this.key === 'stop') {
|
||||
if (split[1]) {
|
||||
split[1] = split[1].replace(new RegExp('"', 'g'), '');
|
||||
}
|
||||
this.setValue(split[1]);
|
||||
}
|
||||
}
|
||||
|
||||
trySetBoolFromValue(value: string) {
|
||||
const valueSplits = value?.split(';');
|
||||
if (valueSplits.includes(this.value)) {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { UiLoaderComponent } from './loader.component';
|
||||
import { UiButtonLoaderComponent, UiLoaderComponent } from './loader.component';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { UiButtonLoaderComponent } from '@ui/loader';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiIconModule],
|
||||
|
||||
18
apps/ui/modal/src/lib/error-modal/error-modal.component.scss
Normal file
18
apps/ui/modal/src/lib/error-modal/error-modal.component.scss
Normal file
@@ -0,0 +1,18 @@
|
||||
:host {
|
||||
@apply flex flex-col;
|
||||
}
|
||||
|
||||
.title {
|
||||
@apply text-xl text-center;
|
||||
}
|
||||
|
||||
.message {
|
||||
@apply text-base text-center whitespace-pre-line break-words;
|
||||
}
|
||||
|
||||
.actions {
|
||||
@apply text-center;
|
||||
button {
|
||||
@apply px-5 py-3 bg-brand text-white text-cta-l rounded-full border-none outline-none;
|
||||
}
|
||||
}
|
||||
54
apps/ui/modal/src/lib/error-modal/error-modal.component.ts
Normal file
54
apps/ui/modal/src/lib/error-modal/error-modal.component.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { isResponseArgs } from '@utils/object';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { UiModalRef } from '../defs';
|
||||
|
||||
@Component({
|
||||
selector: 'ui-error-modal',
|
||||
template: `
|
||||
<h1 class="title">Es ist ein Fehler aufgetreten</h1>
|
||||
<p class="message">
|
||||
{{ errorMessage }}
|
||||
</p>
|
||||
<div class="actions">
|
||||
<button (click)="modalRef.close()">OK</button>
|
||||
</div>
|
||||
`,
|
||||
styleUrls: ['./error-modal.component.scss'],
|
||||
})
|
||||
export class UiErrorModalComponent implements OnInit {
|
||||
get errorMessage() {
|
||||
if (this.error instanceof HttpErrorResponse) {
|
||||
if (isResponseArgs(this.error?.error)) {
|
||||
return (
|
||||
this.getMessageFromInvalidProperties(this.error?.error?.invalidProperties) || this.error?.error?.message || this.error?.message
|
||||
);
|
||||
}
|
||||
return this.getMessageFromHttpErrorResponse(this.error);
|
||||
}
|
||||
return this.error?.message;
|
||||
}
|
||||
|
||||
get error() {
|
||||
return this.modalRef.data;
|
||||
}
|
||||
|
||||
constructor(public modalRef: UiModalRef<undefined, Error>) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
getMessageFromInvalidProperties(invalidProperties: Record<string, string>): string {
|
||||
if (!isEmpty(invalidProperties)) {
|
||||
return Object.values(invalidProperties).join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
getMessageFromHttpErrorResponse(error: HttpErrorResponse) {
|
||||
return `HTTP Status: ${error.status} - ${error.statusText}
|
||||
Type: ${error.type}
|
||||
URL: ${error.url}
|
||||
Message: ${error.message}
|
||||
`;
|
||||
}
|
||||
}
|
||||
3
apps/ui/modal/src/lib/error-modal/index.ts
Normal file
3
apps/ui/modal/src/lib/error-modal/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// start:ng42.barrel
|
||||
export * from './error-modal.component';
|
||||
// end:ng42.barrel
|
||||
@@ -5,4 +5,5 @@ export * from './debug-modal/debug-modal.component';
|
||||
export * from './message-modal.component';
|
||||
export * from './modal.module';
|
||||
export * from './modal.service';
|
||||
export * from './error-modal';
|
||||
// end:ng42.barrel
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
}
|
||||
|
||||
::ng-deep .cdk-overlay-pane.modal-overflow ui-modal {
|
||||
@apply overflow-auto;
|
||||
@apply overflow-x-hidden overflow-y-scroll;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
}
|
||||
|
||||
.quantity-control-wrapper {
|
||||
@apply relative w-10;
|
||||
@apply relative w-11;
|
||||
|
||||
&.open {
|
||||
@apply px-4;
|
||||
@@ -23,7 +23,7 @@ button.action {
|
||||
}
|
||||
|
||||
button.current-quantity {
|
||||
@apply flex flex-row justify-between items-center bg-white text-base outline-none border-none text-left font-bold w-full;
|
||||
@apply flex flex-row justify-between items-center bg-white text-base outline-none border-none text-left font-bold w-full px-0 mx-0;
|
||||
|
||||
ui-icon {
|
||||
@apply ml-2;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { UiLoaderModule } from '@ui/loader';
|
||||
import { UiContentLoaderComponent } from '@ui/scroll-container';
|
||||
import { UiContentLoaderComponent } from './content-loader';
|
||||
import { UiScrollContainerDirective } from './directives';
|
||||
import { UiScrollContainerComponent } from './scroll-container.component';
|
||||
import { UiSkeletonLoaderComponent } from './skeleton-loader';
|
||||
|
||||
Reference in New Issue
Block a user