Compare commits

...

34 Commits

Author SHA1 Message Date
Lorenz Hilpert
02b507aca9 Merge branch 'hotfix/4323-WBS-Fehlende-Wannenummer' 2023-09-29 16:10:57 +02:00
Lorenz Hilpert
05f94c65fc 4323 Remi // WBS ohne Wannennummer -> Fehlermeldung 2023-09-29 16:09:46 +02:00
Nino Righi
85d8d75da8 Merged PR 1630: #4299 Take Price and priceMaintained from Catalog First
#4299 Take Price and priceMaintained from Catalog First
2023-09-19 12:20:54 +00:00
Nino Righi
423cd498cf Merged PR 1628: #4271 Added canAdd request for adding items to Kulturpass Cart Modal
#4271 Added canAdd request for adding items to Kulturpass Cart Modal
2023-09-18 08:42:26 +00:00
Nino Righi
df308c98ff Merged PR 1626: #4299 Hotfix Kulturpass Fallback if Delivery Availability Is Missing
#4299 Hotfix Kulturpass Fallback if Delivery Availability Is Missing
2023-09-14 14:02:44 +00:00
Lorenz Hilpert
f4df6e8799 Merge branch 'hotfix/4270-4269-Archiv-Artikel' 2023-08-30 10:31:58 +02:00
Lorenz Hilpert
e9a63fd553 #4274 Kaufoption - Preis nicht übernommen 2023-08-29 11:31:58 +02:00
Lorenz Hilpert
23b77c7e48 #4269 Preis wird nicht von Shipping AVA übernommen 2023-08-28 17:01:20 +02:00
Lorenz Hilpert
8b6188a6b5 #4270 Kaufoptionen Bestellung via Mehrfachauswahl wirft Fehler 2023-08-28 14:39:37 +02:00
Lorenz Hilpert
822625a1c2 #4269 PDP Preisanzeige 2023-08-28 14:36:29 +02:00
Lorenz Hilpert
819827cc4c Merge branch 'hotfix/4266-Archivartikel' 2023-08-24 20:04:40 +02:00
Lorenz Hilpert
d09b5b1ce7 #4266 Archivartikel nach Preis-Eingabe Button ausgegraut 2023-08-24 20:03:59 +02:00
Michael Auer
180e93a7da Merge branch 'release/2.3' 2023-08-24 11:50:39 +02:00
Lorenz Hilpert
9671683a93 #4246 UI Searchbox Hint Erneut anzeigen 2023-08-04 15:56:51 +02:00
Lorenz Hilpert
d909d6e804 #4236 Kulturpass - Artikel ohne Preisbindung erhalten günstigeren Preis
(cherry picked from commit 1d865c47d7)
2023-08-03 17:06:46 +02:00
Lorenz Hilpert
15c50779b4 #4245 Wannernummer-Prüfung - Leerzeichen entfernen 2023-08-03 17:05:45 +02:00
Lorenz Hilpert
5bdfec7c3f #4222 Packstückprüfung aktiviert 2023-08-02 10:55:54 +02:00
Lorenz Hilpert
810653c4d1 #4194 Icons DR und PP hinzugefügt 2023-07-28 14:50:44 +02:00
Lorenz Hilpert
eddff0d93f #4232 Preisanzeige bei Versanbestellung 2023-07-27 17:50:09 +02:00
Lorenz Hilpert
44b406fad4 #4221 Scanner - Adapter sind nicht bereit
(cherry picked from commit 78e76818b5)
2023-07-25 14:57:09 +02:00
Lorenz Hilpert
8416028113 (cherry picked from commit edb21308d4) 2023-07-21 10:52:21 +02:00
Lorenz Hilpert
44b33c1e4c Revert "#4209 - FIX - KulturPass-Einlösecode lässt Abholfrist ändern"
This reverts commit 02d60e9bd5.
2023-07-20 13:56:08 +02:00
Lorenz Hilpert
6fb72e4b2f #4121 Vormerker kann nicht manuell bearbeitet werden 2023-07-20 11:42:41 +02:00
Lorenz Hilpert
fce50daff6 #4209 - FIX - KulturPass-Einlösecode lässt Abholfrist ändern 2023-07-19 18:41:06 +02:00
Lorenz Hilpert
b954947bb7 Merge branch 'release/2.3' of https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend into release/2.3 2023-07-19 17:45:36 +02:00
Lorenz Hilpert
ddd5d50c5d #4211 Kaufoptionen popup - Prüfung ob Artikel mit Kunden kombinierbar ist 2023-07-19 17:45:17 +02:00
Lorenz Hilpert
215d7ca341 Benachrichtigung für Packstückprüfung einblenden 2023-07-17 01:31:17 +02:00
Lorenz Hilpert
1255df10e0 Benachrichtigungen für Packstückprüfung ausblenden 2023-07-17 01:30:40 +02:00
Lorenz Hilpert
ac35cc237e Leere Notifications nicht anzeigen 2023-07-14 14:50:08 +02:00
Lorenz Hilpert
4fe5034e1c #3666 Design Anpassung 2023-07-14 13:12:48 +02:00
Nino Righi
eec1cb5666 Merged PR 1589: #4180 Hotfix Mehrfachauswahl Für Download Artikel direkt Logistician setzen
#4180 Hotfix Mehrfachauswahl Für Download Artikel direkt Logistician setzen
2023-07-13 08:05:16 +00:00
Lorenz Hilpert
b62e6e8e35 #3666 Benachrichtigung über die Glocke 2023-07-12 17:57:31 +02:00
Nino Righi
b845147050 Merged PR 1584: #4180 Hotfix Add Logistician to Download Destination
#4180 Hotfix Add Logistician to Download Destination
2023-07-11 11:45:10 +00:00
Michael Auer
6bc265a358 Merge branch 'release/2.3' 2023-07-11 12:20:14 +02:00
103 changed files with 1413 additions and 894 deletions

View File

@@ -14,7 +14,6 @@ export class ScanAdapterService {
async init(): Promise<void> {
for (const adapter of this.scanAdapters) {
const isReady = await adapter.init();
console.log('ScanAdapterService.init', adapter.name, isReady);
this._readyAdapters[adapter.name] = isReady;
}
}
@@ -24,52 +23,30 @@ export class ScanAdapterService {
}
getAdapter(name: string): ScanAdapter | undefined {
return this.scanAdapters.find((adapter) => adapter.name === name);
return this._readyAdapters[name] && this.scanAdapters.find((adapter) => adapter.name === name);
}
// return true if at least one adapter is ready
isReady(): boolean {
return Object.values(this._readyAdapters).some((ready) => ready);
}
scan(ops: { use?: string; include?: string[]; exclude?: string[] } = {}): Observable<string> {
scan(): Observable<string> {
const adapterOrder = ['Native', 'Scandit', 'Dev'];
let adapter: ScanAdapter;
if (ops.use == undefined) {
const adapterOrder = ['Native', 'Scandit', 'Dev'];
for (const name of adapterOrder) {
adapter = this.getAdapter(name);
for (const name of adapterOrder) {
adapter = this.getAdapter(name);
if (adapter) {
break;
}
if (adapter) {
break;
}
// get the first adapter that is ready to use
// adapter = this.scanAdapters
// .filter((adapter) => {
// if (ops.include?.length) {
// return ops.include.includes(adapter.name);
// } else if (ops.exclude?.length) {
// return !ops.exclude.includes(adapter.name);
// } else {
// return true;
// }
// })
// .find((adapter) => this._readyAdapters[adapter.name]);
} else {
adapter = this.getAdapter(ops.use);
}
if (!adapter) {
return throwError('No adapter found');
}
if (this._readyAdapters[adapter.name] == false) {
return throwError('Adapter is not ready');
}
return adapter.scan();
}
}

View File

@@ -23,6 +23,7 @@ import { ResponseArgsOfIEnumerableOfStockInfoDTO, StockDTO, StockInfoDTO, StockS
import { PriceDTO } from '@swagger/availability';
import { AvailabilityByBranchDTO, ItemData } from './defs';
import { Availability } from './defs/availability';
import { isEmpty } from 'lodash';
@Injectable()
export class DomainAvailabilityService {
@@ -155,7 +156,6 @@ export class DomainAvailabilityService {
quantity: number;
branch?: BranchDTO;
}): Observable<AvailabilityDTO> {
console.log('getTakeAwayAvailability', item, quantity, branch);
const request = !!branch ? this.getStockByBranch(branch.id) : this.getDefaultStock();
return request.pipe(
switchMap((s) =>
@@ -480,6 +480,10 @@ export class DomainAvailabilityService {
};
}
private _priceIsEmpty(price: PriceDTO) {
return isEmpty(price?.value) || isEmpty(price?.vat);
}
private _mapToTakeAwayAvailability({
response,
supplier,
@@ -500,7 +504,7 @@ export class DomainAvailabilityService {
inStock: inStock,
supplierSSC: quantity <= inStock ? '999' : '',
supplierSSCText: quantity <= inStock ? 'Filialentnahme' : '',
price: price ?? stockInfo?.retailPrice,
price: this._priceIsEmpty(price) ? stockInfo?.retailPrice : price,
supplier: { id: supplier?.id },
// TODO: Change after API Update
// LH: 2021-03-09 preis Property hat nun ein Fallback auf retailPrice

View File

@@ -27,6 +27,9 @@ import {
StoreCheckoutPayerService,
StoreCheckoutBranchService,
ItemsResult,
KulturPassService,
ProductDTO,
KulturPassResult,
} from '@swagger/checkout';
import {
DisplayOrderDTO,
@@ -44,7 +47,7 @@ import * as DomainCheckoutActions from './store/domain-checkout.actions';
import { DomainAvailabilityService } from '@domain/availability';
import { HttpErrorResponse } from '@angular/common/http';
import { ApplicationService } from '@core/application';
import { CustomerDTO, EntityDTOContainerOfAttributeDTO } from '@swagger/crm';
import { CustomerDTO } from '@swagger/crm';
@Injectable()
export class DomainCheckoutService {
@@ -58,7 +61,8 @@ export class DomainCheckoutService {
private _paymentService: StoreCheckoutPaymentService,
private _buyerService: StoreCheckoutBuyerService,
private _payerService: StoreCheckoutPayerService,
private _branchService: StoreCheckoutBranchService
private _branchService: StoreCheckoutBranchService,
private _kulturpassService: KulturPassService
) {}
//#region shoppingcart
@@ -205,6 +209,10 @@ export class DomainCheckoutService {
);
}
canAddItemsKulturpass(payload: ProductDTO[]): Observable<KulturPassResult[]> {
return this._kulturpassService.KulturPassCanAddForKulturPass({ payload }).pipe(map((response) => response?.result));
}
canAddItems({
processId,
payload,

View File

@@ -4,61 +4,118 @@ import { SignalrHub, SignalRHubOptions } from '@core/signalr';
import { BehaviorSubject, merge, of } from 'rxjs';
import { filter, map, shareReplay, tap, withLatestFrom } from 'rxjs/operators';
import { EnvelopeDTO, MessageBoardItemDTO } from './defs';
import { cloneDeep } from 'lodash';
export const NOTIFICATIONS_HUB_OPTIONS = new InjectionToken<SignalRHubOptions>('hub.notifications.options');
@Injectable()
export class NotificationsHub extends SignalrHub {
updateNotification$ = new BehaviorSubject<MessageBoardItemDTO>(undefined);
get branchNo() {
return String(this._auth.getClaimByKey('branch_no') || this._auth.getClaimByKey('sub'));
}
// get sessionStoragesessionStorageKey() {
// return `NOTIFICATIONS_BOARD_${this.branchNo}`;
// }
get sessionStoragesessionStorageKey() {
return `NOTIFICATIONS_BOARD_${this.branchNo}`;
return `NOTIFICATIONS_BOARD_AREA_${this.branchNo}`;
}
messageBoardItems$ = new BehaviorSubject<Record<string, MessageBoardItemDTO[]>>({});
constructor(@Inject(NOTIFICATIONS_HUB_OPTIONS) options: SignalRHubOptions, private _auth: AuthService) {
super(options);
this.messageBoardItems$.next(this._getNotifications());
this.messageBoardItems$.subscribe((data) => {
this._storeNotifactions(data);
});
this.listen<EnvelopeDTO<MessageBoardItemDTO[]>>('messageBoard').subscribe((envelope) => {
if (envelope.action === 'refresh') {
this.refreshMessageBoardItems(envelope.target.area, envelope.data);
}
});
}
notifications$ = merge(
of(this._getNotifications()).pipe(filter((f) => !!f)),
this.listen<EnvelopeDTO<MessageBoardItemDTO[]>>('messageBoard')
).pipe(
withLatestFrom(this.updateNotification$),
map(([d, update]) => {
const data = d;
if (update && !!data && !data?.data?.find((message) => message?.category === 'ISA-Update')) {
data.data.push(update);
refreshMessageBoardItems(targetArea: string, messages: MessageBoardItemDTO[]) {
const current = cloneDeep(this.messageBoardItems$.value);
current[targetArea] = messages ?? [];
this.messageBoardItems$.next(current);
}
notifications$ = this.messageBoardItems$.asObservable().pipe(
map((data) => {
const messages = { ...data };
const keys = Object.keys(data);
for (let key of keys) {
if (data[key].length === 0 || data[key] === undefined) {
delete messages[key];
}
}
return data;
}),
tap((data) => this._storeNotifactions(data)),
shareReplay(1)
return messages;
})
);
private _storeNotifactions(data: EnvelopeDTO<MessageBoardItemDTO[]>) {
if (data) {
sessionStorage.setItem(this.sessionStoragesessionStorageKey, JSON.stringify(data));
}
}
// notifications$ = merge(
// of(this._getNotifications()).pipe(filter((f) => !!f)),
// this.listen<EnvelopeDTO<MessageBoardItemDTO[]>>('messageBoard')
// ).pipe(
// withLatestFrom(this.updateNotification$),
// map(([d, update]) => {
// console.log('notifications$', d, update);
// const data = d;
// if (update && !!data && !data?.data?.find((message) => message?.category === 'ISA-Update')) {
// data.data.push(update);
// }
// return data;
// }),
// tap((data) => this._storeNotifactions(data)),
// shareReplay(1)
// );
private _getNotifications(): EnvelopeDTO<MessageBoardItemDTO[]> {
// private _storeNotifactions(data: EnvelopeDTO<MessageBoardItemDTO[]>) {
// if (data) {
// sessionStorage.setItem(this.sessionStoragesessionStorageKey, JSON.stringify(data));
// }
// }
// private _getNotifications(): EnvelopeDTO<MessageBoardItemDTO[]> {
// const stringData = sessionStorage.getItem(this.sessionStoragesessionStorageKey);
// if (stringData) {
// return JSON.parse(stringData);
// }
// return undefined;
// }
private _getNotifications(): Record<string, MessageBoardItemDTO[]> {
const stringData = sessionStorage.getItem(this.sessionStoragesessionStorageKey);
if (stringData) {
return JSON.parse(stringData);
}
return undefined;
return {};
}
private _storeNotifactions(data: Record<string, MessageBoardItemDTO[]>) {
if (data) {
delete data['messageBoard/isa-update'];
sessionStorage.setItem(this.sessionStoragesessionStorageKey, JSON.stringify(data));
}
}
updateNotification() {
this.updateNotification$.next({
category: 'ISA-Update',
type: 'update',
headline: 'Update Benachrichtigung',
text: 'Es steht eine aktuellere Version der ISA bereit. Bitte aktualisieren Sie die Anwendung.',
});
this.refreshMessageBoardItems('messageBoard/isa-update', [
{
category: 'ISA-Update',
type: 'update',
headline: 'Update Benachrichtigung',
text: 'Es steht eine aktuellere Version der ISA bereit. Bitte aktualisieren Sie die Anwendung.',
},
]);
}
}

View File

@@ -73,10 +73,10 @@
<ui-icon icon="documents_refresh" size="24px"></ui-icon>
Remission
</a>
<!-- <a [routerLink]="['/filiale/package-inspection']" routerLinkActive="active" (click)="fetchAndOpenPackages()">
<a [routerLink]="['/filiale/package-inspection']" routerLinkActive="active" (click)="fetchAndOpenPackages()">
<ui-svg-icon icon="clipboard-check-outline" [size]="24"></ui-svg-icon>
Wareneingang
</a> -->
</a>
</ng-container>
</shell-footer>
</div>

View File

@@ -29,7 +29,9 @@ export class ShellComponent {
notifications$ = this._notificationsHub.notifications$;
notificationCount$ = this.notifications$.pipe(map((message) => message?.data?.length));
notificationCount$ = this.notifications$.pipe(
map((notifications) => Object.values(notifications).reduce((acc, val) => acc + val?.length ?? 0, 0))
);
get activatedProcessId$() {
return this._appService.getActivatedProcessId$().pipe(

View File

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="22px" height="18px" viewBox="0 0 22 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.2 (67145) - http://www.bohemiancoding.com/sketch -->
<title>Icon_HC</title>
<desc>Created with Sketch.</desc>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Hugendubel_Icons" transform="translate(-29.000000, -177.000000)" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.3">
<path d="M32.725699,178.000628 C32.7430505,177.999791 32.7604307,177.999791 32.7777823,178.000628 L37.5260449,178.000628 C38.53109,178.000628 39.44018,178.547926 40.0000026,179.340692 C40.5598253,178.547926 41.4689153,178.000628 42.4739603,178.000628 L47.222223,178.000628 C47.529035,178.00066 47.7777477,178.256627 47.7777784,178.572389 L47.7777784,179.71591 L49.4444446,179.71591 C49.7512567,179.715942 49.9999694,179.971909 50,180.287671 L50,192.008763 C49.9999694,192.324524 49.7512567,192.580492 49.4444446,192.580523 L42.4739603,192.580523 C41.4766486,192.580523 40.8524541,192.949423 40.4947942,193.688309 C40.3998428,193.879608 40.208727,194 40.0000026,194 C39.7912783,194 39.6001624,193.879608 39.5052111,193.688309 C39.1475512,192.949423 38.5233566,192.580523 37.5260449,192.580523 L30.5555607,192.580523 C30.2487486,192.580492 30.0000359,192.324524 30.0000053,192.008763 L30.0000053,180.287671 C29.9987652,179.991708 30.2171687,179.743681 30.5034773,179.71591 C30.5208289,179.715072 30.5382091,179.715072 30.5555607,179.71591 L32.2222269,179.71591 L32.2222269,178.572389 C32.2209869,178.276426 32.4393904,178.028399 32.725699,178.000628 Z M33.3333377,179.14415 L33.3333377,189.43584 L36.6232674,189.43584 C37.6190746,189.43584 38.5547188,189.729711 39.2621556,190.356017 C39.3270606,190.413476 39.3849347,190.480265 39.4444472,190.543626 L39.4444472,180.957703 C39.4433388,180.936873 39.4433388,180.915996 39.4444472,180.895166 C39.4444472,180.068361 38.4768339,179.14415 37.5260449,179.14415 L33.3333377,179.14415 Z M42.4739603,179.14415 C41.5231714,179.14415 40.555558,180.068361 40.555558,180.895166 C40.5555806,180.898144 40.5555806,180.901122 40.555558,180.9041 L40.555558,190.543626 C40.6150705,190.480265 40.6729447,190.413476 40.7378497,190.356017 C41.4452864,189.729711 42.3809306,189.43584 43.3767379,189.43584 L46.6666675,189.43584 L46.6666675,179.14415 L42.4739603,179.14415 Z M31.1111161,180.859431 L31.1111161,191.437002 L37.5260449,191.437002 C38.0365968,191.437002 38.5189494,191.531483 38.9496557,191.713949 C38.8273679,191.527334 38.6888269,191.36055 38.5329891,191.222592 C38.0547048,190.799175 37.405738,190.579361 36.6232674,190.579361 L32.7777823,190.579361 C32.4709702,190.57933 32.2222575,190.323362 32.2222269,190.007601 L32.2222269,180.859431 L31.1111161,180.859431 Z M47.7777784,180.859431 L47.7777784,190.007601 C47.7777477,190.323362 47.529035,190.57933 47.222223,190.579361 L43.3767379,190.579361 C42.5942672,190.579361 41.9453004,190.799175 41.4670161,191.222592 C41.3107359,191.360944 41.1725734,191.526903 41.0503496,191.713949 C41.4810558,191.531483 41.9634085,191.437002 42.4739603,191.437002 L48.8888892,191.437002 L48.8888892,180.859431 L47.7777784,180.859431 Z M35.5,182.116677 L37.5,182.116677 C37.7761424,182.116677 38,182.340535 38,182.616677 L38,182.645847 C38,182.921989 37.7761424,183.145847 37.5,183.145847 L35.5,183.145847 C35.2238576,183.145847 35,182.921989 35,182.645847 L35,182.616677 C35,182.340535 35.2238576,182.116677 35.5,182.116677 Z M35.5,184.175016 L37.5,184.175016 C37.7761424,184.175016 38,184.398874 38,184.675016 L38,184.704185 C38,184.980328 37.7761424,185.204185 37.5,185.204185 L35.5,185.204185 C35.2238576,185.204185 35,184.980328 35,184.704185 L35,184.675016 C35,184.398874 35.2238576,184.175016 35.5,184.175016 Z M35.5,186.233355 L37.5,186.233355 C37.7761424,186.233355 38,186.457212 38,186.733355 L38,186.762524 C38,187.038666 37.7761424,187.262524 37.5,187.262524 L35.5,187.262524 C35.2238576,187.262524 35,187.038666 35,186.762524 L35,186.733355 C35,186.457212 35.2238576,186.233355 35.5,186.233355 Z M42.5,182.116677 L44.5,182.116677 C44.7761424,182.116677 45,182.340535 45,182.616677 L45,182.645847 C45,182.921989 44.7761424,183.145847 44.5,183.145847 L42.5,183.145847 C42.2238576,183.145847 42,182.921989 42,182.645847 L42,182.616677 C42,182.340535 42.2238576,182.116677 42.5,182.116677 Z M42.5,184.175016 L44.5,184.175016 C44.7761424,184.175016 45,184.398874 45,184.675016 L45,184.704185 C45,184.980328 44.7761424,185.204185 44.5,185.204185 L42.5,185.204185 C42.2238576,185.204185 42,184.980328 42,184.704185 L42,184.675016 C42,184.398874 42.2238576,184.175016 42.5,184.175016 Z M42.5,186.233355 L44.5,186.233355 C44.7761424,186.233355 45,186.457212 45,186.733355 L45,186.762524 C45,187.038666 44.7761424,187.262524 44.5,187.262524 L42.5,187.262524 C42.2238576,187.262524 42,187.038666 42,186.762524 L42,186.733355 C42,186.457212 42.2238576,186.233355 42.5,186.233355 Z" id="Icon_HC"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="22px" height="18px" viewBox="0 0 22 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.2 (67145) - http://www.bohemiancoding.com/sketch -->
<title>Icon_HC</title>
<desc>Created with Sketch.</desc>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Hugendubel_Icons" transform="translate(-29.000000, -177.000000)" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.3">
<path d="M32.725699,178.000628 C32.7430505,177.999791 32.7604307,177.999791 32.7777823,178.000628 L37.5260449,178.000628 C38.53109,178.000628 39.44018,178.547926 40.0000026,179.340692 C40.5598253,178.547926 41.4689153,178.000628 42.4739603,178.000628 L47.222223,178.000628 C47.529035,178.00066 47.7777477,178.256627 47.7777784,178.572389 L47.7777784,179.71591 L49.4444446,179.71591 C49.7512567,179.715942 49.9999694,179.971909 50,180.287671 L50,192.008763 C49.9999694,192.324524 49.7512567,192.580492 49.4444446,192.580523 L42.4739603,192.580523 C41.4766486,192.580523 40.8524541,192.949423 40.4947942,193.688309 C40.3998428,193.879608 40.208727,194 40.0000026,194 C39.7912783,194 39.6001624,193.879608 39.5052111,193.688309 C39.1475512,192.949423 38.5233566,192.580523 37.5260449,192.580523 L30.5555607,192.580523 C30.2487486,192.580492 30.0000359,192.324524 30.0000053,192.008763 L30.0000053,180.287671 C29.9987652,179.991708 30.2171687,179.743681 30.5034773,179.71591 C30.5208289,179.715072 30.5382091,179.715072 30.5555607,179.71591 L32.2222269,179.71591 L32.2222269,178.572389 C32.2209869,178.276426 32.4393904,178.028399 32.725699,178.000628 Z M33.3333377,179.14415 L33.3333377,189.43584 L36.6232674,189.43584 C37.6190746,189.43584 38.5547188,189.729711 39.2621556,190.356017 C39.3270606,190.413476 39.3849347,190.480265 39.4444472,190.543626 L39.4444472,180.957703 C39.4433388,180.936873 39.4433388,180.915996 39.4444472,180.895166 C39.4444472,180.068361 38.4768339,179.14415 37.5260449,179.14415 L33.3333377,179.14415 Z M42.4739603,179.14415 C41.5231714,179.14415 40.555558,180.068361 40.555558,180.895166 C40.5555806,180.898144 40.5555806,180.901122 40.555558,180.9041 L40.555558,190.543626 C40.6150705,190.480265 40.6729447,190.413476 40.7378497,190.356017 C41.4452864,189.729711 42.3809306,189.43584 43.3767379,189.43584 L46.6666675,189.43584 L46.6666675,179.14415 L42.4739603,179.14415 Z M31.1111161,180.859431 L31.1111161,191.437002 L37.5260449,191.437002 C38.0365968,191.437002 38.5189494,191.531483 38.9496557,191.713949 C38.8273679,191.527334 38.6888269,191.36055 38.5329891,191.222592 C38.0547048,190.799175 37.405738,190.579361 36.6232674,190.579361 L32.7777823,190.579361 C32.4709702,190.57933 32.2222575,190.323362 32.2222269,190.007601 L32.2222269,180.859431 L31.1111161,180.859431 Z M47.7777784,180.859431 L47.7777784,190.007601 C47.7777477,190.323362 47.529035,190.57933 47.222223,190.579361 L43.3767379,190.579361 C42.5942672,190.579361 41.9453004,190.799175 41.4670161,191.222592 C41.3107359,191.360944 41.1725734,191.526903 41.0503496,191.713949 C41.4810558,191.531483 41.9634085,191.437002 42.4739603,191.437002 L48.8888892,191.437002 L48.8888892,180.859431 L47.7777784,180.859431 Z M35.5,182.116677 L37.5,182.116677 C37.7761424,182.116677 38,182.340535 38,182.616677 L38,182.645847 C38,182.921989 37.7761424,183.145847 37.5,183.145847 L35.5,183.145847 C35.2238576,183.145847 35,182.921989 35,182.645847 L35,182.616677 C35,182.340535 35.2238576,182.116677 35.5,182.116677 Z M35.5,184.175016 L37.5,184.175016 C37.7761424,184.175016 38,184.398874 38,184.675016 L38,184.704185 C38,184.980328 37.7761424,185.204185 37.5,185.204185 L35.5,185.204185 C35.2238576,185.204185 35,184.980328 35,184.704185 L35,184.675016 C35,184.398874 35.2238576,184.175016 35.5,184.175016 Z M35.5,186.233355 L37.5,186.233355 C37.7761424,186.233355 38,186.457212 38,186.733355 L38,186.762524 C38,187.038666 37.7761424,187.262524 37.5,187.262524 L35.5,187.262524 C35.2238576,187.262524 35,187.038666 35,186.762524 L35,186.733355 C35,186.457212 35.2238576,186.233355 35.5,186.233355 Z M42.5,182.116677 L44.5,182.116677 C44.7761424,182.116677 45,182.340535 45,182.616677 L45,182.645847 C45,182.921989 44.7761424,183.145847 44.5,183.145847 L42.5,183.145847 C42.2238576,183.145847 42,182.921989 42,182.645847 L42,182.616677 C42,182.340535 42.2238576,182.116677 42.5,182.116677 Z M42.5,184.175016 L44.5,184.175016 C44.7761424,184.175016 45,184.398874 45,184.675016 L45,184.704185 C45,184.980328 44.7761424,185.204185 44.5,185.204185 L42.5,185.204185 C42.2238576,185.204185 42,184.980328 42,184.704185 L42,184.675016 C42,184.398874 42.2238576,184.175016 42.5,184.175016 Z M42.5,186.233355 L44.5,186.233355 C44.7761424,186.233355 45,186.457212 45,186.733355 L45,186.762524 C45,187.038666 44.7761424,187.262524 44.5,187.262524 L42.5,187.262524 C42.2238576,187.262524 42,187.038666 42,186.762524 L42,186.733355 C42,186.457212 42.2238576,186.233355 42.5,186.233355 Z" id="Icon_HC"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="22px" height="18px" viewBox="0 0 22 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.2 (67145) - http://www.bohemiancoding.com/sketch -->
<title>Icon_HC</title>
<desc>Created with Sketch.</desc>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Hugendubel_Icons" transform="translate(-29.000000, -177.000000)" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.3">
<path d="M32.725699,178.000628 C32.7430505,177.999791 32.7604307,177.999791 32.7777823,178.000628 L37.5260449,178.000628 C38.53109,178.000628 39.44018,178.547926 40.0000026,179.340692 C40.5598253,178.547926 41.4689153,178.000628 42.4739603,178.000628 L47.222223,178.000628 C47.529035,178.00066 47.7777477,178.256627 47.7777784,178.572389 L47.7777784,179.71591 L49.4444446,179.71591 C49.7512567,179.715942 49.9999694,179.971909 50,180.287671 L50,192.008763 C49.9999694,192.324524 49.7512567,192.580492 49.4444446,192.580523 L42.4739603,192.580523 C41.4766486,192.580523 40.8524541,192.949423 40.4947942,193.688309 C40.3998428,193.879608 40.208727,194 40.0000026,194 C39.7912783,194 39.6001624,193.879608 39.5052111,193.688309 C39.1475512,192.949423 38.5233566,192.580523 37.5260449,192.580523 L30.5555607,192.580523 C30.2487486,192.580492 30.0000359,192.324524 30.0000053,192.008763 L30.0000053,180.287671 C29.9987652,179.991708 30.2171687,179.743681 30.5034773,179.71591 C30.5208289,179.715072 30.5382091,179.715072 30.5555607,179.71591 L32.2222269,179.71591 L32.2222269,178.572389 C32.2209869,178.276426 32.4393904,178.028399 32.725699,178.000628 Z M33.3333377,179.14415 L33.3333377,189.43584 L36.6232674,189.43584 C37.6190746,189.43584 38.5547188,189.729711 39.2621556,190.356017 C39.3270606,190.413476 39.3849347,190.480265 39.4444472,190.543626 L39.4444472,180.957703 C39.4433388,180.936873 39.4433388,180.915996 39.4444472,180.895166 C39.4444472,180.068361 38.4768339,179.14415 37.5260449,179.14415 L33.3333377,179.14415 Z M42.4739603,179.14415 C41.5231714,179.14415 40.555558,180.068361 40.555558,180.895166 C40.5555806,180.898144 40.5555806,180.901122 40.555558,180.9041 L40.555558,190.543626 C40.6150705,190.480265 40.6729447,190.413476 40.7378497,190.356017 C41.4452864,189.729711 42.3809306,189.43584 43.3767379,189.43584 L46.6666675,189.43584 L46.6666675,179.14415 L42.4739603,179.14415 Z M31.1111161,180.859431 L31.1111161,191.437002 L37.5260449,191.437002 C38.0365968,191.437002 38.5189494,191.531483 38.9496557,191.713949 C38.8273679,191.527334 38.6888269,191.36055 38.5329891,191.222592 C38.0547048,190.799175 37.405738,190.579361 36.6232674,190.579361 L32.7777823,190.579361 C32.4709702,190.57933 32.2222575,190.323362 32.2222269,190.007601 L32.2222269,180.859431 L31.1111161,180.859431 Z M47.7777784,180.859431 L47.7777784,190.007601 C47.7777477,190.323362 47.529035,190.57933 47.222223,190.579361 L43.3767379,190.579361 C42.5942672,190.579361 41.9453004,190.799175 41.4670161,191.222592 C41.3107359,191.360944 41.1725734,191.526903 41.0503496,191.713949 C41.4810558,191.531483 41.9634085,191.437002 42.4739603,191.437002 L48.8888892,191.437002 L48.8888892,180.859431 L47.7777784,180.859431 Z M35.5,182.116677 L37.5,182.116677 C37.7761424,182.116677 38,182.340535 38,182.616677 L38,182.645847 C38,182.921989 37.7761424,183.145847 37.5,183.145847 L35.5,183.145847 C35.2238576,183.145847 35,182.921989 35,182.645847 L35,182.616677 C35,182.340535 35.2238576,182.116677 35.5,182.116677 Z M35.5,184.175016 L37.5,184.175016 C37.7761424,184.175016 38,184.398874 38,184.675016 L38,184.704185 C38,184.980328 37.7761424,185.204185 37.5,185.204185 L35.5,185.204185 C35.2238576,185.204185 35,184.980328 35,184.704185 L35,184.675016 C35,184.398874 35.2238576,184.175016 35.5,184.175016 Z M35.5,186.233355 L37.5,186.233355 C37.7761424,186.233355 38,186.457212 38,186.733355 L38,186.762524 C38,187.038666 37.7761424,187.262524 37.5,187.262524 L35.5,187.262524 C35.2238576,187.262524 35,187.038666 35,186.762524 L35,186.733355 C35,186.457212 35.2238576,186.233355 35.5,186.233355 Z M42.5,182.116677 L44.5,182.116677 C44.7761424,182.116677 45,182.340535 45,182.616677 L45,182.645847 C45,182.921989 44.7761424,183.145847 44.5,183.145847 L42.5,183.145847 C42.2238576,183.145847 42,182.921989 42,182.645847 L42,182.616677 C42,182.340535 42.2238576,182.116677 42.5,182.116677 Z M42.5,184.175016 L44.5,184.175016 C44.7761424,184.175016 45,184.398874 45,184.675016 L45,184.704185 C45,184.980328 44.7761424,185.204185 44.5,185.204185 L42.5,185.204185 C42.2238576,185.204185 42,184.980328 42,184.704185 L42,184.675016 C42,184.398874 42.2238576,184.175016 42.5,184.175016 Z M42.5,186.233355 L44.5,186.233355 C44.7761424,186.233355 45,186.457212 45,186.733355 L45,186.762524 C45,187.038666 44.7761424,187.262524 44.5,187.262524 L42.5,187.262524 C42.2238576,187.262524 42,187.038666 42,186.762524 L42,186.733355 C42,186.457212 42.2238576,186.233355 42.5,186.233355 Z" id="Icon_HC"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -1,8 +1,11 @@
<div class="notification-headline">
<h1>{{ item.headline }}</h1>
<button class="notification-edit-cta" (click)="itemSelected.emit(item)">
Bearbeiten
</button>
<div class="grid grid-cols-[1fr_auto] items-center gap-4">
<div class="grid grid-flow-row gap-4">
<h1 class="text-left font-bold text-lg">{{ item.headline }}</h1>
<div class="notification-text">{{ item.text }}</div>
</div>
<div>
<button *ngIf="editButton" class="notification-edit-cta text-brand font-bold text-lg px-4 py-3" (click)="itemSelected.emit(item)">
{{ editButtonLabel }}
</button>
</div>
</div>
<div class="notification-text">{{ item.text }}</div>

View File

@@ -13,5 +13,11 @@ export class ModalNotificationsListItemComponent {
@Output()
itemSelected = new EventEmitter<MessageBoardItemDTO>();
@Input()
editButton = true;
@Input()
editButtonLabel = 'Bearbeiten';
constructor() {}
}

View File

@@ -0,0 +1,11 @@
<div class="notification-list scroll-bar">
<ng-container *ngFor="let notification of notifications">
<modal-notifications-list-item
(click)="itemSelected(notification)"
[editButtonLabel]="'Packstück-Prüfung'"
[item]="notification"
(itemSelected)="itemSelected($event)"
></modal-notifications-list-item>
<hr />
</ng-container>
</div>

View File

@@ -0,0 +1,101 @@
import { createComponentFactory, Spectator, SpyObject } from '@ngneat/spectator';
import { CommonModule } from '@angular/common';
import { RouterTestingModule } from '@angular/router/testing';
import { UiIconModule } from '@ui/icon';
import { Router } from '@angular/router';
import { UiFilter } from '@ui/filter';
import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
import { Component } from '@angular/core';
import { ModalNotificationsListItemComponent } from '../notifications-list-item/notifications-list-item.component';
import { ModalNotificationsRemissionGroupComponent } from './notifications-remission-group.component';
// DummyComponent Class
@Component({
selector: 'dummy-component',
template: '<div></div>',
})
class DummyComponent {
constructor() {}
}
describe('ModalNotificationsRemissionGroupComponent', () => {
let spectator: Spectator<ModalNotificationsRemissionGroupComponent>;
let uiFilterMock: SpyObject<UiFilter>;
let router: Router;
const createComponent = createComponentFactory({
component: ModalNotificationsRemissionGroupComponent,
declarations: [ModalNotificationsListItemComponent],
imports: [
CommonModule,
RouterTestingModule.withRoutes([
{ path: 'filiale/goods/in/results', component: DummyComponent },
{ path: 'filiale/remission/create', component: DummyComponent },
]),
UiIconModule,
],
providers: [],
mocks: [UiFilter],
});
beforeEach(() => {
spectator = createComponent({ props: { notifications: [] } });
router = spectator.inject(Router);
uiFilterMock = spectator.inject(UiFilter);
});
it('should create', () => {
expect(spectator.component).toBeTruthy();
});
describe('notifications input', () => {
it('should display the right notification-counter value based on the length of the input array', () => {
spectator.setInput({ notifications: [{}, {}, {}] });
expect(spectator.query('.notification-counter')).toHaveText('3');
});
it('should not display notification-counter if input array has length 0', () => {
spectator.setInput({ notifications: [] });
expect(spectator.query('.notification-counter')).toHaveText('');
});
it('should render modal-notifications-list-item based on the input array', () => {
const notifications = [{}, {}];
spectator.setInput({ notifications });
spectator.detectComponentChanges();
expect(spectator.queryAll('modal-notifications-list-item')).toHaveLength(notifications.length);
});
});
describe('itemSelected()', () => {
it('should navigate to results with queryParams from UiFilter.getQueryParamsFromQueryTokenDTO()', () => {
const item: MessageBoardItemDTO = { queryToken: { input: { main_qs: 'test' } } };
spyOn(UiFilter, 'getQueryParamsFromQueryTokenDTO').and.returnValue(item.queryToken.input);
spyOn(router, 'navigate');
spectator.component.itemSelected(item);
expect(router.navigate).toHaveBeenCalledWith(['/filiale/goods/in/results'], { queryParams: item.queryToken.input });
});
it('should emit the navigated event after select item', () => {
const item: MessageBoardItemDTO = { queryToken: { input: { main_qs: 'test' } } };
spyOn(spectator.component.navigated, 'emit');
spectator.component.itemSelected(item);
expect(spectator.component.navigated.emit).toHaveBeenCalled();
});
});
describe('actions CTA', () => {
it('should navigate to remission page after clicking the CTA', () => {
const cta = spectator.query('.cta-primary');
expect(cta).toHaveText('Zur Remission');
expect(cta).toHaveAttribute('href', '/filiale/remission/create');
});
it('should emit the navigated event after clicking the CTA', () => {
const cta = spectator.query('.cta-primary') as HTMLAnchorElement;
spyOn(spectator.component.navigated, 'emit');
spectator.click(cta);
expect(spectator.component.navigated.emit).toHaveBeenCalled();
});
});
});

View File

@@ -0,0 +1,23 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import { Router } from '@angular/router';
import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
@Component({
selector: 'modal-notifications-package-inspection-group',
templateUrl: 'notifications-package-inspection-group.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ModalNotificationsPackageInspectionGroupComponent {
@Input()
notifications: MessageBoardItemDTO[];
@Output()
navigated = new EventEmitter<void>();
constructor(private _router: Router) {}
itemSelected(item: MessageBoardItemDTO) {
this._router.navigate(['/filiale/package-inspection/packages']);
this.navigated.emit();
}
}

View File

@@ -1,13 +1,3 @@
<div class="header">
<div class="notification-icon">
<span class="notification-counter">{{ notifications.length }}</span>
<ui-icon icon="notification" size="26px"></ui-icon>
</div>
<h2>Remission</h2>
</div>
<hr />
<div class="notification-list scroll-bar">
<ng-container *ngFor="let notification of notifications">
<modal-notifications-list-item [item]="notification" (itemSelected)="itemSelected($event)"></modal-notifications-list-item>

View File

@@ -1,13 +1,3 @@
<div class="header">
<div class="notification-icon">
<div class="notification-counter">{{ notifications.length }}</div>
<ui-icon icon="notification" size="26px"></ui-icon>
</div>
<h2>Reservierungsanfragen</h2>
</div>
<hr />
<div class="notification-list scroll-bar">
<ng-container *ngFor="let notification of notifications">
<modal-notifications-list-item [item]="notification" (itemSelected)="itemSelected($event)"></modal-notifications-list-item>

View File

@@ -1,13 +1,3 @@
<div class="header">
<div class="notification-icon">
<span class="notification-counter">{{ notifications.length }}</span>
<ui-icon icon="notification" size="26px"></ui-icon>
</div>
<h2>Tätigkeitskalender</h2>
</div>
<hr />
<div class="notification-list scroll-bar">
<ng-container *ngFor="let notification of notifications">
<modal-notifications-list-item [item]="notification" (itemSelected)="itemSelected($event)"></modal-notifications-list-item>

View File

@@ -1,13 +1,3 @@
<div class="header">
<div class="notification-icon">
<span class="notification-counter">{{ notifications.length }}</span>
<ui-icon icon="notification" size="26px"></ui-icon>
</div>
<h2>ISA-Update</h2>
</div>
<hr />
<div class="notification-list scroll-bar">
<ng-container *ngFor="let notification of notifications">
<div class="notification-headline">

View File

@@ -1,34 +1,39 @@
<h1>Sie haben neue Nachrichten</h1>
<ng-container *ngFor="let notification of groupedNotifications$ | async">
<button
*ngIf="notification.group !== (activeCard$ | async)"
type="button"
class="notification-card"
(click)="activeCard = notification.group"
>
{{ notification.group }}
<ng-container *ngFor="let notification of notifications$ | async | keyvalue">
<button type="button" class="notification-card" (click)="selectArea(notification.key)">
<div class="notification-icon">
<div class="notification-counter">{{ notification.value?.length }}</div>
<ui-icon icon="notification" size="26px"></ui-icon>
</div>
<span>{{ notification.value?.[0]?.category }}</span>
</button>
</ng-container>
<ng-container [ngSwitch]="activeCard$ | async">
<modal-notifications-update-group
*ngSwitchCase="'ISA-Update'"
[notifications]="activeNotifications$ | async"
></modal-notifications-update-group>
<modal-notifications-reservation-group
*ngSwitchCase="'Reservierungsanfragen'"
[notifications]="activeNotifications$ | async"
(navigated)="close()"
></modal-notifications-reservation-group>
<modal-notifications-remission-group
*ngSwitchCase="'Remission'"
[notifications]="activeNotifications$ | async"
(navigated)="close()"
></modal-notifications-remission-group>
<modal-notifications-task-calendar-group
*ngSwitchCase="'Tätigkeitskalender'"
[notifications]="activeNotifications$ | async"
(navigated)="close()"
></modal-notifications-task-calendar-group>
<hr class="-mx-4" />
<ng-container *ngIf="notification.key === selectedArea" [ngSwitch]="notification.value?.[0]?.category">
<modal-notifications-update-group
*ngSwitchCase="'ISA-Update'"
[notifications]="notifications[selectedArea]"
></modal-notifications-update-group>
<modal-notifications-reservation-group
*ngSwitchCase="'Reservierungsanfragen'"
[notifications]="notifications[selectedArea]"
(navigated)="close()"
></modal-notifications-reservation-group>
<modal-notifications-remission-group
*ngSwitchCase="'Remission'"
[notifications]="notifications[selectedArea]"
(navigated)="close()"
></modal-notifications-remission-group>
<modal-notifications-task-calendar-group
*ngSwitchCase="'Tätigkeitskalender'"
[notifications]="notifications[selectedArea]"
(navigated)="close()"
></modal-notifications-task-calendar-group>
<modal-notifications-package-inspection-group
*ngSwitchCase="'Wareneingang Lagerware'"
[notifications]="notifications[selectedArea]"
(navigated)="close()"
>
</modal-notifications-package-inspection-group>
</ng-container>
</ng-container>

View File

@@ -2,46 +2,44 @@ modal-notifications {
@apply flex flex-col relative h-full;
h1 {
@apply text-xl font-bold text-center mb-10;
@apply text-xl font-bold text-center;
}
// .notification-card {
// @apply text-center text-xl text-inactive-branch block bg-white rounded-t-card font-bold no-underline py-4 border-none outline-none shadow-card -ml-4;
// width: calc(100% + 2rem);
// }
.notification-card {
@apply text-center text-xl text-inactive-branch block bg-white rounded-t-card font-bold no-underline py-4 border-none outline-none shadow-card -ml-4;
width: calc(100% + 2rem);
@apply grid grid-flow-col items-center justify-center gap-4;
@apply text-inactive-branch bg-white;
@apply font-bold text-xl -mx-4 py-4;
.notification-icon {
@apply relative;
.notification-counter {
@apply absolute font-normal text-base -top-2 -right-1 bg-brand text-white rounded-full w-5 h-5 flex items-center justify-center;
z-index: 10;
}
ui-icon {
@apply text-inactive-branch;
}
}
h2 {
@apply font-bold text-2xl ml-4;
}
}
modal-notifications-remission-group,
modal-notifications-reservation-group,
modal-notifications-task-calendar-group,
modal-notifications-update-group {
modal-notifications-update-group,
modal-notifications-package-inspection-group {
@apply flex flex-col relative pb-2;
.header {
@apply flex flex-row justify-center items-center mt-5;
.notification-icon {
@apply relative;
.notification-counter {
@apply absolute -top-2 -right-1 bg-brand text-white rounded-full w-5 h-5 flex items-center justify-center;
z-index: 10;
}
ui-icon {
@apply text-inactive-branch;
}
}
h2 {
@apply font-bold text-2xl ml-4;
}
}
hr {
@apply bg-disabled-branch h-px-2 -ml-4 my-4;
width: calc(100% + 2rem);
}
.notification-list {
@apply overflow-y-scroll -ml-4;
max-height: calc(100vh - 450px);
@@ -60,7 +58,7 @@ modal-notifications {
modal-notifications-list-item,
modal-notifications-update-group {
@apply flex flex-col relative py-1 px-4;
@apply flex flex-col relative p-4;
.notification-headline {
@apply flex flex-row justify-between items-start;

View File

@@ -1,14 +1,11 @@
import { ChangeDetectionStrategy, Component, OnInit, ViewEncapsulation } from '@angular/core';
import { ComponentStore } from '@ngrx/component-store';
import { Group, groupBy } from '@ui/common';
import { UiModalRef } from '@ui/modal';
import { EnvelopeDTO, MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
import { combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';
import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
interface ModalNotificationComponentState {
activeCard: string;
groupedNotifications: Group<string, MessageBoardItemDTO>[];
selectedArea: string;
notifications: Record<string, MessageBoardItemDTO[]>;
}
@Component({
@@ -18,44 +15,61 @@ interface ModalNotificationComponentState {
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
})
export class ModalNotificationsComponent extends ComponentStore<ModalNotificationComponentState> implements OnInit {
set activeCard(activeCard: string) {
if (this.activeCard !== activeCard) {
this.patchState({ activeCard });
export class ModalNotificationsComponent extends ComponentStore<ModalNotificationComponentState> {
private _selectedAreaSelector = (state: ModalNotificationComponentState) => {
if (state.selectedArea) {
return state.selectedArea;
}
const keys = Object.keys(state.notifications);
for (const key of keys) {
if (state.notifications[key]?.length > 0) {
return key;
}
}
return undefined;
};
get selectedArea() {
return this.get(this._selectedAreaSelector);
}
activeCard$ = this.select((s) => s.activeCard);
selectedArea$ = this.select(this._selectedAreaSelector);
get activeCard() {
return this.get((s) => s.activeCard);
private _categorySelector = (state: ModalNotificationComponentState) => {
const selectedArea = this._selectedAreaSelector(state);
console.log('_categorySelector', state.notifications[selectedArea]?.[0]?.category);
return state.notifications[selectedArea]?.[0]?.category;
};
get category() {
return this.get(this._categorySelector);
}
get groupedNotifications() {
return this.get((s) => s.groupedNotifications);
}
groupedNotifications$ = this.select((s) => s.groupedNotifications);
category$ = this.select(this._categorySelector);
set groupedNotifications(groupedNotifications: Group<string, MessageBoardItemDTO>[]) {
this.patchState({ groupedNotifications });
get notifications() {
return this.get((s) => s.notifications);
}
activeNotifications$ = combineLatest([this.activeCard$, this.groupedNotifications$]).pipe(
map(([activeCard, notifications]) => notifications.find((n) => n.group === activeCard)?.items)
);
notifications$ = this.select((s) => s.notifications);
constructor(private _modalRef: UiModalRef<any, EnvelopeDTO<MessageBoardItemDTO[]>>) {
constructor(private _modalRef: UiModalRef<any, Record<string, MessageBoardItemDTO[]>>) {
super({
activeCard: undefined,
groupedNotifications: groupBy(_modalRef.data.data, (item: MessageBoardItemDTO) => item.category),
selectedArea: undefined,
notifications: _modalRef.data,
});
}
ngOnInit() {
this.patchState({ activeCard: this.groupedNotifications?.find((_) => true)?.group });
}
close() {
this._modalRef.close();
}
selectArea(area: string) {
this.patchState({
selectedArea: area,
});
}
}

View File

@@ -9,6 +9,7 @@ import { ModalNotificationsReservationGroupComponent } from './notifications-res
import { ModalNotificationsTaskCalendarGroupComponent } from './notifications-task-calendar-group/notifications-task-calendar-group.component';
import { ModalNotificationsUpdateGroupComponent } from './notifications-update-group/notifications-update-group.component';
import { ModalNotificationsComponent } from './notifications.component';
import { ModalNotificationsPackageInspectionGroupComponent } from './notifications-package-inspection-group/notifications-package-inspection-group.component';
@NgModule({
imports: [CommonModule, UiCommonModule, UiIconModule, RouterModule],
@@ -19,6 +20,7 @@ import { ModalNotificationsComponent } from './notifications.component';
ModalNotificationsTaskCalendarGroupComponent,
ModalNotificationsUpdateGroupComponent,
ModalNotificationsListItemComponent,
ModalNotificationsPackageInspectionGroupComponent,
],
exports: [
ModalNotificationsComponent,
@@ -27,6 +29,7 @@ import { ModalNotificationsComponent } from './notifications.component';
ModalNotificationsTaskCalendarGroupComponent,
ModalNotificationsUpdateGroupComponent,
ModalNotificationsListItemComponent,
ModalNotificationsPackageInspectionGroupComponent,
],
})
export class ModalNotificationsModule {}

View File

@@ -51,16 +51,9 @@
</div>
<div class="right">
<div class="price" *ngIf="item.catalogAvailability?.price?.value?.value; else retailPrice">
{{ item.catalogAvailability?.price?.value?.value | currency: item.catalogAvailability?.price?.value?.currency:'code' }}
<div class="price" *ngIf="price$ | async; let price">
{{ price?.value?.value | currency: price?.value?.currency:'code' }}
</div>
<ng-template #retailPrice>
<div class="price" *ngIf="store.takeAwayAvailability$ | async; let takeAwayAvailability">
{{
takeAwayAvailability?.retailPrice?.value?.value | currency: takeAwayAvailability?.retailPrice?.value?.currency:'code'
}}
</div>
</ng-template>
<div *ngIf="store.promotionPoints$ | async; let promotionPoints">{{ promotionPoints }} Lesepunkte</div>
</div>
</div>

View File

@@ -118,6 +118,38 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
shareReplay(1)
);
price$ = combineLatest([
this.store.item$,
this.store.takeAwayAvailability$,
this.store.deliveryAvailability$,
this.store.deliveryDigAvailability$,
this.store.deliveryB2BAvailability$,
]).pipe(
map(([item, takeAway, delivery, deliveryDig, deliveryB2B]) => {
if (item?.catalogAvailability?.price?.value?.value) {
return item?.catalogAvailability?.price;
}
if (takeAway?.price?.value?.value) {
return takeAway.price;
}
if (delivery?.price?.value?.value) {
return delivery.price;
}
if (deliveryDig?.price?.value?.value) {
return deliveryDig.price;
}
if (deliveryB2B?.price?.value?.value) {
return deliveryB2B.price;
}
return null;
})
);
constructor(
public readonly applicationService: ApplicationService,
private activatedRoute: ActivatedRoute,

View File

@@ -15,6 +15,7 @@ import { debounceTime, first, map, switchMap } from 'rxjs/operators';
import { ArticleSearchService } from '../article-search.store';
import { AddedToCartModalComponent } from './added-to-cart-modal/added-to-cart-modal.component';
import { SearchResultItemComponent } from './search-result-item.component';
import { DomainAvailabilityService, ItemData } from '@domain/availability';
@Component({
selector: 'page-search-results',
@@ -54,7 +55,8 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
private breadcrumb: BreadcrumbService,
private cache: CacheService,
private _uiModal: UiModalService,
private _checkoutService: DomainCheckoutService
private _checkoutService: DomainCheckoutService,
private _availability: DomainAvailabilityService
) {}
ngOnInit() {
@@ -258,11 +260,12 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
for (const item of selectedItems) {
const isDownload = item?.product?.format === 'EB' || item?.product?.format === 'DL';
const price = item?.catalogAvailability?.price;
const shoppingCartItem: AddToShoppingCartDTO = {
quantity: 1,
availability: {
availabilityType: item?.catalogAvailability?.status,
price: item?.catalogAvailability?.price,
price,
supplierProductNumber: item?.ids?.dig ? String(item.ids?.dig) : item?.product?.supplierProductNumber,
},
product: {
@@ -274,7 +277,13 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
};
if (isDownload) {
shoppingCartItem.destination = { data: { target: 16 } };
const itemId = item?.id;
const ean = item?.product?.ean;
const downloadItem: ItemData = { ean, itemId, price };
// #4180 Für Download Artikel muss hier immer zwingend der logistician gesetzt werden, da diese Artikel direkt zugeordnet dem Warenkorb hinzugefügt werden
const downloadAvailability = await this._availability.getDownloadAvailability({ item: downloadItem }).pipe(first()).toPromise();
shoppingCartItem.destination = { data: { target: 16, logistician: downloadAvailability?.logistician } };
canAddItemsPayload.push({
availabilities: [{ ...item.catalogAvailability, format: 'DL' }],
id: item.product.catalogProductNumber,

View File

@@ -11,5 +11,6 @@
[hint]="hint$ | async"
(scan)="search($event)"
[scanner]="true"
(hintCleared)="clearHint()"
></ui-searchbox>
</div>

View File

@@ -59,8 +59,12 @@ export class FinishShippingDocumentComponent implements OnInit, OnDestroy {
this._onDestroy$.complete();
}
search(query: string) {
clearHint() {
this.hint$.next('');
}
search(query: string) {
query = query?.trim();
if (!query) {
this.hint$.next('Ungültige Eingabe');
return;

View File

@@ -8,7 +8,7 @@ import { ComponentStore, tapResponse } from '@ngrx/component-store';
import { ReturnDTO } from '@swagger/remi';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { NEVER, Observable } from 'rxjs';
import { catchError, filter, first, map, shareReplay, switchMap, tap, withLatestFrom } from 'rxjs/operators';
import { catchError, filter, first, map, shareReplay, switchMap, take, tap, withLatestFrom } from 'rxjs/operators';
import { ShortReceiptNumberPipe } from '../../pipes/short-receipt-number.pipe';
import { RemissionListComponentStore } from '../../remission-list/remission-list.component-store';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
@@ -44,7 +44,7 @@ export class ShippingDocumentDetailsComponent extends ComponentStore<ShippingDoc
}
get remissionStarted$() {
return this.select((s) => s.remissionStarted).pipe(shareReplay());
return this.select((s) => s.remissionStarted);
}
get return() {
@@ -56,11 +56,15 @@ export class ShippingDocumentDetailsComponent extends ComponentStore<ShippingDoc
}
get return$() {
return this.select((s) => s.return).pipe(shareReplay());
return this.select((s) => s.return);
}
get packageNumber$() {
return this.select((s) => s.packageNumber).pipe(shareReplay());
return this.select((s) => s.packageNumber);
}
get packageNumber() {
return this.get((s) => s.packageNumber);
}
scrollPosition$ = this._breadcrumb.getBreadcrumbsByKeyAndTags$(this.processId, ['remission']).pipe(
@@ -176,24 +180,24 @@ export class ShippingDocumentDetailsComponent extends ComponentStore<ShippingDoc
async completeReceipt() {
const returnId = this.return?.id;
const receiptId = this.firstReceipt?.id;
const packageNumber = this.packageNumber;
if (receiptId) {
if (!packageNumber) {
await this._router.navigate(['/filiale/remission', returnId, 'finish-shipping-document', receiptId], {
queryParams: { complete: true },
});
return false;
}
try {
await this._remissionService.completeReceipt(returnId, receiptId);
return true;
} catch (err) {
this._modal.open({
content: UiErrorModalComponent,
title: 'Fehler beim Abschließen des Warenbegleitscheins',
data: err,
});
this._modal.error('Fehler beim Abschließen des Warenbegleitscheins', err);
}
} else {
this._modal.open({
content: UiErrorModalComponent,
title: 'Fehler beim Abschließen des Warenbegleitscheins',
data: new Error('Keine gültige ID'),
});
this._modal.error('Fehler beim Abschließen des Warenbegleitscheins', new Error('Keine gültige ID'));
}
return false;
}

View File

@@ -154,7 +154,7 @@
</div>
<ui-form-control label="Vormerker" variant="inline">
<ui-select formControlName="isPrebooked">
<ui-select formControlName="isPrebooked" readonly="true">
<ui-select-option label="Ja" [value]="true"></ui-select-option>
<ui-select-option label="Nein" [value]="false"></ui-select-option>
</ui-select>

View File

@@ -0,0 +1,47 @@
import { AfterContentInit, ChangeDetectionStrategy, Component, ElementRef, Renderer2 } from '@angular/core';
@Component({
selector: 'shared-scale-content, [sharedScaleContent]',
template: '<ng-content></ng-content>',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
styles: [
`
:host {
overflow-y: hidden;
}
`,
],
})
export class ScaleContentComponent implements AfterContentInit {
// TODO: Bessere Lösung finden? Falls keine bessere Lösung gefunden wird, dann muss die Komponente auslagen
fontSizeInEm = 1;
adjustmentSteps = 0.05;
constructor(private _elementRef: ElementRef<HTMLElement>, private _renderer: Renderer2) {}
ngAfterContentInit(): void {
this.adjustFontSize();
}
adjustFontSize() {
const element = this._elementRef.nativeElement;
const clientRect = element?.getClientRects();
const scrollHeight = element?.scrollHeight;
const domRect = clientRect && clientRect[0];
if (domRect && Math.ceil(domRect?.height) < scrollHeight) {
this.fontSizeInEm -= this.adjustmentSteps;
} else {
return;
}
this._renderer.setStyle(element, 'font-size', `${this.fontSizeInEm}em`);
setTimeout(() => this.adjustFontSize(), 1);
}
}

View File

@@ -0,0 +1 @@
export * from './lib/scale-content.component';

View File

@@ -1,8 +1,16 @@
import { Injectable } from '@angular/core';
import { ComponentStore, OnStoreInit, tapResponse } from '@ngrx/component-store';
import { AddToShoppingCartDTO, AvailabilityDTO, BranchDTO, CheckoutDTO, ShoppingCartDTO, ShoppingCartItemDTO } from '@swagger/checkout';
import {
AddToShoppingCartDTO,
AvailabilityDTO,
BranchDTO,
CheckoutDTO,
KulturPassResult,
ShoppingCartDTO,
ShoppingCartItemDTO,
} from '@swagger/checkout';
import { DomainCheckoutService } from '@domain/checkout';
import { mergeMap, switchMap, tap, withLatestFrom } from 'rxjs/operators';
import { catchError, mergeMap, switchMap, tap, withLatestFrom } from 'rxjs/operators';
import {
BranchService,
DisplayOrderDTO,
@@ -12,9 +20,9 @@ import {
ResponseArgsOfIEnumerableOfBranchDTO,
ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString,
} from '@swagger/oms';
import { Observable } from 'rxjs';
import { Observable, of, zip } from 'rxjs';
import { AuthService } from '@core/auth';
import { UiModalService } from '@ui/modal';
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
import { getCatalogProductNumber } from './catalog-product-number';
import { ItemDTO } from '@swagger/cat';
import { DomainAvailabilityService } from '@domain/availability';
@@ -198,11 +206,51 @@ export class KulturpassOrderModalStore extends ComponentStore<KulturpassOrderMod
return this.shoppingCart?.items?.find((i) => getCatalogProductNumber(i?.data) === catalogProductNumber)?.data?.quantity ?? 0;
}
canAddItem = this.effect((item$: Observable<ItemDTO>) =>
item$.pipe(
switchMap((item) =>
this._checkoutService
.canAddItemsKulturpass([item?.product])
.pipe(
tapResponse(
(results) => this.handleCanAddItemResponse({ item, result: results?.find((_) => true) }),
this.handleCanAddItemError
)
)
)
)
);
handleCanAddItemResponse = ({ item, result }: { item: ItemDTO; result: KulturPassResult }) => {
if (result?.canAdd) {
this.addItemToShoppingCart(item);
} else {
this._modal.open({
content: UiMessageModalComponent,
title: 'Artikel nicht förderfähig',
data: { message: result?.message, closeAction: 'ohne Artikel fortfahren' },
});
}
};
handleCanAddItemError = (err: any) => {
this._modal.error('Fehler beim Hinzufügen des Artikels', err);
};
addItemToShoppingCart = this.effect((item$: Observable<ItemDTO>) =>
item$.pipe(
mergeMap((item) =>
this._availabilityService
.getTakeAwayAvailability({
mergeMap((item) => {
const takeAwayAvailability$ = this._availabilityService.getTakeAwayAvailability({
item: {
ean: item.product.ean,
itemId: item.id,
price: item.catalogAvailability.price,
},
quantity: this.itemQuantityByCatalogProductNumber(getCatalogProductNumber(item)) + 1,
});
const deliveryAvailability$ = this._availabilityService
.getDeliveryAvailability({
item: {
ean: item.product.ean,
itemId: item.id,
@@ -210,20 +258,60 @@ export class KulturpassOrderModalStore extends ComponentStore<KulturpassOrderMod
},
quantity: this.itemQuantityByCatalogProductNumber(getCatalogProductNumber(item)) + 1,
})
.pipe(tapResponse(this.handleAddItemToShoppingCartResponse(item), this.handleAddItemToShoppingCartError))
)
.pipe(
catchError((err) => {
return of(undefined);
})
);
return zip(takeAwayAvailability$, deliveryAvailability$).pipe(
tapResponse(this.handleAddItemToShoppingCartResponse2(item), this.handleAddItemToShoppingCartError)
);
})
)
);
handleAddItemToShoppingCartResponse = (item: ItemDTO) => (availability: AvailabilityDTO) => {
handleAddItemToShoppingCartResponse2 = (item: ItemDTO) => ([takeAwayAvailability, deliveryAvailability]: [
AvailabilityDTO,
AvailabilityDTO
]) => {
let isPriceMaintained = item?.catalogAvailability?.priceMaintained;
let onlinePrice = -1;
if (!!deliveryAvailability) {
isPriceMaintained = isPriceMaintained ?? deliveryAvailability['priceMaintained'] ?? false;
onlinePrice = deliveryAvailability?.price?.value?.value ?? -1;
}
// Preis und priceMaintained werden immer erst vom Katalog genommen. Bei nicht Verfügbarkeit greifen die anderen Availabilities
const offlinePrice = item?.catalogAvailability?.price?.value?.value ?? takeAwayAvailability?.price?.value?.value ?? -1;
const availability = takeAwayAvailability;
availability.price = item?.catalogAvailability?.price ?? takeAwayAvailability?.price;
/**
* Onlinepreis ist niedliger als der Offlinepreis
* wenn der Artikel nicht Preisgebunden ist, wird der Onlinepreis genommen
* wenn der Artikel Preisgebunden ist, wird der Ladenpreis verwendet
*/
/**
* Offlinepreis ist niedliger als der Onlinepreis
* wenn der Artikel nicht Preisgebunden ist, wird der Ladenpreis genommen
* wenn der Artikel Preisgebunden ist, wird der Ladenpreis verwendet
*/
if (!!deliveryAvailability && onlinePrice < offlinePrice && !isPriceMaintained) {
availability.price = deliveryAvailability.price;
}
this.setAvailability({
catalogProductNumber: getCatalogProductNumber(item),
availability: availability,
availability,
});
const addToShoppingCartDTO: AddToShoppingCartDTO = {
quantity: 1,
availability: availability,
availability,
destination: {
data: {
target: 1,

View File

@@ -91,7 +91,7 @@ export class KulturpassOrderSearchboxStore extends ComponentStore<KulturpassOrde
return;
}
this._parentStore.addItemToShoppingCart(res.result).add(() => {
this._parentStore.canAddItem(res.result).add(() => {
this.patchState({ query: '', fetching: false });
});
};

View File

@@ -6,7 +6,7 @@
<div class="shared-purchase-options-list-item__contributors font-bold">
{{ product?.contributors }}
</div>
<div class="shared-purchase-options-list-item__name font-bold h-12" scaleContent>
<div class="shared-purchase-options-list-item__name font-bold h-12" sharedScaleContent>
{{ product?.name }}
</div>
<div class="shared-purchase-options-list-item__format flex flex-row items-center">
@@ -82,67 +82,40 @@
</div>
</div>
<div class="shared-purchase-options-list-item__price text-right ml-4 flex flex-col items-end">
<div
class="shared-purchase-options-list-item__price-value font-bold text-xl flex flex-row items-center"
*ngIf="!(canEditPrice$ | async)"
>
<div class="shared-purchase-options-list-item__price-value font-bold text-xl flex flex-row items-center">
<ui-svg-icon class="mr-3" [uiOverlayTrigger]="tooltip" icon="mat-info" *ngIf="priceMaintained$ | async"></ui-svg-icon>
<ui-tooltip #tooltip yPosition="above" xPosition="after" [yOffset]="-8" [xOffset]="5" [closeable]="true">
Günstigerer Preis aus Hugendubel Katalog wird übernommen
</ui-tooltip>
<ng-container *ngIf="!(setManualPrice$ | async); else setManualPrice">
{{ priceValue$ | async | currency: 'EUR':'code' }}
</ng-container>
<ng-template #setManualPrice>
<div class="relative flex flex-row items-start">
<ui-select
class="w-[6.5rem] min-h-[3.4375rem] p-4 rounded-card border border-solid border-[#AEB7C1] mr-4"
tabindex="-1"
[formControl]="manualVatFormControl"
[defaultLabel]="'MwSt'"
>
<ui-select-option *ngFor="let vat of vats$ | async" [label]="vat.name + '%'" [value]="vat.vatType"></ui-select-option>
</ui-select>
<shared-input-control [class.ml-8]="manualPriceFormControl?.invalid && manualPriceFormControl?.dirty">
<shared-input-control-indicator>
<ui-svg-icon *ngIf="manualPriceFormControl?.invalid && manualPriceFormControl?.dirty" icon="mat-info"></ui-svg-icon>
</shared-input-control-indicator>
<input
triggerOn="init"
#quantityInput
sharedInputControlInput
type="string"
class="w-24"
[formControl]="manualPriceFormControl"
placeholder="00,00"
(sharedOnInit)="quantityInput.focus()"
sharedNumberValue
/>
<shared-input-control-suffix>EUR</shared-input-control-suffix>
<shared-input-control-error error="required">Preis ist ungültig</shared-input-control-error>
<shared-input-control-error error="pattern">Preis ist ungültig</shared-input-control-error>
<shared-input-control-error error="max">Preis ist ungültig</shared-input-control-error>
</shared-input-control>
</div>
</ng-template>
</div>
<div class="shared-purchase-options-list-item__price-value font-bold text-xl" *ngIf="canEditPrice$ | async">
<div class="relative flex flex-col">
<shared-input-control>
<div class="relative flex flex-row justify-end items-start">
<ui-select
*ngIf="canEditVat$ | async"
class="w-[6.5rem] min-h-[3.4375rem] p-4 rounded-card border border-solid border-[#AEB7C1] mr-4"
tabindex="-1"
[formControl]="manualVatFormControl"
[defaultLabel]="'MwSt'"
>
<ui-select-option *ngFor="let vat of vats$ | async" [label]="vat.name + '%'" [value]="vat.vatType"></ui-select-option>
</ui-select>
<shared-input-control
[class.ml-6]="priceFormControl?.invalid && priceFormControl?.dirty"
*ngIf="canEditPrice$ | async; else priceTmpl"
>
<shared-input-control-indicator>
<ui-svg-icon *ngIf="priceFormControl?.invalid && priceFormControl?.dirty" icon="mat-info"></ui-svg-icon>
</shared-input-control-indicator>
<input
[uiOverlayTrigger]="tooltip"
triggerOn="init"
[uiOverlayTrigger]="giftCardTooltip"
triggerOn="none"
#quantityInput
#priceOverlayTrigger="uiOverlayTrigger"
sharedInputControlInput
type="string"
class="w-24"
[formControl]="priceFormControl"
placeholder="00,00"
(sharedOnInit)="quantityInput.focus()"
(sharedOnInit)="onPriceInputInit(quantityInput, priceOverlayTrigger)"
sharedNumberValue
/>
<shared-input-control-suffix>EUR</shared-input-control-suffix>
@@ -152,11 +125,14 @@
<shared-input-control-error error="max">Preis ist ungültig</shared-input-control-error>
</shared-input-control>
<ui-tooltip [warning]="true" xPosition="after" yPosition="below" [xOffset]="-55" [yOffset]="18" [closeable]="true" #tooltip>
<ui-tooltip [warning]="true" xPosition="after" yPosition="below" [xOffset]="-55" [yOffset]="18" [closeable]="true" #giftCardTooltip>
Tragen Sie hier den <br />
Gutscheinbetrag ein.
</ui-tooltip>
</div>
<ng-template #priceTmpl>
{{ priceValue$ | async | currency: 'EUR':'code' }}
</ng-template>
</div>
<ui-quantity-dropdown class="mt-2" [formControl]="quantityFormControl" [range]="maxSelectableQuantity$ | async"> </ui-quantity-dropdown>
<div class="pt-7">
@@ -169,6 +145,12 @@
/>
</div>
<ng-container *ngIf="canAddResult$ | async; let canAddResult">
<span *ngIf="!canAddResult.canAdd" class="inline-block font-bold text-[#BE8100] mt-[14px] max-w-[19rem]">
{{ canAddResult.message }}
</span>
</ng-container>
<span *ngIf="showMaxAvailableQuantity$ | async" class="font-bold text-[#BE8100] mt-[14px]">
{{ (availability$ | async)?.inStock }} Exemplare sofort lieferbar
</span>

View File

@@ -1,78 +1,22 @@
import { CommonModule } from '@angular/common';
import {
Component,
ChangeDetectionStrategy,
Input,
OnInit,
OnDestroy,
OnChanges,
SimpleChanges,
AfterContentInit,
ElementRef,
Renderer2,
} from '@angular/core';
import { Component, ChangeDetectionStrategy, Input, OnInit, OnDestroy, OnChanges, SimpleChanges } from '@angular/core';
import { FormControl, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { ProductImageModule } from '@cdn/product-image';
import { InputControlModule } from '@shared/components/input-control';
import { ElementLifecycleModule } from '@shared/directives/element-lifecycle';
import { UiCommonModule } from '@ui/common';
import { UiCommonModule, UiOverlayTriggerDirective } from '@ui/common';
import { UiIconModule } from '@ui/icon';
import { UiQuantityDropdownModule } from '@ui/quantity-dropdown';
import { UiSpinnerModule } from '@ui/spinner';
import { UiTooltipModule } from '@ui/tooltip';
import { combineLatest, ReplaySubject, Subscription } from 'rxjs';
import { map, take, shareReplay, startWith, switchMap, withLatestFrom, last } from 'rxjs/operators';
import { map, take, shareReplay, startWith, switchMap, withLatestFrom, last, tap } from 'rxjs/operators';
import { GIFT_CARD_MAX_PRICE, PRICE_PATTERN } from '../constants';
import { Item, PurchaseOptionsStore } from '../store';
import { OrderDeadlinePipeModule } from '@shared/pipes/order-deadline';
import { UiSelectModule } from '@ui/select';
import { KeyValueDTOOfStringAndString } from '@swagger/cat';
@Component({
selector: 'scale-content, [scaleContent]',
template: '<ng-content></ng-content>',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
styles: [
`
:host {
overflow-y: hidden;
}
`,
],
})
export class ScaleContentComponent implements AfterContentInit {
// TODO: Bessere Lösung finden? Falls keine bessere Lösung gefunden wird, dann muss die Komponente auslagen
fontSizeInEm = 1;
adjustmentSteps = 0.05;
constructor(private _elementRef: ElementRef<HTMLElement>, private _renderer: Renderer2) {}
ngAfterContentInit(): void {
this.adjustFontSize();
}
adjustFontSize() {
const element = this._elementRef.nativeElement;
const clientRect = element?.getClientRects();
const scrollHeight = element?.scrollHeight;
const domRect = clientRect && clientRect[0];
if (domRect && Math.ceil(domRect?.height) < scrollHeight) {
this.fontSizeInEm -= this.adjustmentSteps;
} else {
return;
}
this._renderer.setStyle(element, 'font-size', `${this.fontSizeInEm}em`);
setTimeout(() => this.adjustFontSize(), 1);
}
}
import { ScaleContentComponent } from '@shared/components/scale-content';
@Component({
selector: 'shared-purchase-options-list-item',
@@ -115,14 +59,22 @@ export class PurchaseOptionsListItemComponent implements OnInit, OnDestroy, OnCh
quantityFormControl = new FormControl<number>(null);
priceFormControl = new FormControl<string>(null, [
private readonly _giftCardValidators = [
Validators.required,
Validators.min(1),
Validators.max(GIFT_CARD_MAX_PRICE),
Validators.pattern(PRICE_PATTERN),
]);
];
private readonly _defaultValidators = [
Validators.required,
Validators.min(0.01),
Validators.max(999.99),
Validators.pattern(PRICE_PATTERN),
];
priceFormControl = new FormControl<string>(null);
manualPriceFormControl = new FormControl<string>(null, [Validators.required, Validators.max(999.99), Validators.pattern(PRICE_PATTERN)]);
manualVatFormControl = new FormControl<string>('', [Validators.required]);
selectedFormControl = new FormControl<boolean>(false);
@@ -158,10 +110,20 @@ export class PurchaseOptionsListItemComponent implements OnInit, OnDestroy, OnCh
})
);
canEditPrice$ = this.item$.pipe(switchMap((item) => this._store.getCanEditPrice$(item.id)));
canAddResult$ = this.item$.pipe(switchMap((item) => this._store.getCanAddResultForItemAndCurrentPurchaseOption$(item.id)));
canEditPrice$ = this.item$.pipe(
switchMap((item) => combineLatest([this.canAddResult$, this._store.getCanEditPrice$(item.id)])),
map(([canAddResult, canEditPrice]) => canAddResult?.canAdd && canEditPrice)
);
canEditVat$ = this.item$.pipe(
switchMap((item) => combineLatest([this.canAddResult$, this._store.getCanEditVat$(item.id)])),
map(([canAddResult, canEditVat]) => canAddResult?.canAdd && canEditVat)
);
isGiftCard$ = this.item$.pipe(switchMap((item) => this._store.getIsGiftCard$(item.id)));
maxSelectableQuantity$ = combineLatest([this._store.purchaseOption$, this.availability$]).pipe(
map(([purchaseOption, availability]) => {
if (purchaseOption === 'in-store') {
@@ -203,6 +165,14 @@ export class PurchaseOptionsListItemComponent implements OnInit, OnDestroy, OnCh
constructor(private _store: PurchaseOptionsStore) {}
onPriceInputInit(target: HTMLElement, overlayTrigger: UiOverlayTriggerDirective) {
if (this._store.getIsGiftCard(this.item.id)) {
overlayTrigger.open();
}
target?.focus();
}
// Wichtig für das korrekte Setzen des Preises an das Item für den Endpoint request
parsePrice(value: string) {
if (PRICE_PATTERN.test(value)) {
@@ -223,10 +193,11 @@ export class PurchaseOptionsListItemComponent implements OnInit, OnDestroy, OnCh
}
ngOnInit(): void {
this.initPriceValidatorSubscription();
this.initQuantitySubscription();
this.initPriceSubscription();
this.initVatSubscription();
this.initSelectedSubscription();
this.initManualPriceSubscriptions();
}
ngOnChanges({ item }: SimpleChanges) {
@@ -240,14 +211,16 @@ export class PurchaseOptionsListItemComponent implements OnInit, OnDestroy, OnCh
this._subscriptions.unsubscribe();
}
// Ticket #4074 analog zu Ticket #2244
// Logik gilt ausschließlich für Archivartikel und über die Kaufoptionen. Nicht über den Warenkorb
async initManualPriceSubscriptions() {
const isManualPrice = await this.setManualPrice$.pipe(last()).toPromise();
if (!!isManualPrice) {
this.initManualPriceSubscription();
this.initManualVatSubscription();
}
initPriceValidatorSubscription() {
const sub = this.item$.pipe(switchMap((item) => this._store.getIsGiftCard$(item.id))).subscribe((isGiftCard) => {
if (isGiftCard) {
this.priceFormControl.setValidators(this._giftCardValidators);
} else {
this.priceFormControl.setValidators(this._defaultValidators);
}
});
this._subscriptions.add(sub);
}
initQuantitySubscription() {
@@ -268,7 +241,11 @@ export class PurchaseOptionsListItemComponent implements OnInit, OnDestroy, OnCh
}
initPriceSubscription() {
const sub = this.price$.subscribe((price) => {
const sub = combineLatest([this.canEditPrice$, this.price$]).subscribe(([canEditPrice, price]) => {
if (!canEditPrice) {
return;
}
const priceStr = this.stringifyPrice(price?.value?.value);
if (priceStr === '') return;
@@ -277,7 +254,11 @@ export class PurchaseOptionsListItemComponent implements OnInit, OnDestroy, OnCh
}
});
const valueChangesSub = this.priceFormControl.valueChanges.subscribe((value) => {
const valueChangesSub = combineLatest([this.canEditPrice$, this.priceFormControl.valueChanges]).subscribe(([canEditPrice, value]) => {
if (!canEditPrice) {
return;
}
const price = this._store.getPrice(this.item.id);
const parsedPrice = this.parsePrice(value);
@@ -294,34 +275,7 @@ export class PurchaseOptionsListItemComponent implements OnInit, OnDestroy, OnCh
this._subscriptions.add(valueChangesSub);
}
initManualPriceSubscription() {
const sub = this.price$.subscribe((price) => {
const priceStr = this.stringifyPrice(price?.value?.value);
if (priceStr === '') return;
if (this.parsePrice(this.manualPriceFormControl.value) !== price?.value?.value) {
this.manualPriceFormControl.setValue(priceStr);
}
});
const valueChangesSub = this.manualPriceFormControl.valueChanges.subscribe((value) => {
const price = this._store.getPrice(this.item.id);
const parsedPrice = this.parsePrice(value);
if (!parsedPrice) {
this._store.setPrice(this.item.id, null, true);
return;
}
if (price[this.item.id] !== parsedPrice) {
this._store.setPrice(this.item.id, this.parsePrice(value), true);
}
});
this._subscriptions.add(sub);
this._subscriptions.add(valueChangesSub);
}
initManualVatSubscription() {
initVatSubscription() {
const valueChangesSub = this.manualVatFormControl.valueChanges.pipe(withLatestFrom(this.vats$)).subscribe(([formVatType, vats]) => {
const price = this._store.getPrice(this.item.id);

View File

@@ -25,18 +25,13 @@
</div>
<div class="text-center -mx-4 border-t border-gray-200 p-4 border-solid">
<ng-container *ngIf="type === 'add'">
<button
type="button"
class="isa-cta-button"
[disabled]="!(canContinue$ | async) || saving || !(hasPrice$ | async)"
(click)="save('continue-shopping')"
>
<button type="button" class="isa-cta-button" [disabled]="!(canContinue$ | async) || saving" (click)="save('continue-shopping')">
Weiter einkaufen
</button>
<button
type="button"
class="ml-4 isa-cta-button isa-button-primary"
[disabled]="!(canContinue$ | async) || saving || !(hasPrice$ | async)"
[disabled]="!(canContinue$ | async) || saving"
(click)="save('continue')"
>
Fortfahren
@@ -46,7 +41,7 @@
<button
type="button"
class="ml-4 isa-cta-button isa-button-primary"
[disabled]="!(canContinue$ | async) || saving || !(hasPrice$ | async)"
[disabled]="!(canContinue$ | async) || saving"
(click)="save('continue')"
>
Fortfahren

View File

@@ -13,7 +13,7 @@ import {
PickupPurchaseOptionTileComponent,
} from './purchase-options-tile';
import { isGiftCard, Item, PurchaseOption, PurchaseOptionsStore } from './store';
import { delay, map, shareReplay, skip, switchMap, takeUntil } from 'rxjs/operators';
import { delay, map, shareReplay, skip, switchMap, takeUntil, tap } from 'rxjs/operators';
import { KeyValueDTOOfStringAndString } from '@swagger/cat';
@Component({
@@ -83,7 +83,7 @@ export class PurchaseOptionsModalComponent implements OnInit, OnDestroy {
hasDownload$ = this.purchasingOptions$.pipe(map((purchasingOptions) => purchasingOptions.includes('download')));
canContinue$ = this.store.canContinue$.pipe(shareReplay(1));
canContinue$ = this.store.canContinue$;
private _onDestroy$ = new Subject<void>();

View File

@@ -60,6 +60,14 @@ export function isGiftCard(item: Item, type: ActionType): boolean {
}
}
export function isArchive(item: Item, type: ActionType): boolean {
if (isItemDTO(item, type)) {
return item?.features?.some((f) => f.key === 'ARC');
} else {
return !!item?.features?.['ARC'];
}
}
export function mapToItemPayload({
item,
quantity,

View File

@@ -1,6 +1,6 @@
import { PriceDTO, PriceValueDTO } from '@swagger/checkout';
import { DEFAULT_PRICE_DTO, DEFAULT_PRICE_VALUE, GIFT_CARD_MAX_PRICE, GIFT_CARD_TYPE, PURCHASE_OPTIONS } from '../constants';
import { isGiftCard, isItemDTO } from './purchase-options.helpers';
import { isArchive, isGiftCard, isItemDTO } from './purchase-options.helpers';
import { PurchaseOptionsState } from './purchase-options.state';
import { ActionType, Availability, Branch, CanAdd, FetchingAvailability, Item, PurchaseOption } from './purchase-options.types';
@@ -82,7 +82,7 @@ export function getCanAddForItemWithPurchaseOption(
): (state: PurchaseOptionsState) => CanAdd {
return (state: PurchaseOptionsState) => {
const canAddResults = getCanAddResults(state);
return canAddResults.find((ca) => ca.itemId === itemId && ca.purchaseOption === purchaseOption);
return canAddResults.find((ca) => ca.canAdd && ca.itemId === itemId && ca.purchaseOption === purchaseOption);
};
}
@@ -202,25 +202,47 @@ export function getCanEditPrice(itemId: number): (state: PurchaseOptionsState) =
return (state) => {
const item = getItems(state).find((item) => item.id === itemId);
if (isGiftCard(item, getType(state))) {
return true;
}
const purchaseOption = getPurchaseOption(state);
if (isArchive(item, getType(state)) && !getAvailabilityPriceForPurchaseOption(itemId, purchaseOption)(state)) {
return true;
}
return false;
};
}
export function getCanEditVat(itemId: number): (state: PurchaseOptionsState) => boolean {
return (state) => {
const item = getItems(state).find((item) => item.id === itemId);
const purchaseOption = getPurchaseOption(state);
if (isArchive(item, getType(state)) && !getAvailabilityPriceForPurchaseOption(itemId, purchaseOption)(state)) {
return true;
}
return false;
};
}
export function getIsGiftCard(itemId: number): (state: PurchaseOptionsState) => boolean {
return (state) => {
const item = getItems(state).find((item) => item.id === itemId);
return isGiftCard(item, getType(state));
};
}
export function getPriceForPurchaseOption(
export function getAvailabilityPriceForPurchaseOption(
itemId: number,
purchaseOption: PurchaseOption
): (state: PurchaseOptionsState) => PriceDTO & { fromCatalogue?: boolean } {
): (state: PurchaseOptionsState) => (PriceDTO & { fromCatalogue?: boolean }) | undefined {
return (state) => {
const price = getPrices(state)[itemId];
if (price) {
return price;
}
const item = getItems(state).find((item) => item.id === itemId);
const type = getType(state);
let availabilities = getAvailabilitiesForItem(itemId)(state);
let availability = availabilities.find((availability) => availability.purchaseOption === purchaseOption);
@@ -257,13 +279,29 @@ export function getPriceForPurchaseOption(
}
if (isItemDTO(item, type)) {
return item?.catalogAvailability?.price ?? DEFAULT_PRICE_DTO;
return item?.catalogAvailability?.price;
} else {
return item?.unitPrice ?? DEFAULT_PRICE_DTO;
return item?.unitPrice;
}
};
}
export function getPriceForPurchaseOption(
itemId: number,
purchaseOption: PurchaseOption
): (state: PurchaseOptionsState) => PriceDTO & { fromCatalogue?: boolean } {
return (state) => {
if (getCanEditPrice(itemId)(state)) {
const price = getPrices(state)[itemId];
if (price) {
return price;
}
}
return getAvailabilityPriceForPurchaseOption(itemId, purchaseOption)(state) ?? DEFAULT_PRICE_DTO;
};
}
export function getQuantityForItem(itemId: number): (state: PurchaseOptionsState) => number {
return (state) => {
const item = getItems(state).find((item) => item.id === itemId);
@@ -343,12 +381,21 @@ export function canContinue(state: PurchaseOptionsState): boolean {
return false;
}
const actionType = getType(state);
for (let item of items) {
if (isGiftCard(item, getType(state))) {
if (isGiftCard(item, actionType)) {
const price = getPriceForPurchaseOption(item.id, purchaseOption)(state);
if (!(price?.value?.value > 0 && price?.value?.value <= GIFT_CARD_MAX_PRICE)) {
return false;
}
} else if (isArchive(item, actionType) && !getAvailabilityPriceForPurchaseOption(item.id, purchaseOption)(state)) {
const price = getPriceForPurchaseOption(item.id, purchaseOption)(state);
const hasPrice = price?.value?.value > 0;
const hasVat = price?.vat?.vatType > 0;
if (!(hasPrice && hasVat)) {
return false;
}
}
}

View File

@@ -133,9 +133,9 @@ export class PurchaseOptionsService {
};
}
getDownloadDestination(): EntityDTOContainerOfDestinationDTO {
getDownloadDestination(availability: AvailabilityDTO): EntityDTOContainerOfDestinationDTO {
return {
data: { target: 16 },
data: { target: 16, logistician: availability?.logistician },
};
}

View File

@@ -612,8 +612,8 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
});
}
isGiftcard(itemId: number) {
return this._service;
getIsGiftCard(itemId: number) {
return this.get(Selectors.getIsGiftCard(itemId));
}
getPrice(itemId: number) {
@@ -640,9 +640,22 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
return this.select(Selectors.getCanEditPrice(itemId));
}
getCanEditVat(itemId: number) {
return this.get(Selectors.getCanEditVat(itemId));
}
getCanEditVat$(itemId: number) {
return this.select(Selectors.getCanEditVat(itemId));
}
getIsGiftCard$(itemId: number) {
return this.select(Selectors.getIsGiftCard(itemId));
}
setPrice(itemId: number, value: number, manually: boolean = false) {
const prices = this.prices;
let price = prices[itemId];
if (price?.value?.value !== value) {
if (!price) {
price = {
@@ -719,7 +732,7 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
} else if (purchaseOption === 'in-store') {
destination = this._service.getInStoreDestination(this.inStoreBranch);
} else if (purchaseOption === 'download') {
destination = this._service.getDownloadDestination();
destination = this._service.getDownloadDestination(availability.data);
}
return {
@@ -755,7 +768,7 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
} else if (purchaseOption === 'in-store') {
destination = this._service.getInStoreDestination(this.inStoreBranch);
} else if (purchaseOption === 'download') {
destination = this._service.getDownloadDestination();
destination = this._service.getDownloadDestination(availability.data);
}
return {

View File

@@ -3,6 +3,7 @@ import { NgModule, ModuleWithProviders } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { CheckoutConfiguration, CheckoutConfigurationInterface } from './checkout-configuration';
import { KulturPassService } from './services/kultur-pass.service';
import { StoreCheckoutBranchService } from './services/store-checkout-branch.service';
import { StoreCheckoutBuyerService } from './services/store-checkout-buyer.service';
import { StoreCheckoutService } from './services/store-checkout.service';
@@ -27,6 +28,7 @@ import { StoreCheckoutVATService } from './services/store-checkout-vat.service';
declarations: [],
providers: [
CheckoutConfiguration,
KulturPassService,
StoreCheckoutBranchService,
StoreCheckoutBuyerService,
StoreCheckoutService,

View File

@@ -1,3 +1,17 @@
export { ResponseArgsOfIEnumerableOfKulturPassResult } from './models/response-args-of-ienumerable-of-kultur-pass-result';
export { KulturPassResult } from './models/kultur-pass-result';
export { ProductDTO } from './models/product-dto';
export { SizeOfString } from './models/size-of-string';
export { WeightOfAvoirdupois } from './models/weight-of-avoirdupois';
export { Avoirdupois } from './models/avoirdupois';
export { TouchedBase } from './models/touched-base';
export { ResponseArgs } from './models/response-args';
export { DialogOfString } from './models/dialog-of-string';
export { DialogSettings } from './models/dialog-settings';
export { DialogContentType } from './models/dialog-content-type';
export { KeyValueDTOOfStringAndString } from './models/key-value-dtoof-string-and-string';
export { IPublicUserInfo } from './models/ipublic-user-info';
export { ProblemDetails } from './models/problem-details';
export { ResponseArgsOfIEnumerableOfBranchDTO } from './models/response-args-of-ienumerable-of-branch-dto';
export { BranchDTO } from './models/branch-dto';
export { EntityDTOContainerOfLabelDTO } from './models/entity-dtocontainer-of-label-dto';
@@ -6,7 +20,7 @@ export { EntityDTOBaseOfLabelDTOAndILabel } from './models/entity-dtobase-of-lab
export { EntityDTOBase } from './models/entity-dtobase';
export { EntityDTO } from './models/entity-dto';
export { EntityStatus } from './models/entity-status';
export { TouchedBase } from './models/touched-base';
export { CRUDA } from './models/cruda';
export { EntityDTOReferenceContainer } from './models/entity-dtoreference-container';
export { ExternalReferenceDTO } from './models/external-reference-dto';
export { EntityDTOContainerOfBranchDTO } from './models/entity-dtocontainer-of-branch-dto';
@@ -14,13 +28,6 @@ export { AddressDTO } from './models/address-dto';
export { GeoLocation } from './models/geo-location';
export { BranchType } from './models/branch-type';
export { EntityDTOBaseOfBranchDTOAndIBranch } from './models/entity-dtobase-of-branch-dtoand-ibranch';
export { ResponseArgs } from './models/response-args';
export { DialogOfString } from './models/dialog-of-string';
export { DialogSettings } from './models/dialog-settings';
export { DialogContentType } from './models/dialog-content-type';
export { KeyValueDTOOfStringAndString } from './models/key-value-dtoof-string-and-string';
export { IPublicUserInfo } from './models/ipublic-user-info';
export { ProblemDetails } from './models/problem-details';
export { BranchQueryTokenDTO } from './models/branch-query-token-dto';
export { ResponseArgsOfCheckoutDTO } from './models/response-args-of-checkout-dto';
export { CheckoutDTO } from './models/checkout-dto';
@@ -73,10 +80,6 @@ export { CompanyDTO } from './models/company-dto';
export { EntityDTOBaseOfCompanyDTOAndICompany } from './models/entity-dtobase-of-company-dtoand-icompany';
export { EntityDTOContainerOfCategoryDTO } from './models/entity-dtocontainer-of-category-dto';
export { CategoryDTO } from './models/category-dto';
export { EntityDTOBaseOfCategoryDTOAndICategory } from './models/entity-dtobase-of-category-dtoand-icategory';
export { SizeOfString } from './models/size-of-string';
export { WeightOfAvoirdupois } from './models/weight-of-avoirdupois';
export { Avoirdupois } from './models/avoirdupois';
export { ItemType } from './models/item-type';
export { EntityDTOContainerOfFileDTO } from './models/entity-dtocontainer-of-file-dto';
export { FileDTO } from './models/file-dto';
@@ -115,7 +118,6 @@ export { SupplierType } from './models/supplier-type';
export { EntityDTOBaseOfSupplierDTOAndISupplier } from './models/entity-dtobase-of-supplier-dtoand-isupplier';
export { ShippingDTO } from './models/shipping-dto';
export { EntityDTOBaseOfShopItemDTOAndIShopItem } from './models/entity-dtobase-of-shop-item-dtoand-ishop-item';
export { ProductDTO } from './models/product-dto';
export { ShoppingCartItemStatus } from './models/shopping-cart-item-status';
export { OrderItemType } from './models/order-item-type';
export { EntityDTOContainerOfShopDTO } from './models/entity-dtocontainer-of-shop-dto';

View File

@@ -1,8 +1,8 @@
/* tslint:disable */
import { EntityDTOBaseOfCategoryDTOAndICategory } from './entity-dtobase-of-category-dtoand-icategory';
import { EntityDTOBase } from './entity-dtobase';
import { EntityDTOContainerOfCategoryDTO } from './entity-dtocontainer-of-category-dto';
import { EntityDTOContainerOfTenantDTO } from './entity-dtocontainer-of-tenant-dto';
export interface CategoryDTO extends EntityDTOBaseOfCategoryDTOAndICategory{
export interface CategoryDTO extends EntityDTOBase{
key?: string;
name?: string;
parent?: EntityDTOContainerOfCategoryDTO;

View File

@@ -0,0 +1,2 @@
/* tslint:disable */
export type CRUDA = 0 | 1 | 2 | 4 | 8 | 16;

View File

@@ -1,11 +1,14 @@
/* tslint:disable */
import { TouchedBase } from './touched-base';
import { CRUDA } from './cruda';
import { EntityStatus } from './entity-status';
export interface EntityDTO extends TouchedBase{
changed?: string;
created?: string;
cruda?: CRUDA;
id?: number;
pId?: string;
status?: EntityStatus;
uId?: string;
version?: number;
}

View File

@@ -1,4 +0,0 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfCategoryDTOAndICategory extends EntityDTOBase{
}

View File

@@ -8,4 +8,5 @@ export interface EntityDTOReferenceContainer extends TouchedBase{
id?: number;
pId?: string;
selected?: boolean;
uId?: string;
}

View File

@@ -0,0 +1,23 @@
/* tslint:disable */
import { ProductDTO } from './product-dto';
/**
* KulturPassResult
*/
export interface KulturPassResult {
/**
* Can add
*/
canAdd: boolean;
/**
* Message
*/
message?: string;
/**
* Product
*/
productDTO?: ProductDTO;
}

View File

@@ -1,2 +1,2 @@
/* tslint:disable */
export type OrderItemType = 0 | 1 | 2 | 4 | 8 | 16 | 32 | 64;
export type OrderItemType = 0 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 256 | 512 | 1024;

View File

@@ -14,6 +14,7 @@ export interface ProductDTO extends TouchedBase{
manufacturer?: string;
name?: string;
productGroup?: string;
productGroupDetails?: string;
publicationDate?: string;
serial?: string;
size?: SizeOfString;

View File

@@ -0,0 +1,6 @@
/* tslint:disable */
import { ResponseArgs } from './response-args';
import { KulturPassResult } from './kultur-pass-result';
export interface ResponseArgsOfIEnumerableOfKulturPassResult extends ResponseArgs{
result?: Array<KulturPassResult>;
}

View File

@@ -1,3 +1,4 @@
export { KulturPassService } from './services/kultur-pass.service';
export { StoreCheckoutBranchService } from './services/store-checkout-branch.service';
export { StoreCheckoutBuyerService } from './services/store-checkout-buyer.service';
export { StoreCheckoutService } from './services/store-checkout.service';

View File

@@ -0,0 +1,90 @@
/* tslint:disable */
import { Injectable } from '@angular/core';
import { HttpClient, HttpRequest, HttpResponse, HttpHeaders } from '@angular/common/http';
import { BaseService as __BaseService } from '../base-service';
import { CheckoutConfiguration as __Configuration } from '../checkout-configuration';
import { StrictHttpResponse as __StrictHttpResponse } from '../strict-http-response';
import { Observable as __Observable } from 'rxjs';
import { map as __map, filter as __filter } from 'rxjs/operators';
import { ResponseArgsOfIEnumerableOfKulturPassResult } from '../models/response-args-of-ienumerable-of-kultur-pass-result';
import { ProductDTO } from '../models/product-dto';
@Injectable({
providedIn: 'root',
})
class KulturPassService extends __BaseService {
static readonly KulturPassCanAddForKulturPassPath = '/store/shoppingcart/kulturpass/canadd';
constructor(
config: __Configuration,
http: HttpClient
) {
super(config, http);
}
/**
* Überprüfung, ob die Artikel zu einer KulturPass-Bestellung hinzugefügt werden können
* @param params The `KulturPassService.KulturPassCanAddForKulturPassParams` containing the following parameters:
*
* - `payload`: Daten (EAN und ProductGroup müssen übergeben werden)
*
* - `locale`: Lokalisierung
*/
KulturPassCanAddForKulturPassResponse(params: KulturPassService.KulturPassCanAddForKulturPassParams): __Observable<__StrictHttpResponse<ResponseArgsOfIEnumerableOfKulturPassResult>> {
let __params = this.newParams();
let __headers = new HttpHeaders();
let __body: any = null;
__body = params.payload;
if (params.locale != null) __params = __params.set('locale', params.locale.toString());
let req = new HttpRequest<any>(
'POST',
this.rootUrl + `/store/shoppingcart/kulturpass/canadd`,
__body,
{
headers: __headers,
params: __params,
responseType: 'json'
});
return this.http.request<any>(req).pipe(
__filter(_r => _r instanceof HttpResponse),
__map((_r) => {
return _r as __StrictHttpResponse<ResponseArgsOfIEnumerableOfKulturPassResult>;
})
);
}
/**
* Überprüfung, ob die Artikel zu einer KulturPass-Bestellung hinzugefügt werden können
* @param params The `KulturPassService.KulturPassCanAddForKulturPassParams` containing the following parameters:
*
* - `payload`: Daten (EAN und ProductGroup müssen übergeben werden)
*
* - `locale`: Lokalisierung
*/
KulturPassCanAddForKulturPass(params: KulturPassService.KulturPassCanAddForKulturPassParams): __Observable<ResponseArgsOfIEnumerableOfKulturPassResult> {
return this.KulturPassCanAddForKulturPassResponse(params).pipe(
__map(_r => _r.body as ResponseArgsOfIEnumerableOfKulturPassResult)
);
}
}
module KulturPassService {
/**
* Parameters for KulturPassCanAddForKulturPass
*/
export interface KulturPassCanAddForKulturPassParams {
/**
* Daten (EAN und ProductGroup müssen übergeben werden)
*/
payload: Array<ProductDTO>;
/**
* Lokalisierung
*/
locale?: null | string;
}
}
export { KulturPassService }

View File

@@ -5,7 +5,6 @@ import { IsaConfiguration, IsaConfigurationInterface } from './isa-configuration
import { AuthService } from './services/auth.service';
import { InfoService } from './services/info.service';
import { MessageService } from './services/message.service';
import { UserStateService } from './services/user-state.service';
/**
@@ -23,7 +22,6 @@ import { UserStateService } from './services/user-state.service';
IsaConfiguration,
AuthService,
InfoService,
MessageService,
UserStateService
],
})

View File

@@ -10,42 +10,6 @@ export { DialogSettings } from './models/dialog-settings';
export { DialogContentType } from './models/dialog-content-type';
export { KeyValueDTOOfStringAndString } from './models/key-value-dtoof-string-and-string';
export { IPublicUserInfo } from './models/ipublic-user-info';
export { EnvelopeDTOOfMessageBoardItemDTO } from './models/envelope-dtoof-message-board-item-dto';
export { TargetDTO } from './models/target-dto';
export { EntityDTOContainerOfUserDTO } from './models/entity-dtocontainer-of-user-dto';
export { UserDTO } from './models/user-dto';
export { ElevationMode } from './models/elevation-mode';
export { EntityDTOContainerOfLabelDTO } from './models/entity-dtocontainer-of-label-dto';
export { LabelDTO } from './models/label-dto';
export { EntityDTOContainerOfTenantDTO } from './models/entity-dtocontainer-of-tenant-dto';
export { TenantDTO } from './models/tenant-dto';
export { EntityDTOOfTenantDTOAndITenant } from './models/entity-dtoof-tenant-dtoand-itenant';
export { ReadOnlyEntityDTOOfTenantDTOAndITenant } from './models/read-only-entity-dtoof-tenant-dtoand-itenant';
export { EntityDTO } from './models/entity-dto';
export { EntityStatus } from './models/entity-status';
export { TouchedBase } from './models/touched-base';
export { EntityDTOReferenceContainer } from './models/entity-dtoreference-container';
export { ExternalReferenceDTO } from './models/external-reference-dto';
export { EntityDTOOfLabelDTOAndILabel } from './models/entity-dtoof-label-dtoand-ilabel';
export { ReadOnlyEntityDTOOfLabelDTOAndILabel } from './models/read-only-entity-dtoof-label-dtoand-ilabel';
export { EntityDTOContainerOfBranchDTO } from './models/entity-dtocontainer-of-branch-dto';
export { BranchDTO } from './models/branch-dto';
export { AddressDTO } from './models/address-dto';
export { GeoLocation } from './models/geo-location';
export { CommunicationDetailsDTO } from './models/communication-details-dto';
export { BranchType } from './models/branch-type';
export { EntityDTOOfBranchDTOAndIBranch } from './models/entity-dtoof-branch-dtoand-ibranch';
export { ReadOnlyEntityDTOOfBranchDTOAndIBranch } from './models/read-only-entity-dtoof-branch-dtoand-ibranch';
export { Gender } from './models/gender';
export { EntityDTOContainerOfApplicationDTO } from './models/entity-dtocontainer-of-application-dto';
export { ApplicationDTO } from './models/application-dto';
export { EntityDTOOfApplicationDTOAndIApplication } from './models/entity-dtoof-application-dtoand-iapplication';
export { ReadOnlyEntityDTOOfApplicationDTOAndIApplication } from './models/read-only-entity-dtoof-application-dtoand-iapplication';
export { UserAccountType } from './models/user-account-type';
export { ReadOnlyEntityDTOOfUserDTOAndIUser } from './models/read-only-entity-dtoof-user-dtoand-iuser';
export { MessageBoardItemDTO } from './models/message-board-item-dto';
export { QueryTokenDTO } from './models/query-token-dto';
export { OrderByDTO } from './models/order-by-dto';
export { UserState } from './models/user-state';
export { ResponseArgsOfUserState } from './models/response-args-of-user-state';
export { Log } from './models/log';

View File

@@ -1,17 +0,0 @@
/* tslint:disable */
import { GeoLocation } from './geo-location';
export interface AddressDTO {
apartment?: string;
careOf?: string;
city?: string;
country?: string;
district?: string;
geoLocation?: GeoLocation;
info?: string;
po?: string;
region?: string;
state?: string;
street?: string;
streetNumber?: string;
zipCode?: string;
}

View File

@@ -1,9 +0,0 @@
/* tslint:disable */
import { EntityDTOOfApplicationDTOAndIApplication } from './entity-dtoof-application-dtoand-iapplication';
import { EntityDTOContainerOfTenantDTO } from './entity-dtocontainer-of-tenant-dto';
export interface ApplicationDTO extends EntityDTOOfApplicationDTOAndIApplication{
bitMask?: number;
key?: string;
name?: string;
tenant?: EntityDTOContainerOfTenantDTO;
}

View File

@@ -1,24 +0,0 @@
/* tslint:disable */
import { EntityDTOOfBranchDTOAndIBranch } from './entity-dtoof-branch-dtoand-ibranch';
import { AddressDTO } from './address-dto';
import { BranchType } from './branch-type';
import { CommunicationDetailsDTO } from './communication-details-dto';
import { EntityDTOContainerOfLabelDTO } from './entity-dtocontainer-of-label-dto';
import { EntityDTOContainerOfBranchDTO } from './entity-dtocontainer-of-branch-dto';
export interface BranchDTO extends EntityDTOOfBranchDTOAndIBranch{
address?: AddressDTO;
branchNumber?: string;
branchType: BranchType;
communicationDetailsExternal?: CommunicationDetailsDTO;
communicationDetailsInternal?: CommunicationDetailsDTO;
extBranchNo?: string;
isOnline?: boolean;
isOrderingEnabled?: boolean;
isShippingEnabled?: boolean;
key?: string;
label?: EntityDTOContainerOfLabelDTO;
name?: string;
parent?: EntityDTOContainerOfBranchDTO;
shortName?: string;
web?: string;
}

View File

@@ -1,2 +0,0 @@
/* tslint:disable */
export type BranchType = 0 | 1 | 2 | 4 | 8 | 16;

View File

@@ -1,7 +0,0 @@
/* tslint:disable */
export interface CommunicationDetailsDTO {
email?: string;
fax?: string;
mobile?: string;
phone?: string;
}

View File

@@ -1,2 +0,0 @@
/* tslint:disable */
export type ElevationMode = 0 | 1 | 32 | 1024 | 1048576 | 268435456 | 1073741824;

View File

@@ -1,11 +0,0 @@
/* tslint:disable */
import { TouchedBase } from './touched-base';
import { EntityStatus } from './entity-status';
export interface EntityDTO extends TouchedBase{
changed?: string;
created?: string;
id?: number;
pId?: string;
status?: EntityStatus;
version?: number;
}

View File

@@ -1,6 +0,0 @@
/* tslint:disable */
import { EntityDTOReferenceContainer } from './entity-dtoreference-container';
import { ApplicationDTO } from './application-dto';
export interface EntityDTOContainerOfApplicationDTO extends EntityDTOReferenceContainer{
data?: ApplicationDTO;
}

View File

@@ -1,6 +0,0 @@
/* tslint:disable */
import { EntityDTOReferenceContainer } from './entity-dtoreference-container';
import { BranchDTO } from './branch-dto';
export interface EntityDTOContainerOfBranchDTO extends EntityDTOReferenceContainer{
data?: BranchDTO;
}

View File

@@ -1,6 +0,0 @@
/* tslint:disable */
import { EntityDTOReferenceContainer } from './entity-dtoreference-container';
import { LabelDTO } from './label-dto';
export interface EntityDTOContainerOfLabelDTO extends EntityDTOReferenceContainer{
data?: LabelDTO;
}

View File

@@ -1,6 +0,0 @@
/* tslint:disable */
import { EntityDTOReferenceContainer } from './entity-dtoreference-container';
import { TenantDTO } from './tenant-dto';
export interface EntityDTOContainerOfTenantDTO extends EntityDTOReferenceContainer{
data?: TenantDTO;
}

View File

@@ -1,6 +0,0 @@
/* tslint:disable */
import { EntityDTOReferenceContainer } from './entity-dtoreference-container';
import { UserDTO } from './user-dto';
export interface EntityDTOContainerOfUserDTO extends EntityDTOReferenceContainer{
data?: UserDTO;
}

View File

@@ -1,4 +0,0 @@
/* tslint:disable */
import { ReadOnlyEntityDTOOfApplicationDTOAndIApplication } from './read-only-entity-dtoof-application-dtoand-iapplication';
export interface EntityDTOOfApplicationDTOAndIApplication extends ReadOnlyEntityDTOOfApplicationDTOAndIApplication{
}

View File

@@ -1,4 +0,0 @@
/* tslint:disable */
import { ReadOnlyEntityDTOOfBranchDTOAndIBranch } from './read-only-entity-dtoof-branch-dtoand-ibranch';
export interface EntityDTOOfBranchDTOAndIBranch extends ReadOnlyEntityDTOOfBranchDTOAndIBranch{
}

View File

@@ -1,4 +0,0 @@
/* tslint:disable */
import { ReadOnlyEntityDTOOfLabelDTOAndILabel } from './read-only-entity-dtoof-label-dtoand-ilabel';
export interface EntityDTOOfLabelDTOAndILabel extends ReadOnlyEntityDTOOfLabelDTOAndILabel{
}

View File

@@ -1,4 +0,0 @@
/* tslint:disable */
import { ReadOnlyEntityDTOOfTenantDTOAndITenant } from './read-only-entity-dtoof-tenant-dtoand-itenant';
export interface EntityDTOOfTenantDTOAndITenant extends ReadOnlyEntityDTOOfTenantDTOAndITenant{
}

View File

@@ -1,11 +0,0 @@
/* tslint:disable */
import { TouchedBase } from './touched-base';
import { ExternalReferenceDTO } from './external-reference-dto';
export interface EntityDTOReferenceContainer extends TouchedBase{
displayLabel?: string;
enabled?: boolean;
externalReference?: ExternalReferenceDTO;
id?: number;
pId?: string;
selected?: boolean;
}

View File

@@ -1,2 +0,0 @@
/* tslint:disable */
export type EntityStatus = 0 | 1 | 2 | 4 | 8;

View File

@@ -1,11 +0,0 @@
/* tslint:disable */
import { MessageBoardItemDTO } from './message-board-item-dto';
import { TargetDTO } from './target-dto';
export interface EnvelopeDTOOfMessageBoardItemDTO {
action?: string;
data?: MessageBoardItemDTO;
sequence?: number;
target?: TargetDTO;
timestamp: string;
uId?: string;
}

View File

@@ -1,13 +0,0 @@
/* tslint:disable */
import { TouchedBase } from './touched-base';
import { EntityStatus } from './entity-status';
export interface ExternalReferenceDTO extends TouchedBase{
externalChanged?: string;
externalCreated?: string;
externalNumber?: string;
externalPK?: string;
externalRepository?: string;
externalStatus: EntityStatus;
externalVersion?: number;
publishToken?: string;
}

View File

@@ -1,2 +0,0 @@
/* tslint:disable */
export type Gender = 0 | 1 | 2 | 4;

View File

@@ -1,7 +0,0 @@
/* tslint:disable */
import { TouchedBase } from './touched-base';
export interface GeoLocation extends TouchedBase{
altitude?: number;
latitude?: number;
longitude?: number;
}

View File

@@ -3,6 +3,7 @@ export interface KeyValueDTOOfStringAndString {
command?: string;
description?: string;
enabled?: boolean;
group?: string;
key?: string;
label?: string;
selected?: boolean;

View File

@@ -1,9 +0,0 @@
/* tslint:disable */
import { EntityDTOOfLabelDTOAndILabel } from './entity-dtoof-label-dtoand-ilabel';
import { EntityDTOContainerOfTenantDTO } from './entity-dtocontainer-of-tenant-dto';
export interface LabelDTO extends EntityDTOOfLabelDTOAndILabel{
bitMask?: number;
key?: string;
name?: string;
tenant?: EntityDTOContainerOfTenantDTO;
}

View File

@@ -1,48 +0,0 @@
/* tslint:disable */
import { QueryTokenDTO } from './query-token-dto';
/**
* Message board item
*/
export interface MessageBoardItemDTO {
/**
* Kategorie / Gruppierung
*/
category?: string;
/**
* Command
*/
command?: string;
/**
* Ablaufdatum
*/
expirationDate?: string;
/**
* Überschrift
*/
headline?: string;
/**
* Abfrageparameter
*/
queryToken?: QueryTokenDTO;
/**
* Text
*/
text?: string;
/**
* Art der Nachricht
*/
type?: string;
/**
* Unique Id
*/
uId?: string;
}

View File

@@ -1,6 +0,0 @@
/* tslint:disable */
export interface OrderByDTO {
by?: string;
desc?: boolean;
label?: string;
}

View File

@@ -1,13 +0,0 @@
/* tslint:disable */
import { OrderByDTO } from './order-by-dto';
export interface QueryTokenDTO {
filter?: {[key: string]: string};
friendlyName?: string;
fuzzy?: number;
hitsOnly?: boolean;
ids?: Array<number>;
input?: {[key: string]: string};
orderBy?: Array<OrderByDTO>;
skip?: number;
take?: number;
}

View File

@@ -1,4 +0,0 @@
/* tslint:disable */
import { EntityDTO } from './entity-dto';
export interface ReadOnlyEntityDTOOfApplicationDTOAndIApplication extends EntityDTO{
}

View File

@@ -1,4 +0,0 @@
/* tslint:disable */
import { EntityDTO } from './entity-dto';
export interface ReadOnlyEntityDTOOfBranchDTOAndIBranch extends EntityDTO{
}

View File

@@ -1,4 +0,0 @@
/* tslint:disable */
import { EntityDTO } from './entity-dto';
export interface ReadOnlyEntityDTOOfLabelDTOAndILabel extends EntityDTO{
}

View File

@@ -1,4 +0,0 @@
/* tslint:disable */
import { EntityDTO } from './entity-dto';
export interface ReadOnlyEntityDTOOfTenantDTOAndITenant extends EntityDTO{
}

View File

@@ -1,4 +0,0 @@
/* tslint:disable */
import { EntityDTO } from './entity-dto';
export interface ReadOnlyEntityDTOOfUserDTOAndIUser extends EntityDTO{
}

View File

@@ -1,8 +0,0 @@
/* tslint:disable */
import { EntityDTOContainerOfBranchDTO } from './entity-dtocontainer-of-branch-dto';
import { EntityDTOContainerOfUserDTO } from './entity-dtocontainer-of-user-dto';
export interface TargetDTO {
area?: string;
branches?: Array<EntityDTOContainerOfBranchDTO>;
users?: Array<EntityDTOContainerOfUserDTO>;
}

View File

@@ -1,7 +0,0 @@
/* tslint:disable */
import { EntityDTOOfTenantDTOAndITenant } from './entity-dtoof-tenant-dtoand-itenant';
export interface TenantDTO extends EntityDTOOfTenantDTOAndITenant{
bitMask?: number;
key?: string;
name?: string;
}

View File

@@ -1,3 +0,0 @@
/* tslint:disable */
export interface TouchedBase {
}

View File

@@ -1,2 +0,0 @@
/* tslint:disable */
export type UserAccountType = 0 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128;

View File

@@ -1,40 +0,0 @@
/* tslint:disable */
import { ReadOnlyEntityDTOOfUserDTOAndIUser } from './read-only-entity-dtoof-user-dtoand-iuser';
import { UserAccountType } from './user-account-type';
import { EntityDTOContainerOfBranchDTO } from './entity-dtocontainer-of-branch-dto';
import { EntityDTOContainerOfApplicationDTO } from './entity-dtocontainer-of-application-dto';
import { ElevationMode } from './elevation-mode';
import { Gender } from './gender';
import { EntityDTOContainerOfLabelDTO } from './entity-dtocontainer-of-label-dto';
export interface UserDTO extends ReadOnlyEntityDTOOfUserDTOAndIUser{
accountType?: UserAccountType;
activeFrom?: string;
activeUntil?: string;
alias?: string;
availableInApplication?: number;
branch?: EntityDTOContainerOfBranchDTO;
changedByApplication?: EntityDTOContainerOfApplicationDTO;
clientCertificatePublicKey?: string;
confirmationGenerated?: string;
confirmationToken?: string;
confirmed?: string;
createdByApplication?: EntityDTOContainerOfApplicationDTO;
cultureInfo?: string;
dateOfBirth?: string;
description?: string;
elevation?: ElevationMode;
email?: string;
firstName?: string;
friendlyName?: string;
gender?: Gender;
isActive?: boolean;
label?: EntityDTOContainerOfLabelDTO;
language?: string;
lastName?: string;
memberOf?: number;
name?: string;
organisation?: string;
privateKey?: string;
title?: string;
token?: string;
}

View File

@@ -1,4 +1,3 @@
export { AuthService } from './services/auth.service';
export { InfoService } from './services/info.service';
export { MessageService } from './services/message.service';
export { UserStateService } from './services/user-state.service';

View File

@@ -1,64 +0,0 @@
/* tslint:disable */
import { Injectable } from '@angular/core';
import { HttpClient, HttpRequest, HttpResponse, HttpHeaders } from '@angular/common/http';
import { BaseService as __BaseService } from '../base-service';
import { IsaConfiguration as __Configuration } from '../isa-configuration';
import { StrictHttpResponse as __StrictHttpResponse } from '../strict-http-response';
import { Observable as __Observable } from 'rxjs';
import { map as __map, filter as __filter } from 'rxjs/operators';
import { EnvelopeDTOOfMessageBoardItemDTO } from '../models/envelope-dtoof-message-board-item-dto';
@Injectable({
providedIn: 'root',
})
class MessageService extends __BaseService {
static readonly MessageSendToMessageBoardPath = '/isa/messageboard';
constructor(
config: __Configuration,
http: HttpClient
) {
super(config, http);
}
/**
* Nachricht an message board senden
* @param message undefined
*/
MessageSendToMessageBoardResponse(message: EnvelopeDTOOfMessageBoardItemDTO): __Observable<__StrictHttpResponse<null>> {
let __params = this.newParams();
let __headers = new HttpHeaders();
let __body: any = null;
__body = message;
let req = new HttpRequest<any>(
'POST',
this.rootUrl + `/isa/messageboard`,
__body,
{
headers: __headers,
params: __params,
responseType: 'json'
});
return this.http.request<any>(req).pipe(
__filter(_r => _r instanceof HttpResponse),
__map((_r) => {
return _r as __StrictHttpResponse<null>;
})
);
}
/**
* Nachricht an message board senden
* @param message undefined
*/
MessageSendToMessageBoard(message: EnvelopeDTOOfMessageBoardItemDTO): __Observable<null> {
return this.MessageSendToMessageBoardResponse(message).pipe(
__map(_r => _r.body as null)
);
}
}
module MessageService {
}
export { MessageService }

View File

@@ -24,7 +24,7 @@ export class UiOverlayTriggerDirective implements OnInit, OnDestroy, OnChanges {
component: UiOverlayTrigger;
@Input()
triggerOn: 'click' | 'hover' | 'init' = 'click';
triggerOn: 'click' | 'hover' | 'init' | 'none' = 'click';
@Input()
overlayTriggerDisabled: boolean;

View File

@@ -7,10 +7,10 @@ button.clear {
}
.hint {
@apply text-brand text-x-small font-bold;
@apply text-brand font-bold;
&.readonly-hint {
@apply text-inactive-branch font-normal;
@apply text-ucla-blue font-normal;
}
}

View File

@@ -13,13 +13,15 @@ export abstract class UiFormControlDirective<T> {
private _readonly = false;
@Input()
@HostBinding('readonly')
@Input('readonly')
_isReadonly: BooleanInput = false;
get readonly(): boolean {
return this._readonly;
return coerceBooleanProperty(this._isReadonly);
}
set readonly(value: BooleanInput) {
this._readonly = coerceBooleanProperty(value);
set readonly(value: boolean) {
this._isReadonly = coerceBooleanProperty(value);
}
focused = new EventEmitter<boolean>();

View File

@@ -82,6 +82,9 @@ export class UiSearchboxNextComponent extends UiFormControlDirective<any>
@Input()
hint: string = '';
@Output()
hintCleared = new EventEmitter<void>();
@Input()
autocompleteValueSelector: (item: any) => string = (item: any) => item;
@@ -196,6 +199,7 @@ export class UiSearchboxNextComponent extends UiFormControlDirective<any>
clearHint() {
this.hint = '';
this.focused.emit(true);
this.hintCleared.emit();
this.cdr.markForCheck();
}

Some files were not shown because too many files have changed in this diff Show More