mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
Merge branch 'release/2.1'
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
import { ShoppingCartItemDTO } from '@swagger/checkout';
|
||||
|
||||
export interface CheckoutDummyData extends ShoppingCartItemDTO {}
|
||||
@@ -7,6 +7,7 @@ import { DateAdapter } from '@ui/common';
|
||||
import { UiErrorModalComponent, UiModalRef, UiModalService } from '@ui/modal';
|
||||
import { Subject } from 'rxjs';
|
||||
import { first, shareReplay, takeUntil } from 'rxjs/operators';
|
||||
import { CheckoutDummyData } from './checkout-dummy-data';
|
||||
import { CheckoutDummyStore } from './checkout-dummy.store';
|
||||
|
||||
@Component({
|
||||
@@ -41,7 +42,7 @@ export class CheckoutDummyComponent implements OnInit, OnDestroy {
|
||||
private _dateAdapter: DateAdapter,
|
||||
private _modal: UiModalService,
|
||||
private _store: CheckoutDummyStore,
|
||||
private _ref: UiModalRef<any, any>,
|
||||
private _ref: UiModalRef<any, CheckoutDummyData>,
|
||||
private readonly _applicationService: ApplicationService
|
||||
) {}
|
||||
|
||||
@@ -57,18 +58,8 @@ export class CheckoutDummyComponent implements OnInit, OnDestroy {
|
||||
|
||||
if (!!this._ref?.data && Object.keys(this._ref?.data).length !== 0) {
|
||||
const data = this._ref?.data;
|
||||
const item = {
|
||||
ean: data.ean || '',
|
||||
name: data.name || '',
|
||||
quantity: data.quantity || '',
|
||||
estimatedShippingDate: data.estimatedShippingDate || this._dateAdapter.today().toISOString(),
|
||||
contributors: data.contributors || '',
|
||||
manufacturer: data.manufacturer || '',
|
||||
supplier: data.supplier || 5,
|
||||
price: data.price || '',
|
||||
vat: data.vat || '',
|
||||
};
|
||||
this.populateFormFromModalData(item);
|
||||
this._store.patchState({ shoppingCartItem: data });
|
||||
this.populateFormFromModalData(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,17 +113,22 @@ export class CheckoutDummyComponent implements OnInit, OnDestroy {
|
||||
this.control.get('vat').setValue(item?.catalogAvailability?.price?.vat?.vatType);
|
||||
}
|
||||
|
||||
populateFormFromModalData(item: any) {
|
||||
this.control.get('name').setValue(item.name);
|
||||
this.control.get('contributors').setValue(item.contributors);
|
||||
this.control.get('manufacturer').setValue(item.manufacturer);
|
||||
this.control.get('price').setValue(item.price ? String(item.price).replace('.', ',') : '');
|
||||
this.control.get('vat').setValue(Number(item.vat));
|
||||
populateFormFromModalData(item: CheckoutDummyData) {
|
||||
let price = item?.availability?.price?.value?.value ?? '';
|
||||
price = String(price).replace('.', ',');
|
||||
|
||||
let estimatedShippingDate = item?.estimatedShippingDate ?? this._dateAdapter.today().toISOString();
|
||||
|
||||
this.control.get('name').setValue(item?.product?.name ?? '');
|
||||
this.control.get('contributors').setValue(item?.product?.contributors ?? '');
|
||||
this.control.get('manufacturer').setValue(item?.product?.manufacturer ?? '');
|
||||
this.control.get('price').setValue(price);
|
||||
this.control.get('vat').setValue(Number(item?.availability?.price?.vat?.vatType));
|
||||
this.control.get('quantity').setValue(item.quantity);
|
||||
this.control.get('ean').setValue(item.ean);
|
||||
this.control.get('supplier').setValue(Number(item.supplier));
|
||||
this.control.get('estimatedShippingDate').setValue(item.estimatedShippingDate);
|
||||
this.changeEstimatedShippingDate(new Date(item.estimatedShippingDate)); // Update View
|
||||
this.control.get('ean').setValue(item?.product?.ean);
|
||||
this.control.get('supplier').setValue(Number(item?.availability?.supplier?.id));
|
||||
this.control.get('estimatedShippingDate').setValue(estimatedShippingDate);
|
||||
this.changeEstimatedShippingDate(new Date(estimatedShippingDate)); // Update View
|
||||
}
|
||||
|
||||
clearForm(withEan?: boolean) {
|
||||
|
||||
@@ -7,7 +7,16 @@ import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { DomainOmsService } from '@domain/oms';
|
||||
import { ComponentStore, tapResponse } from '@ngrx/component-store';
|
||||
import { ItemDTO } from '@swagger/cat';
|
||||
import { AddToShoppingCartDTO, AvailabilityDTO, BranchDTO, DestinationDTO, PriceDTO, ProductDTO, PromotionDTO } from '@swagger/checkout';
|
||||
import {
|
||||
AddToShoppingCartDTO,
|
||||
AvailabilityDTO,
|
||||
BranchDTO,
|
||||
DestinationDTO,
|
||||
PriceDTO,
|
||||
ProductDTO,
|
||||
PromotionDTO,
|
||||
ShoppingCartItemDTO,
|
||||
} from '@swagger/checkout';
|
||||
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
|
||||
import { Observable } from 'rxjs';
|
||||
import { first, map, switchMap, tap, withLatestFrom } from 'rxjs/operators';
|
||||
@@ -15,6 +24,7 @@ import { first, map, switchMap, tap, withLatestFrom } from 'rxjs/operators';
|
||||
interface CheckoutDummyState {
|
||||
item: ItemDTO;
|
||||
shoppingCartItemId: number;
|
||||
shoppingCartItem?: ShoppingCartItemDTO;
|
||||
addToCartItem: AddToShoppingCartDTO;
|
||||
estimatedShippingDate: string;
|
||||
message: string;
|
||||
@@ -297,6 +307,7 @@ export class CheckoutDummyStore extends ComponentStore<CheckoutDummyState> {
|
||||
}
|
||||
const availability = this._createAvailabilityDTO({ price, control });
|
||||
const product = this._createProductDTO({ item, control });
|
||||
|
||||
const newItem: AddToShoppingCartDTO = {
|
||||
quantity,
|
||||
availability,
|
||||
@@ -305,17 +316,11 @@ export class CheckoutDummyStore extends ComponentStore<CheckoutDummyState> {
|
||||
destination: {
|
||||
data: { target: 1, targetBranch: { id: branch.id } },
|
||||
},
|
||||
itemType: this.item.type,
|
||||
itemType: this.item?.type ?? this.get((s) => s.shoppingCartItem)?.itemType,
|
||||
};
|
||||
|
||||
if (update) {
|
||||
const shoppingCart = await this._checkoutService
|
||||
.getShoppingCart({ processId: this._application.activatedProcessId })
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
const existingItem = shoppingCart?.items?.find(
|
||||
(i) => i?.data?.product?.ean === i?.data?.product?.ean && i?.data?.features['orderType'] === 'Abholung'
|
||||
);
|
||||
const existingItem = this.get((s) => s.shoppingCartItem);
|
||||
this.patchState({ addToCartItem: newItem, shoppingCartItemId: existingItem?.id });
|
||||
}
|
||||
this.patchState({ addToCartItem: newItem });
|
||||
|
||||
@@ -21,6 +21,7 @@ import { emailNotificationValidator, mobileNotificationValidator } from '@shared
|
||||
import { PurchasingOptionsListModalComponent } from '../modals/purchasing-options-list-modal';
|
||||
import { PurchasingOptionsListModalData } from '../modals/purchasing-options-list-modal/purchasing-options-list-modal.data';
|
||||
import { ComponentStore, tapResponse } from '@ngrx/component-store';
|
||||
import { CheckoutDummyData } from '../checkout-dummy/checkout-dummy-data';
|
||||
|
||||
export interface CheckoutReviewComponentState {
|
||||
shoppingCart: ShoppingCartDTO;
|
||||
@@ -409,7 +410,7 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
|
||||
}
|
||||
}
|
||||
|
||||
openDummyModal(data?: any) {
|
||||
openDummyModal(data?: CheckoutDummyData) {
|
||||
this.uiModal.open({
|
||||
content: CheckoutDummyComponent,
|
||||
data,
|
||||
@@ -417,18 +418,19 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
|
||||
}
|
||||
|
||||
changeDummyItem({ shoppingCartItem }: { shoppingCartItem: ShoppingCartItemDTO }) {
|
||||
const data = {
|
||||
price: shoppingCartItem?.availability?.price?.value?.value,
|
||||
vat: shoppingCartItem?.availability?.price?.vat?.vatType,
|
||||
supplier: shoppingCartItem?.availability?.supplier?.id,
|
||||
estimatedShippingDate: shoppingCartItem?.estimatedShippingDate,
|
||||
manufacturer: shoppingCartItem?.product?.manufacturer,
|
||||
name: shoppingCartItem?.product?.name,
|
||||
contributors: shoppingCartItem?.product?.contributors,
|
||||
ean: shoppingCartItem?.product?.ean,
|
||||
quantity: shoppingCartItem?.quantity,
|
||||
};
|
||||
this.openDummyModal(data);
|
||||
// const data: CheckoutDummyData = {
|
||||
// itemType: shoppingCartItem.itemType,
|
||||
// price: shoppingCartItem?.availability?.price?.value?.value,
|
||||
// vat: shoppingCartItem?.availability?.price?.vat?.vatType,
|
||||
// supplier: shoppingCartItem?.availability?.supplier?.id,
|
||||
// estimatedShippingDate: shoppingCartItem?.estimatedShippingDate,
|
||||
// manufacturer: shoppingCartItem?.product?.manufacturer,
|
||||
// name: shoppingCartItem?.product?.name,
|
||||
// contributors: shoppingCartItem?.product?.contributors,
|
||||
// ean: shoppingCartItem?.product?.ean,
|
||||
// quantity: shoppingCartItem?.quantity,
|
||||
// };
|
||||
this.openDummyModal(shoppingCartItem);
|
||||
}
|
||||
|
||||
async changeItem({ shoppingCartItem }: { shoppingCartItem: ShoppingCartItemDTO }) {
|
||||
|
||||
@@ -378,6 +378,10 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
async save() {
|
||||
if (this.busy$.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.form.invalid) {
|
||||
this.form.markAllAsTouched();
|
||||
return;
|
||||
@@ -385,6 +389,7 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
|
||||
|
||||
try {
|
||||
this.busy$.next(true);
|
||||
|
||||
this.form.disable();
|
||||
const customer: CustomerDTO = await this.getCustomerFromFormData();
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
[data]="data.p4m"
|
||||
(dataChanges)="patchFormData('p4m', $event)"
|
||||
[focusAfterInit]="!data?._meta?.p4mRequired"
|
||||
[asyncValidatorFns]="asyncLoyaltyCardValidatorFn"
|
||||
>
|
||||
</app-p4m-number-form-block>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core';
|
||||
import { ValidatorFn, Validators } from '@angular/forms';
|
||||
import { AsyncValidatorFn, ValidatorFn, Validators } from '@angular/forms';
|
||||
import { Result } from '@domain/defs';
|
||||
import { CustomerDTO, CustomerInfoDTO, KeyValueDTOOfStringAndString, PayerDTO } from '@swagger/crm';
|
||||
import { CustomerDTO, KeyValueDTOOfStringAndString, PayerDTO } from '@swagger/crm';
|
||||
import { NameFormBlockData } from '../../form-blocks/name/name-form-block-data';
|
||||
import { AbstractCreateCustomer } from '../abstract-create-customer';
|
||||
import { CreateP4MCustomerComponent } from '../create-p4m-customer';
|
||||
@@ -42,6 +42,8 @@ export class UpdateP4MWebshopCustomerComponent extends AbstractCreateCustomer im
|
||||
country: [Validators.required],
|
||||
};
|
||||
|
||||
asyncLoyaltyCardValidatorFn: AsyncValidatorFn[] = [this.checkLoyalityCardValidator];
|
||||
|
||||
get billingAddress(): PayerDTO | undefined {
|
||||
const payers = this.formData?._meta?.customerDto?.payers;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { UiFilter, UiFilterInputGroupMainComponent } from '@ui/filter';
|
||||
import { isEqual } from 'lodash';
|
||||
import { combineLatest, NEVER, Observable, Subject } from 'rxjs';
|
||||
import { debounceTime, filter, map, switchMap, takeUntil } from 'rxjs/operators';
|
||||
import { CustomerCreateFormData, encodeFormData } from '../../create-customer';
|
||||
|
||||
@Component({
|
||||
selector: 'page-customer-search-main',
|
||||
@@ -81,11 +82,16 @@ export class CustomerSearchMainComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
updateCustomerCreateQueryParams(value: string) {
|
||||
const data: CustomerCreateFormData = {};
|
||||
if (this.isValidEmail(value)) {
|
||||
this.customerCreateQueryParams = { email: value };
|
||||
data.email = value;
|
||||
} else {
|
||||
this.customerCreateQueryParams = { lastName: value };
|
||||
data.name = { lastName: value };
|
||||
}
|
||||
|
||||
this.customerCreateQueryParams = {
|
||||
formData: encodeFormData(data),
|
||||
};
|
||||
}
|
||||
|
||||
isValidEmail(email: string) {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
<ui-form-control label="Kundenkartencode" requiredMark="*">
|
||||
<ui-form-control label="Kundenkartencode" requiredMark="*" class="flex-grow">
|
||||
<input uiInput type="text" [formControl]="control" [tabindex]="tabIndexStart" [readonly]="readonly" [autofocus]="focusAfterInit" />
|
||||
</ui-form-control>
|
||||
<button type="button" *ngIf="!readonly && canScan()" (click)="scan()">
|
||||
<ui-svg-icon icon="barcode-scan" size="32"></ui-svg-icon>
|
||||
</button>
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
:host {
|
||||
@apply block;
|
||||
@apply block relative;
|
||||
}
|
||||
|
||||
button {
|
||||
@apply absolute -right-2 top-0 h-14 w-14 border-none outline-none bg-transparent items-center justify-center rounded-full bg-brand;
|
||||
|
||||
ui-svg-icon {
|
||||
@apply flex justify-center items-center text-white;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
|
||||
import { FormControl, Validators } from '@angular/forms';
|
||||
import { FormBlockControl } from '../form-block';
|
||||
import { ScanAdapterService } from '@adapter/scan';
|
||||
|
||||
@Component({
|
||||
selector: 'app-p4m-number-form-block',
|
||||
@@ -13,7 +14,7 @@ export class P4mNumberFormBlockComponent extends FormBlockControl<string> {
|
||||
return this.tabIndexStart;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
constructor(private scanAdapter: ScanAdapterService, private changeDetectorRef: ChangeDetectorRef) {
|
||||
super();
|
||||
}
|
||||
|
||||
@@ -30,4 +31,15 @@ export class P4mNumberFormBlockComponent extends FormBlockControl<string> {
|
||||
_patchValue(update: { previous: string; current: string }): void {
|
||||
this.control.patchValue(update.current);
|
||||
}
|
||||
|
||||
scan() {
|
||||
this.scanAdapter.scan().subscribe((result) => {
|
||||
this.control.patchValue(result);
|
||||
this.changeDetectorRef.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
canScan() {
|
||||
return this.scanAdapter.isReady();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,10 @@ import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { UiFormControlModule } from '@ui/form-control';
|
||||
import { UiInputModule } from '@ui/input';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiCommonModule, ReactiveFormsModule, UiFormControlModule, UiInputModule],
|
||||
imports: [CommonModule, UiCommonModule, ReactiveFormsModule, UiFormControlModule, UiInputModule, UiIconModule],
|
||||
exports: [P4mNumberFormBlockComponent],
|
||||
declarations: [P4mNumberFormBlockComponent],
|
||||
})
|
||||
|
||||
@@ -225,7 +225,7 @@ export class CustomerTypeSelectorComponent extends ComponentStore<CustomerTypeSe
|
||||
} else {
|
||||
// wenn customerType nicht gesetzt wird und p4mUser false ist,
|
||||
// dann customerType auf den ersten verfügbaren setzen der nicht mit dem aktuellen customerType übereinstimmt.
|
||||
this.customerType = first(this.enabledOptions.filter((o) => o.value !== this.customerType))?.value ?? this.customerType;
|
||||
this.customerType = first(this.enabledOptions.filter((o) => o.value === this.customerType))?.value ?? this.customerType;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -210,13 +210,32 @@ export class GoodsInReservationComponent implements OnInit, OnDestroy {
|
||||
try {
|
||||
for (const buyerNumber of buyerNumbers) {
|
||||
const itemsToUpdateForEachCustomer = itemsToUpdate.filter((item) => item.buyerNumber === buyerNumber);
|
||||
const itemQuantity = new Map(itemsToUpdateForEachCustomer.map((item) => [item.orderItemSubsetId, item.quantity]));
|
||||
const data: OrderItemsContext = {
|
||||
items: itemsToUpdateForEachCustomer,
|
||||
shippingDelayComment: `Aktion: ${action.label}`,
|
||||
itemQuantity,
|
||||
};
|
||||
await this._commandService.handleCommand(action.command, data);
|
||||
|
||||
const itemsToUpdateGroupedByCommand = itemsToUpdateForEachCustomer.reduce<Record<string, OrderItemListItemDTO[]>>((acc, item) => {
|
||||
const command = item.actions.find((a) => a.value === action.value)?.command;
|
||||
if (!acc[command]) {
|
||||
acc[command] = [];
|
||||
}
|
||||
acc[command].push(item);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
let compartmentCode: string;
|
||||
|
||||
for (const command of Object.keys(itemsToUpdateGroupedByCommand)) {
|
||||
const itemsToUpdateForCommand = itemsToUpdateGroupedByCommand[command];
|
||||
const itemQuantity = new Map(itemsToUpdateForCommand.map((item) => [item.orderItemSubsetId, item.quantity]));
|
||||
|
||||
const data: OrderItemsContext = {
|
||||
items: itemsToUpdateForCommand,
|
||||
shippingDelayComment: `Aktion: ${action.label}`,
|
||||
itemQuantity,
|
||||
compartmentCode,
|
||||
};
|
||||
|
||||
const result = await this._commandService.handleCommand(command, data);
|
||||
compartmentCode = result.compartmentCode;
|
||||
}
|
||||
}
|
||||
this._store.reload();
|
||||
this.unselectAll();
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
<div class="inline-flex flex-row bg-white rounded-md mt-4">
|
||||
<button
|
||||
class="w-48 py-2 bg-white text-black rounded-md font-bold"
|
||||
class="w-48 py-2 bg-white rounded-md font-bold"
|
||||
type="button"
|
||||
*ngFor="let source of sources$ | async"
|
||||
[class.bg-active-branch]="(selectedSource$ | async) === source"
|
||||
|
||||
@@ -40,7 +40,7 @@ export class TaskSearchbarComponent implements OnInit, OnDestroy {
|
||||
ngOnInit(): void {
|
||||
this.control.patchValue(this.getControlValueFromQuery());
|
||||
|
||||
this.control.valueChanges.pipe(takeUntil(this._onDestroy$), debounceTime(500)).subscribe((value) => {
|
||||
this.control.valueChanges.pipe(takeUntil(this._onDestroy$), debounceTime(250)).subscribe((value) => {
|
||||
this.setValueInFilter(value);
|
||||
this._cdr.markForCheck();
|
||||
});
|
||||
@@ -86,7 +86,8 @@ export class TaskSearchbarComponent implements OnInit, OnDestroy {
|
||||
this.navigate('/filiale/task-calendar/search', params);
|
||||
|
||||
// ActivatedRouteChange wird nicht aufgerufen, wenn sich die URL nicht verändert. In dem Fall erneute Suche ausführen
|
||||
if (isEqual(filter.getQueryParams(), this._activatedRoute.snapshot.queryParams)) {
|
||||
const isSearchPage = this._router.url.startsWith('/filiale/task-calendar/search?');
|
||||
if (isSearchPage && isEqual(filter.getQueryParams(), this._activatedRoute.snapshot.queryParams)) {
|
||||
this.taskCalendarStore.search({ clear: true });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,8 @@ export class TaskCalendarFilterComponent implements OnInit, OnDestroy {
|
||||
this.navigate('/filiale/task-calendar/search', queryParams);
|
||||
|
||||
// ActivatedRouteChange wird nicht aufgerufen, wenn sich die URL nicht verändert. In dem Fall erneute Suche ausführen
|
||||
if (isEqual(filters.getQueryParams(), this._activatedRoute.snapshot.queryParams)) {
|
||||
const isSearchPage = this._router.url.startsWith('/filiale/task-calendar/search?');
|
||||
if (isSearchPage && isEqual(filters.getQueryParams(), this._activatedRoute.snapshot.queryParams)) {
|
||||
this.taskCalendarStore.search({ clear: true });
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Component, ViewChild, ElementRef, OnInit, OnDestroy } from '@angular/co
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Config } from '@core/config';
|
||||
import { UiFilter } from '@ui/filter';
|
||||
import { isEqual } from 'lodash';
|
||||
import { delay, isEqual } from 'lodash';
|
||||
import { BehaviorSubject, combineLatest, Subject } from 'rxjs';
|
||||
import { first, map, shareReplay, takeUntil, debounceTime } from 'rxjs/operators';
|
||||
import { TaskSearchbarComponent } from './components/task-searchbar/task-searchbar.component';
|
||||
@@ -46,13 +46,15 @@ export class PageTaskCalendarComponent implements OnInit, OnDestroy {
|
||||
this.searchbar?.focus();
|
||||
});
|
||||
|
||||
this._activatedRoute.queryParams.pipe(takeUntil(this._onDestroy$), debounceTime(500)).subscribe(async (queryParams) => {
|
||||
this._activatedRoute.queryParams.pipe(takeUntil(this._onDestroy$), debounceTime(250)).subscribe(async (queryParams) => {
|
||||
const filters = UiFilter.create(await this.taskCalendarStore.selectInitialFilter.pipe(first()).toPromise());
|
||||
if (queryParams) {
|
||||
filters.fromQueryParams(queryParams);
|
||||
}
|
||||
this.taskCalendarStore.setFilter({ filters });
|
||||
});
|
||||
|
||||
this.taskCalendarStore.loadItems();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
|
||||
@@ -70,7 +70,7 @@ export class TaskSearchComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this._activatedRoute.queryParams.pipe(takeUntil(this._onDestroy$), debounceTime(500)).subscribe(async (queryParams) => {
|
||||
this._activatedRoute.queryParams.pipe(takeUntil(this._onDestroy$), debounceTime(250)).subscribe(async (queryParams) => {
|
||||
this.taskCalendarStore.search({ clear: true });
|
||||
this.updateBreadcrumb(queryParams);
|
||||
});
|
||||
@@ -79,7 +79,7 @@ export class TaskSearchComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.taskCalendarStore.searchTarget$.pipe(takeUntil(this._onDestroy$), debounceTime(500)).subscribe((target) => {
|
||||
this.taskCalendarStore.searchTarget$.pipe(takeUntil(this._onDestroy$), debounceTime(250)).subscribe((target) => {
|
||||
setTimeout(() => {
|
||||
document.getElementById(target)?.scrollIntoView();
|
||||
}, 0);
|
||||
|
||||
@@ -50,7 +50,6 @@ export class TasksComponent implements OnInit {
|
||||
this.updateBreadcrumb({});
|
||||
}
|
||||
|
||||
this.taskCalendarStore.loadItems();
|
||||
this.removeSearchBreadcrumbs();
|
||||
|
||||
this.taskCalendarStore.resetSearch();
|
||||
|
||||
@@ -7,8 +7,8 @@ import { DateAdapter } from '@ui/common';
|
||||
import { Filter, FilterOption, SelectFilter, UiFilter, UiFilterMappingService } from '@ui/filter';
|
||||
import { UiMessageModalComponent, UiModalRef, UiModalResult, UiModalService } from '@ui/modal';
|
||||
import { clone } from 'lodash';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { debounceTime, map, switchMap, tap, withLatestFrom, first, filter } from 'rxjs/operators';
|
||||
import { Observable, Subject, zip } from 'rxjs';
|
||||
import { debounceTime, map, switchMap, tap, withLatestFrom, first, takeWhile, filter } 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';
|
||||
@@ -91,21 +91,21 @@ export class TaskCalendarStore extends ComponentStore<TaskCalendarState> impleme
|
||||
const fdow = this.dateAdapter.getFirstDateOfWeek(displayedDate);
|
||||
const fdowWithOffset = this.dateAdapter.addCalendarDays(fdow, -7);
|
||||
const ldow = this.dateAdapter.getLastDateOfWeek(displayedDate);
|
||||
const ldowWithOffset = this.dateAdapter.addCalendarDays(ldow, 7);
|
||||
|
||||
return {
|
||||
start: fdowWithOffset,
|
||||
stop: ldowWithOffset,
|
||||
stop: ldow,
|
||||
};
|
||||
} else {
|
||||
const fdom = this.dateAdapter.getFirstDateOfMonth(displayedDate);
|
||||
const fdomWithOffset = this.dateAdapter.addCalendarDays(fdom, -7);
|
||||
const ldom = this.dateAdapter.getLastDateOfMonth(displayedDate);
|
||||
const ldomWithOffset = this.dateAdapter.addCalendarDays(ldom, 7);
|
||||
return {
|
||||
start: fdomWithOffset,
|
||||
stop: ldomWithOffset,
|
||||
};
|
||||
const month = this.dateAdapter.getDatesAndCalendarWeeksForMonth(displayedDate);
|
||||
if (month.length > 0) {
|
||||
const firstWeekOfMonth = month[0];
|
||||
const lastWeekOfMonth = month[month.length - 1];
|
||||
return {
|
||||
start: firstWeekOfMonth.dates[0],
|
||||
stop: lastWeekOfMonth.dates[lastWeekOfMonth.dates.length - 1],
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -166,68 +166,73 @@ export class TaskCalendarStore extends ComponentStore<TaskCalendarState> impleme
|
||||
searchTarget,
|
||||
}));
|
||||
|
||||
readonly search = this.effect((options$: Observable<{ clear?: boolean }>) =>
|
||||
options$.pipe(
|
||||
search = this.effect((options$: Observable<{ clear?: boolean }>) => {
|
||||
const currentBranch$ = this.domainTaskCalendarService.currentBranchId$.pipe(filter((f) => !!f));
|
||||
const selectFilter$ = this.selectFilter.pipe(filter((f) => !!f));
|
||||
return options$.pipe(
|
||||
tap(() => this.patchState({ isSearching: true, searchTarget: '' })),
|
||||
debounceTime(500),
|
||||
withLatestFrom(this.domainTaskCalendarService.currentBranchId$, this.selectFilter),
|
||||
switchMap(([options, branchId, filter]) => {
|
||||
const querytoken = {
|
||||
...filter?.getQueryToken(),
|
||||
// Paging ist vorbereitet aber vorerst deaktiviert
|
||||
// skip: results.length || 0,
|
||||
// take: 50,
|
||||
};
|
||||
debounceTime(150),
|
||||
switchMap((options) =>
|
||||
zip(currentBranch$, selectFilter$).pipe(
|
||||
switchMap(([branchId, filter]) => {
|
||||
const querytoken = {
|
||||
...filter?.getQueryToken(),
|
||||
};
|
||||
|
||||
// Im Zeitraum von 6 Wochen in der Vergangenheit und 2 Wochen in der Zukunft abfragen
|
||||
const start = this.dateAdapter.addCalendarDays(this.dateAdapter.today(), -42);
|
||||
const stop = this.dateAdapter.addCalendarDays(this.dateAdapter.today(), 14);
|
||||
return this.domainTaskCalendarService
|
||||
.getInfos({
|
||||
...querytoken,
|
||||
filter: {
|
||||
timespan: `"${start.toISOString()}"-"${stop?.toISOString()}"`,
|
||||
...querytoken?.filter,
|
||||
branch_id: String(branchId),
|
||||
},
|
||||
// Im Zeitraum von 6 Wochen in der Vergangenheit und 2 Wochen in der Zukunft abfragen
|
||||
const start = this.dateAdapter.addCalendarDays(this.dateAdapter.today(), -42);
|
||||
const stop = this.dateAdapter.addCalendarDays(this.dateAdapter.today(), 14);
|
||||
return this.domainTaskCalendarService
|
||||
.getInfos({
|
||||
...querytoken,
|
||||
filter: {
|
||||
timespan: `"${start.toISOString()}"-"${stop?.toISOString()}"`,
|
||||
...querytoken?.filter,
|
||||
branch_id: String(branchId),
|
||||
},
|
||||
})
|
||||
.pipe(
|
||||
tapResponse(
|
||||
(response) => {
|
||||
if (!response.error) {
|
||||
response = this.preparePreInfos(response);
|
||||
|
||||
const results = this.get((s) => s.searchResults);
|
||||
const searchResults = results.length > 0 && !options?.clear ? [...results, ...response.result] : [...response.result];
|
||||
const sorted = searchResults.sort((a, b) =>
|
||||
this.dateAdapter.findClosestDate(
|
||||
new Date(a.taskDate || a.publicationDate),
|
||||
new Date(b.taskDate || b.publicationDate)
|
||||
)
|
||||
);
|
||||
const searchTarget =
|
||||
sorted?.length > 0
|
||||
? this.domainTaskCalendarService.getDateGroupKey(sorted[0].taskDate || sorted[0].publicationDate)
|
||||
: '';
|
||||
|
||||
this.patchState({
|
||||
searchResults,
|
||||
searchTarget,
|
||||
isSearching: false,
|
||||
message: undefined,
|
||||
hits: response.hits,
|
||||
});
|
||||
} else {
|
||||
this.uiModal.open({ content: UiMessageModalComponent, data: response });
|
||||
this.patchState({ searchResults: [], isSearching: false, message: 'Keine Suchergebnisse' });
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.error(error);
|
||||
this.patchState({ searchResults: [], isSearching: false, message: 'Keine Suchergebnisse' });
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
.pipe(
|
||||
tapResponse(
|
||||
(response) => {
|
||||
if (!response.error) {
|
||||
response = this.preparePreInfos(response);
|
||||
|
||||
const results = this.get((s) => s.searchResults);
|
||||
const searchResults = results.length > 0 && !options?.clear ? [...results, ...response.result] : [...response.result];
|
||||
const sorted = searchResults.sort((a, b) =>
|
||||
this.dateAdapter.findClosestDate(new Date(a.taskDate || a.publicationDate), new Date(b.taskDate || b.publicationDate))
|
||||
);
|
||||
const searchTarget =
|
||||
sorted?.length > 0
|
||||
? this.domainTaskCalendarService.getDateGroupKey(sorted[0].taskDate || sorted[0].publicationDate)
|
||||
: '';
|
||||
|
||||
this.patchState({
|
||||
searchResults,
|
||||
searchTarget,
|
||||
isSearching: false,
|
||||
message: undefined,
|
||||
hits: response.hits,
|
||||
});
|
||||
} else {
|
||||
this.uiModal.open({ content: UiMessageModalComponent, data: response });
|
||||
this.patchState({ searchResults: [], isSearching: false, message: 'Keine Suchergebnisse' });
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.error(error);
|
||||
this.patchState({ searchResults: [], isSearching: false, message: 'Keine Suchergebnisse' });
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
resetSearch() {
|
||||
this.patchState({ searchResults: [], hits: undefined });
|
||||
@@ -241,45 +246,52 @@ export class TaskCalendarStore extends ComponentStore<TaskCalendarState> impleme
|
||||
this._searchbarFocus$.complete();
|
||||
}
|
||||
|
||||
readonly loadItems = this.effect(($: Observable<void>) =>
|
||||
$.pipe(
|
||||
loadItems = this.effect(($: Observable<void>) => {
|
||||
const currentBranch$ = this.domainTaskCalendarService.currentBranchId$.pipe(filter((f) => !!f));
|
||||
const selectStartStop$ = this.selectStartStop.pipe(filter((f) => !!f));
|
||||
const selectInitialFilter$ = this.selectInitialFilter.pipe(filter((f) => !!f));
|
||||
|
||||
return $.pipe(
|
||||
tap(() => this.patchState({ fetching: true })),
|
||||
debounceTime(500),
|
||||
withLatestFrom(this.domainTaskCalendarService.currentBranchId$, this.selectStartStop, this.selectInitialFilter),
|
||||
switchMap(([_, branchId, date, filter]) => {
|
||||
const querytoken = { ...filter?.getQueryToken() };
|
||||
return this.domainTaskCalendarService
|
||||
.getInfos({
|
||||
...querytoken,
|
||||
filter: {
|
||||
...querytoken?.filter,
|
||||
branch_id: String(branchId),
|
||||
timespan: `"${date?.start?.toISOString()}"-"${date.stop?.toISOString()}"`,
|
||||
},
|
||||
debounceTime(250),
|
||||
switchMap((_) =>
|
||||
zip(currentBranch$, selectStartStop$, selectInitialFilter$).pipe(
|
||||
switchMap(([branchId, date, filter]) => {
|
||||
const querytoken = { ...filter?.getQueryToken() };
|
||||
return this.domainTaskCalendarService
|
||||
.getInfos({
|
||||
...querytoken,
|
||||
filter: {
|
||||
...querytoken?.filter,
|
||||
branch_id: String(branchId),
|
||||
timespan: `"${date?.start?.toISOString()}"-"${date.stop?.toISOString()}"`,
|
||||
},
|
||||
})
|
||||
.pipe(
|
||||
tapResponse(
|
||||
(response) => {
|
||||
if (!response.error) {
|
||||
response = this.preparePreInfos(response);
|
||||
this.patchState({ displayInfos: response.result, fetching: false, message: undefined });
|
||||
} else {
|
||||
this.uiModal.open({
|
||||
content: UiMessageModalComponent,
|
||||
data: response,
|
||||
});
|
||||
this.patchState({ displayInfos: [], fetching: false, message: 'Keine Suchergebnisse' });
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.error(error);
|
||||
this.patchState({ displayInfos: [], fetching: false, message: 'Keine Suchergebnisse' });
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
.pipe(
|
||||
tapResponse(
|
||||
(response) => {
|
||||
if (!response.error) {
|
||||
response = this.preparePreInfos(response);
|
||||
this.patchState({ displayInfos: response.result, fetching: false, message: undefined });
|
||||
} else {
|
||||
this.uiModal.open({
|
||||
content: UiMessageModalComponent,
|
||||
data: response,
|
||||
});
|
||||
this.patchState({ displayInfos: [], fetching: false, message: 'Keine Suchergebnisse' });
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.error(error);
|
||||
this.patchState({ displayInfos: [], fetching: false, message: 'Keine Suchergebnisse' });
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
preparePreInfos(response) {
|
||||
const preInfos = response.result.filter((info) => this.domainTaskCalendarService.getInfoType(info) === 'PreInfo');
|
||||
|
||||
@@ -134,7 +134,7 @@
|
||||
<input uiInput formControlName="price" />
|
||||
</ui-form-control>
|
||||
|
||||
<ui-form-control label="IBAN/EAN" [clearable]="true" variant="inline" requiredMark=" *">
|
||||
<ui-form-control label="ISBN/EAN" [clearable]="true" variant="inline" requiredMark=" *">
|
||||
<input uiInput formControlName="ean" />
|
||||
</ui-form-control>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { UISvgIconComponent } from './svg-icon.component';
|
||||
import { IconRegistry } from './icon-registry';
|
||||
import { UI_ICON_CFG } from './tokens';
|
||||
import { UiIconConfig } from './icon-config';
|
||||
import { mdiAccount, mdiPackageVariantClosed } from '@mdi/js';
|
||||
import { mdiAccount, mdiPackageVariantClosed, mdiMagnify, mdiBarcodeScan } from '@mdi/js';
|
||||
|
||||
export function _rootIconRegistryFactory(config: UiIconConfig): IconRegistry {
|
||||
const registry = new IconRegistry();
|
||||
@@ -28,6 +28,8 @@ const DEFAULT_ICON_CONFIG: UiIconConfig = {
|
||||
icons: [
|
||||
{ name: 'account', data: mdiAccount },
|
||||
{ name: 'package-variant-closed', data: mdiPackageVariantClosed },
|
||||
{ name: 'magnify', data: mdiMagnify },
|
||||
{ name: 'barcode-scan', data: mdiBarcodeScan },
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
464
package-lock.json
generated
464
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user