mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Merge branch 'develop' into feature/rd-customer
This commit is contained in:
@@ -1504,5 +1504,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": false
|
||||
}
|
||||
}
|
||||
@@ -31,14 +31,8 @@ export class ApplicationService {
|
||||
return this.activatedProcessIdSubject.asObservable();
|
||||
}
|
||||
|
||||
title$ = this.store.select(selectTitle);
|
||||
|
||||
constructor(private store: Store) {}
|
||||
|
||||
setTitle(title: string) {
|
||||
this.store.dispatch(setTitle({ title }));
|
||||
}
|
||||
|
||||
getProcesses$(section?: 'customer' | 'branch') {
|
||||
const processes$ = this.store.select(selectProcesses);
|
||||
return processes$.pipe(map((processes) => processes.filter((process) => (section ? process.section === section : true))));
|
||||
@@ -52,6 +46,14 @@ export class ApplicationService {
|
||||
return this.store.select(selectSection);
|
||||
}
|
||||
|
||||
getTitle$() {
|
||||
return this.getSection$().pipe(
|
||||
map((section) => {
|
||||
return section === 'customer' ? 'Kundenbereich' : 'Filialbereich';
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
getActivatedProcessId$() {
|
||||
return this.store.select(selectActivatedProcess).pipe(map((process) => process?.id));
|
||||
|
||||
@@ -22,7 +22,7 @@ export interface Breadcrumb {
|
||||
/**
|
||||
* Url
|
||||
*/
|
||||
path: string;
|
||||
path: string | any[];
|
||||
|
||||
/**
|
||||
* Query Parameter
|
||||
|
||||
@@ -1,17 +1,53 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Platform } from '@angular/cdk/platform';
|
||||
import { NativeContainerService } from 'native-container';
|
||||
import { BreakpointObserver } from '@angular/cdk/layout';
|
||||
import { shareReplay } from 'rxjs/operators';
|
||||
|
||||
const MATCH_TABLET = '(max-width: 1024px)';
|
||||
|
||||
const MATCH_DESKTOP_SMALL = '(min-width: 1025px) and (max-width: 1439px)';
|
||||
|
||||
const MATCH_DESKTOP = '(min-width: 1440px)';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class EnvironmentService {
|
||||
constructor(private _platform: Platform, private _nativeContainer: NativeContainerService) {}
|
||||
constructor(
|
||||
private _platform: Platform,
|
||||
private _nativeContainer: NativeContainerService,
|
||||
private _breakpointObserver: BreakpointObserver
|
||||
) {}
|
||||
|
||||
matchTablet(): boolean {
|
||||
return this._breakpointObserver.isMatched(MATCH_TABLET);
|
||||
}
|
||||
|
||||
matchTablet$ = this._breakpointObserver.observe(MATCH_TABLET).pipe(shareReplay());
|
||||
|
||||
matchDesktopSmall(): boolean {
|
||||
return this._breakpointObserver.isMatched(MATCH_DESKTOP_SMALL);
|
||||
}
|
||||
|
||||
matchDesktopSmall$ = this._breakpointObserver.observe(MATCH_DESKTOP_SMALL).pipe(shareReplay());
|
||||
|
||||
matchDesktop(): boolean {
|
||||
return this._breakpointObserver.isMatched(MATCH_DESKTOP);
|
||||
}
|
||||
|
||||
matchDesktop$ = this._breakpointObserver.observe(MATCH_DESKTOP).pipe(shareReplay());
|
||||
|
||||
/**
|
||||
* @deprecated Use `matchDesktopSmall` or 'matchDesktop' instead.
|
||||
*/
|
||||
isDesktop(): boolean {
|
||||
return !this.isTablet();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `matchTablet` instead.
|
||||
*/
|
||||
isTablet(): boolean {
|
||||
return this.isNative() || this.isSafari();
|
||||
}
|
||||
@@ -21,6 +57,6 @@ export class EnvironmentService {
|
||||
}
|
||||
|
||||
isSafari(): boolean {
|
||||
return (this._platform.ANDROID || this._platform.IOS) && this._platform.SAFARI;
|
||||
return this._platform.IOS && this._platform.SAFARI;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
<ui-icon icon="close" size="20px"></ui-icon>
|
||||
</button>
|
||||
<div class="toast-content flex flex-col justify-center items-center">
|
||||
<h1 class="text-card-sub font-bold text-center py-3 whitespace-pre-wrap">{{ data.title }}</h1>
|
||||
<h1 class="text-xl font-bold text-center py-3 whitespace-pre-wrap">{{ data.title }}</h1>
|
||||
<ng-container *ngIf="data.text; else templateRef">
|
||||
<p class="block text-base overflow-y-hidden pb-3 text-center overflow-x-hidden">{{ data.text }}</p>
|
||||
<p class="block text-p2 overflow-y-hidden pb-3 text-center overflow-x-hidden">{{ data.text }}</p>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -165,7 +165,7 @@ export class DomainAvailabilityService {
|
||||
),
|
||||
map(([response, supplier, defaultBranch]) => {
|
||||
const price = item?.price;
|
||||
return this._mapToTakeAwayAvailability({ response, supplier, branchId: branch.id ?? defaultBranch.id, quantity, price });
|
||||
return this._mapToTakeAwayAvailability({ response, supplier, branchId: branch?.id ?? defaultBranch?.id, quantity, price });
|
||||
}),
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
AutocompleteTokenDTO,
|
||||
BranchService,
|
||||
ChangeStockStatusCodeValues,
|
||||
HistoryDTO,
|
||||
@@ -11,9 +10,7 @@ import {
|
||||
OrderItemSubsetDTO,
|
||||
OrderListItemDTO,
|
||||
OrderService,
|
||||
QueryTokenDTO,
|
||||
ReceiptService,
|
||||
ResponseArgsOfIEnumerableOfHistoryDTO,
|
||||
StatusValues,
|
||||
StockStatusCodeService,
|
||||
ValueTupleOfLongAndReceiptTypeAndEntityDTOContainerOfReceiptDTO,
|
||||
@@ -22,7 +19,7 @@ import {
|
||||
} from '@swagger/oms';
|
||||
import { memorize } from '@utils/common';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, mergeMap, shareReplay } from 'rxjs/operators';
|
||||
import { map, shareReplay } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
export class DomainOmsService {
|
||||
@@ -191,6 +188,10 @@ export class DomainOmsService {
|
||||
);
|
||||
}
|
||||
|
||||
getOrderSource(orderId: number): Observable<string> {
|
||||
return this.getOrder(orderId).pipe(map((order) => order?.features?.orderSource));
|
||||
}
|
||||
|
||||
updateNotifications(orderId: number, changes: { selected: NotificationChannel; email: string; mobile: string }) {
|
||||
const communicationDetails = {
|
||||
email: changes.email,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { ApplicationProcess, ApplicationService } from '@core/application';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { ProductCatalogNavigationService } from '@shared/services';
|
||||
import { first } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
@@ -9,6 +10,7 @@ export class CanActivateProductGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly _applicationService: ApplicationService,
|
||||
private readonly _checkoutService: DomainCheckoutService,
|
||||
private readonly _navigationService: ProductCatalogNavigationService,
|
||||
private readonly _router: Router
|
||||
) {}
|
||||
|
||||
@@ -38,7 +40,7 @@ export class CanActivateProductGuard implements CanActivate {
|
||||
}
|
||||
|
||||
if (!lastActivatedProcessId) {
|
||||
await this.fromCartProcess(processes, route);
|
||||
await this.fromCartProcess(processes);
|
||||
return false;
|
||||
} else {
|
||||
await this._router.navigate(this.getUrlFromSnapshot(route, ['/kunde', String(lastActivatedProcessId)]));
|
||||
@@ -48,7 +50,7 @@ export class CanActivateProductGuard implements CanActivate {
|
||||
}
|
||||
|
||||
// Bei offener Artikelsuche/Kundensuche und Klick auf Footer Artikelsuche
|
||||
async fromCartProcess(processes: ApplicationProcess[], route: ActivatedRouteSnapshot) {
|
||||
async fromCartProcess(processes: ApplicationProcess[]) {
|
||||
const newProcessId = Date.now();
|
||||
await this._applicationService.createProcess({
|
||||
id: newProcessId,
|
||||
@@ -57,7 +59,7 @@ export class CanActivateProductGuard implements CanActivate {
|
||||
name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === 'cart'))}`,
|
||||
});
|
||||
|
||||
await this._router.navigate(this.getUrlFromSnapshot(route, ['/kunde', String(newProcessId)]));
|
||||
await this._navigationService.navigateToProductSearch({ processId: newProcessId });
|
||||
}
|
||||
|
||||
// Bei offener Warenausgabe und Klick auf Footer Artikelsuche
|
||||
|
||||
@@ -263,6 +263,16 @@
|
||||
"name": "event-available",
|
||||
"data": "M438 830 296 688l58-58 84 84 168-168 58 58-226 226ZM200 976q-33 0-56.5-23.5T120 896V336q0-33 23.5-56.5T200 256h40v-80h80v80h320v-80h80v80h40q33 0 56.5 23.5T840 336v560q0 33-23.5 56.5T760 976H200Zm0-80h560V496H200v400Zm0-480h560v-80H200v80Zm0 0v-80 80Z",
|
||||
"viewBox": "0 96 960 960"
|
||||
},
|
||||
{
|
||||
"name": "remove",
|
||||
"data": "M200 606v-60h560v60H200Z",
|
||||
"viewBox": "0 96 960 960"
|
||||
},
|
||||
{
|
||||
"name": "add",
|
||||
"data": "M450 856V606H200v-60h250V296h60v250h250v60H510v250h-60Z",
|
||||
"viewBox": "0 96 960 960"
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
|
||||
@@ -264,7 +264,46 @@
|
||||
"name": "event-available",
|
||||
"data": "M438 830 296 688l58-58 84 84 168-168 58 58-226 226ZM200 976q-33 0-56.5-23.5T120 896V336q0-33 23.5-56.5T200 256h40v-80h80v80h320v-80h80v80h40q33 0 56.5 23.5T840 336v560q0 33-23.5 56.5T760 976H200Zm0-80h560V496H200v400Zm0-480h560v-80H200v80Zm0 0v-80 80Z",
|
||||
"viewBox": "0 96 960 960"
|
||||
},
|
||||
{
|
||||
"name": "remove",
|
||||
"data": "M200 606v-60h560v60H200Z",
|
||||
"viewBox": "0 96 960 960"
|
||||
},
|
||||
{
|
||||
"name": "add",
|
||||
"data": "M450 856V606H200v-60h250V296h60v250h250v60H510v250h-60Z",
|
||||
"viewBox": "0 96 960 960"
|
||||
}, {
|
||||
"name": "isa-abholfach",
|
||||
"data": "M12.25,9.15l4.688,10.054l2.266,-1.057l-5.072,-10.876l-1.882,0.878l-0,-3.149l-2.5,-0l-0,14l2.5,0l-0,-9.85Zm-6.5,-2.15l-0,12l2.5,0l-0,-12l-2.5,0Z"
|
||||
},
|
||||
{
|
||||
"name": "keyboard-arrow-down",
|
||||
"data": "M480-344 240-584l43-43 197 197 197-197 43 43-240 240Z",
|
||||
"viewBox": "0 -960 960 960"
|
||||
},
|
||||
{
|
||||
"name": "assignment-return",
|
||||
"data": "m479-333 43-43-74-74h182v-60H448l74-74-43-43-147 147 147 147ZM180-120q-24.75 0-42.375-17.625T120-180v-600q0-24.75 17.625-42.375T180-840h205q5-35 32-57.5t63-22.5q36 0 63 22.5t32 57.5h205q24.75 0 42.375 17.625T840-780v600q0 24.75-17.625 42.375T780-120H180Zm0-60h600v-600H180v600Zm300-617q14 0 24.5-10.5T515-832q0-14-10.5-24.5T480-867q-14 0-24.5 10.5T445-832q0 14 10.5 24.5T480-797ZM180-180v-600 600Z",
|
||||
"viewBox": "0 -960 960 960"
|
||||
},
|
||||
{
|
||||
"name": "dashboard",
|
||||
"data": "M510-570v-270h330v270H510ZM120-450v-390h330v390H120Zm390 330v-390h330v390H510Zm-390 0v-270h330v270H120Zm60-390h210v-270H180v270Zm390 330h210v-270H570v270Zm0-450h210v-150H570v150ZM180-180h210v-150H180v150Zm210-330Zm180-120Zm0 180ZM390-330Z",
|
||||
"viewBox": "0 -960 960 960"
|
||||
},
|
||||
{
|
||||
"name": "shopping-cart",
|
||||
"data": "M286.788-81Q257-81 236-102.212q-21-21.213-21-51Q215-183 236.212-204q21.213-21 51-21Q317-225 338-203.788q21 21.213 21 51Q359-123 337.788-102q-21.213 21-51 21Zm400 0Q657-81 636-102.212q-21-21.213-21-51Q615-183 636.212-204q21.213-21 51-21Q717-225 738-203.788q21 21.213 21 51Q759-123 737.788-102q-21.213 21-51 21ZM235-741l110 228h288l125-228H235Zm-30-60h589.074q22.964 0 34.945 21Q841-759 829-738L694-495q-11 19-28.559 30.5Q647.881-453 627-453H324l-56 104h491v60H277q-42 0-60.5-28t.5-63l64-118-152-322H51v-60h117l37 79Zm140 288h288-288Z",
|
||||
"viewBox": "0 -960 960 960"
|
||||
},
|
||||
{
|
||||
"name": "shopping-cart-bold",
|
||||
"data": "M286.788-70Q257-70 236-91.212q-21-21.213-21-51Q215-172 236.212-193q21.213-21 51-21Q317-214 338-192.788q21 21.213 21 51Q359-112 337.788-91q-21.213 21-51 21Zm400 0Q657-70 636-91.212q-21-21.213-21-51Q615-172 636.212-193q21.213-21 51-21Q717-214 738-192.788q21 21.213 21 51Q759-112 737.788-91q-21.213 21-51 21ZM254-730l93 194h285l105-194H254Zm-42-82h560.074q36.176 0 55.051 32t.875 65L710-501q-13 21-32.508 34.5-19.509 13.5-44.63 13.5H337l-49 93h482v82H277q-50 0-71.5-34t1.5-74l61-112-146-311H40v-82h135l37 79Zm135 276h285-285Z",
|
||||
"viewBox": "0 -960 960 960"
|
||||
}
|
||||
|
||||
],
|
||||
"aliases": [
|
||||
{
|
||||
|
||||
@@ -264,6 +264,45 @@
|
||||
"name": "event-available",
|
||||
"data": "M438 830 296 688l58-58 84 84 168-168 58 58-226 226ZM200 976q-33 0-56.5-23.5T120 896V336q0-33 23.5-56.5T200 256h40v-80h80v80h320v-80h80v80h40q33 0 56.5 23.5T840 336v560q0 33-23.5 56.5T760 976H200Zm0-80h560V496H200v400Zm0-480h560v-80H200v80Zm0 0v-80 80Z",
|
||||
"viewBox": "0 96 960 960"
|
||||
},
|
||||
{
|
||||
"name": "remove",
|
||||
"data": "M200 606v-60h560v60H200Z",
|
||||
"viewBox": "0 96 960 960"
|
||||
},
|
||||
{
|
||||
"name": "add",
|
||||
"data": "M450 856V606H200v-60h250V296h60v250h250v60H510v250h-60Z",
|
||||
"viewBox": "0 96 960 960"
|
||||
},
|
||||
{
|
||||
"name": "isa-abholfach",
|
||||
"data": "M12.25,9.15l4.688,10.054l2.266,-1.057l-5.072,-10.876l-1.882,0.878l-0,-3.149l-2.5,-0l-0,14l2.5,0l-0,-9.85Zm-6.5,-2.15l-0,12l2.5,0l-0,-12l-2.5,0Z"
|
||||
},
|
||||
{
|
||||
"name": "keyboard-arrow-down",
|
||||
"data": "M480-344 240-584l43-43 197 197 197-197 43 43-240 240Z",
|
||||
"viewBox": "0 -960 960 960"
|
||||
},
|
||||
{
|
||||
"name": "assignment-return",
|
||||
"data": "m479-333 43-43-74-74h182v-60H448l74-74-43-43-147 147 147 147ZM180-120q-24.75 0-42.375-17.625T120-180v-600q0-24.75 17.625-42.375T180-840h205q5-35 32-57.5t63-22.5q36 0 63 22.5t32 57.5h205q24.75 0 42.375 17.625T840-780v600q0 24.75-17.625 42.375T780-120H180Zm0-60h600v-600H180v600Zm300-617q14 0 24.5-10.5T515-832q0-14-10.5-24.5T480-867q-14 0-24.5 10.5T445-832q0 14 10.5 24.5T480-797ZM180-180v-600 600Z",
|
||||
"viewBox": "0 -960 960 960"
|
||||
},
|
||||
{
|
||||
"name": "dashboard",
|
||||
"data": "M510-570v-270h330v270H510ZM120-450v-390h330v390H120Zm390 330v-390h330v390H510Zm-390 0v-270h330v270H120Zm60-390h210v-270H180v270Zm390 330h210v-270H570v270Zm0-450h210v-150H570v150ZM180-180h210v-150H180v150Zm210-330Zm180-120Zm0 180ZM390-330Z",
|
||||
"viewBox": "0 -960 960 960"
|
||||
},
|
||||
{
|
||||
"name": "shopping-cart",
|
||||
"data": "M286.788-81Q257-81 236-102.212q-21-21.213-21-51Q215-183 236.212-204q21.213-21 51-21Q317-225 338-203.788q21 21.213 21 51Q359-123 337.788-102q-21.213 21-51 21Zm400 0Q657-81 636-102.212q-21-21.213-21-51Q615-183 636.212-204q21.213-21 51-21Q717-225 738-203.788q21 21.213 21 51Q759-123 737.788-102q-21.213 21-51 21ZM235-741l110 228h288l125-228H235Zm-30-60h589.074q22.964 0 34.945 21Q841-759 829-738L694-495q-11 19-28.559 30.5Q647.881-453 627-453H324l-56 104h491v60H277q-42 0-60.5-28t.5-63l64-118-152-322H51v-60h117l37 79Zm140 288h288-288Z",
|
||||
"viewBox": "0 -960 960 960"
|
||||
},
|
||||
{
|
||||
"name": "shopping-cart-bold",
|
||||
"data": "M286.788-70Q257-70 236-91.212q-21-21.213-21-51Q215-172 236.212-193q21.213-21 51-21Q317-214 338-192.788q21 21.213 21 51Q359-112 337.788-91q-21.213 21-51 21Zm400 0Q657-70 636-91.212q-21-21.213-21-51Q615-172 636.212-193q21.213-21 51-21Q717-214 738-192.788q21 21.213 21 51Q759-112 737.788-91q-21.213 21-51 21ZM254-730l93 194h285l105-194H254Zm-42-82h560.074q36.176 0 55.051 32t.875 65L710-501q-13 21-32.508 34.5-19.509 13.5-44.63 13.5H337l-49 93h482v82H277q-50 0-71.5-34t1.5-74l61-112-146-311H40v-82h135l37 79Zm135 276h285-285Z",
|
||||
"viewBox": "0 -960 960 960"
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
|
||||
@@ -11,56 +11,21 @@
|
||||
@import './scss/customer';
|
||||
@import './scss/branch';
|
||||
|
||||
.par-select-list {
|
||||
@apply z-dropdown;
|
||||
}
|
||||
|
||||
:root {
|
||||
--par-base: #ffffff;
|
||||
--par-base-content: #000000;
|
||||
--par-primary-300: #324bc9;
|
||||
--par-primary-200: #324bc9;
|
||||
--par-primary-100: #d3d8f4; /*NEU*/
|
||||
--par-subtle-300: #596470;
|
||||
--par-subtle-200: #aeb7c1;
|
||||
--par-subtle-100: #edeff0;
|
||||
--par-subtle-50: #f5f7fa;
|
||||
--par-disabled-content: #aeb7c1;
|
||||
--par-disabled: #ebeaef; /*??*/
|
||||
--par-error-content: #f70400;
|
||||
--par-error: #ffc5c4; /*NEU*/
|
||||
--par-success-content: #26830c;
|
||||
--par-success: #d2fac7; /*NEU*/
|
||||
--par-warning-content: #be8100;
|
||||
--par-warning: #ffcc01; /*heller: #ffeb9a*/
|
||||
--par-secondary-300: #1f466c; /*für tooltips*/
|
||||
--par-secondary-200: #0556b4; /*für links */
|
||||
/* --par-secondary-100: #0556B4; */
|
||||
--par-tertiary-300: #d52a5d;
|
||||
--par-tertiary-200: #f70400;
|
||||
/*--par-tertiary-100: #f7d4df; /*selbst generiert*/
|
||||
--par-random-1: #f66131;
|
||||
--par-random-2: #008079;
|
||||
|
||||
--par-border-radius-input: 0.3125rem; /*5px*/
|
||||
--par-border-radius-button: 0.3125rem; /*5px*/
|
||||
--par-border-radius-checkbox: 0.3125rem; /*5px*/
|
||||
|
||||
--par-shadow-input: 0px 0px 4px 2.5px;
|
||||
--par-shadow-button: 0px 0px 4px 2.5px;
|
||||
|
||||
--par-font-family: 'Open Sans';
|
||||
}
|
||||
|
||||
* {
|
||||
@apply font-sans;
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--bg-color);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1680px) {
|
||||
:root {
|
||||
font-size: 19px;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-background;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0; // remove scrollbar space
|
||||
height: 0;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
@apply text-center text-regular my-6;
|
||||
@apply text-center text-p2 my-6;
|
||||
}
|
||||
|
||||
.bold {
|
||||
@@ -62,7 +62,7 @@ hr {
|
||||
@apply flex flex-row items-center;
|
||||
|
||||
.cta-reserve {
|
||||
@apply absolute bg-transparent text-brand text-base font-bold border-none px-1 -mr-1;
|
||||
@apply absolute bg-transparent text-brand text-p2 font-bold border-none px-1 -mr-1;
|
||||
right: 85px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ modal-notifications {
|
||||
}
|
||||
|
||||
.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;
|
||||
@apply text-center text-xl text-inactive-branch block bg-white rounded-t font-bold no-underline py-4 border-none outline-none shadow-card -ml-4;
|
||||
width: calc(100% + 2rem);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ modal-notifications {
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply font-bold text-2xl ml-4;
|
||||
@apply font-bold text-h3 ml-4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,11 +66,11 @@ modal-notifications {
|
||||
@apply flex flex-row justify-between items-start;
|
||||
|
||||
h1 {
|
||||
@apply text-regular font-bold mb-2;
|
||||
@apply text-p2 font-bold mb-2;
|
||||
}
|
||||
|
||||
.notification-edit-cta {
|
||||
@apply bg-transparent text-brand text-base font-bold border-none px-1 -mr-1;
|
||||
@apply bg-transparent text-brand text-p2 font-bold border-none px-1 -mr-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
}
|
||||
|
||||
.error-message {
|
||||
@apply text-center text-regular font-semibold text-brand;
|
||||
@apply text-center text-p2 font-semibold text-brand;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ ui-select {
|
||||
@apply mt-px-35 text-center;
|
||||
|
||||
.print-btn {
|
||||
@apply border-none outline-none bg-brand text-white font-bold text-cta-l px-px-25 py-px-15 rounded-full my-8;
|
||||
@apply border-none outline-none bg-brand text-white font-bold text-p1 px-px-25 py-px-15 rounded-full my-8;
|
||||
|
||||
&:disabled {
|
||||
@apply bg-inactive-branch;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
}
|
||||
|
||||
h3 {
|
||||
@apply text-regular font-semibold text-center;
|
||||
@apply text-p2 font-semibold text-center;
|
||||
}
|
||||
|
||||
hr {
|
||||
@@ -23,11 +23,11 @@ hr {
|
||||
@apply flex flex-col ml-5;
|
||||
|
||||
.product-name {
|
||||
@apply text-regular font-bold;
|
||||
@apply text-p2 font-bold;
|
||||
}
|
||||
|
||||
.product-format {
|
||||
@apply mt-5 text-regular font-bold flex items-center;
|
||||
@apply mt-5 text-p2 font-bold flex items-center;
|
||||
|
||||
.format-icon {
|
||||
@apply mr-2;
|
||||
@@ -35,11 +35,11 @@ hr {
|
||||
}
|
||||
|
||||
.product-ean {
|
||||
@apply text-regular font-bold;
|
||||
@apply text-p2 font-bold;
|
||||
}
|
||||
|
||||
.quantity {
|
||||
@apply text-regular font-bold;
|
||||
@apply text-p2 font-bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,12 +31,12 @@
|
||||
}
|
||||
|
||||
.title {
|
||||
@apply ml-5 text-regular font-bold;
|
||||
@apply ml-5 text-p2 font-bold;
|
||||
}
|
||||
|
||||
.btn-expand,
|
||||
.btn-collapse {
|
||||
@apply border-none bg-transparent outline-none text-regular text-ucla-blue font-bold -mt-2;
|
||||
@apply border-none bg-transparent outline-none text-p2 text-ucla-blue font-bold -mt-2;
|
||||
|
||||
ui-icon {
|
||||
@apply inline mx-1 align-middle;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
|
||||
import { Config } from '@core/config';
|
||||
|
||||
@@ -14,11 +13,10 @@ export class AssortmentComponent implements OnInit {
|
||||
return this._config.get('process.ids.assortment');
|
||||
}
|
||||
|
||||
constructor(private _config: Config, private _breadcrumb: BreadcrumbService, private _app: ApplicationService) {}
|
||||
constructor(private _config: Config, private _breadcrumb: BreadcrumbService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.createBreadcrumbIfNotExists();
|
||||
this._app.setTitle('Sortiment');
|
||||
}
|
||||
|
||||
async createBreadcrumbIfNotExists(): Promise<void> {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<div
|
||||
class="page-price-update-item__item-header flex flex-row w-full items-center justify-between bg-[rgba(0,128,121,0.15)] mb-px-2 px-5 h-[53px] rounded-t-card"
|
||||
class="page-price-update-item__item-header flex flex-row w-full items-center justify-between bg-[rgba(0,128,121,0.15)] mb-px-2 px-5 h-[53px] rounded-t"
|
||||
>
|
||||
<p class="page-price-update-item__item-instruction font-bold text-lg">{{ item?.task?.instruction }}</p>
|
||||
<p class="page-price-update-item__item-due-date text-base">
|
||||
<p class="page-price-update-item__item-due-date text-p2">
|
||||
gültig ab <span class="font-bold ml-2">{{ item?.task?.dueDate | date }}</span>
|
||||
</p>
|
||||
</div>
|
||||
@@ -20,15 +20,15 @@
|
||||
|
||||
<div class="page-price-update-item__item-details">
|
||||
<div class="page-price-update-item__item-contributors flex flex-row">
|
||||
{{ environment.isTablet() ? (item?.product?.contributors | substr: 42) : item?.product?.contributors }}
|
||||
{{ environment.isTablet() ? (item?.product?.contributors | substr: 38) : item?.product?.contributors }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="page-price-update-item__item-title font-bold text-2xl"
|
||||
class="page-price-update-item__item-title font-bold text-h3"
|
||||
[class.text-xl]="item?.product?.name?.length >= 35"
|
||||
[class.text-lg]="item?.product?.name?.length >= 40"
|
||||
[class.text-md]="item?.product?.name?.length >= 50"
|
||||
[class.text-sm]="item?.product?.name?.length >= 60"
|
||||
[class.text-p3]="item?.product?.name?.length >= 60"
|
||||
[class.text-xs]="item?.product?.name?.length >= 100"
|
||||
>
|
||||
{{ item?.product?.name }}
|
||||
@@ -43,7 +43,7 @@
|
||||
src="assets/images/Icon_{{ item?.product?.format }}.svg"
|
||||
[alt]="item?.product?.formatDetail"
|
||||
/>
|
||||
{{ item?.product?.formatDetail }}
|
||||
{{ environment.isTablet() ? (item?.product?.formatDetail | substr: 25) : item?.product?.formatDetail }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
Drucken
|
||||
</button>
|
||||
<div class="flex flex-row items-center justify-end">
|
||||
<div *ngIf="getSelectableItems().length > 0" class="text-[#0556B4] font-bold text-sm mr-5">
|
||||
<div *ngIf="getSelectableItems().length > 0" class="text-[#0556B4] font-bold text-p3 mr-5">
|
||||
<ng-container *ngIf="selectedItemUids$ | async; let selectedItems">
|
||||
<button class="page-price-update-list__cta-unselect-all" *ngIf="selectedItems?.length > 0" type="button" (click)="unselectAll()">
|
||||
Alle entfernen ({{ selectedItems?.length }})
|
||||
@@ -18,7 +18,7 @@
|
||||
</button>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="page-price-update-list__items-count inline-flex flex-row items-center pr-5 text-sm">
|
||||
<div class="page-price-update-list__items-count inline-flex flex-row items-center pr-5 text-p3">
|
||||
{{ items?.length ??
|
||||
0 }}
|
||||
Titel
|
||||
@@ -26,7 +26,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-price-update-list__order-by h-[53px] flex flex-row items-center justify-center bg-white rounded-t-card mb-px-2">
|
||||
<div class="page-price-update-list__order-by h-[53px] flex flex-row items-center justify-center bg-white rounded-t mb-px-2">
|
||||
<ui-order-by-filter [orderBy]="orderBy$ | async" (selectedOrderByChange)="search()"> </ui-order-by-filter>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="flex flex-row items-center h-14 bg-white relative rounded-t font-bold shadow-lg">
|
||||
<h3 class="text-center grow font-bold text-2xl">Preisänderung</h3>
|
||||
<h3 class="text-center grow font-bold text-h3">Preisänderung</h3>
|
||||
<button
|
||||
(click)="filterOverlay.open()"
|
||||
class="absolute right-0 top-0 h-14 rounded px-5 text-lg bg-cadet-blue flex flex-row flex-nowrap items-center justify-center"
|
||||
@@ -54,5 +54,5 @@
|
||||
</shell-filter-overlay>
|
||||
|
||||
<ng-template #noResults>
|
||||
<div class="bg-white text-2xl text-center pt-10 font-bold rounded-b h-[calc(100vh_-_370px)]">Keine Preisänderungen vorhanden.</div>
|
||||
<div class="bg-white text-h3 text-center pt-10 font-bold rounded-b h-[calc(100vh_-_370px)]">Keine Preisänderungen vorhanden.</div>
|
||||
</ng-template>
|
||||
|
||||
@@ -1,124 +1,240 @@
|
||||
<ng-container *ngIf="!showRecommendations">
|
||||
<div #detailsContainer class="product-card">
|
||||
<div class="page-article-details__container px-5 relative">
|
||||
<ng-container *ngIf="store.item$ | async; let item">
|
||||
<div class="product-details">
|
||||
<div class="product-image">
|
||||
<button class="image-button" (click)="showImages()">
|
||||
<img (load)="loadImage()" [src]="item.imageId | productImage: 195:315:true" alt="product image" />
|
||||
<ui-icon *ngIf="imageLoaded$ | async" icon="search_add" size="22px"></ui-icon>
|
||||
</button>
|
||||
<div class="page-article-details__product-details mb-3">
|
||||
<div class="page-article-details__product-bookmark justify-self-end">
|
||||
<div *ngIf="showArchivBadge$ | async" class="archiv-badge">
|
||||
<button [uiOverlayTrigger]="archivTooltip" class="p-0 m-0 outline-none border-none bg-transparent relative -top-px-5">
|
||||
<img src="/assets/images/bookmark_benachrichtigung_archiv.svg" alt="Archiv Badge" />
|
||||
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #archivTooltip [closeable]="true">
|
||||
<ng-container *ngIf="isAvailable$ | async; else notAvailable">
|
||||
Archivtitel. Wird nicht mehr gedruckt. Artikel ist bestellbar, weil lieferbar.
|
||||
</ng-container>
|
||||
<ng-template #notAvailable>
|
||||
Archivtitel. Wird nicht mehr gedruckt. Nicht bestellbar.
|
||||
</ng-template>
|
||||
</ui-tooltip>
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="showSubscriptionBadge$ | async">
|
||||
<button [uiOverlayTrigger]="subscribtionTooltip" class="p-0 m-0 outline-none border-none bg-transparent relative -top-px-5">
|
||||
<img src="/assets/images/bookmark_subscription.svg" alt="Fortsetzungsartikel Badge" />
|
||||
</button>
|
||||
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #subscribtionTooltip [closeable]="true"
|
||||
>Artikel ist ein Fortsetzungsartikel,<br />
|
||||
Artikel muss über eine Aboabteilung<br />
|
||||
bestellt werden.
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
<div *ngIf="showPromotionBadge$ | async" class="promotion-badge">
|
||||
<button [uiOverlayTrigger]="promotionTooltip" class="p-0 m-0 outline-none border-none bg-transparent relative -top-px-5">
|
||||
<ui-icon-badge icon="gift" alt="Prämienkatalog Badge"></ui-icon-badge>
|
||||
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #promotionTooltip [closeable]="true">
|
||||
Dieser Artikel befindet sich im Prämienkatalog.
|
||||
</ui-tooltip>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button (click)="showReviews()" class="recessions" *ngIf="item.reviews?.length > 0">
|
||||
<div class="page-article-details__product-image-recessions flex flex-col items-center">
|
||||
<div class="page-article-details__product-image">
|
||||
<button class="border-none outline-none bg-transparent relative" (click)="showImages()">
|
||||
<img
|
||||
class="max-h-[19.6875rem] max-w-[12.1875rem] rounded"
|
||||
(load)="loadImage()"
|
||||
[src]="item.imageId | productImage: 195:315:true"
|
||||
alt="product image"
|
||||
/>
|
||||
<ui-icon
|
||||
class="absolute text-[#A7B9CB] inline-block bottom-[14px] right-[18px]"
|
||||
*ngIf="imageLoaded$ | async"
|
||||
icon="search_add"
|
||||
size="25px"
|
||||
></ui-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button
|
||||
(click)="showReviews()"
|
||||
class="page-article-details__product-recessions flex flex-col mt-2 items-center bg-transparent border-none outline-none"
|
||||
*ngIf="item.reviews?.length > 0"
|
||||
>
|
||||
<ui-stars [rating]="store.reviewRating$ | async"></ui-stars>
|
||||
|
||||
<div class="cta-recessions">{{ item.reviews.length }} Rezensionen</div>
|
||||
<div class="text-p2 text-[#0556B4] font-bold">{{ item.reviews.length }} Rezensionen</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="product-info">
|
||||
<div class="row" [class.bookmark-badge-gap]="isBadgeVisible$ | async">
|
||||
<div>
|
||||
<a
|
||||
*ngFor="let contributor of contributors$ | async; let last = last"
|
||||
class="autor"
|
||||
[routerLink]="['/kunde', applicationService.activatedProcessId, 'product', 'search', 'results']"
|
||||
[queryParams]="{ main_qs: contributor, main_author: 'author' }"
|
||||
>
|
||||
{{ contributor }}{{ last ? '' : ';' }}
|
||||
</a>
|
||||
<div class="page-article-details__product-contributors">
|
||||
<a
|
||||
*ngFor="let contributor of contributors$ | async; let last = last"
|
||||
class="text-[#0556B4] font-semibold no-underline text-p2"
|
||||
[routerLink]="resultsPath"
|
||||
[queryParams]="{ main_qs: contributor, main_author: 'author' }"
|
||||
>
|
||||
{{ contributor }}{{ last ? '' : ';' }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-print justify-self-end" [class.mt-4]="isBadgeVisible$ | async">
|
||||
<button class="bg-transparent text-brand font-bold text-lg outline-none border-none p-0" (click)="print()">Drucken</button>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-title text-h3 font-bold mb-6">
|
||||
{{ item.product?.name }}
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-misc flex flex-col mb-4">
|
||||
<div
|
||||
class="page-article-details__product-format flex items-center font-bold text-p3"
|
||||
*ngIf="item?.product?.format && item?.product?.formatDetail"
|
||||
>
|
||||
<img
|
||||
*ngIf="item?.product?.format !== '--'"
|
||||
class="flex mr-2 h-[1.125rem]"
|
||||
[src]="'/assets/images/Icon_' + item.product?.format + '.svg'"
|
||||
[alt]="item.product?.formatDetail"
|
||||
/>
|
||||
{{ item.product?.formatDetail }}
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-volume" *ngIf="item?.product?.volume">Band/Reihe {{ item?.product?.volume }}</div>
|
||||
|
||||
<div class="page-article-details__product-publication">{{ publicationDate$ | async }}</div>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-price-info flex flex-col mb-4">
|
||||
<div
|
||||
class="page-article-details__product-price font-bold text-xl self-end"
|
||||
*ngIf="item.catalogAvailability?.price?.value?.value; else retailPrice"
|
||||
>
|
||||
{{ item.catalogAvailability?.price?.value?.value | currency: item.catalogAvailability?.price?.value?.currency:'code' }}
|
||||
</div>
|
||||
<ng-template #retailPrice>
|
||||
<div
|
||||
class="page-article-details__product-price font-bold text-xl self-end"
|
||||
*ngIf="store.takeAwayAvailability$ | async; let takeAwayAvailability"
|
||||
>
|
||||
{{ takeAwayAvailability?.retailPrice?.value?.value | currency: takeAwayAvailability?.retailPrice?.value?.currency:'code' }}
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<button class="cta-print right" (click)="print()">Drucken</button>
|
||||
</div>
|
||||
<div class="title">
|
||||
{{ item.product?.name }}
|
||||
<div class="page-article-details__product-points self-end" *ngIf="store.promotionPoints$ | async; let promotionPoints">
|
||||
{{ promotionPoints }} Lesepunkte
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div>
|
||||
<div class="format" *ngIf="item?.product?.format && item?.product?.formatDetail">
|
||||
<img
|
||||
*ngIf="item?.product?.format !== '--'"
|
||||
class="format-icon"
|
||||
[src]="'/assets/images/Icon_' + item.product?.format + '.svg'"
|
||||
[alt]="item.product?.formatDetail"
|
||||
/>
|
||||
{{ item.product?.formatDetail }}
|
||||
<!-- TODO: Ticket PREISGEBUNDEN -->
|
||||
<div class="page-article-details__product-price-bound self-end"></div>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-origin-infos flex flex-col mb-4">
|
||||
<div class="page-article-details__product-manufacturer" data-name="product-manufacturer">{{ item.product?.manufacturer }}</div>
|
||||
|
||||
<div class="page-article-details__product-language" *ngIf="item?.product?.locale" data-name="product-language">
|
||||
{{ item?.product?.locale }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-stock flex justify-end items-center">
|
||||
<div class="h-5 w-16 bg-[#e6eff9] animate-[load_0.75s_linear_infinite]" *ngIf="store.fetchingTakeAwayAvailability$ | async"></div>
|
||||
<div
|
||||
class="flex flex-row py-4 pl-4"
|
||||
[uiOverlayTrigger]="tooltip"
|
||||
[overlayTriggerDisabled]="!(stockTooltipText$ | async)"
|
||||
*ngIf="!(store.fetchingTakeAwayAvailability$ | async)"
|
||||
>
|
||||
<ng-container *ngIf="store.takeAwayAvailability$ | async; let takeAwayAvailability">
|
||||
<ui-icon class="mr-2 mb-1" icon="home" size="15px"></ui-icon>
|
||||
<span class="font-bold text-p3">{{ takeAwayAvailability.inStock || 0 }}x</span>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
<ui-tooltip #tooltip yPosition="above" xPosition="after" [yOffset]="-8" [closeable]="true">
|
||||
{{ stockTooltipText$ | async }}
|
||||
</ui-tooltip>
|
||||
|
||||
<div class="page-article-details__product-ean-specs flex flex-col">
|
||||
<div class="page-article-details__product-ean" data-name="product-ean">{{ item.product?.ean }}</div>
|
||||
|
||||
<div class="page-article-details__product-specs">
|
||||
<ng-container *ngIf="item?.specs?.length > 0">
|
||||
{{ (item?.specs)[0]?.value }}
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-availabilities flex flex-row items-center justify-end mt-4">
|
||||
<div
|
||||
class="h-5 w-6 bg-[#e6eff9] animate-[load_0.75s_linear_infinite]"
|
||||
*ngIf="store.fetchingTakeAwayAvailability$ | async; else showAvailabilityTakeAwayIcon"
|
||||
></div>
|
||||
<ng-template #showAvailabilityTakeAwayIcon>
|
||||
<div
|
||||
*ngIf="store.isTakeAwayAvailabilityAvailable$ | async"
|
||||
class="w-[2.25rem] h-[2.25rem] bg-[#D8DFE5] rounded-[5px_5px_0px_5px] flex items-center justify-center"
|
||||
>
|
||||
<ui-icon class="mx-1" icon="shopping_bag" size="18px"> </ui-icon>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<div
|
||||
class="h-5 w-6 bg-[#e6eff9] animate-[load_0.75s_linear_infinite]"
|
||||
*ngIf="store.fetchingPickUpAvailability$ | async; else showAvailabilityPickUpIcon"
|
||||
></div>
|
||||
<ng-template #showAvailabilityPickUpIcon>
|
||||
<div
|
||||
*ngIf="store.isPickUpAvailabilityAvailable$ | async"
|
||||
class="w-[2.25rem] h-[2.25rem] bg-[#D8DFE5] rounded-[5px_5px_0px_5px] flex items-center justify-center ml-3"
|
||||
>
|
||||
<ui-icon class="mx-1" icon="box_out" size="18px"></ui-icon>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<div
|
||||
class="h-5 w-6 bg-[#e6eff9] animate-[load_0.75s_linear_infinite]"
|
||||
*ngIf="store.fetchingDeliveryAvailability$ | async; else showAvailabilityDeliveryIcon"
|
||||
></div>
|
||||
<ng-template #showAvailabilityDeliveryIcon>
|
||||
<div
|
||||
*ngIf="showDeliveryTruck$ | async"
|
||||
class="w-[2.25rem] h-[2.25rem] bg-[#D8DFE5] rounded-[5px_5px_0px_5px] flex items-center justify-center ml-3"
|
||||
>
|
||||
<ui-icon class="-mb-px-5 -mt-px-5 mx-1" icon="truck" size="30px"></ui-icon>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<div
|
||||
class="h-5 w-6 bg-[#e6eff9] animate-[load_0.75s_linear_infinite]"
|
||||
*ngIf="store.fetchingDeliveryB2BAvailability$ | async; else showAvailabilityDeliveryB2BIcon"
|
||||
></div>
|
||||
<ng-template #showAvailabilityDeliveryB2BIcon>
|
||||
<div
|
||||
*ngIf="showDeliveryB2BTruck$ | async"
|
||||
class="w-[2.25rem] h-[2.25rem] bg-[#D8DFE5] rounded-[5px_5px_0px_5px] flex items-center justify-center ml-3"
|
||||
>
|
||||
<ui-icon class="-mb-px-10 -mt-px-10 mx-1" icon="truck_b2b" size="30px"> </ui-icon>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<span *ngIf="store.isDownload$ | async" class="flex flex-row items-center">
|
||||
<div class="w-[2.25rem] h-[2.25rem] bg-[#D8DFE5] rounded-[5px_5px_0px_5px] flex items-center justify-center ml-3">
|
||||
<ui-icon class="mx-1" icon="download" size="18px"></ui-icon>
|
||||
<span class="font-bold">Download</span>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__shelf-ssc">
|
||||
<div class="page-article-details__ssc flex justify-end my-2 font-bold text-lg">
|
||||
<div class="w-52 h-px-20 bg-[#e6eff9] animate-[load_0.75s_linear_infinite]" *ngIf="fetchingAvailabilities$ | async"></div>
|
||||
<ng-container *ngIf="!(fetchingAvailabilities$ | async)">
|
||||
<div *ngIf="store.sscText$ | async; let sscText">
|
||||
{{ sscText }}
|
||||
</div>
|
||||
<div *ngIf="item?.product?.volume">Band/Reihe {{ item?.product?.volume }}</div>
|
||||
|
||||
<div>{{ publicationDate$ | async }}</div>
|
||||
</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>
|
||||
<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>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<div class="row stock">
|
||||
<div data-name="product-manufacturer">{{ item.product?.manufacturer }}</div>
|
||||
|
||||
<div class="right quantity" [uiOverlayTrigger]="tooltip" [overlayTriggerDisabled]="!(stockTooltipText$ | async)">
|
||||
<div class="fetching small" *ngIf="store.fetchingTakeAwayAvailability$ | async"></div>
|
||||
<ng-container *ngIf="!(store.fetchingTakeAwayAvailability$ | async)">
|
||||
<ng-container *ngIf="store.takeAwayAvailability$ | async; let takeAwayAvailability">
|
||||
<ui-icon icon="home" size="22px"></ui-icon>
|
||||
{{ takeAwayAvailability.inStock || 0 }}x
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
<ui-tooltip #tooltip yPosition="above" xPosition="after" [yOffset]="-8" [closeable]="true">
|
||||
{{ stockTooltipText$ | async }}
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
<div *ngIf="item?.product?.locale" data-name="product-language">{{ item?.product?.locale }}</div>
|
||||
|
||||
<div class="row">
|
||||
<div data-name="product-ean">{{ item.product?.ean }}</div>
|
||||
<div class="right">
|
||||
<div class="availability-icons">
|
||||
<div class="fetching xsmall" *ngIf="store.fetchingTakeAwayAvailability$ | async; else showAvailabilityTakeAwayIcon"></div>
|
||||
<ng-template #showAvailabilityTakeAwayIcon>
|
||||
<ui-icon *ngIf="store.isTakeAwayAvailabilityAvailable$ | async" icon="shopping_bag" size="18px"> </ui-icon>
|
||||
</ng-template>
|
||||
|
||||
<div class="fetching xsmall" *ngIf="store.fetchingPickUpAvailability$ | async; else showAvailabilityPickUpIcon"></div>
|
||||
<ng-template #showAvailabilityPickUpIcon>
|
||||
<ui-icon *ngIf="store.isPickUpAvailabilityAvailable$ | async" icon="box_out" size="18px"></ui-icon>
|
||||
</ng-template>
|
||||
|
||||
<div class="fetching xsmall" *ngIf="store.fetchingDeliveryAvailability$ | async; else showAvailabilityDeliveryIcon"></div>
|
||||
<ng-template #showAvailabilityDeliveryIcon>
|
||||
<ui-icon *ngIf="showDeliveryTruck$ | async" class="truck" icon="truck" size="30px"></ui-icon>
|
||||
</ng-template>
|
||||
|
||||
<div
|
||||
class="fetching xsmall"
|
||||
*ngIf="store.fetchingDeliveryB2BAvailability$ | async; else showAvailabilityDeliveryB2BIcon"
|
||||
></div>
|
||||
<ng-template #showAvailabilityDeliveryB2BIcon>
|
||||
<ui-icon *ngIf="showDeliveryB2BTruck$ | async" class="truck_b2b" icon="truck_b2b" size="40px"> </ui-icon>
|
||||
</ng-template>
|
||||
|
||||
<span *ngIf="store.isDownload$ | async" class="download-icon">
|
||||
<ui-icon icon="download" size="18px"></ui-icon>
|
||||
<span class="label">Download</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="shelfinfo right" *ngIf="store.isDownload$ | async">
|
||||
<div class="page-article-details__shelfinfo" *ngIf="store.isDownload$ | async">
|
||||
<ng-container
|
||||
*ngIf="
|
||||
item?.stockInfos && item?.shelfInfos && (item?.stockInfos)[0]?.compartment && (item?.shelfInfos)[0]?.label;
|
||||
@@ -145,24 +261,7 @@
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="specs">
|
||||
<ng-container *ngIf="item?.specs?.length > 0">
|
||||
{{ (item?.specs)[0]?.value }}
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="right ssc">
|
||||
<div class="fetching" *ngIf="fetchingAvailabilities$ | async"></div>
|
||||
<ng-container *ngIf="!(fetchingAvailabilities$ | async)">
|
||||
<div *ngIf="store.sscText$ | async; let sscText">
|
||||
{{ sscText }}
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="shelfinfo right" *ngIf="!(store.isDownload$ | async)">
|
||||
<div class="page-article-details__shelfinfo text-right" *ngIf="!(store.isDownload$ | async)">
|
||||
<ng-container
|
||||
*ngIf="
|
||||
item?.stockInfos && item?.shelfInfos && (item?.stockInfos)[0]?.compartment && (item?.shelfInfos)[0]?.label;
|
||||
@@ -186,109 +285,118 @@
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bookmark">
|
||||
<div *ngIf="showArchivBadge$ | async" class="archiv-badge">
|
||||
<button [uiOverlayTrigger]="archivTooltip" class="bookmark-badge">
|
||||
<img src="/assets/images/bookmark_benachrichtigung_archiv.svg" alt="Archiv Badge" />
|
||||
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #archivTooltip [closeable]="true">
|
||||
<ng-container *ngIf="isAvailable$ | async; else notAvailable">
|
||||
Archivtitel. Wird nicht mehr gedruckt. Artikel ist bestellbar, weil lieferbar.
|
||||
</ng-container>
|
||||
<ng-template #notAvailable>
|
||||
Archivtitel. Wird nicht mehr gedruckt. Nicht bestellbar.
|
||||
</ng-template>
|
||||
</ui-tooltip>
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="showSubscriptionBadge$ | async">
|
||||
<button [uiOverlayTrigger]="subscribtionTooltip" class="bookmark-badge">
|
||||
<img src="/assets/images/bookmark_subscription.svg" alt="Fortsetzungsartikel Badge" />
|
||||
</button>
|
||||
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #subscribtionTooltip [closeable]="true"
|
||||
>Artikel ist ein Fortsetzungsartikel,<br />
|
||||
Artikel muss über eine Aboabteilung<br />
|
||||
bestellt werden.
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
<div *ngIf="showPromotionBadge$ | async" class="promotion-badge">
|
||||
<button [uiOverlayTrigger]="promotionTooltip" class="bookmark-badge">
|
||||
<ui-icon-badge icon="gift" alt="Prämienkatalog Badge"></ui-icon-badge>
|
||||
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #promotionTooltip [closeable]="true">
|
||||
Dieser Artikel befindet sich im Prämienkatalog.
|
||||
</ui-tooltip>
|
||||
</button>
|
||||
<div class="page-article-details__product-formats-container mt-3" *ngIf="item.family?.length > 0">
|
||||
<hr class="bg-[#E6EFF9] border-t-2" />
|
||||
<div class="pt-3">
|
||||
<div class="page-article-details__product-formats">
|
||||
<span class="mr-2">Auch verfügbar als</span>
|
||||
|
||||
<ui-slider [scrollDistance]="250">
|
||||
<a
|
||||
class="mr-4 text-[#0556B4] font-bold no-underline px-2"
|
||||
*ngFor="let format of item.family"
|
||||
[routerLink]="getDetailsPath(format.product.ean)"
|
||||
[queryParamsHandling]="!(isTablet$ | async) ? 'preserve' : ''"
|
||||
>
|
||||
<span class="flex items-center">
|
||||
<img
|
||||
class="mr-2"
|
||||
*ngIf="!!format.product?.format"
|
||||
[src]="'/assets/images/OF_Icon_' + format.product?.format + '.svg'"
|
||||
alt="format icon"
|
||||
/>
|
||||
{{ format.product?.formatDetail }}
|
||||
<span class="ml-1">{{ format.catalogAvailability?.price?.value?.value | currency: '€' }}</span>
|
||||
</span>
|
||||
</a>
|
||||
</ui-slider>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="product-actions">
|
||||
<button *ngIf="!(store.isDownload$ | async)" class="cta-availabilities" (click)="showAvailabilities()">
|
||||
Vorrätig in anderer Filiale?
|
||||
</button>
|
||||
<button
|
||||
class="cta-continue"
|
||||
(click)="showPurchasingModal()"
|
||||
[disabled]="
|
||||
!(isAvailable$ | async) || (fetchingAvailabilities$ | async) || (item?.features && (item?.features)[0]?.key === 'PFO')
|
||||
"
|
||||
>
|
||||
In den Warenkorb
|
||||
</button>
|
||||
</div>
|
||||
<hr class="bg-[#E6EFF9] border-t-2 my-3" />
|
||||
|
||||
<hr />
|
||||
<ng-container *ngIf="item.family?.length > 0">
|
||||
<div class="product-formats">
|
||||
<span class="label">Auch verfügbar als</span>
|
||||
|
||||
<ui-slider [scrollDistance]="250">
|
||||
<a
|
||||
class="product-family"
|
||||
*ngFor="let format of item.family"
|
||||
[routerLink]="['/kunde', applicationService.activatedProcessId, 'product', 'details', 'ean', format.product.ean]"
|
||||
>
|
||||
<span class="format-detail">
|
||||
<img
|
||||
*ngIf="!!format.product?.format"
|
||||
[src]="'/assets/images/OF_Icon_' + format.product?.format + '.svg'"
|
||||
alt="format icon"
|
||||
/>
|
||||
{{ format.product?.formatDetail }}
|
||||
<span class="price">{{ format.catalogAvailability?.price?.value?.value | currency: '€' }}</span>
|
||||
</span>
|
||||
</a>
|
||||
</ui-slider>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
</ng-container>
|
||||
|
||||
<div class="product-description" *ngIf="item.texts?.length > 0">
|
||||
<div class="info">
|
||||
<div
|
||||
#description
|
||||
class="page-article-details__product-description flex flex-col flex-grow overflow-hidden overflow-y-scroll"
|
||||
*ngIf="item.texts?.length > 0"
|
||||
>
|
||||
<div class="whitespace-pre-line">
|
||||
{{ item.texts[0].value }}
|
||||
</div>
|
||||
|
||||
<div class="product-text">
|
||||
<button
|
||||
class="font-bold flex flex-row text-[#0556B4] items-center mt-2"
|
||||
*ngIf="!showMore && item?.texts?.length > 1"
|
||||
(click)="showMore = !showMore"
|
||||
>
|
||||
Mehr <ui-icon class="ml-2" size="15px" icon="arrow"></ui-icon>
|
||||
</button>
|
||||
|
||||
<div *ngIf="showMore" class="page-article-details__product-description-text flex flex-col whitespace-pre-line break-words">
|
||||
<span *ngFor="let text of item.texts | slice: 1">
|
||||
<h3 class="header">{{ text.label }}</h3>
|
||||
<h3 class="my-4 text-p2 font-bold">{{ text.label }}</h3>
|
||||
{{ text.value }}
|
||||
</span>
|
||||
<button class="scroll-top-cta" (click)="scrollTop()">
|
||||
<ui-icon class="arrow" icon="arrow" size="20px"></ui-icon>
|
||||
|
||||
<button class="font-bold flex flex-row text-[#0556B4] items-center mt-2" (click)="showMore = !showMore">
|
||||
<ui-icon class="transform ml-0 mr-2 rotate-180" size="15px" icon="arrow"></ui-icon> Weniger
|
||||
</button>
|
||||
|
||||
<button class="page-article-details__scroll-top-cta" (click)="scrollTop(description)">
|
||||
<ui-icon class="text-[#0556B4]" icon="arrow" size="20px"></ui-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="min-h-[6.25rem]"></div>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="!showRecommendations">
|
||||
<div
|
||||
*ngIf="store.item$ | async; let item"
|
||||
class="page-article-details__actions w-full absolute text-center left-0 bottom-10 z-fixed"
|
||||
>
|
||||
<button
|
||||
*ngIf="!(store.isDownload$ | async)"
|
||||
class="text-brand border-2 border-brand bg-white font-bold text-lg px-[1.375rem] py-4 rounded-full mr-px-30"
|
||||
(click)="showAvailabilities()"
|
||||
>
|
||||
Bestände in anderen Filialen
|
||||
</button>
|
||||
<button
|
||||
class="text-white bg-brand border-brand font-bold text-lg px-[1.375rem] py-4 rounded-full border-none no-underline"
|
||||
(click)="showPurchasingModal()"
|
||||
[disabled]="
|
||||
!(isAvailable$ | async) || (fetchingAvailabilities$ | async) || (item?.features && (item?.features)[0]?.key === 'PFO')
|
||||
"
|
||||
>
|
||||
In den Warenkorb
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div class="page-article-details__product-recommendations -mx-5">
|
||||
<button
|
||||
*ngIf="store.item$ | async; let item"
|
||||
class="shadow-[#dce2e9_0px_-2px_18px_0px] sticky bottom-4 border-none outline-none left-0 right-0 flex items-center px-5 h-14 min-h-[3.5rem] bg-white w-full"
|
||||
(click)="showRecommendations = true"
|
||||
>
|
||||
<span class="uppercase text-[#0556B4] font-bold text-p3">Empfehlungen</span>
|
||||
<img class="absolute right-5 bottom-3 h-12" src="assets/images/recommendation_tag.png" alt="recommendation icon" />
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<button *ngIf="store.item$ | async; let item" class="product-recommendations" (click)="showRecommendations = true">
|
||||
<span class="label">Empfehlungen</span>
|
||||
<img src="assets/images/recommendation_tag.png" alt="recommendation icon" />
|
||||
</button>
|
||||
</ng-container>
|
||||
|
||||
<div class="recommendations-overlay" @slideYAnimation *ngIf="showRecommendations">
|
||||
<button class="product-button" (click)="showRecommendations = false">{{ (store.item$ | async)?.product?.name }}</button>
|
||||
<div class="page-article-details__recommendations-overlay absolute top-16 rounded-t" @slideYAnimation *ngIf="showRecommendations">
|
||||
<button
|
||||
class="h-[3.75rem] shadow-[0_-2px_24px_0_#dce2e9] flex flex-row justify-center items-center w-full text-xl bg-white text-ucla-blue font-bold border-none outline-none rounded-t"
|
||||
(click)="showRecommendations = false"
|
||||
>
|
||||
{{ (store.item$ | async)?.product?.name }}
|
||||
</button>
|
||||
<page-article-recommendations (close)="showRecommendations = false"></page-article-recommendations>
|
||||
</div>
|
||||
|
||||
@@ -1,269 +1,99 @@
|
||||
:host {
|
||||
@apply flex flex-col;
|
||||
@apply box-border block h-[calc(100vh-16.5rem)] desktop-small:h-[calc(100vh-15.1rem)];
|
||||
}
|
||||
|
||||
.product-card {
|
||||
@apply flex flex-col bg-white w-full rounded-card shadow-card;
|
||||
|
||||
.product-details {
|
||||
@apply flex flex-row p-5;
|
||||
|
||||
.bookmark {
|
||||
@apply absolute flex;
|
||||
top: 52px;
|
||||
right: 25px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.bookmark-badge {
|
||||
@apply p-0 m-0 outline-none border-none bg-transparent relative;
|
||||
}
|
||||
|
||||
.promotion-badge {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.bookmark-badge-gap {
|
||||
@apply mt-px-35;
|
||||
}
|
||||
|
||||
.product-image {
|
||||
@apply flex flex-col items-center justify-start mr-5;
|
||||
|
||||
.recessions {
|
||||
@apply flex flex-col items-center mt-4 bg-transparent border-none outline-none;
|
||||
|
||||
.cta-recessions {
|
||||
@apply text-regular text-dark-cerulean font-bold mt-2;
|
||||
}
|
||||
}
|
||||
|
||||
.image-button {
|
||||
@apply border-none outline-none bg-transparent relative;
|
||||
|
||||
ui-icon {
|
||||
@apply absolute text-dark-cerulean inline-block;
|
||||
bottom: 1rem;
|
||||
right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
@apply rounded-xl shadow-card;
|
||||
box-shadow: 0 0 18px 0 #b8b3b7;
|
||||
max-height: 315px;
|
||||
max-width: 195px;
|
||||
}
|
||||
}
|
||||
|
||||
.product-info {
|
||||
@apply w-full;
|
||||
|
||||
.title {
|
||||
@apply text-3xl font-bold mb-6;
|
||||
}
|
||||
|
||||
.format,
|
||||
.ssc,
|
||||
.quantity {
|
||||
@apply font-bold text-lg;
|
||||
}
|
||||
|
||||
.stock {
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
.quantity {
|
||||
@apply flex justify-end mt-4;
|
||||
|
||||
ui-icon {
|
||||
@apply mr-1 text-ucla-blue;
|
||||
}
|
||||
}
|
||||
|
||||
.format {
|
||||
@apply flex items-center;
|
||||
|
||||
.format-icon {
|
||||
@apply flex mr-2;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.ssc {
|
||||
@apply flex justify-end my-2;
|
||||
}
|
||||
|
||||
.price {
|
||||
@apply font-bold text-xl;
|
||||
}
|
||||
|
||||
.shelfinfo {
|
||||
@apply text-ucla-blue;
|
||||
}
|
||||
|
||||
.fetching {
|
||||
@apply w-52 h-px-20;
|
||||
background-color: #e6eff9;
|
||||
animation: load 0.75s linear infinite;
|
||||
}
|
||||
|
||||
.xsmall {
|
||||
@apply w-6;
|
||||
}
|
||||
|
||||
.small {
|
||||
@apply w-16;
|
||||
}
|
||||
|
||||
.medium {
|
||||
@apply w-40;
|
||||
}
|
||||
|
||||
.availability-icons {
|
||||
@apply flex flex-row items-center justify-end text-dark-cerulean mt-4;
|
||||
|
||||
ui-icon {
|
||||
@apply mx-1;
|
||||
}
|
||||
|
||||
.truck {
|
||||
@apply -mb-px-5 -mt-px-5;
|
||||
}
|
||||
|
||||
.truck_b2b {
|
||||
@apply -mb-px-10 -mt-px-10;
|
||||
}
|
||||
|
||||
.label {
|
||||
@apply font-bold;
|
||||
}
|
||||
|
||||
.download-icon {
|
||||
@apply flex flex-row items-center;
|
||||
}
|
||||
}
|
||||
|
||||
.cta-print {
|
||||
@apply bg-transparent text-brand font-bold text-xl outline-none border-none p-0;
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
@apply grid items-end;
|
||||
grid-template-columns: auto auto;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
@apply text-right self-start;
|
||||
}
|
||||
|
||||
hr {
|
||||
@apply bg-glitter h-1;
|
||||
}
|
||||
|
||||
.product-description {
|
||||
@apply flex flex-col flex-grow px-5 py-5;
|
||||
min-height: calc(100vh - 769px);
|
||||
|
||||
.info {
|
||||
@apply whitespace-pre-line;
|
||||
}
|
||||
|
||||
.product-text {
|
||||
@apply flex flex-col whitespace-pre-line mb-px-100 break-words;
|
||||
|
||||
h3 {
|
||||
@apply my-4;
|
||||
}
|
||||
|
||||
.header {
|
||||
@apply text-regular font-bold;
|
||||
}
|
||||
|
||||
.scroll-top-cta {
|
||||
@apply flex items-center justify-center self-end border-none outline-none bg-white relative rounded p-0 mt-8 mr-4;
|
||||
box-shadow: 0px 0px 20px 0px rgba(89, 100, 112, 0.5);
|
||||
transform: rotate(-90deg);
|
||||
border-radius: 100%;
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
|
||||
.arrow {
|
||||
color: #1f466c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.product-actions {
|
||||
@apply text-right px-5 py-4;
|
||||
|
||||
.cta-availabilities {
|
||||
@apply text-brand border-none border-brand bg-white font-bold text-lg px-4 py-2 rounded-full;
|
||||
}
|
||||
.cta-continue {
|
||||
@apply text-white bg-brand font-bold text-lg px-4 py-2 rounded-full border-none ml-4 no-underline;
|
||||
|
||||
&:disabled {
|
||||
@apply bg-inactive-branch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.product-formats {
|
||||
@apply grid whitespace-nowrap items-center px-5 py-4;
|
||||
grid-template-rows: auto;
|
||||
grid-template-columns: auto 1fr;
|
||||
max-width: 100%;
|
||||
|
||||
.label {
|
||||
@apply mr-2;
|
||||
}
|
||||
|
||||
.product-family {
|
||||
@apply mr-4 text-active-customer font-bold no-underline px-2;
|
||||
|
||||
.format-detail {
|
||||
@apply flex items-center;
|
||||
|
||||
img {
|
||||
@apply mr-2;
|
||||
}
|
||||
}
|
||||
|
||||
.price {
|
||||
@apply ml-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.page-article-details__container {
|
||||
@apply h-full w-full bg-white rounded shadow-card flex flex-col;
|
||||
}
|
||||
|
||||
.product-recommendations {
|
||||
@apply sticky bottom-0 border-none outline-none left-0 right-0 flex items-center px-5 h-16 bg-white w-full;
|
||||
box-shadow: #dce2e9 0px -2px 18px 0px;
|
||||
|
||||
.label {
|
||||
@apply uppercase text-active-customer font-bold text-small;
|
||||
}
|
||||
|
||||
img {
|
||||
@apply absolute right-5 bottom-5 h-12;
|
||||
}
|
||||
.page-article-details__product-details {
|
||||
@apply grid gap-x-5;
|
||||
grid-template-columns: max-content auto;
|
||||
grid-template-rows: 2.1875rem repeat(11, minmax(auto, max-content));
|
||||
grid-template-areas:
|
||||
'. . . bookmark'
|
||||
'image contributors contributors contributors'
|
||||
'image title title print'
|
||||
'image title title .'
|
||||
'image misc misc price'
|
||||
'image misc misc price'
|
||||
'image origin origin stock'
|
||||
'image origin origin stock'
|
||||
'image specs availabilities availabilities'
|
||||
'image specs ssc ssc'
|
||||
'image . ssc ssc'
|
||||
'image . ssc ssc';
|
||||
}
|
||||
|
||||
.recommendations-overlay {
|
||||
@apply absolute w-full top-0 rounded-t-card;
|
||||
top: 56px;
|
||||
.page-article-details__product-bookmark {
|
||||
grid-area: bookmark;
|
||||
}
|
||||
|
||||
.product-button {
|
||||
@apply flex flex-row justify-center items-center w-full text-xl bg-white text-ucla-blue font-bold border-none outline-none rounded-t-card;
|
||||
box-shadow: 0 -2px 24px 0 #dce2e9;
|
||||
height: 60px;
|
||||
.page-article-details__product-image-recessions {
|
||||
grid-area: image;
|
||||
}
|
||||
|
||||
.page-article-details__product-contributors {
|
||||
grid-area: contributors;
|
||||
}
|
||||
|
||||
.page-article-details__product-print {
|
||||
grid-area: print;
|
||||
}
|
||||
|
||||
.page-article-details__product-title {
|
||||
grid-area: title;
|
||||
}
|
||||
|
||||
.page-article-details__product-misc {
|
||||
grid-area: misc;
|
||||
}
|
||||
|
||||
.page-article-details__product-price-info {
|
||||
grid-area: price;
|
||||
}
|
||||
|
||||
.page-article-details__product-origin-infos {
|
||||
grid-area: origin;
|
||||
}
|
||||
|
||||
.page-article-details__product-stock {
|
||||
grid-area: stock;
|
||||
}
|
||||
|
||||
.page-article-details__product-ean-specs {
|
||||
grid-area: specs;
|
||||
}
|
||||
|
||||
.page-article-details__product-availabilities {
|
||||
grid-area: availabilities;
|
||||
}
|
||||
|
||||
.page-article-details__shelf-ssc {
|
||||
grid-area: ssc;
|
||||
}
|
||||
|
||||
.page-article-details__product-description-text {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.page-article-details__product-formats {
|
||||
@apply grid whitespace-nowrap items-center max-w-full;
|
||||
grid-template-rows: auto;
|
||||
grid-template-columns: auto 1fr;
|
||||
}
|
||||
|
||||
.page-article-details__scroll-top-cta {
|
||||
@apply flex items-center justify-center self-end border-none outline-none bg-white relative rounded p-0 mt-8 mr-4;
|
||||
box-shadow: 0px 0px 20px 0px rgba(89, 100, 112, 0.5);
|
||||
transform: rotate(-90deg);
|
||||
border-radius: 100%;
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
}
|
||||
|
||||
.page-article-details__actions {
|
||||
&:disabled {
|
||||
@apply bg-inactive-branch;
|
||||
}
|
||||
}
|
||||
|
||||
.autor {
|
||||
@apply text-active-customer font-bold no-underline;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { BranchDTO } from '@swagger/checkout';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { ModalReviewsComponent } from '@modal/reviews';
|
||||
import { BehaviorSubject, combineLatest, Subscription } from 'rxjs';
|
||||
import { debounceTime, filter, first, map, shareReplay, switchMap } from 'rxjs/operators';
|
||||
import { debounceTime, filter, first, map, shareReplay, switchMap, takeUntil, withLatestFrom } from 'rxjs/operators';
|
||||
import { ArticleDetailsStore } from './article-details.store';
|
||||
import { ModalImagesComponent } from 'apps/modal/images/src/public-api';
|
||||
import { ProductImageService } from 'apps/cdn/product-image/src/public-api';
|
||||
@@ -20,6 +20,9 @@ import { DateAdapter } from '@ui/common';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { PurchaseOptionsModalService } from '@shared/modals/purchase-options-modal';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { ProductCatalogNavigationService } from '@shared/services';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
|
||||
@Component({
|
||||
selector: 'page-article-details',
|
||||
@@ -65,6 +68,10 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
|
||||
this.store.isDeliveryB2BAvailabilityAvailable$,
|
||||
]).pipe(map(([digDelivery, b2bDelivery]) => b2bDelivery && !digDelivery));
|
||||
|
||||
customerFeatures$ = this.applicationService.activatedProcessId$.pipe(
|
||||
switchMap((processId) => this._domainCheckoutService.getCustomerFeatures({ processId }))
|
||||
);
|
||||
|
||||
showSubscriptionBadge$ = this.store.item$.pipe(map((item) => item?.features?.find((i) => i.key === 'PFO')));
|
||||
|
||||
showPromotionBadge$ = this.store.item$.pipe(map((item) => item?.features?.find((i) => i.key === 'Promotion')));
|
||||
@@ -113,6 +120,19 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
get isTablet$() {
|
||||
return this._environment.matchTablet$.pipe(
|
||||
map((state) => state?.matches),
|
||||
shareReplay()
|
||||
);
|
||||
}
|
||||
|
||||
get resultsPath() {
|
||||
return this._navigationService.getArticleSearchResultsPath(this.applicationService.activatedProcessId);
|
||||
}
|
||||
|
||||
showMore: boolean = false;
|
||||
|
||||
constructor(
|
||||
public readonly applicationService: ApplicationService,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
@@ -126,7 +146,10 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
|
||||
public elementRef: ElementRef,
|
||||
private _purchaseOptionsModalService: PurchaseOptionsModalService,
|
||||
private _availability: DomainAvailabilityService,
|
||||
private _router: Router
|
||||
private _navigationService: ProductCatalogNavigationService,
|
||||
private _environment: EnvironmentService,
|
||||
private _router: Router,
|
||||
private _domainCheckoutService: DomainCheckoutService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -161,16 +184,30 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
|
||||
filter((f) => !!f)
|
||||
);
|
||||
|
||||
const more$ = this.activatedRoute.params.subscribe(() => (this.showMore = false));
|
||||
|
||||
this.subscriptions.add(processIdSubscription);
|
||||
this.subscriptions.add(more$);
|
||||
this.subscriptions.add(this.store.loadItemById(id$));
|
||||
this.subscriptions.add(this.store.loadItemByEan(ean$));
|
||||
this.subscriptions.add(this.store.item$.pipe(filter((item) => !!item)).subscribe((item) => this.updateBreadcrumb(item)));
|
||||
this.subscriptions.add(
|
||||
this.store.item$
|
||||
.pipe(
|
||||
withLatestFrom(this.isTablet$),
|
||||
filter(([item, isTablet]) => !!item)
|
||||
)
|
||||
.subscribe(([item, isTablet]) => (isTablet ? this.updateBreadcrumb(item) : this.updateBreadcrumbDesktop(item)))
|
||||
);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.subscriptions.unsubscribe();
|
||||
}
|
||||
|
||||
getDetailsPath(ean?: string) {
|
||||
return this._navigationService.getArticleDetailsPath({ processId: this.applicationService.activatedProcessId, ean });
|
||||
}
|
||||
|
||||
async updateBreadcrumb(item: ItemDTO) {
|
||||
const crumbs = await this.breadcrumb
|
||||
.getBreadcrumbsByKeyAndTags$(this.applicationService.activatedProcessId, ['catalog', 'details', `${item.id}`])
|
||||
@@ -184,13 +221,41 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
|
||||
this.breadcrumb.addBreadcrumbIfNotExists({
|
||||
key: this.applicationService.activatedProcessId,
|
||||
name: item.product?.name,
|
||||
path: `/kunde/${this.applicationService.activatedProcessId}/product/details/${item.id}`,
|
||||
path: this._navigationService.getArticleDetailsPath({ processId: this.applicationService.activatedProcessId, itemId: item.id }),
|
||||
params: this.activatedRoute.snapshot.queryParams,
|
||||
tags: ['catalog', 'details', `${item.id}`],
|
||||
section: 'customer',
|
||||
});
|
||||
}
|
||||
|
||||
async updateBreadcrumbDesktop(item: ItemDTO) {
|
||||
const crumbs = await this.breadcrumb
|
||||
.getBreadcrumbsByKeyAndTags$(this.applicationService.activatedProcessId, ['catalog', 'details'])
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
if (crumbs.length === 0) {
|
||||
this.breadcrumb.addBreadcrumbIfNotExists({
|
||||
key: this.applicationService.activatedProcessId,
|
||||
name: item.product?.name,
|
||||
path: this._navigationService.getArticleDetailsPath({ processId: this.applicationService.activatedProcessId, itemId: item.id }),
|
||||
params: this.activatedRoute.snapshot.queryParams,
|
||||
tags: ['catalog', 'details', `${item.id}`],
|
||||
section: 'customer',
|
||||
});
|
||||
} else {
|
||||
const crumb = crumbs.find((_) => true);
|
||||
this.breadcrumb.patchBreadcrumb(crumb.id, {
|
||||
key: this.applicationService.activatedProcessId,
|
||||
name: item.product?.name,
|
||||
path: this._navigationService.getArticleDetailsPath({ processId: this.applicationService.activatedProcessId, itemId: item.id }),
|
||||
params: this.activatedRoute.snapshot.queryParams,
|
||||
tags: ['catalog', 'details', `${item.id}`],
|
||||
section: 'customer',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async print() {
|
||||
const item = await this.store.item$.pipe(first()).toPromise();
|
||||
this.uiModal.open({
|
||||
@@ -271,9 +336,17 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
|
||||
processId: this.applicationService.activatedProcessId,
|
||||
items: [item],
|
||||
})
|
||||
.afterClosed$.subscribe((result) => {
|
||||
.afterClosed$.subscribe(async (result) => {
|
||||
if (result?.data === 'continue') {
|
||||
this.navigateToShoppingCart();
|
||||
const customer = await this._domainCheckoutService
|
||||
.getBuyer({ processId: this.applicationService.activatedProcessId })
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
if (customer) {
|
||||
this.navigateToShoppingCart();
|
||||
} else {
|
||||
this.navigateToCustomerSearch();
|
||||
}
|
||||
console.log('continue');
|
||||
} else if (result?.data === 'continue-shopping') {
|
||||
this.navigateToResultList();
|
||||
@@ -286,6 +359,24 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
|
||||
this._router.navigate([`/kunde/${this.applicationService.activatedProcessId}/cart/review`]);
|
||||
}
|
||||
|
||||
async navigateToCustomerSearch() {
|
||||
try {
|
||||
const response = await this.customerFeatures$
|
||||
.pipe(
|
||||
first(),
|
||||
switchMap((customerFeatures) => {
|
||||
return this._domainCheckoutService.canSetCustomer({ processId: this.applicationService.activatedProcessId, customerFeatures });
|
||||
})
|
||||
)
|
||||
.toPromise();
|
||||
this._router.navigate(['/kunde', this.applicationService.activatedProcessId, 'customer', 'search'], {
|
||||
queryParams: { filter_customertype: response.filter.customertype },
|
||||
});
|
||||
} catch (error) {
|
||||
this._router.navigate(['/kunde', this.applicationService.activatedProcessId, 'customer', 'search']);
|
||||
}
|
||||
}
|
||||
|
||||
async navigateToResultList() {
|
||||
let crumbs = await this.breadcrumb
|
||||
.getBreadcrumbsByKeyAndTags$(this.applicationService.activatedProcessId, ['catalog'])
|
||||
@@ -302,9 +393,8 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
scrollTop() {
|
||||
const element = this.elementRef.nativeElement.closest('.main-wrapper');
|
||||
element?.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
scrollTop(div: HTMLDivElement) {
|
||||
div?.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
loadImage() {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
:host {
|
||||
@apply flex flex-col bg-white;
|
||||
@apply flex flex-col bg-white h-[calc(100vh-16.5rem-3.75rem)] desktop-small:h-[calc(100vh-15.1rem-3.75rem)];
|
||||
box-shadow: 0px -2px 24px 0px #dce2e9;
|
||||
height: calc(100vh - 342px);
|
||||
}
|
||||
|
||||
h1 {
|
||||
@@ -18,7 +17,7 @@ p {
|
||||
@apply mt-10;
|
||||
|
||||
.label {
|
||||
@apply flex flex-row items-center uppercase text-dark-cerulean font-bold text-sm ml-6;
|
||||
@apply flex flex-row items-center uppercase text-dark-cerulean font-bold text-p3 ml-6;
|
||||
|
||||
ui-icon {
|
||||
@apply mr-2;
|
||||
@@ -26,7 +25,7 @@ p {
|
||||
}
|
||||
|
||||
.empty-message {
|
||||
@apply flex justify-center text-cta-l mt-12;
|
||||
@apply flex justify-center text-p1 mt-12;
|
||||
}
|
||||
|
||||
.article {
|
||||
@@ -40,7 +39,7 @@ p {
|
||||
}
|
||||
|
||||
.format {
|
||||
@apply text-regular mt-2;
|
||||
@apply text-p2 mt-2;
|
||||
}
|
||||
|
||||
.price {
|
||||
|
||||
@@ -1,13 +1 @@
|
||||
<button class="filter" [class.active]="hasFilter$ | async" (click)="filterActive$.next(true); shellFilterOverlay.open()">
|
||||
<ui-icon size="20px" icon="filter_alit"></ui-icon>
|
||||
<span class="label">Filter</span>
|
||||
</button>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
<shell-filter-overlay #shellFilterOverlay>
|
||||
<page-article-search-filter
|
||||
*ngIf="filterActive$ | async"
|
||||
(close)="filterActive$.next(false); shellFilterOverlay.close()"
|
||||
></page-article-search-filter>
|
||||
</shell-filter-overlay>
|
||||
|
||||
@@ -1,17 +1,3 @@
|
||||
:host {
|
||||
@apply flex flex-col w-full box-content relative;
|
||||
}
|
||||
|
||||
.filter {
|
||||
@apply font-sans flex self-end items-center mb-4 font-bold bg-wild-blue-yonder border-0 text-regular py-px-8 px-px-15 rounded-filter justify-center z-sticky;
|
||||
width: 106px;
|
||||
min-width: 106px;
|
||||
|
||||
.label {
|
||||
@apply ml-px-5;
|
||||
}
|
||||
|
||||
&.active {
|
||||
@apply bg-active-customer text-white ml-px-5;
|
||||
}
|
||||
@apply flex flex-col w-full h-[calc(100vh-16.5rem)] desktop-small:h-[calc(100vh-15.1rem)] box-content relative;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { UiFilterAutocompleteProvider } from '@ui/filter';
|
||||
import { isEqual } from 'lodash';
|
||||
import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
||||
import { filter, first, map, takeUntil, withLatestFrom } from 'rxjs/operators';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { map, takeUntil, withLatestFrom } from 'rxjs/operators';
|
||||
import { ArticleSearchService } from './article-search.store';
|
||||
import { FocusSearchboxEvent } from './focus-searchbox.event';
|
||||
import { ArticleSearchMainAutocompleteProvider } from './providers';
|
||||
import { ProductCatalogNavigationService } from '@shared/services';
|
||||
import { FilterAutocompleteProvider } from 'apps/shared/components/filter/src/lib';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'page-article-search',
|
||||
@@ -15,9 +16,8 @@ import { ArticleSearchMainAutocompleteProvider } from './providers';
|
||||
styleUrls: ['article-search.component.scss'],
|
||||
providers: [
|
||||
FocusSearchboxEvent,
|
||||
ArticleSearchService,
|
||||
{
|
||||
provide: UiFilterAutocompleteProvider,
|
||||
provide: FilterAutocompleteProvider,
|
||||
useClass: ArticleSearchMainAutocompleteProvider,
|
||||
multi: true,
|
||||
},
|
||||
@@ -28,22 +28,16 @@ export class ArticleSearchComponent implements OnInit, OnDestroy {
|
||||
private _onDestroy$ = new Subject();
|
||||
private _processId$: Observable<number>;
|
||||
|
||||
initialFilter$ = this._articleSearch.filter$.pipe(
|
||||
filter((filter) => !!filter),
|
||||
first()
|
||||
);
|
||||
get isTablet() {
|
||||
return this._environmentService.matchTablet();
|
||||
}
|
||||
|
||||
hasFilter$ = this._articleSearch.filter$.pipe(
|
||||
withLatestFrom(this.initialFilter$),
|
||||
map(([filter, initialFilter]) => !isEqual(filter?.getQueryParams(), initialFilter?.getQueryParams()))
|
||||
);
|
||||
|
||||
filterActive$ = new BehaviorSubject<boolean>(false);
|
||||
constructor(
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
private _router: Router,
|
||||
private _articleSearch: ArticleSearchService,
|
||||
private _activatedRoute: ActivatedRoute
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _navigationService: ProductCatalogNavigationService,
|
||||
private _environmentService: EnvironmentService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -60,12 +54,17 @@ export class ArticleSearchComponent implements OnInit, OnDestroy {
|
||||
.pipe(takeUntil(this._onDestroy$), withLatestFrom(this._processId$))
|
||||
.subscribe(([state, processId]) => {
|
||||
if (state.searchState === '') {
|
||||
const params = state.filter.getQueryParams();
|
||||
if (state.hits === 1) {
|
||||
const item = state.items.find((f) => f);
|
||||
this._router.navigate(['/kunde', processId, 'product', 'details', item.id]);
|
||||
this._navigationService.navigateToDetails({
|
||||
processId,
|
||||
itemId: item.id,
|
||||
queryParams: this.isTablet ? undefined : params,
|
||||
});
|
||||
} else {
|
||||
const params = state.filter.getQueryParams();
|
||||
this._router.navigate(['/kunde', processId, 'product', 'search', 'results'], {
|
||||
this._navigationService.navigateToResults({
|
||||
processId,
|
||||
queryParams: params,
|
||||
});
|
||||
}
|
||||
@@ -73,6 +72,20 @@ export class ArticleSearchComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
cleanupQueryParams(params: Record<string, string> = {}) {
|
||||
const clean = { ...params };
|
||||
|
||||
for (const key in clean) {
|
||||
if (Object.prototype.hasOwnProperty.call(clean, key)) {
|
||||
if (clean[key] == undefined) {
|
||||
delete clean[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return clean;
|
||||
}
|
||||
|
||||
initProcessId() {
|
||||
this._processId$ = this._activatedRoute.parent.data.pipe(map((data) => Number(data.processId)));
|
||||
}
|
||||
@@ -96,7 +109,7 @@ export class ArticleSearchComponent implements OnInit, OnDestroy {
|
||||
await this._breadcrumb.addBreadcrumbIfNotExists({
|
||||
key: processId,
|
||||
name: 'Artikelsuche',
|
||||
path: `/kunde/${processId}/product`,
|
||||
path: this._navigationService.getArticleSearchBasePath(processId),
|
||||
params: queryParams,
|
||||
tags: ['catalog', 'main'],
|
||||
section: 'customer',
|
||||
|
||||
@@ -6,12 +6,13 @@ import { ArticleSearchComponent } from './article-search.component';
|
||||
import { SearchResultsModule } from './search-results/search-results.module';
|
||||
import { SearchMainModule } from './search-main/search-main.module';
|
||||
import { SearchFilterModule } from './search-filter/search-filter.module';
|
||||
import { ArticleSearchService } from './article-search.store';
|
||||
import { SharedFilterOverlayModule } from '@shared/components/filter-overlay';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, RouterModule, UiIconModule, SearchResultsModule, SearchMainModule, SearchFilterModule, SharedFilterOverlayModule],
|
||||
exports: [ArticleSearchComponent],
|
||||
declarations: [ArticleSearchComponent],
|
||||
providers: [],
|
||||
providers: [ArticleSearchService],
|
||||
})
|
||||
export class ArticleSearchModule {}
|
||||
|
||||
@@ -3,24 +3,31 @@ import { DomainCatalogService } from '@domain/catalog';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { debounceTime, map, switchMap, tap, withLatestFrom } from 'rxjs/operators';
|
||||
|
||||
import { UiFilter } from '@ui/filter';
|
||||
import { ComponentStore, tapResponse } from '@ngrx/component-store';
|
||||
import { ItemDTO, QueryTokenDTO } from '@swagger/cat';
|
||||
import { ItemDTO, QueryTokenDTO, UISettingsDTO } from '@swagger/cat';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { BranchDTO } from '@swagger/checkout';
|
||||
import { Filter } from 'apps/shared/components/filter/src/lib';
|
||||
|
||||
export interface ArticleSearchState {
|
||||
processId: number;
|
||||
filter: UiFilter;
|
||||
filter: Filter;
|
||||
searchState: '' | 'fetching' | 'empty' | 'error';
|
||||
items: ItemDTO[];
|
||||
hits: number;
|
||||
selectedBranch: BranchDTO;
|
||||
selectedItemIds: number[];
|
||||
defaultSettings?: UISettingsDTO;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class ArticleSearchService extends ComponentStore<ArticleSearchState> {
|
||||
get defaultSettings() {
|
||||
return this.get((s) => s.defaultSettings);
|
||||
}
|
||||
|
||||
readonly defaultSettings$ = this.select((s) => s.defaultSettings);
|
||||
|
||||
get processId() {
|
||||
return this.get((s) => s.processId);
|
||||
}
|
||||
@@ -100,19 +107,19 @@ export class ArticleSearchService extends ComponentStore<ArticleSearchState> {
|
||||
}
|
||||
|
||||
async setDefaultFilter(defaultQueryParams?: Record<string, string>) {
|
||||
const filter = await this.catalog
|
||||
.getSettings()
|
||||
.pipe(map((settings) => UiFilter.create(settings)))
|
||||
.toPromise();
|
||||
const defaultSettings = await this.catalog.getSettings().toPromise();
|
||||
|
||||
const filter = Filter.create(defaultSettings);
|
||||
|
||||
if (!!defaultQueryParams) {
|
||||
filter?.fromQueryParams(defaultQueryParams);
|
||||
}
|
||||
|
||||
this.setFilter(filter);
|
||||
this.patchState({ defaultSettings });
|
||||
}
|
||||
|
||||
setFilter(filter: UiFilter) {
|
||||
setFilter(filter: Filter) {
|
||||
this.patchState({ filter });
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DomainCatalogService } from '@domain/catalog';
|
||||
import { UiFilterAutocomplete, UiFilterAutocompleteProvider, UiInput } from '@ui/filter';
|
||||
import { FilterAutocomplete, FilterAutocompleteProvider, FilterInput } from 'apps/shared/components/filter/src/lib';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
export class ArticleSearchMainAutocompleteProvider extends UiFilterAutocompleteProvider {
|
||||
export class ArticleSearchMainAutocompleteProvider extends FilterAutocompleteProvider {
|
||||
for = 'catalog';
|
||||
|
||||
constructor(private domainCatalogSearch: DomainCatalogService) {
|
||||
super();
|
||||
}
|
||||
|
||||
complete(input: UiInput): Observable<UiFilterAutocomplete[]> {
|
||||
complete(input: FilterInput): Observable<FilterAutocomplete[]> {
|
||||
const token = input?.parent?.parent?.getQueryToken();
|
||||
const filter = token?.filter;
|
||||
const type = Object.keys(token?.input).join(';');
|
||||
|
||||
@@ -1,30 +1,38 @@
|
||||
<ng-container *ngIf="filter$ | async; let filter">
|
||||
<div class="catalog-search-filter-content">
|
||||
<button class="btn-close" type="button" (click)="close.emit()">
|
||||
<ui-icon icon="close" size="20px"></ui-icon>
|
||||
</button>
|
||||
<div class="w-full flex flex-row justify-end items-center">
|
||||
<button (click)="clearFilter(filter)" class="text-[#0556B4] p-4">Alle Filter entfernen</button>
|
||||
<a
|
||||
*ngIf="showFilterClose$ | async"
|
||||
class="text-black p-4 outline-none border-none bg-transparent"
|
||||
[routerLink]="closeFilterRoute"
|
||||
queryParamsHandling="preserve"
|
||||
>
|
||||
<ui-svg-icon icon="close" [size]="25"></ui-svg-icon>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="catalog-search-filter-content-main">
|
||||
<h1 class="text-3xl font-bold text-center py-4">Filter</h1>
|
||||
<ui-filter
|
||||
<div class="catalog-search-filter-content-main -mt-14 desktop-small:-mt-8 desktop:-mt-12">
|
||||
<h1 class="text-h3 text-[1.625rem] font-bold text-center pt-6 pb-10">Filter</h1>
|
||||
<shared-filter
|
||||
[filter]="filter"
|
||||
[loading]="fetching$ | async"
|
||||
(search)="applyFilter(filter)"
|
||||
[hint]="searchboxHint$ | async"
|
||||
resizeInputOptionsToElement="page-article-search-filter .cta-wrapper"
|
||||
[scanner]="true"
|
||||
></ui-filter>
|
||||
></shared-filter>
|
||||
</div>
|
||||
|
||||
<div class="cta-wrapper">
|
||||
<button class="cta-reset-filter" (click)="resetFilter(filter)" [disabled]="fetching$ | async">
|
||||
Filter zurücksetzen
|
||||
</button>
|
||||
|
||||
<button class="cta-apply-filter" (click)="applyFilter(filter)" [disabled]="fetching$ | async">
|
||||
<ui-spinner [show]="fetching$ | async">
|
||||
Filter anwenden
|
||||
</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cta-wrapper">
|
||||
<button class="cta-reset-filter" (click)="resetFilter(filter)" [disabled]="fetching$ | async">
|
||||
Filter zurücksetzen
|
||||
</button>
|
||||
|
||||
<button class="cta-apply-filter" (click)="applyFilter(filter)" [disabled]="fetching$ | async">
|
||||
<ui-spinner [show]="fetching$ | async">
|
||||
Filter anwenden
|
||||
</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
:host {
|
||||
@apply block bg-glitter;
|
||||
@apply block bg-white h-[calc(100vh-16.5rem)] desktop-small:h-[calc(100vh-15.1rem)];
|
||||
}
|
||||
|
||||
.catalog-search-filter-content {
|
||||
@apply relative mx-auto p-4;
|
||||
}
|
||||
|
||||
.btn-close {
|
||||
@apply absolute text-cool-grey top-3 p-4 right-4 outline-none border-none bg-transparent;
|
||||
}
|
||||
|
||||
.catalog-search-filter-content-main {
|
||||
h1.title {
|
||||
@apply text-center;
|
||||
@@ -17,14 +13,12 @@
|
||||
}
|
||||
|
||||
.cta-wrapper {
|
||||
@apply fixed bottom-8 whitespace-nowrap;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
@apply text-center whitespace-nowrap absolute bottom-8 left-0 w-full;
|
||||
}
|
||||
|
||||
.cta-reset-filter,
|
||||
.cta-apply-filter {
|
||||
@apply text-lg font-bold px-6 py-3 rounded-full border-solid border-2 border-brand outline-none mx-2;
|
||||
@apply text-lg font-bold px-6 py-[0.85rem] rounded-full border-solid border-2 border-brand outline-none mx-2;
|
||||
|
||||
&:disabled {
|
||||
@apply bg-inactive-branch cursor-not-allowed border-none text-white;
|
||||
@@ -38,3 +32,7 @@
|
||||
.cta-apply-filter {
|
||||
@apply text-white bg-brand;
|
||||
}
|
||||
|
||||
::ng-deep page-article-search-filter shared-filter shared-filter-input-group-main {
|
||||
@apply desktop:hidden px-16;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core';
|
||||
import { UiFilter, UiFilterComponent } from '@ui/filter';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, take } from 'rxjs/operators';
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { map, takeUntil, withLatestFrom } from 'rxjs/operators';
|
||||
import { ArticleSearchService } from '../article-search.store';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { ProductCatalogNavigationService } from '@shared/services';
|
||||
import { Filter, FilterComponent } from 'apps/shared/components/filter/src/lib';
|
||||
|
||||
@Component({
|
||||
selector: 'page-article-search-filter',
|
||||
@@ -10,51 +14,102 @@ import { ArticleSearchService } from '../article-search.store';
|
||||
styleUrls: ['search-filter.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ArticleSearchFilterComponent implements OnInit {
|
||||
export class ArticleSearchFilterComponent implements OnInit, OnDestroy {
|
||||
@Output()
|
||||
close = new EventEmitter();
|
||||
|
||||
_processId$ = this._activatedRoute.parent.data.pipe(map((data) => Number(data.processId)));
|
||||
|
||||
fetching$: Observable<boolean>;
|
||||
|
||||
filter$: Observable<UiFilter>;
|
||||
filter$: Observable<Filter>;
|
||||
|
||||
searchboxHint$ = this.articleSearch.searchboxHint$;
|
||||
|
||||
@ViewChild(UiFilterComponent, { static: false })
|
||||
uiFilterComponent: UiFilterComponent;
|
||||
@ViewChild(FilterComponent, { static: false })
|
||||
uiFilterComponent: FilterComponent;
|
||||
|
||||
constructor(private articleSearch: ArticleSearchService) {}
|
||||
get isDesktop() {
|
||||
return this._environment.matchDesktop();
|
||||
}
|
||||
|
||||
get showFilterClose$() {
|
||||
return this._environment.matchDesktop$.pipe(map((state) => !(state?.matches && this.leftOutlet === 'search')));
|
||||
}
|
||||
|
||||
get leftOutlet() {
|
||||
return this._navigationService.getOutletLocations(this._activatedRoute)?.left;
|
||||
}
|
||||
|
||||
get mainOutlet() {
|
||||
return this._navigationService.getOutletLocations(this._activatedRoute)?.main;
|
||||
}
|
||||
|
||||
get closeFilterRoute() {
|
||||
const processId = Number(this._activatedRoute?.parent?.snapshot?.data?.processId);
|
||||
const itemId = this._navigationService.getOutletParams(this._activatedRoute)?.right?.id;
|
||||
if (!itemId) {
|
||||
if (this.leftOutlet === 'search') {
|
||||
return this._navigationService.getArticleSearchBasePath(processId);
|
||||
} else if (this.mainOutlet === 'results' || this.leftOutlet === 'results') {
|
||||
return this._navigationService.getArticleSearchResultsPath(processId);
|
||||
}
|
||||
} else {
|
||||
return this._navigationService.getArticleDetailsPath({ processId, itemId });
|
||||
}
|
||||
}
|
||||
|
||||
private _onDestroy$ = new Subject();
|
||||
|
||||
constructor(
|
||||
private articleSearch: ArticleSearchService,
|
||||
private _environment: EnvironmentService,
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
public application: ApplicationService,
|
||||
private _navigationService: ProductCatalogNavigationService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.fetching$ = this.articleSearch.fetching$;
|
||||
this.filter$ = this.articleSearch.filter$.pipe(
|
||||
map((filter) => UiFilter.create(filter))
|
||||
// tap((filter) =>
|
||||
// filter.fromQueryParams({
|
||||
// main_qs: 'harry potter',
|
||||
// filter_format: 'eb;!hc',
|
||||
// filter_dbhwgr: '110;121',
|
||||
// main_author: 'author',
|
||||
// filter_region: '9780*|9781*;97884*',
|
||||
// 'filter_reading-age': '1-10',
|
||||
// main_stock: '1-',
|
||||
// })
|
||||
// )
|
||||
);
|
||||
this.filter$ = this.articleSearch.filter$.pipe(map((filter) => Filter.create(filter)));
|
||||
}
|
||||
|
||||
applyFilter(value: UiFilter) {
|
||||
ngOnDestroy(): void {
|
||||
this._onDestroy$.next();
|
||||
this._onDestroy$.complete();
|
||||
}
|
||||
|
||||
applyFilter(value: Filter) {
|
||||
this.uiFilterComponent?.cancelAutocomplete();
|
||||
this.articleSearch.setFilter(value);
|
||||
this.articleSearch.search({ clear: true });
|
||||
this.articleSearch.searchCompleted.pipe(take(1)).subscribe((s) => {
|
||||
if (s.searchState === '') {
|
||||
this.close.emit();
|
||||
}
|
||||
});
|
||||
this.articleSearch.searchCompleted
|
||||
.pipe(takeUntil(this._onDestroy$), withLatestFrom(this._processId$))
|
||||
.subscribe(([state, processId]) => {
|
||||
if (state.searchState === '') {
|
||||
// Check if desktop is necessary, otherwise it would trigger navigation twice (Inside Article-Search.component and here)
|
||||
if (state.hits === 1 && !this.isDesktop) {
|
||||
const item = state.items.find((f) => f);
|
||||
this._navigationService.navigateToDetails({
|
||||
processId,
|
||||
itemId: item.id,
|
||||
});
|
||||
} else if (!this.isDesktop) {
|
||||
const params = state.filter.getQueryParams();
|
||||
this._navigationService.navigateToResults({
|
||||
processId,
|
||||
queryParams: params,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
resetFilter(value: UiFilter) {
|
||||
clearFilter(value: Filter) {
|
||||
value.unselectAll();
|
||||
}
|
||||
|
||||
resetFilter(value: Filter) {
|
||||
const queryParams = { main_qs: value?.getQueryParams()?.main_qs || '' };
|
||||
this.articleSearch.setDefaultFilter(queryParams);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { UiFilterNextModule } from '@ui/filter';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { UiSpinnerModule } from '@ui/spinner';
|
||||
|
||||
import { ArticleSearchFilterComponent } from './search-filter.component';
|
||||
import { FilterNextModule } from 'apps/shared/components/filter/src/lib';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiFilterNextModule, UiIconModule, UiSpinnerModule],
|
||||
imports: [CommonModule, RouterModule, FilterNextModule, UiIconModule, UiSpinnerModule],
|
||||
exports: [ArticleSearchFilterComponent],
|
||||
declarations: [ArticleSearchFilterComponent],
|
||||
providers: [],
|
||||
|
||||
@@ -1,26 +1,50 @@
|
||||
<div class="card-search-article">
|
||||
<h1 class="title">Artikelsuche</h1>
|
||||
<p class="info">
|
||||
<div class="bg-white rounded py-10 px-4 text-center shadow-[0_-2px_24px_0_#dce2e9] h-full">
|
||||
<h1 class="text-h3 text-[1.625rem] font-bold mb-[0.375rem]">Artikelsuche</h1>
|
||||
<p class="text-lg mb-10">
|
||||
Welchen Artikel suchen Sie?
|
||||
</p>
|
||||
<ng-container *ngIf="filter$ | async; let filter">
|
||||
<ui-filter-filter-group-main [inputGroup]="filter?.filter | group: 'main'"></ui-filter-filter-group-main>
|
||||
<ui-filter-input-group-main
|
||||
[hint]="searchboxHint$ | async"
|
||||
[loading]="fetching$ | async"
|
||||
[inputGroup]="filter?.input | group: 'main'"
|
||||
(search)="search(filter)"
|
||||
[showDescription]="false"
|
||||
[scanner]="true"
|
||||
></ui-filter-input-group-main>
|
||||
<shared-filter-filter-group-main
|
||||
class="mb-8 w-full"
|
||||
*ngIf="!(isDesktop$ | async)"
|
||||
[inputGroup]="filter?.filter | group: 'main'"
|
||||
></shared-filter-filter-group-main>
|
||||
<div class="flex flex-row px-12 justify-center desktop:px-0">
|
||||
<shared-filter-input-group-main
|
||||
class="block w-full mr-3 desktop:mx-auto"
|
||||
[hint]="searchboxHint$ | async"
|
||||
[loading]="fetching$ | async"
|
||||
[inputGroup]="filter?.input | group: 'main'"
|
||||
(search)="search(filter)"
|
||||
[showDescription]="false"
|
||||
[scanner]="true"
|
||||
></shared-filter-input-group-main>
|
||||
<a
|
||||
*ngIf="!(isDesktop$ | async)"
|
||||
class="page-search-main__filter w-[6.75rem] h-14 rounded font-bold px-5 mb-4 text-lg bg-[#AEB7C1] flex flex-row flex-nowrap items-center justify-center"
|
||||
[class.active]="hasFilter$ | async"
|
||||
[routerLink]="openFilterRoute"
|
||||
queryParamsHandling="preserve"
|
||||
>
|
||||
<ui-svg-icon class="mr-2" icon="filter-variant"></ui-svg-icon>
|
||||
Filter
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="recent-searches-wrapper">
|
||||
<h3 class="recent-searches-header">Deine letzten Suchanfragen</h3>
|
||||
<ul>
|
||||
<li class="recent-searches-items" *ngFor="let recentQuery of history$ | async">
|
||||
<button (click)="setQueryHistory(filter, recentQuery.friendlyName)">
|
||||
<ui-icon icon="search" size="15px"></ui-icon>
|
||||
<p>{{ recentQuery.friendlyName }}</p>
|
||||
<div class="flex flex-col items-start ml-12 desktop:ml-8 py-6 bg-white">
|
||||
<h3 class="text-p3 font-bold mb-3">Deine letzten Suchanfragen</h3>
|
||||
<ul class="flex flex-col justify-start overflow-hidden items-start m-0 p-0 bg-white w-full">
|
||||
<li class="list-none pb-3" *ngFor="let recentQuery of history$ | async">
|
||||
<button
|
||||
class="flex flex-row items-center outline-none border-none bg-white text-black text-p2 m-0 p-0"
|
||||
(click)="setQueryHistory(filter, recentQuery.friendlyName)"
|
||||
>
|
||||
<ui-icon
|
||||
class="flex w-8 h-8 justify-center items-center mr-3 rounded-full text-black bg-[#edeff0]"
|
||||
icon="search"
|
||||
size="0.875rem"
|
||||
></ui-icon>
|
||||
<p class="m-0 p-0 whitespace-nowrap overflow-hidden overflow-ellipsis max-w-[25rem]">{{ recentQuery.friendlyName }}</p>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1,71 +1,13 @@
|
||||
:host {
|
||||
@apply flex flex-col box-border;
|
||||
@apply flex flex-col box-border h-full;
|
||||
}
|
||||
|
||||
.title {
|
||||
@apply text-page-heading font-bold;
|
||||
}
|
||||
|
||||
.info {
|
||||
@apply text-2xl mt-1 mb-px-30;
|
||||
}
|
||||
|
||||
.filter-chips {
|
||||
@apply flex flex-row justify-center;
|
||||
}
|
||||
|
||||
.card-search-article {
|
||||
@apply bg-white rounded p-4 text-center;
|
||||
|
||||
box-shadow: 0 -2px 24px 0 #dce2e9;
|
||||
}
|
||||
|
||||
.card-search-article {
|
||||
min-height: calc(100vh - 380px);
|
||||
}
|
||||
|
||||
ui-filter-filter-group-main {
|
||||
@apply mb-8 w-full;
|
||||
.page-search-main__filter {
|
||||
&.active {
|
||||
@apply bg-[#596470] text-white ml-px-5;
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep page-article-search-main ui-filter-filter-group-main .ui-filter-chip:not(.selected) {
|
||||
@apply bg-glitter;
|
||||
}
|
||||
|
||||
ui-filter-input-group-main {
|
||||
@apply block mx-auto;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.recent-searches-wrapper {
|
||||
@apply flex flex-col mx-auto items-start py-6 bg-white;
|
||||
width: 50%;
|
||||
z-index: 0;
|
||||
|
||||
.recent-searches-header {
|
||||
@apply text-sm font-bold mb-4;
|
||||
}
|
||||
|
||||
ul {
|
||||
@apply flex flex-col justify-start overflow-hidden items-start m-0 p-0 bg-white w-full;
|
||||
z-index: 0;
|
||||
|
||||
.recent-searches-items {
|
||||
@apply list-none pb-px-15;
|
||||
|
||||
button {
|
||||
@apply flex flex-row items-center outline-none border-none bg-white text-black text-base m-0 p-0;
|
||||
|
||||
ui-icon {
|
||||
@apply flex w-px-35 h-px-35 justify-center items-center mr-3 rounded-full text-black;
|
||||
background-color: #e6eff9;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply m-0 p-0 whitespace-nowrap overflow-hidden overflow-ellipsis;
|
||||
max-width: 400px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,13 @@ import { ActivatedRoute } from '@angular/router';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { DomainCatalogService } from '@domain/catalog';
|
||||
import { UiFilter, UiFilterInputGroupMainComponent } from '@ui/filter';
|
||||
import { combineLatest, NEVER, Subscription } from 'rxjs';
|
||||
import { catchError, debounceTime, first, switchMap } from 'rxjs/operators';
|
||||
import { catchError, debounceTime, first, switchMap, map, shareReplay } from 'rxjs/operators';
|
||||
import { ArticleSearchService } from '../article-search.store';
|
||||
import { isEqual } from 'lodash';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { Filter, FilterInputGroupMainComponent } from 'apps/shared/components/filter/src/lib';
|
||||
import { ProductCatalogNavigationService } from '@shared/services';
|
||||
|
||||
@Component({
|
||||
selector: 'page-article-search-main',
|
||||
@@ -26,15 +28,47 @@ export class ArticleSearchMainComponent implements OnInit, OnDestroy {
|
||||
|
||||
subscriptions = new Subscription();
|
||||
|
||||
@ViewChild(UiFilterInputGroupMainComponent, { static: false })
|
||||
uiInputGroupMain: UiFilterInputGroupMainComponent;
|
||||
hasFilter$ = combineLatest([this.searchService.filter$, this.searchService.defaultSettings$]).pipe(
|
||||
map(([filter, defaultFilter]) => {
|
||||
const filterQueryParams = filter?.getQueryParams();
|
||||
return !isEqual(this.resetQueryParamsQueryAndOrderBy(filterQueryParams), Filter.create(defaultFilter).getQueryParams());
|
||||
})
|
||||
);
|
||||
|
||||
@ViewChild(FilterInputGroupMainComponent, { static: false })
|
||||
sharedFilterInputGroupMain: FilterInputGroupMainComponent;
|
||||
|
||||
get isDesktop$() {
|
||||
return this._environment.matchDesktop$.pipe(
|
||||
map((state) => state?.matches),
|
||||
shareReplay()
|
||||
);
|
||||
}
|
||||
|
||||
get leftOutlet() {
|
||||
return this._navigationService.getOutletLocations(this.route.parent)?.left;
|
||||
}
|
||||
|
||||
get openFilterRoute() {
|
||||
if (this.leftOutlet === 'search') {
|
||||
return this._navigationService.getArticleSearchBaseAndFilterPath(this.application.activatedProcessId);
|
||||
} else {
|
||||
const itemId = this._navigationService?.getOutletParams(this.route)?.right?.id;
|
||||
return this._navigationService.getArticleSearchResultsAndFilterPath({
|
||||
processId: this.application.activatedProcessId,
|
||||
itemId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
constructor(
|
||||
private searchService: ArticleSearchService,
|
||||
private catalog: DomainCatalogService,
|
||||
private route: ActivatedRoute,
|
||||
private application: ApplicationService,
|
||||
private breadcrumb: BreadcrumbService
|
||||
private breadcrumb: BreadcrumbService,
|
||||
private _environment: EnvironmentService,
|
||||
private _navigationService: ProductCatalogNavigationService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -44,7 +78,7 @@ export class ArticleSearchMainComponent implements OnInit, OnDestroy {
|
||||
.subscribe(async ([processId, queryParams]) => {
|
||||
const processChanged = processId !== this.searchService.processId;
|
||||
|
||||
if (!(this.searchService.filter instanceof UiFilter)) {
|
||||
if (!(this.searchService.filter instanceof Filter)) {
|
||||
await this.searchService.setDefaultFilter();
|
||||
}
|
||||
|
||||
@@ -57,6 +91,7 @@ export class ArticleSearchMainComponent implements OnInit, OnDestroy {
|
||||
const cleanQueryParams = this.cleanupQueryParams(queryParams);
|
||||
|
||||
if (!isEqual(cleanQueryParams, this.cleanupQueryParams(this.searchService.filter.getQueryParams()))) {
|
||||
// Reset Filter on Product Search Shell Navigation click
|
||||
await this.searchService.setDefaultFilter(queryParams);
|
||||
}
|
||||
|
||||
@@ -85,16 +120,30 @@ export class ArticleSearchMainComponent implements OnInit, OnDestroy {
|
||||
this.updateBreadcrumb(this.searchService.processId, this.searchService.filter.getQueryParams());
|
||||
}
|
||||
|
||||
search(filter: UiFilter) {
|
||||
this.uiInputGroupMain.cancelAutocomplete();
|
||||
search(filter: Filter) {
|
||||
this.sharedFilterInputGroupMain.cancelAutocomplete();
|
||||
this.searchService.setFilter(filter);
|
||||
this.searchService.search({ clear: true });
|
||||
}
|
||||
|
||||
setQueryHistory(filter: UiFilter, query: string) {
|
||||
setQueryHistory(filter: Filter, query: string) {
|
||||
filter.fromQueryParams({ main_qs: query });
|
||||
}
|
||||
|
||||
resetQueryParamsQueryAndOrderBy(params: Record<string, string> = {}) {
|
||||
const clean = { ...params };
|
||||
|
||||
for (const key in clean) {
|
||||
if (key === 'main_qs' || key?.includes('order_by')) {
|
||||
clean[key] = undefined;
|
||||
} else if (key?.includes('order_by')) {
|
||||
delete clean[key];
|
||||
}
|
||||
}
|
||||
|
||||
return clean;
|
||||
}
|
||||
|
||||
cleanupQueryParams(params: Record<string, string> = {}) {
|
||||
const clean = { ...params };
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { UiFilterNextModule } from '@ui/filter';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { ArticleSearchMainComponent } from './search-main.component';
|
||||
import { FilterNextModule } from 'apps/shared/components/filter/src/lib';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiIconModule, UiFilterNextModule],
|
||||
imports: [CommonModule, RouterModule, UiIconModule, FilterNextModule],
|
||||
exports: [ArticleSearchMainComponent],
|
||||
declarations: [ArticleSearchMainComponent],
|
||||
providers: [],
|
||||
|
||||
@@ -1,17 +1,38 @@
|
||||
<div class="thumbnail animation"></div>
|
||||
<div class="col">
|
||||
<div class="author animation"></div>
|
||||
<div class="row">
|
||||
<div class="title animation"></div>
|
||||
<div class="price animation"></div>
|
||||
<ng-container *ngIf="!mainOutletActive; else mainOutlet">
|
||||
<div class="bg-ucla-blue rounded w-[4.375rem] h-[5.625rem] animate-[load_1s_linear_infinite]"></div>
|
||||
<div class="flex flex-col flex-grow">
|
||||
<div class="h-4 bg-ucla-blue ml-4 mb-2 w-[7.8125rem] animate-[load_1s_linear_infinite]"></div>
|
||||
<div class="flex flex-row justify-between flex-grow">
|
||||
<div class="h-6 bg-ucla-blue ml-4 w-[12.5rem] animate-[load_1s_linear_infinite]"></div>
|
||||
<div class="h-6 bg-ucla-blue ml-4 w-[4.6875rem] animate-[load_1s_linear_infinite]"></div>
|
||||
</div>
|
||||
<div class="flex-grow"></div>
|
||||
<div class="flex flex-row justify-between flex-grow">
|
||||
<div class="h-4 bg-ucla-blue ml-4 w-[7.8125rem] animate-[load_1s_linear_infinite]"></div>
|
||||
<div class="h-4 bg-ucla-blue ml-4 w-[3.125rem] animate-[load_1s_linear_infinite]"></div>
|
||||
</div>
|
||||
<div class="flex flex-row justify-between flex-grow">
|
||||
<div class="h-4 bg-ucla-blue ml-4 w-[7.8125rem] animate-[load_1s_linear_infinite]"></div>
|
||||
<div class="h-4 bg-ucla-blue ml-4 w-[7.8125rem] animate-[load_1s_linear_infinite]"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space"></div>
|
||||
<div class="row">
|
||||
<div class="category animation"></div>
|
||||
<div class="stock animation"></div>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #mainOutlet>
|
||||
<div class="bg-ucla-blue rounded w-[3rem] h-[4.125rem] animate-[load_1s_linear_infinite]"></div>
|
||||
<div class="flex flex-col ml-4 w-[36.6%]">
|
||||
<div class="h-4 bg-ucla-blue mb-2 w-[8.8125rem] animate-[load_1s_linear_infinite]"></div>
|
||||
<div class="h-6 bg-ucla-blue mb-2 w-[13.5rem] animate-[load_1s_linear_infinite]"></div>
|
||||
<div class="h-6 bg-ucla-blue w-[13.5rem] animate-[load_1s_linear_infinite]"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="manufacturer animation"></div>
|
||||
<div class="ava animation"></div>
|
||||
<div class="flex flex-col w-[32.5%]">
|
||||
<div class="h-4 bg-ucla-blue mb-2 w-[8.8125rem] animate-[load_1s_linear_infinite]"></div>
|
||||
<div class="h-4 bg-ucla-blue mb-2 w-[8.8125rem] animate-[load_1s_linear_infinite]"></div>
|
||||
<div class="h-4 bg-ucla-blue w-[8.8125rem] animate-[load_1s_linear_infinite]"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col w-[20%]">
|
||||
<div class="h-4 bg-ucla-blue mb-2 w-[8.8125rem] animate-[load_1s_linear_infinite]"></div>
|
||||
<div class="h-4 bg-ucla-blue mb-2 w-[8.8125rem] animate-[load_1s_linear_infinite]"></div>
|
||||
<div class="h-4 bg-ucla-blue w-[8.8125rem] animate-[load_1s_linear_infinite]"></div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
@@ -1,61 +1,3 @@
|
||||
:host {
|
||||
@apply flex flex-row rounded-card bg-white mb-2 p-4;
|
||||
height: 187px;
|
||||
}
|
||||
|
||||
.thumbnail {
|
||||
width: 70px;
|
||||
height: 90px;
|
||||
@apply bg-ucla-blue rounded-card;
|
||||
}
|
||||
|
||||
.space {
|
||||
@apply flex-grow;
|
||||
}
|
||||
|
||||
.col {
|
||||
@apply flex flex-col flex-grow;
|
||||
}
|
||||
|
||||
.row {
|
||||
@apply flex flex-row justify-between flex-grow;
|
||||
}
|
||||
|
||||
.author {
|
||||
width: 150px;
|
||||
@apply h-4 bg-ucla-blue ml-4 mb-2;
|
||||
}
|
||||
|
||||
.title {
|
||||
width: 300px;
|
||||
@apply h-6 bg-ucla-blue ml-4;
|
||||
}
|
||||
|
||||
.price {
|
||||
width: 100px;
|
||||
@apply h-6 bg-ucla-blue ml-4;
|
||||
}
|
||||
|
||||
.category {
|
||||
width: 200px;
|
||||
@apply h-4 bg-ucla-blue ml-4;
|
||||
}
|
||||
|
||||
.manufacturer {
|
||||
width: 200px;
|
||||
@apply h-4 bg-ucla-blue ml-4;
|
||||
}
|
||||
|
||||
.stock {
|
||||
width: 75px;
|
||||
@apply h-4 bg-ucla-blue ml-4;
|
||||
}
|
||||
|
||||
.ava {
|
||||
width: 150px;
|
||||
@apply h-4 bg-ucla-blue ml-4;
|
||||
}
|
||||
|
||||
.animation {
|
||||
animation: load 1s linear infinite;
|
||||
@apply flex flex-row rounded bg-white mb-2 p-4 w-full h-[212px] desktop-small:h-[181px];
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, HostBinding, Input } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'page-search-result-item-loading',
|
||||
@@ -7,5 +7,12 @@ import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class SearchResultItemLoadingComponent {
|
||||
@Input()
|
||||
mainOutletActive?: boolean = false;
|
||||
|
||||
constructor() {}
|
||||
|
||||
@HostBinding('style') get class() {
|
||||
return this.mainOutletActive ? { height: '6.125rem' } : '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,81 +1,124 @@
|
||||
<a class="product-list-result-content" [routerLink]="['/kunde', applicationService.activatedProcessId, 'product', 'details', item?.id]">
|
||||
<div class="item-thumbnail">
|
||||
<img loading="lazy" *ngIf="item?.imageId | thumbnailUrl; let thumbnailUrl" [src]="thumbnailUrl" [alt]="item?.product?.name" />
|
||||
</div>
|
||||
|
||||
<div class="item-contributors">
|
||||
<a
|
||||
*ngFor="let contributor of contributors; let last = last"
|
||||
[routerLink]="['/kunde', applicationService.activatedProcessId, 'product', 'search', 'results']"
|
||||
[queryParams]="{ main_qs: contributor, main_author: 'author' }"
|
||||
(click)="$event?.stopPropagation()"
|
||||
>
|
||||
{{ contributor }}{{ last ? '' : ';' }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="item-title"
|
||||
[class.xl]="item?.product?.name?.length >= 35"
|
||||
[class.lg]="item?.product?.name?.length >= 40"
|
||||
[class.md]="item?.product?.name?.length >= 50"
|
||||
[class.sm]="item?.product?.name?.length >= 60"
|
||||
[class.xs]="item?.product?.name?.length >= 100"
|
||||
>
|
||||
{{ item?.product?.name }}
|
||||
</div>
|
||||
|
||||
<div class="item-price">
|
||||
{{ item?.catalogAvailability?.price?.value?.value | currency: 'EUR':'code' }}
|
||||
</div>
|
||||
|
||||
<div *ngIf="selectable" class="item-data-selector">
|
||||
<ui-select-bullet [ngModel]="selected" (ngModelChange)="setSelected($event)"></ui-select-bullet>
|
||||
</div>
|
||||
|
||||
<div class="item-stock z-dropdown" [uiOverlayTrigger]="tooltip" [overlayTriggerDisabled]="!(stockTooltipText$ | async)">
|
||||
<ng-container *ngIf="isOrderBranch$ | async">
|
||||
<div class="flex flex-row items-center justify-between">
|
||||
<ui-icon icon="home" size="1em"></ui-icon>
|
||||
<span
|
||||
*ngIf="inStock$ | async; let stock"
|
||||
[class.skeleton]="stock.inStock === undefined"
|
||||
class="min-w-[1rem] text-right inline-block"
|
||||
>{{ stock?.inStock }}</span
|
||||
>
|
||||
<span>x</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!(isOrderBranch$ | async)">
|
||||
<div class="flex flex-row items-center justify-between z-dropdown">
|
||||
<ui-icon class="block" icon="home" size="1em"></ui-icon>
|
||||
<span class="min-w-[1rem] text-center inline-block">-</span>
|
||||
<span>x</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
<ui-tooltip #tooltip yPosition="above" xPosition="after" [yOffset]="-8" [closeable]="true">
|
||||
{{ stockTooltipText$ | async }}
|
||||
</ui-tooltip>
|
||||
<!-- <div class="item-stock"><ui-icon icon="home" size="1em"></ui-icon> {{ item?.stockInfos | stockInfos }} x</div> -->
|
||||
|
||||
<div class="item-ssc" [class.xs]="item?.catalogAvailability?.sscText?.length >= 60">
|
||||
{{ item?.catalogAvailability?.ssc }} - {{ item?.catalogAvailability?.sscText }}
|
||||
</div>
|
||||
|
||||
<div class="item-format" *ngIf="item?.product?.format && item?.product?.formatDetail">
|
||||
<a
|
||||
class="page-search-result-item__item-card hover p-5 desktop-small:px-4 desktop-small:py-[0.625rem] h-[13.25rem] desktop-small:h-[11.3125rem] bg-white border border-solid border-transparent rounded"
|
||||
[class.page-search-result-item__item-card-main]="mainOutletActive"
|
||||
[routerLink]="detailsPath"
|
||||
[routerLinkActive]="!isTablet && !mainOutletActive ? 'active' : ''"
|
||||
[queryParamsHandling]="!isTablet ? 'preserve' : ''"
|
||||
(click)="isDesktop ? scrollIntoView() : ''"
|
||||
>
|
||||
<div class="page-search-result-item__item-thumbnail text-center mr-4 w-[50px] h-[79px]">
|
||||
<img
|
||||
*ngIf="item?.product?.format !== '--'"
|
||||
class="page-search-result-item__item-image w-[50px] h-[79px]"
|
||||
loading="lazy"
|
||||
src="assets/images/Icon_{{ item?.product?.format }}.svg"
|
||||
[alt]="item?.product?.formatDetail"
|
||||
*ngIf="item?.imageId | thumbnailUrl; let thumbnailUrl"
|
||||
[src]="thumbnailUrl"
|
||||
[alt]="item?.product?.name"
|
||||
/>
|
||||
{{ item?.product?.formatDetail }}
|
||||
</div>
|
||||
|
||||
<div class="item-misc">
|
||||
{{ item?.product?.manufacturer | substr: 18 }} | {{ item?.product?.ean }} <br />
|
||||
{{ item?.product?.volume }} <span *ngIf="item?.product?.volume && item?.product?.publicationDate">|</span>
|
||||
{{ publicationDate }}
|
||||
<div class="page-search-result-item__item-grid-container" [class.page-search-result-item__item-grid-container-main]="mainOutletActive">
|
||||
<div
|
||||
class="page-search-result-item__item-contributors desktop-small:text-p3 font-bold text-[#0556B4] text-ellipsis overflow-hidden max-w-[24rem] whitespace-nowrap"
|
||||
>
|
||||
<a
|
||||
*ngFor="let contributor of contributors; let last = last"
|
||||
[routerLink]="resultsPath"
|
||||
[queryParams]="{ main_qs: contributor, main_author: 'author' }"
|
||||
(click)="$event?.stopPropagation()"
|
||||
>
|
||||
{{ contributor }}{{ last ? '' : ';' }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="page-search-result-item__item-title font-bold text-h3"
|
||||
[class.text-xl]="item?.product?.name?.length >= 35 && isTablet"
|
||||
[class.text-lg]="item?.product?.name?.length >= 40 && isTablet"
|
||||
[class.text-md]="item?.product?.name?.length >= 50 && isTablet"
|
||||
[class.text-p3]="item?.product?.name?.length >= 60 || !isTablet"
|
||||
[class.text-xs]="item?.product?.name?.length >= 100"
|
||||
>
|
||||
{{ item?.product?.name }}
|
||||
</div>
|
||||
|
||||
<div class="page-search-result-item__item-format desktop-small:text-p3">
|
||||
<div *ngIf="item?.product?.format && item?.product?.formatDetail" class="font-bold flex flex-row">
|
||||
<img
|
||||
class="mr-3"
|
||||
*ngIf="item?.product?.format !== '--'"
|
||||
loading="lazy"
|
||||
src="assets/images/Icon_{{ item?.product?.format }}.svg"
|
||||
[alt]="item?.product?.formatDetail"
|
||||
/>
|
||||
{{ item?.product?.formatDetail | substr: 30 }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-search-result-item__item-manufacturer desktop-small:text-p3">
|
||||
{{ item?.product?.manufacturer | substr: 18 }} | {{ item?.product?.ean }}
|
||||
</div>
|
||||
|
||||
<div class="page-search-result-item__item-misc desktop-small:text-p3">
|
||||
{{ item?.product?.volume }} <span *ngIf="item?.product?.volume && item?.product?.publicationDate">|</span>
|
||||
{{ publicationDate }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="page-search-result-item__item-price desktop-small:text-p3 font-bold justify-self-end"
|
||||
[class.page-search-result-item__item-price-main]="mainOutletActive"
|
||||
>
|
||||
{{ item?.catalogAvailability?.price?.value?.value | currency: 'EUR':'code' }}
|
||||
</div>
|
||||
|
||||
<div class="page-search-result-item__item-select-bullet justify-self-end">
|
||||
<input
|
||||
*ngIf="selectable"
|
||||
(click)="$event.stopPropagation()"
|
||||
[ngModel]="selected$ | async"
|
||||
(ngModelChange)="setSelected()"
|
||||
class="isa-select-bullet"
|
||||
type="checkbox"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="page-search-result-item__item-stock desktop-small:text-p3 font-bold z-dropdown justify-self-start"
|
||||
[class.justify-self-end]="!mainOutletActive"
|
||||
[uiOverlayTrigger]="tooltip"
|
||||
[overlayTriggerDisabled]="!(stockTooltipText$ | async)"
|
||||
>
|
||||
<ng-container *ngIf="isOrderBranch$ | async">
|
||||
<div class="flex flex-row items-center justify-between">
|
||||
<ui-icon icon="home" size="1em"></ui-icon>
|
||||
<span
|
||||
*ngIf="inStock$ | async; let stock"
|
||||
[class.skeleton]="stock.inStock === undefined"
|
||||
class="min-w-[1rem] text-right inline-block"
|
||||
>{{ stock?.inStock }}</span
|
||||
>
|
||||
<span>x</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!(isOrderBranch$ | async)">
|
||||
<div class="flex flex-row items-center justify-between z-dropdown">
|
||||
<ui-icon class="block" icon="home" size="1em"></ui-icon>
|
||||
<span class="min-w-[1rem] text-center inline-block">-</span>
|
||||
<span>x</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
<ui-tooltip #tooltip yPosition="above" xPosition="after" [yOffset]="-8" [closeable]="true">
|
||||
{{ stockTooltipText$ | async }}
|
||||
</ui-tooltip>
|
||||
|
||||
<div
|
||||
class="page-search-result-item__item-ssc desktop-small:text-p3 w-full text-right overflow-hidden text-ellipsis whitespace-nowrap"
|
||||
[class.page-search-result-item__item-ssc-main]="mainOutletActive"
|
||||
>
|
||||
<div class="hidden" [class.page-search-result-item__item-ssc-tooltip]="mainOutletActive">
|
||||
{{ item?.catalogAvailability?.ssc }} - {{ item?.catalogAvailability?.sscText }}
|
||||
</div>
|
||||
<strong>{{ item?.catalogAvailability?.ssc }}</strong> - {{ item?.catalogAvailability?.sscText }}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
@@ -1,113 +1,104 @@
|
||||
.product-list-result-content {
|
||||
@apply text-black no-underline grid;
|
||||
grid-template-columns: 102px 50% auto;
|
||||
grid-template-rows: auto;
|
||||
:host {
|
||||
@apply flex flex-col w-full h-[13.25rem] desktop-small:h-[11.3125rem];
|
||||
}
|
||||
|
||||
.page-search-result-item__item-card {
|
||||
@apply grid grid-flow-col;
|
||||
grid-template-columns: 3.9375rem auto;
|
||||
box-shadow: 0px 0px 10px rgba(220, 226, 233, 0.5);
|
||||
}
|
||||
|
||||
.page-search-result-item__item-grid-container {
|
||||
@apply grid grid-flow-row gap-y-[0.375rem] gap-x-6;
|
||||
grid-template-areas:
|
||||
'item-thumbnail item-contributors item-contributors'
|
||||
'item-thumbnail item-title item-price'
|
||||
'item-thumbnail item-title item-data-selector'
|
||||
'item-thumbnail item-format item-stock'
|
||||
'item-thumbnail item-misc item-ssc';
|
||||
'contributors contributors contributors'
|
||||
'title title price'
|
||||
'title title price'
|
||||
'title title select'
|
||||
'format format select'
|
||||
'manufacturer manufacturer stock'
|
||||
'misc ssc ssc';
|
||||
}
|
||||
|
||||
.item-thumbnail {
|
||||
grid-area: item-thumbnail;
|
||||
width: 70px;
|
||||
@apply mr-8;
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 150px;
|
||||
@apply rounded-card shadow-cta;
|
||||
.page-search-result-item__item-grid-container-main {
|
||||
@apply gap-x-4;
|
||||
grid-template-rows: 1.3125rem 1.3125rem auto;
|
||||
grid-template-columns: 37.5% 32.5% 20% auto;
|
||||
grid-template-areas:
|
||||
'contributors format price .'
|
||||
'title manufacturer stock select'
|
||||
'title misc ssc .';
|
||||
}
|
||||
|
||||
.page-search-result-item__item-contributors {
|
||||
grid-area: contributors;
|
||||
}
|
||||
|
||||
.page-search-result-item__item-price {
|
||||
grid-area: price;
|
||||
}
|
||||
|
||||
.page-search-result-item__item-price-main {
|
||||
@apply justify-self-start;
|
||||
}
|
||||
|
||||
.page-search-result-item__item-title {
|
||||
grid-area: title;
|
||||
}
|
||||
|
||||
.page-search-result-item__item-format {
|
||||
grid-area: format;
|
||||
}
|
||||
|
||||
.page-search-result-item__item-manufacturer {
|
||||
grid-area: manufacturer;
|
||||
}
|
||||
|
||||
.page-search-result-item__item-misc {
|
||||
grid-area: misc;
|
||||
}
|
||||
|
||||
.page-search-result-item__item-select-bullet {
|
||||
grid-area: select;
|
||||
}
|
||||
|
||||
.page-search-result-item__item-stock {
|
||||
grid-area: stock;
|
||||
}
|
||||
|
||||
.page-search-result-item__item-ssc {
|
||||
grid-area: ssc;
|
||||
}
|
||||
|
||||
.page-search-result-item__item-ssc:hover {
|
||||
.page-search-result-item__item-ssc-tooltip {
|
||||
@apply absolute whitespace-normal w-[25%] block rounded bg-white z-tooltip p-2 -mt-[2rem] -ml-[4rem] text-p2 shadow;
|
||||
}
|
||||
}
|
||||
|
||||
.item-contributors {
|
||||
grid-area: item-contributors;
|
||||
height: 22px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
max-width: 600px;
|
||||
white-space: nowrap;
|
||||
.page-search-result-item__item-ssc-main {
|
||||
@apply text-left overflow-hidden text-ellipsis whitespace-nowrap;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply text-active-customer font-bold no-underline;
|
||||
}
|
||||
}
|
||||
|
||||
.item-title {
|
||||
grid-area: item-title;
|
||||
@apply font-bold text-2xl;
|
||||
height: 64px;
|
||||
max-height: 64px;
|
||||
}
|
||||
|
||||
.item-title.xl {
|
||||
@apply font-bold text-xl;
|
||||
}
|
||||
|
||||
.item-title.lg {
|
||||
@apply font-bold text-lg;
|
||||
}
|
||||
|
||||
.item-title.md {
|
||||
@apply font-bold text-base;
|
||||
}
|
||||
|
||||
.item-title.sm {
|
||||
@apply font-bold text-sm;
|
||||
}
|
||||
|
||||
.item-title.xs {
|
||||
@apply font-bold text-xs;
|
||||
}
|
||||
|
||||
.item-price {
|
||||
grid-area: item-price;
|
||||
@apply font-bold text-xl text-right;
|
||||
}
|
||||
|
||||
.item-format {
|
||||
grid-area: item-format;
|
||||
@apply flex flex-row items-center font-bold text-lg whitespace-nowrap;
|
||||
|
||||
img {
|
||||
@apply mr-2;
|
||||
}
|
||||
}
|
||||
|
||||
.item-stock {
|
||||
grid-area: item-stock;
|
||||
@apply flex flex-row justify-end items-baseline font-bold text-lg;
|
||||
|
||||
ui-icon {
|
||||
@apply text-active-customer mr-2;
|
||||
}
|
||||
}
|
||||
|
||||
.item-misc {
|
||||
grid-area: item-misc;
|
||||
}
|
||||
|
||||
.item-ssc {
|
||||
grid-area: item-ssc;
|
||||
@apply font-bold text-right;
|
||||
}
|
||||
|
||||
.item-ssc.xs {
|
||||
@apply font-bold text-xs;
|
||||
}
|
||||
|
||||
.item-data-selector {
|
||||
@apply w-full flex justify-end;
|
||||
grid-area: item-data-selector;
|
||||
}
|
||||
|
||||
ui-select-bullet {
|
||||
@apply p-4 -m-4 z-dropdown;
|
||||
}
|
||||
|
||||
@media (min-width: 1025px) {
|
||||
.item-contributors {
|
||||
max-width: 780px;
|
||||
.page-search-result-item__item-image {
|
||||
box-shadow: 0px 6px 18px rgba(0, 0, 0, 0.197935);
|
||||
}
|
||||
|
||||
.active,
|
||||
.hover:hover {
|
||||
@apply bg-[#D8DFE5] border border-solid border-[#0556B4];
|
||||
|
||||
.page-search-result-item__item-select-bullet {
|
||||
.isa-select-bullet::before {
|
||||
@apply bg-[#fff];
|
||||
}
|
||||
|
||||
.isa-select-bullet:checked:before {
|
||||
@apply bg-[#596470];
|
||||
}
|
||||
|
||||
.isa-select-bullet:hover::before {
|
||||
@apply bg-[#778490];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { Component, ChangeDetectionStrategy, Input, EventEmitter, Output } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, Input, EventEmitter, Output, HostBinding, ElementRef } from '@angular/core';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { DomainAvailabilityService, DomainInStockService } from '@domain/availability';
|
||||
import { ComponentStore } from '@ngrx/component-store';
|
||||
import { ItemDTO } from '@swagger/cat';
|
||||
@@ -9,6 +10,7 @@ import { isEqual } from 'lodash';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { debounceTime, switchMap, map, shareReplay, filter } from 'rxjs/operators';
|
||||
import { ArticleSearchService } from '../article-search.store';
|
||||
import { ProductCatalogNavigationService } from '@shared/services';
|
||||
|
||||
export interface SearchResultItemComponentState {
|
||||
item?: ItemDTO;
|
||||
@@ -36,16 +38,7 @@ export class SearchResultItemComponent extends ComponentStore<SearchResultItemCo
|
||||
|
||||
readonly item$ = this.select((s) => s.item);
|
||||
|
||||
@Input()
|
||||
get selected() {
|
||||
return this.get((s) => s.selected);
|
||||
}
|
||||
set selected(selected: boolean) {
|
||||
if (this.selected !== selected) {
|
||||
this.patchState({ selected });
|
||||
}
|
||||
}
|
||||
readonly selected$ = this.select((s) => s.selected);
|
||||
selected$ = this._articleSearchService.selectedItemIds$.pipe(map((selectedItemIds) => selectedItemIds.includes(this.item?.id)));
|
||||
|
||||
@Input()
|
||||
get selectable() {
|
||||
@@ -57,8 +50,11 @@ export class SearchResultItemComponent extends ComponentStore<SearchResultItemCo
|
||||
}
|
||||
}
|
||||
|
||||
@Input()
|
||||
mainOutletActive?: boolean = false;
|
||||
|
||||
@Output()
|
||||
selectedChange = new EventEmitter<boolean>();
|
||||
selectedChange = new EventEmitter<ItemDTO>();
|
||||
|
||||
get contributors() {
|
||||
return this.item?.product?.contributors?.split(';').map((val) => val.trim());
|
||||
@@ -77,6 +73,22 @@ export class SearchResultItemComponent extends ComponentStore<SearchResultItemCo
|
||||
return '';
|
||||
}
|
||||
|
||||
get isTablet() {
|
||||
return this._environment.matchTablet();
|
||||
}
|
||||
|
||||
get isDesktop() {
|
||||
return this._environment.matchDesktop();
|
||||
}
|
||||
|
||||
get detailsPath() {
|
||||
return this._navigationService.getArticleDetailsPath({ processId: this.applicationService.activatedProcessId, itemId: this.item?.id });
|
||||
}
|
||||
|
||||
get resultsPath() {
|
||||
return this._navigationService.getArticleSearchResultsPath(this.applicationService.activatedProcessId);
|
||||
}
|
||||
|
||||
defaultBranch$ = this._availability.getDefaultBranch();
|
||||
|
||||
selectedBranchId$ = this.applicationService.activatedProcessId$.pipe(
|
||||
@@ -123,7 +135,10 @@ export class SearchResultItemComponent extends ComponentStore<SearchResultItemCo
|
||||
private _articleSearchService: ArticleSearchService,
|
||||
public applicationService: ApplicationService,
|
||||
private _stockService: DomainInStockService,
|
||||
private _availability: DomainAvailabilityService
|
||||
private _availability: DomainAvailabilityService,
|
||||
private _environment: EnvironmentService,
|
||||
private _navigationService: ProductCatalogNavigationService,
|
||||
private _elRef: ElementRef<HTMLElement>
|
||||
) {
|
||||
super({
|
||||
selected: false,
|
||||
@@ -131,7 +146,20 @@ export class SearchResultItemComponent extends ComponentStore<SearchResultItemCo
|
||||
});
|
||||
}
|
||||
|
||||
setSelected(selected: boolean) {
|
||||
this._articleSearchService.setSelected({ selected, itemId: this.item?.id });
|
||||
scrollIntoView() {
|
||||
this._elRef.nativeElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
|
||||
setSelected() {
|
||||
const isSelected = this._articleSearchService.selectedItemIds.includes(this.item?.id);
|
||||
this._articleSearchService.setSelected({ selected: !isSelected, itemId: this.item?.id });
|
||||
|
||||
if (!this.isTablet) {
|
||||
this.selectedChange.emit(this.item);
|
||||
}
|
||||
}
|
||||
|
||||
@HostBinding('style') get class() {
|
||||
return this.mainOutletActive ? { height: '6.125rem' } : '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,81 @@
|
||||
<div class="filter-wrapper">
|
||||
<div class="hits" *ngIf="hits$ | async; let hits">{{ hits }} Titel</div>
|
||||
<ui-order-by-filter [orderBy]="(filter$ | async)?.orderBy" (selectedOrderByChange)="search(); updateBreadcrumbs()"> </ui-order-by-filter>
|
||||
<div
|
||||
class="page-search-results__header bg-background-liste flex items-end justify-between"
|
||||
[class.pb-4]="!(mainOutletActive$ | async)"
|
||||
[class.flex-col]="!(mainOutletActive$ | async)"
|
||||
>
|
||||
<div class="flex flex-row w-full desktop-small:w-min" [class.desktop:w-full]="!(mainOutletActive$ | async)">
|
||||
<shared-filter-input-group-main
|
||||
*ngIf="filter$ | async; let filter"
|
||||
class="block mr-3 w-full desktop-small:w-[23.5rem]"
|
||||
[class.desktop:w-full]="!(mainOutletActive$ | async)"
|
||||
[hint]="searchboxHint$ | async"
|
||||
[loading]="fetching$ | async"
|
||||
[inputGroup]="filter?.input | group: 'main'"
|
||||
(search)="search(filter)"
|
||||
[showDescription]="false"
|
||||
[scanner]="true"
|
||||
></shared-filter-input-group-main>
|
||||
|
||||
<a
|
||||
class="page-search-results__filter w-[6.75rem] h-14 rounded font-bold px-5 mb-4 text-lg bg-[#AEB7C1] flex flex-row flex-nowrap items-center justify-center"
|
||||
[class.active]="hasFilter$ | async"
|
||||
[routerLink]="filterRoute"
|
||||
queryParamsHandling="preserve"
|
||||
>
|
||||
<ui-svg-icon class="mr-2" icon="filter-variant"></ui-svg-icon>
|
||||
Filter
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div
|
||||
*ngIf="hits$ | async; let hits"
|
||||
class="page-search-results__items-count inline-flex flex-row items-center pr-5 text-p3"
|
||||
[class.mb-4]="mainOutletActive$ | async"
|
||||
>
|
||||
{{ hits ??
|
||||
0 }}
|
||||
Titel
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-search-results__order-by" [class.page-search-results__order-by-main]="mainOutletActive$ | async">
|
||||
<shared-order-by-filter
|
||||
[groupBy]="(mainOutletActive$ | async) ? [2, 2, 2] : []"
|
||||
[orderBy]="(filter$ | async)?.orderBy"
|
||||
(selectedOrderByChange)="search(); updateBreadcrumbs()"
|
||||
>
|
||||
</shared-order-by-filter>
|
||||
</div>
|
||||
|
||||
<cdk-virtual-scroll-viewport
|
||||
#scrollContainer
|
||||
class="product-list scroll-bar scroll-bar-margin"
|
||||
[itemSize]="187"
|
||||
minBufferPx="1200"
|
||||
class="product-list"
|
||||
[itemSize]="(mainOutletActive$ | async) ? 98 : 187"
|
||||
minBufferPx="935"
|
||||
maxBufferPx="1200"
|
||||
(scrolledIndexChange)="scrolledIndexChange($event)"
|
||||
>
|
||||
<div class="product-list-result" *cdkVirtualFor="let item of results$ | async; trackBy: trackByItemId">
|
||||
<search-result-item
|
||||
[selected]="item | searchResultSelected: searchService.selectedItemIds"
|
||||
[selectable]="isSelectable(item)"
|
||||
[item]="item"
|
||||
></search-result-item>
|
||||
</div>
|
||||
<page-search-result-item-loading *ngIf="fetching$ | async"></page-search-result-item-loading>
|
||||
<search-result-item
|
||||
class="page-search-results__result-item"
|
||||
[class.page-search-results__result-item-main]="mainOutletActive$ | async"
|
||||
*cdkVirtualFor="let item of results$ | async; trackBy: trackByItemId"
|
||||
(selectedChange)="addToCart($event)"
|
||||
[selectable]="isSelectable(item)"
|
||||
[item]="item"
|
||||
[mainOutletActive]="mainOutletActive$ | async"
|
||||
></search-result-item>
|
||||
<page-search-result-item-loading
|
||||
[mainOutletActive]="mainOutletActive$ | async"
|
||||
*ngIf="fetching$ | async"
|
||||
></page-search-result-item-loading>
|
||||
</cdk-virtual-scroll-viewport>
|
||||
|
||||
<div class="actions">
|
||||
<div *ngIf="isTablet" class="actions z-fixed">
|
||||
<button
|
||||
[disabled]="loading$ | async"
|
||||
*ngIf="(selectedItemIds$ | async)?.length > 0"
|
||||
class="cta-cart cta-action-primary"
|
||||
(click)="addSelectedItemsToCart()"
|
||||
(click)="addToCart()"
|
||||
>
|
||||
<ui-spinner [show]="loading$ | async">In den Warenkorb legen</ui-spinner>
|
||||
</button>
|
||||
|
||||
@@ -1,34 +1,36 @@
|
||||
:host {
|
||||
@apply box-border grid;
|
||||
max-height: calc(100vh - 364px);
|
||||
height: 100vh;
|
||||
grid-template-rows: auto 1fr;
|
||||
@apply box-border grid h-[calc(100vh-16.5rem)] desktop-small:h-[calc(100vh-15.1rem)];
|
||||
grid-template-rows: auto auto 1fr;
|
||||
}
|
||||
|
||||
.product-list {
|
||||
@apply m-0 p-0 mt-2;
|
||||
@apply m-0 p-0 mt-px-2;
|
||||
}
|
||||
|
||||
.product-list-result {
|
||||
@apply list-none bg-white rounded-card p-4 mb-2;
|
||||
height: 187px;
|
||||
max-height: 187px;
|
||||
.page-search-results__result-item {
|
||||
@apply mb-px-10;
|
||||
}
|
||||
|
||||
.filter-wrapper {
|
||||
@apply block relative;
|
||||
.page-search-results__result-item-main {
|
||||
@apply mb-[5px];
|
||||
}
|
||||
|
||||
.hits {
|
||||
@apply text-inactive-branch font-semibold absolute top-2 right-0;
|
||||
}
|
||||
.page-search-results__order-by {
|
||||
@apply bg-white rounded px-6 desktop-small:px-8;
|
||||
}
|
||||
|
||||
ui-order-by-filter {
|
||||
@apply mx-auto;
|
||||
.page-search-results__order-by-main {
|
||||
@apply pl-[4.9375rem] px-4;
|
||||
}
|
||||
|
||||
.page-search-results__filter {
|
||||
&.active {
|
||||
@apply bg-[#596470] text-white ml-px-5;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
@apply fixed bottom-28 inline-grid grid-flow-col gap-7;
|
||||
@apply fixed bottom-16 inline-grid grid-flow-col gap-7;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
|
||||
@@ -44,3 +46,16 @@
|
||||
@apply bg-brand text-white;
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep page-search-results .page-search-results__order-by-main shared-order-by-filter {
|
||||
@apply grid grid-flow-col justify-items-start gap-x-4 justify-start;
|
||||
grid-template-columns: 37.5% 32.5% 20% auto;
|
||||
|
||||
.group {
|
||||
@apply desktop-small:justify-start;
|
||||
}
|
||||
|
||||
.order-by-filter-button {
|
||||
@apply ml-0 mr-7;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,32 @@
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, ViewChild, ViewChildren, QueryList, TrackByFunction } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
ChangeDetectionStrategy,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
ViewChild,
|
||||
ViewChildren,
|
||||
QueryList,
|
||||
TrackByFunction,
|
||||
AfterViewInit,
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { ItemDTO } from '@swagger/cat';
|
||||
import { AddToShoppingCartDTO } from '@swagger/checkout';
|
||||
import { UiFilter } from '@ui/filter';
|
||||
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
|
||||
import { CacheService } from 'apps/core/cache/src/public-api';
|
||||
import { isEqual } from 'lodash';
|
||||
import { BehaviorSubject, combineLatest, Subscription } from 'rxjs';
|
||||
import { debounceTime, first, map, switchMap } from 'rxjs/operators';
|
||||
import { debounceTime, first, map, switchMap, withLatestFrom } 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 { ProductCatalogNavigationService } from '@shared/services';
|
||||
import { Filter, FilterInputGroupMainComponent } from 'apps/shared/components/filter/src/lib';
|
||||
|
||||
@Component({
|
||||
selector: 'page-search-results',
|
||||
@@ -22,11 +34,14 @@ import { SearchResultItemComponent } from './search-result-item.component';
|
||||
styleUrls: ['search-results.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
|
||||
export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
@ViewChildren(SearchResultItemComponent) listItems: QueryList<SearchResultItemComponent>;
|
||||
@ViewChild('scrollContainer', { static: true })
|
||||
scrollContainer: CdkVirtualScrollViewport;
|
||||
|
||||
@ViewChild(FilterInputGroupMainComponent, { static: false })
|
||||
sharedFilterInputGroupMain: FilterInputGroupMainComponent;
|
||||
|
||||
results$ = this.searchService.items$;
|
||||
fetching$ = this.searchService.fetching$;
|
||||
hits$ = this.searchService.hits$;
|
||||
@@ -35,6 +50,8 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
|
||||
|
||||
selectedItemIds$ = this.searchService.selectedItemIds$;
|
||||
|
||||
searchboxHint$ = this.searchService.searchboxHint$;
|
||||
|
||||
selectedItems$ = combineLatest([this.results$, this.selectedItemIds$]).pipe(
|
||||
map(([items, selectedItemIds]) => {
|
||||
return items?.filter((item) => selectedItemIds?.find((selectedItemId) => item.id === selectedItemId));
|
||||
@@ -47,14 +64,43 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
|
||||
|
||||
trackByItemId: TrackByFunction<ItemDTO> = (index, item) => item.id;
|
||||
|
||||
get isTablet() {
|
||||
return this._environment.matchTablet();
|
||||
}
|
||||
|
||||
get isDesktop() {
|
||||
return this._environment.matchDesktop();
|
||||
}
|
||||
|
||||
hasFilter$ = combineLatest([this.searchService.filter$, this.searchService.defaultSettings$]).pipe(
|
||||
map(([filter, defaultFilter]) => {
|
||||
const filterQueryParams = filter?.getQueryParams();
|
||||
return !isEqual(this.resetQueryParamsQueryAndOrderBy(filterQueryParams), Filter.create(defaultFilter).getQueryParams());
|
||||
})
|
||||
);
|
||||
|
||||
get filterRoute() {
|
||||
const itemId = this._navigationService?.getOutletParams(this.route)?.right?.id;
|
||||
return this._navigationService.getArticleSearchResultsAndFilterPath({
|
||||
processId: this.application.activatedProcessId,
|
||||
itemId,
|
||||
});
|
||||
}
|
||||
|
||||
get mainOutletActive$() {
|
||||
return this._environment.matchTablet$.pipe(map((state) => this._navigationService.mainOutletActive(this.route, state?.matches)));
|
||||
}
|
||||
|
||||
constructor(
|
||||
public searchService: ArticleSearchService,
|
||||
private route: ActivatedRoute,
|
||||
private application: ApplicationService,
|
||||
public application: ApplicationService,
|
||||
private breadcrumb: BreadcrumbService,
|
||||
private cache: CacheService,
|
||||
private _uiModal: UiModalService,
|
||||
private _checkoutService: DomainCheckoutService
|
||||
private _checkoutService: DomainCheckoutService,
|
||||
private _environment: EnvironmentService,
|
||||
private _navigationService: ProductCatalogNavigationService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -72,7 +118,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
|
||||
const branchChanged = selectedBranch?.id !== this.searchService?.selectedBranch?.id;
|
||||
|
||||
if (processChanged) {
|
||||
if (!!this.searchService.processId && this.searchService.filter instanceof UiFilter) {
|
||||
if (!!this.searchService.processId && this.searchService.filter instanceof Filter) {
|
||||
this.cacheCurrentData(
|
||||
this.searchService.processId,
|
||||
this.searchService.filter.getQueryParams(),
|
||||
@@ -87,7 +133,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
|
||||
this.searchService.setBranch(selectedBranch);
|
||||
}
|
||||
|
||||
if (!(this.searchService.filter instanceof UiFilter)) {
|
||||
if (!(this.searchService.filter instanceof Filter)) {
|
||||
await this.searchService.setDefaultFilter();
|
||||
}
|
||||
|
||||
@@ -102,7 +148,11 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
|
||||
if (data.items?.length === 0) {
|
||||
this.search();
|
||||
} else {
|
||||
this.scrollTop(Number(queryParams.scroll_position ?? 0));
|
||||
if (!this.isDesktop || this._navigationService.mainOutletActive(this.route)) {
|
||||
this.scrollTop(Number(queryParams.scroll_position ?? 0));
|
||||
} else {
|
||||
this.scrollItemIntoView();
|
||||
}
|
||||
const selectedItemIds: Array<string> = queryParams?.selected_item_ids?.split(',') ?? [];
|
||||
for (const id of selectedItemIds) {
|
||||
if (id) {
|
||||
@@ -114,9 +164,37 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
|
||||
|
||||
await this.updateBreadcrumbs(processId, queryParams);
|
||||
await this.createBreadcrumb(processId, queryParams);
|
||||
await this.removeDetailsBreadcrumb(processId);
|
||||
if (this.isTablet || this.route?.outlet === 'main') {
|
||||
await this.removeDetailsBreadcrumb(processId);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
this.subscriptions.add(
|
||||
this.searchService.searchCompleted.pipe(withLatestFrom(this.application.activatedProcessId$)).subscribe(([state, processId]) => {
|
||||
if (state.searchState === '') {
|
||||
const params = state.filter.getQueryParams();
|
||||
if ((state.hits === 1 && this.isTablet) || (!this.isTablet && !this._navigationService.mainOutletActive(this.route))) {
|
||||
const item = state.items.find((f) => f);
|
||||
const itemId = this.route?.snapshot?.params?.id ? Number(this.route?.snapshot?.params?.id) : item.id; // Nicht zum ersten Item der Liste springen wenn bereits eines selektiert ist
|
||||
this._navigationService.navigateToDetails({
|
||||
processId,
|
||||
itemId,
|
||||
queryParams: this.isTablet ? undefined : params,
|
||||
});
|
||||
} else if (this.isTablet || this._navigationService.mainOutletActive(this.route)) {
|
||||
this._navigationService.navigateToResults({
|
||||
processId,
|
||||
queryParams: params,
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.scrollItemIntoView();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
@@ -127,7 +205,26 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
|
||||
this.unselectAll();
|
||||
}
|
||||
|
||||
search() {
|
||||
resetQueryParamsQueryAndOrderBy(params: Record<string, string> = {}) {
|
||||
const clean = { ...params };
|
||||
|
||||
for (const key in clean) {
|
||||
if (key === 'main_qs') {
|
||||
clean[key] = undefined;
|
||||
} else if (key?.includes('order_by')) {
|
||||
delete clean[key];
|
||||
}
|
||||
}
|
||||
|
||||
return clean;
|
||||
}
|
||||
|
||||
search(filter?: Filter) {
|
||||
if (!!filter) {
|
||||
this.sharedFilterInputGroupMain.cancelAutocomplete();
|
||||
this.searchService.setFilter(filter);
|
||||
}
|
||||
|
||||
this.searchService.search({ clear: true });
|
||||
}
|
||||
|
||||
@@ -143,6 +240,13 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
|
||||
setTimeout(() => this.scrollContainer.scrollTo({ top: scrollPos }), 0);
|
||||
}
|
||||
|
||||
scrollItemIntoView() {
|
||||
setTimeout(() => {
|
||||
const item = this.listItems?.find((item) => item.item.id === Number(this.route?.snapshot?.params?.id));
|
||||
item?.scrollIntoView();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
async scrolledIndexChange(index: number) {
|
||||
const results = await this.results$.pipe(first()).toPromise();
|
||||
const hits = await this.hits$.pipe(first()).toPromise();
|
||||
@@ -187,7 +291,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
|
||||
await this.breadcrumb.addBreadcrumbIfNotExists({
|
||||
key: processId,
|
||||
name,
|
||||
path: `/kunde/${this.application.activatedProcessId}/product/search/results`,
|
||||
path: this._navigationService.getArticleSearchResultsPath(this.application.activatedProcessId),
|
||||
params: queryParams,
|
||||
section: 'customer',
|
||||
tags: ['catalog', 'filter', 'results'],
|
||||
@@ -250,29 +354,44 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
|
||||
this.searchService.patchState({ selectedItemIds: [] });
|
||||
}
|
||||
|
||||
async addSelectedItemsToCart() {
|
||||
async addToCart(item?: ItemDTO) {
|
||||
this.loading$.next(true);
|
||||
const selectedItems = await this.selectedItems$.pipe(first()).toPromise();
|
||||
|
||||
if (!!item) {
|
||||
await this.addItemsToCart(item);
|
||||
} else {
|
||||
await this.addItemsToCart();
|
||||
}
|
||||
|
||||
this.loading$.next(false);
|
||||
}
|
||||
|
||||
private _createShoppingCartItem(item: ItemDTO): AddToShoppingCartDTO {
|
||||
return {
|
||||
quantity: 1,
|
||||
availability: {
|
||||
availabilityType: item?.catalogAvailability?.status,
|
||||
price: item?.catalogAvailability?.price,
|
||||
supplierProductNumber: item?.ids?.dig ? String(item?.ids?.dig) : item?.product?.supplierProductNumber,
|
||||
},
|
||||
product: {
|
||||
catalogProductNumber: String(item?.id),
|
||||
...item?.product,
|
||||
},
|
||||
itemType: item?.type,
|
||||
promotion: { points: item?.promoPoints },
|
||||
};
|
||||
}
|
||||
|
||||
async addItemsToCart(item?: ItemDTO) {
|
||||
const selectedItems = !item ? await this.selectedItems$.pipe(first()).toPromise() : [item];
|
||||
const items: AddToShoppingCartDTO[] = [];
|
||||
|
||||
const canAddItemsPayload = [];
|
||||
|
||||
for (const item of selectedItems) {
|
||||
const shoppingCartItem = this._createShoppingCartItem(item);
|
||||
const isDownload = item?.product?.format === 'EB' || item?.product?.format === 'DL';
|
||||
const shoppingCartItem: AddToShoppingCartDTO = {
|
||||
quantity: 1,
|
||||
availability: {
|
||||
availabilityType: item?.catalogAvailability?.status,
|
||||
price: item?.catalogAvailability?.price,
|
||||
supplierProductNumber: item?.ids?.dig ? String(item.ids?.dig) : item?.product?.supplierProductNumber,
|
||||
},
|
||||
product: {
|
||||
catalogProductNumber: String(item?.id),
|
||||
...item?.product,
|
||||
},
|
||||
itemType: item.type,
|
||||
promotion: { points: item?.promoPoints },
|
||||
};
|
||||
|
||||
if (isDownload) {
|
||||
shoppingCartItem.destination = { data: { target: 16 } };
|
||||
canAddItemsPayload.push({
|
||||
|
||||
@@ -8,7 +8,6 @@ import { UiCommonModule } from '@ui/common';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { UiSelectBulletModule } from '@ui/select-bullet';
|
||||
import { UiTooltipModule } from '@ui/tooltip';
|
||||
import { UiOrderByFilterModule } from 'apps/ui/filter/src/lib/next/order-by-filter/order-by-filter.module';
|
||||
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
|
||||
import { AddedToCartModalComponent } from './added-to-cart-modal/added-to-cart-modal.component';
|
||||
import { StockInfosPipe } from './order-by-filter/stick-infos.pipe';
|
||||
@@ -16,6 +15,9 @@ import { SearchResultItemLoadingComponent } from './search-result-item-loading.c
|
||||
import { SearchResultItemComponent } from './search-result-item.component';
|
||||
import { ArticleSearchResultsComponent } from './search-results.component';
|
||||
import { SearchResultSelectedPipe } from './selected/search-result-selected.pipe';
|
||||
import { FilterAutocompleteProvider, FilterNextModule, OrderByFilterModule } from 'apps/shared/components/filter/src/lib';
|
||||
import { FocusSearchboxEvent } from '../focus-searchbox.event';
|
||||
import { ArticleSearchMainAutocompleteProvider } from '../providers';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -27,9 +29,10 @@ import { SearchResultSelectedPipe } from './selected/search-result-selected.pipe
|
||||
UiIconModule,
|
||||
UiSelectBulletModule,
|
||||
UiSpinnerModule,
|
||||
UiOrderByFilterModule,
|
||||
OrderByFilterModule,
|
||||
ScrollingModule,
|
||||
UiTooltipModule,
|
||||
FilterNextModule,
|
||||
],
|
||||
exports: [ArticleSearchResultsComponent, SearchResultItemComponent],
|
||||
declarations: [
|
||||
@@ -40,6 +43,13 @@ import { SearchResultSelectedPipe } from './selected/search-result-selected.pipe
|
||||
SearchResultSelectedPipe,
|
||||
AddedToCartModalComponent,
|
||||
],
|
||||
providers: [],
|
||||
providers: [
|
||||
FocusSearchboxEvent,
|
||||
{
|
||||
provide: FilterAutocompleteProvider,
|
||||
useClass: ArticleSearchMainAutocompleteProvider,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class SearchResultsModule {}
|
||||
|
||||
@@ -2,10 +2,65 @@ import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { ArticleDetailsComponent } from './article-details/article-details.component';
|
||||
import { ArticleSearchComponent } from './article-search/article-search.component';
|
||||
import { ArticleSearchFilterComponent } from './article-search/search-filter/search-filter.component';
|
||||
import { ArticleSearchMainComponent } from './article-search/search-main/search-main.component';
|
||||
import { ArticleSearchResultsComponent } from './article-search/search-results/search-results.component';
|
||||
import { PageCatalogComponent } from './page-catalog.component';
|
||||
|
||||
const auxiliaryRoutes = [
|
||||
{
|
||||
path: 'search',
|
||||
component: ArticleSearchComponent,
|
||||
outlet: 'left',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: ArticleSearchMainComponent,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'filter',
|
||||
component: ArticleSearchFilterComponent,
|
||||
outlet: 'right',
|
||||
},
|
||||
{
|
||||
path: 'filter/:id',
|
||||
component: ArticleSearchFilterComponent,
|
||||
outlet: 'right',
|
||||
},
|
||||
{
|
||||
path: 'results',
|
||||
component: ArticleSearchResultsComponent,
|
||||
outlet: 'left',
|
||||
},
|
||||
{
|
||||
path: 'results',
|
||||
component: ArticleSearchResultsComponent,
|
||||
outlet: 'main',
|
||||
},
|
||||
{
|
||||
path: 'results/:id',
|
||||
component: ArticleSearchResultsComponent,
|
||||
outlet: 'left',
|
||||
},
|
||||
{
|
||||
path: 'results/ean/:ean',
|
||||
component: ArticleSearchResultsComponent,
|
||||
outlet: 'left',
|
||||
},
|
||||
{
|
||||
path: 'details/ean/:ean',
|
||||
component: ArticleDetailsComponent,
|
||||
outlet: 'right',
|
||||
},
|
||||
{
|
||||
path: 'details/:id',
|
||||
component: ArticleDetailsComponent,
|
||||
outlet: 'right',
|
||||
},
|
||||
];
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
@@ -19,12 +74,16 @@ const routes: Routes = [
|
||||
path: '',
|
||||
component: ArticleSearchMainComponent,
|
||||
},
|
||||
{
|
||||
path: 'results',
|
||||
component: ArticleSearchResultsComponent,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'results',
|
||||
component: ArticleSearchResultsComponent,
|
||||
},
|
||||
{
|
||||
path: 'filter',
|
||||
component: ArticleSearchFilterComponent,
|
||||
},
|
||||
{
|
||||
path: 'details/ean/:ean',
|
||||
component: ArticleDetailsComponent,
|
||||
@@ -33,6 +92,7 @@ const routes: Routes = [
|
||||
path: 'details/:id',
|
||||
component: ArticleDetailsComponent,
|
||||
},
|
||||
...auxiliaryRoutes,
|
||||
{
|
||||
path: '',
|
||||
pathMatch: 'full',
|
||||
|
||||
@@ -8,4 +8,25 @@
|
||||
>
|
||||
</shared-branch-selector>
|
||||
</shared-breadcrumb>
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
<ng-container *ngIf="routerEvents$ | async">
|
||||
<ng-container *ngIf="!(isDesktop$ | async); else desktop">
|
||||
<router-outlet></router-outlet>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #desktop>
|
||||
<ng-container *ngIf="showMainOutlet$ | async">
|
||||
<router-outlet name="main"></router-outlet>
|
||||
</ng-container>
|
||||
|
||||
<div class="grid grid-cols-[minmax(31rem,.5fr)_1fr] gap-6">
|
||||
<div *ngIf="showLeftOutlet$ | async" class="block">
|
||||
<router-outlet name="left"></router-outlet>
|
||||
</div>
|
||||
|
||||
<div *ngIf="showRightOutlet$ | async">
|
||||
<router-outlet name="right"></router-outlet>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
:host {
|
||||
@apply block relative;
|
||||
@apply block relative h-[calc(100vh-16.5rem)] desktop-small:h-[calc(100vh-15.1rem)];
|
||||
}
|
||||
|
||||
shell-breadcrumb {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { AuthService } from '@core/auth';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
@@ -6,8 +7,8 @@ import { BranchSelectorComponent } from '@shared/components/branch-selector';
|
||||
import { BreadcrumbComponent } from '@shared/components/breadcrumb';
|
||||
import { BranchDTO } from '@swagger/checkout';
|
||||
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
|
||||
import { BehaviorSubject, from, fromEvent, Observable, Subject } from 'rxjs';
|
||||
import { first, map, switchMap, takeUntil } from 'rxjs/operators';
|
||||
import { fromEvent, Observable, Subject } from 'rxjs';
|
||||
import { first, map, shareReplay, switchMap, takeUntil, withLatestFrom } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'page-catalog',
|
||||
@@ -28,37 +29,60 @@ export class PageCatalogComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
_onDestroy$ = new Subject<boolean>();
|
||||
|
||||
get isTablet$() {
|
||||
return this._environmentService.matchTablet$.pipe(
|
||||
map((state) => state.matches),
|
||||
shareReplay()
|
||||
);
|
||||
}
|
||||
|
||||
get isDesktop$() {
|
||||
return this._environmentService.matchDesktop$.pipe(
|
||||
map((state) => {
|
||||
return state.matches;
|
||||
}),
|
||||
shareReplay()
|
||||
);
|
||||
}
|
||||
|
||||
routerEvents$ = this._router.events.pipe(shareReplay());
|
||||
|
||||
showMainOutlet$ = this.routerEvents$.pipe(map((_) => !!this._activatedRoute?.children?.find((child) => child?.outlet === 'main')));
|
||||
|
||||
showLeftOutlet$ = this.routerEvents$.pipe(map((_) => !!this._activatedRoute?.children?.find((child) => child?.outlet === 'left')));
|
||||
|
||||
showRightOutlet$ = this.routerEvents$.pipe(map((_) => !!this._activatedRoute?.children?.find((child) => child?.outlet === 'right')));
|
||||
|
||||
constructor(
|
||||
public application: ApplicationService,
|
||||
private _uiModal: UiModalService,
|
||||
public auth: AuthService,
|
||||
private _environmentService: EnvironmentService,
|
||||
private _renderer: Renderer2
|
||||
private _renderer: Renderer2,
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _router: Router
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
// this.auth.getClaims();
|
||||
this.activatedProcessId$ = this.application.activatedProcessId$.pipe(map((processId) => String(processId)));
|
||||
|
||||
this.selectedBranch$ = this.activatedProcessId$.pipe(switchMap((processId) => this.application.getSelectedBranch$(Number(processId))));
|
||||
|
||||
this.application.setTitle('Artikelsuche');
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
if (this._environmentService.isTablet()) {
|
||||
fromEvent(this.branchSelectorRef.nativeElement, 'focusin')
|
||||
.pipe(takeUntil(this._onDestroy$))
|
||||
.subscribe((_) => {
|
||||
fromEvent(this.branchSelectorRef.nativeElement, 'focusin')
|
||||
.pipe(takeUntil(this._onDestroy$), withLatestFrom(this.isTablet$))
|
||||
.subscribe(([_, isTablet]) => {
|
||||
if (isTablet) {
|
||||
this._renderer.setStyle(this.branchSelectorRef?.nativeElement, 'width', this.branchSelectorWidth);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
fromEvent(this.branchSelectorRef.nativeElement, 'focusout')
|
||||
.pipe(takeUntil(this._onDestroy$))
|
||||
.subscribe((_) => {
|
||||
this._renderer.removeStyle(this.branchSelectorRef?.nativeElement, 'width');
|
||||
});
|
||||
}
|
||||
fromEvent(this.branchSelectorRef.nativeElement, 'focusout')
|
||||
.pipe(takeUntil(this._onDestroy$))
|
||||
.subscribe((_) => {
|
||||
this._renderer.removeStyle(this.branchSelectorRef?.nativeElement, 'width');
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
@apply block bg-white shadow-card rounded-card pt-6;
|
||||
@apply block bg-white shadow-card rounded pt-6;
|
||||
|
||||
.header {
|
||||
@apply text-right;
|
||||
@@ -12,11 +12,11 @@
|
||||
@apply text-center;
|
||||
|
||||
.title {
|
||||
@apply text-2xl text-page-heading font-bold;
|
||||
@apply text-h3 text-h2 font-bold;
|
||||
}
|
||||
|
||||
.paragraph {
|
||||
@apply text-2xl mt-1 mb-0;
|
||||
@apply text-h3 mt-1 mb-0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ button {
|
||||
}
|
||||
|
||||
.card {
|
||||
@apply bg-white rounded-card shadow-card;
|
||||
@apply bg-white rounded shadow-card;
|
||||
}
|
||||
|
||||
.card-empty {
|
||||
@@ -26,7 +26,7 @@ button {
|
||||
width: fit-content;
|
||||
|
||||
h1 {
|
||||
@apply text-2xl font-bold my-1;
|
||||
@apply text-h3 font-bold my-1;
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ button {
|
||||
}
|
||||
|
||||
.sub-header {
|
||||
@apply text-center text-2xl font-normal my-0 mb-8;
|
||||
@apply text-center text-h3 font-normal my-0 mb-8;
|
||||
}
|
||||
|
||||
hr {
|
||||
@@ -134,7 +134,7 @@ h1 {
|
||||
}
|
||||
|
||||
.branch-name {
|
||||
@apply text-regular overflow-hidden overflow-ellipsis ml-4;
|
||||
@apply text-p2 overflow-hidden overflow-ellipsis ml-4;
|
||||
}
|
||||
|
||||
.book-icon {
|
||||
@@ -156,7 +156,7 @@ h1 {
|
||||
}
|
||||
|
||||
.shipping-cost-info {
|
||||
@apply text-sm mr-4 self-end;
|
||||
@apply text-p3 mr-4 self-end;
|
||||
}
|
||||
|
||||
.total-value {
|
||||
@@ -164,5 +164,5 @@ h1 {
|
||||
}
|
||||
|
||||
.total-item-reading-points {
|
||||
@apply text-base font-bold text-ucla-blue;
|
||||
@apply text-p2 font-bold text-ucla-blue;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ button {
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 150px;
|
||||
@apply rounded-card shadow-cta;
|
||||
@apply rounded shadow-cta;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,11 +59,11 @@ button {
|
||||
}
|
||||
|
||||
.item-title.md {
|
||||
@apply font-bold text-base;
|
||||
@apply font-bold text-p2;
|
||||
}
|
||||
|
||||
.item-title.sm {
|
||||
@apply font-bold text-sm;
|
||||
@apply font-bold text-p3;
|
||||
}
|
||||
|
||||
.item-title.xs {
|
||||
@@ -88,7 +88,7 @@ button {
|
||||
}
|
||||
|
||||
.quantity-error {
|
||||
@apply text-dark-goldenrod font-bold text-sm whitespace-nowrap;
|
||||
@apply text-dark-goldenrod font-bold text-p3 whitespace-nowrap;
|
||||
}
|
||||
|
||||
ui-quantity-dropdown {
|
||||
@@ -113,7 +113,7 @@ button {
|
||||
}
|
||||
|
||||
.item-availability-message {
|
||||
@apply text-dark-goldenrod font-bold text-sm whitespace-nowrap;
|
||||
@apply text-dark-goldenrod font-bold text-p3 whitespace-nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,11 +13,11 @@ label {
|
||||
}
|
||||
|
||||
textarea {
|
||||
@apply flex-grow text-base border-none outline-none p-0 resize-none;
|
||||
@apply flex-grow text-p2 border-none outline-none p-0 resize-none;
|
||||
}
|
||||
|
||||
button {
|
||||
@apply text-brand font-bold text-cta-l outline-none border-none bg-transparent ml-1;
|
||||
@apply text-brand font-bold text-p1 outline-none border-none bg-transparent ml-1;
|
||||
|
||||
ui-icon {
|
||||
@apply text-ucla-blue;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
}
|
||||
|
||||
.card {
|
||||
@apply bg-white rounded-card shadow-card overflow-scroll;
|
||||
@apply bg-white rounded shadow-card overflow-scroll;
|
||||
height: calc(100vh - 410px);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
}
|
||||
|
||||
.order-customer {
|
||||
@apply font-bold text-2xl;
|
||||
@apply font-bold text-h3;
|
||||
}
|
||||
|
||||
.grow {
|
||||
@@ -178,15 +178,15 @@
|
||||
}
|
||||
|
||||
.promotion-points {
|
||||
@apply text-ucla-blue text-regular font-bold flex-grow;
|
||||
@apply text-ucla-blue text-p2 font-bold flex-grow;
|
||||
}
|
||||
|
||||
.total-price {
|
||||
@apply font-bold text-cta-l;
|
||||
@apply font-bold text-p1;
|
||||
}
|
||||
|
||||
.price-info {
|
||||
@apply text-right text-sm;
|
||||
@apply text-right text-p3;
|
||||
}
|
||||
|
||||
.actions {
|
||||
|
||||
@@ -13,7 +13,5 @@ export class PageCheckoutComponent implements OnInit {
|
||||
|
||||
constructor(private applicationService: ApplicationService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.applicationService.setTitle('Warenkorb');
|
||||
}
|
||||
ngOnInit() {}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { DomainCustomerOrderService, DomainGoodsService, DomainOmsService, OrderItemsContext } from '@domain/oms';
|
||||
import { ComponentStore, tapResponse } from '@ngrx/component-store';
|
||||
import { ListResponseArgsOfOrderItemListItemDTO, OrderItemListItemDTO, OrderItemProcessingStatusValue } from '@swagger/oms';
|
||||
@@ -63,13 +64,18 @@ export class CustomerOrderDetailsComponent extends ComponentStore<CustomerOrderD
|
||||
|
||||
private _onDestroy$ = new Subject();
|
||||
|
||||
get isTablet() {
|
||||
return this._environment.matchTablet();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _domainGoodsInService: DomainCustomerOrderService,
|
||||
private _omsService: DomainOmsService,
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
private _router: Router,
|
||||
private _uiModal: UiModalService
|
||||
private _uiModal: UiModalService,
|
||||
private _environment: EnvironmentService
|
||||
) {
|
||||
super({
|
||||
fetching: false,
|
||||
@@ -187,19 +193,37 @@ export class CustomerOrderDetailsComponent extends ComponentStore<CustomerOrderD
|
||||
}
|
||||
|
||||
navigateToEditPage(orderItem: OrderItemListItemDTO) {
|
||||
// if (this.isTablet) {
|
||||
this._router.navigate([this.getEditPath(orderItem)], {
|
||||
queryParams: { orderNumber: orderItem.orderNumber, buyerNumber: orderItem.buyerNumber, archive: this.archive },
|
||||
queryParams: { buyerNumber: orderItem.buyerNumber, archive: this.archive },
|
||||
});
|
||||
// } else {
|
||||
// this._router.navigate(this.getEditPathDesktop(orderItem), {
|
||||
// queryParamsHandling: 'preserve',
|
||||
// queryParams: { buyerNumber: orderItem.buyerNumber, archive: this.archive },
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
navigateToDetailsPage(item: OrderItemListItemDTO) {
|
||||
// if (this.isTablet) {
|
||||
this._router.navigate([this.getDetailsPath(item)], {
|
||||
queryParams: { buyerNumber: item.buyerNumber, archive: this.archive },
|
||||
});
|
||||
// } else {
|
||||
// this._router.navigate(this.getDetailsPathDesktop(item), {
|
||||
// queryParamsHandling: 'preserve',
|
||||
// queryParams: { buyerNumber: item.buyerNumber, archive: this.archive },
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
navigateToLandingPage() {
|
||||
// if (this.isTablet) {
|
||||
this._router.navigate([`/kunde/${this.processId}/order`]);
|
||||
// } else {
|
||||
// this._router.navigate(['/kunde', this.processId, 'order', { outlets: { main: null, left: 'search', right: 'filter' } }]);
|
||||
// }
|
||||
}
|
||||
|
||||
async actionHandled(handler: { orderItemsContext: OrderItemsContext; command: string; navigation: 'details' | 'main' | 'reservation' }) {
|
||||
@@ -218,9 +242,65 @@ export class CustomerOrderDetailsComponent extends ComponentStore<CustomerOrderD
|
||||
: `/kunde/${this.processId}/order/details/order/${encodeURIComponent(item?.orderNumber)}/${item?.processingStatus}`;
|
||||
}
|
||||
|
||||
// getDetailsPathDesktop(item: OrderItemListItemDTO) {
|
||||
// return item?.compartmentCode
|
||||
// ? [
|
||||
// '/kunde',
|
||||
// this.processId,
|
||||
// 'order',
|
||||
// {
|
||||
// outlets: {
|
||||
// main: null,
|
||||
// left: 'results',
|
||||
// right: ['details', 'compartment', encodeURIComponent(item?.compartmentCode), item?.processingStatus],
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
// : [
|
||||
// '/kunde',
|
||||
// this.processId,
|
||||
// 'order',
|
||||
// {
|
||||
// outlets: {
|
||||
// main: null,
|
||||
// left: 'results',
|
||||
// right: ['details', 'order', encodeURIComponent(item?.orderNumber), item?.processingStatus],
|
||||
// },
|
||||
// },
|
||||
// ];
|
||||
// }
|
||||
|
||||
getEditPath(item: OrderItemListItemDTO) {
|
||||
return item?.compartmentCode
|
||||
? `/kunde/${this.processId}/order/details/compartment/${encodeURIComponent(item?.compartmentCode)}/${item?.processingStatus}/edit`
|
||||
: `/kunde/${this.processId}/order/details/order/${encodeURIComponent(item?.orderNumber)}/${item?.processingStatus}/edit`;
|
||||
}
|
||||
|
||||
// getEditPathDesktop(item: OrderItemListItemDTO) {
|
||||
// return item?.compartmentCode
|
||||
// ? [
|
||||
// '/kunde',
|
||||
// this.processId,
|
||||
// 'order',
|
||||
// {
|
||||
// outlets: {
|
||||
// main: null,
|
||||
// left: 'results',
|
||||
// right: ['details', 'compartment', encodeURIComponent(item?.compartmentCode), item?.processingStatus, 'edit'],
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
// : [
|
||||
// '/kunde',
|
||||
// this.processId,
|
||||
// 'order',
|
||||
// {
|
||||
// outlets: {
|
||||
// main: null,
|
||||
// left: 'results',
|
||||
// right: ['details', 'order', encodeURIComponent(item?.orderNumber), item?.processingStatus, 'edit'],
|
||||
// },
|
||||
// },
|
||||
// ];
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { DomainCustomerOrderService, DomainGoodsService, DomainOmsService } from '@domain/oms';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
||||
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
|
||||
@@ -48,12 +49,17 @@ export class CustomerOrderEditComponent implements OnInit {
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
get isTablet() {
|
||||
return this._environment.matchTablet();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
private _domainGoodsInService: DomainCustomerOrderService,
|
||||
private _router: Router,
|
||||
private _uiModal: UiModalService
|
||||
private _uiModal: UiModalService,
|
||||
private _environment: EnvironmentService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -84,6 +90,8 @@ export class CustomerOrderEditComponent implements OnInit {
|
||||
const processingStatus = options?.processingStatus ? options.processingStatus : this._activatedRoute.snapshot.params.processingStatus;
|
||||
const buyerNumber = this._activatedRoute.snapshot.queryParams.buyerNumber;
|
||||
const archive = this._activatedRoute.snapshot.queryParams.archive;
|
||||
|
||||
// if (this.isTablet) {
|
||||
compartmentCode
|
||||
? this._router.navigate(
|
||||
[`/kunde/${this.processId}/order/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}`],
|
||||
@@ -92,6 +100,42 @@ export class CustomerOrderEditComponent implements OnInit {
|
||||
: this._router.navigate([`/kunde/${this.processId}/order/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}`], {
|
||||
queryParams: { buyerNumber, archive },
|
||||
});
|
||||
// } else {
|
||||
// compartmentCode
|
||||
// ? this._router.navigate(
|
||||
// [
|
||||
// '/kunde',
|
||||
// this.processId,
|
||||
// 'order',
|
||||
// {
|
||||
// outlets: {
|
||||
// main: null,
|
||||
// left: 'results',
|
||||
// right: ['details', 'compartment', encodeURIComponent(compartmentCode), processingStatus],
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// { queryParamsHandling: 'preserve', queryParams: { buyerNumber, archive } }
|
||||
// )
|
||||
// : this._router.navigate(
|
||||
// [
|
||||
// '/kunde',
|
||||
// this.processId,
|
||||
// 'order',
|
||||
// {
|
||||
// outlets: {
|
||||
// main: null,
|
||||
// left: 'results',
|
||||
// right: ['details', 'order', encodeURIComponent(orderNumber), processingStatus],
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// {
|
||||
// queryParamsHandling: 'preserve',
|
||||
// queryParams: { buyerNumber, archive },
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
||||
openModalIfItemsHaveDifferentCustomers(items: OrderItemListItemDTO[]) {
|
||||
|
||||
@@ -2,11 +2,70 @@ import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { CustomerOrderDetailsComponent, CustomerOrderDetailsModule } from './customer-order-details';
|
||||
import { CustomerOrderEditComponent } from './customer-order-edit';
|
||||
import { CustomerOrderSearchComponent, CustomerOrderSearchModule } from './customer-order-search';
|
||||
import { CustomerOrderSearchComponent, CustomerOrderSearchFilterComponent, CustomerOrderSearchModule } from './customer-order-search';
|
||||
import { CustomerOrderSearchMainComponent, CustomerOrderSearchMainModule } from './customer-order-search/search-main';
|
||||
import { CustomerOrderSearchResultsComponent, CustomerOrderSearchResultsModule } from './customer-order-search/search-results';
|
||||
import { CustomerOrderComponent } from './customer-order.component';
|
||||
|
||||
// const auxiliaryRoutes = [
|
||||
// {
|
||||
// path: 'search',
|
||||
// component: CustomerOrderSearchComponent,
|
||||
// outlet: 'left',
|
||||
// children: [
|
||||
// {
|
||||
// path: '',
|
||||
// component: CustomerOrderSearchMainComponent,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// path: 'filter',
|
||||
// component: CustomerOrderSearchFilterComponent,
|
||||
// outlet: 'right',
|
||||
// },
|
||||
// {
|
||||
// path: 'filter/:compartmentCode/:processingStatus',
|
||||
// component: CustomerOrderSearchFilterComponent,
|
||||
// outlet: 'right',
|
||||
// },
|
||||
// {
|
||||
// path: 'filter/:orderNumber/:processingStatus',
|
||||
// component: CustomerOrderSearchFilterComponent,
|
||||
// outlet: 'right',
|
||||
// },
|
||||
// {
|
||||
// path: 'results',
|
||||
// component: CustomerOrderSearchResultsComponent,
|
||||
// outlet: 'left',
|
||||
// },
|
||||
// {
|
||||
// path: 'results',
|
||||
// component: CustomerOrderSearchResultsComponent,
|
||||
// outlet: 'main',
|
||||
// },
|
||||
// {
|
||||
// path: 'details/compartment/:compartmentCode/:processingStatus',
|
||||
// component: CustomerOrderDetailsComponent,
|
||||
// outlet: 'right',
|
||||
// },
|
||||
// {
|
||||
// path: 'details/order/:orderNumber/:processingStatus',
|
||||
// component: CustomerOrderDetailsComponent,
|
||||
// outlet: 'right',
|
||||
// },
|
||||
// {
|
||||
// path: 'details/compartment/:compartmentCode/:processingStatus/edit',
|
||||
// component: CustomerOrderEditComponent,
|
||||
// outlet: 'right',
|
||||
// },
|
||||
// {
|
||||
// path: 'details/order/:orderNumber/:processingStatus/edit',
|
||||
// component: CustomerOrderEditComponent,
|
||||
// outlet: 'right',
|
||||
// },
|
||||
// ];
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
@@ -20,6 +79,10 @@ const routes: Routes = [
|
||||
{ path: 'results', component: CustomerOrderSearchResultsComponent },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'filter',
|
||||
component: CustomerOrderSearchFilterComponent,
|
||||
},
|
||||
{
|
||||
path: 'details/compartment/:compartmentCode/:processingStatus',
|
||||
component: CustomerOrderDetailsComponent,
|
||||
@@ -36,6 +99,7 @@ const routes: Routes = [
|
||||
path: 'details/order/:orderNumber/:processingStatus/edit',
|
||||
component: CustomerOrderEditComponent,
|
||||
},
|
||||
// ...auxiliaryRoutes,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,31 +1,33 @@
|
||||
<div class="goods-out-search-filter-content">
|
||||
<button class="btn-close" type="button" (click)="close.emit()">
|
||||
<ui-icon icon="close" size="20px"></ui-icon>
|
||||
</button>
|
||||
<ng-container *ngIf="filter$ | async; let filter">
|
||||
<div class="goods-out-search-filter-content">
|
||||
<a class="btn-close" type="button" [routerLink]="closeFilterRouterPath" queryParamsHandling="preserve">
|
||||
<ui-icon icon="close" size="20px"></ui-icon>
|
||||
</a>
|
||||
|
||||
<div class="goods-out-search-filter-content-main">
|
||||
<h1 class="title">Filter</h1>
|
||||
<ui-filter
|
||||
[filter]="filter"
|
||||
[loading]="loading$ | async"
|
||||
(search)="applyFilter()"
|
||||
[hint]="message"
|
||||
resizeInputOptionsToElement="page-goods-out-search-filter .cta-wrapper"
|
||||
[scanner]="true"
|
||||
>
|
||||
<page-order-branch-id-input *uiFilterCustomInput="'order_branch_id'; let input" [input]="input"> </page-order-branch-id-input>
|
||||
</ui-filter>
|
||||
<div class="goods-out-search-filter-content-main">
|
||||
<h1 class="title">Filter</h1>
|
||||
<ui-filter
|
||||
[filter]="filter"
|
||||
[loading]="loading$ | async"
|
||||
(search)="applyFilter(filter)"
|
||||
[hint]="message"
|
||||
resizeInputOptionsToElement="page-goods-out-search-filter .cta-wrapper"
|
||||
[scanner]="true"
|
||||
>
|
||||
<page-order-branch-id-input *uiFilterCustomInput="'order_branch_id'; let input" [input]="input"> </page-order-branch-id-input>
|
||||
</ui-filter>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cta-wrapper">
|
||||
<button class="cta-reset-filter" (click)="resetFilter()" [disabled]="loading$ | async">
|
||||
Filter zurücksetzen
|
||||
</button>
|
||||
<div class="cta-wrapper">
|
||||
<button class="cta-reset-filter" (click)="resetFilter(filter)" [disabled]="loading$ | async">
|
||||
Filter zurücksetzen
|
||||
</button>
|
||||
|
||||
<button class="cta-apply-filter" (click)="applyFilter()" [disabled]="loading$ | async">
|
||||
<ui-spinner [show]="loading$ | async">
|
||||
Filter anwenden
|
||||
</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
<button class="cta-apply-filter" (click)="applyFilter(filter)" [disabled]="loading$ | async">
|
||||
<ui-spinner [show]="loading$ | async">
|
||||
Filter anwenden
|
||||
</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
@@ -22,9 +22,7 @@
|
||||
}
|
||||
|
||||
.cta-wrapper {
|
||||
@apply fixed bottom-8 whitespace-nowrap;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
@apply text-center whitespace-nowrap;
|
||||
}
|
||||
|
||||
.cta-reset-filter,
|
||||
|
||||
@@ -9,13 +9,15 @@ import {
|
||||
Input,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
||||
import { UiFilter, UiFilterComponent } from '@ui/filter';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { take, takeUntil } from 'rxjs/operators';
|
||||
import { map, take, takeUntil } from 'rxjs/operators';
|
||||
import { CustomerOrderSearchStore } from '../customer-order-search.store';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { ApplicationService } from '@core/application';
|
||||
|
||||
@Component({
|
||||
selector: 'page-customer-order-search-filter',
|
||||
@@ -27,12 +29,14 @@ export class CustomerOrderSearchFilterComponent implements OnInit, OnDestroy {
|
||||
@Output()
|
||||
close = new EventEmitter();
|
||||
|
||||
filter: UiFilter;
|
||||
|
||||
loading$: Observable<boolean>;
|
||||
|
||||
message: string;
|
||||
|
||||
get isTablet() {
|
||||
return this._environment.matchTablet();
|
||||
}
|
||||
|
||||
@Input()
|
||||
processId: number;
|
||||
|
||||
@@ -41,11 +45,57 @@ export class CustomerOrderSearchFilterComponent implements OnInit, OnDestroy {
|
||||
@ViewChild(UiFilterComponent, { static: false })
|
||||
uiFilter: UiFilterComponent;
|
||||
|
||||
filter$: Observable<UiFilter>;
|
||||
|
||||
get leftOutletLocation(): string {
|
||||
return this._activatedRoute?.parent?.children?.find((childRoute) => childRoute?.outlet === 'left')?.snapshot?.routeConfig?.path ?? '';
|
||||
}
|
||||
|
||||
get rightOutletParams(): Params {
|
||||
return this._activatedRoute?.parent?.children?.find((childRoute) => childRoute?.outlet === 'right')?.snapshot?.params;
|
||||
}
|
||||
|
||||
get closeFilterRouterPath() {
|
||||
// if (!this.isTablet) {
|
||||
// if (this.leftOutletLocation.includes('results')) {
|
||||
// const params = this.rightOutletParams;
|
||||
// const orderNumber = params?.orderNumber;
|
||||
// const compartmentCode = params?.compartmentCode;
|
||||
// const processingStatus = params?.processingStatus;
|
||||
// return orderNumber
|
||||
// ? [
|
||||
// '/kunde',
|
||||
// this.application.activatedProcessId,
|
||||
// 'order',
|
||||
// { outlets: { main: null, left: 'results', right: ['details', 'order', orderNumber, processingStatus] } },
|
||||
// ]
|
||||
// : [
|
||||
// '/kunde',
|
||||
// this.application.activatedProcessId,
|
||||
// 'order',
|
||||
// {
|
||||
// outlets: {
|
||||
// main: null,
|
||||
// left: 'results',
|
||||
// right: ['details', 'compartment', compartmentCode, processingStatus],
|
||||
// },
|
||||
// },
|
||||
// ];
|
||||
// }
|
||||
// return ['/kunde', this.application.activatedProcessId, 'order', { outlets: { main: null, left: 'search', right: 'filter' } }];
|
||||
// } else {
|
||||
return ['/kunde', this.application.activatedProcessId, 'order', 'results'];
|
||||
// }
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _goodsOutSearchStore: CustomerOrderSearchStore,
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
private _cdr: ChangeDetectorRef,
|
||||
private _router: Router
|
||||
private _router: Router,
|
||||
private _environment: EnvironmentService,
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
public application: ApplicationService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -59,23 +109,23 @@ export class CustomerOrderSearchFilterComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
private _initSettings() {
|
||||
this.filter = UiFilter.create(this._goodsOutSearchStore.filter);
|
||||
this.filter$ = this._goodsOutSearchStore.filter$.pipe(map((filter) => UiFilter.create(filter)));
|
||||
}
|
||||
|
||||
private _initLoading$() {
|
||||
this.loading$ = this._goodsOutSearchStore.fetching$;
|
||||
}
|
||||
|
||||
async resetFilter() {
|
||||
const queryParams = { main_qs: this.filter?.getQueryParams()?.main_qs || '' };
|
||||
async resetFilter(filter: UiFilter) {
|
||||
const queryParams = { main_qs: filter?.getQueryParams()?.main_qs || '' };
|
||||
this._goodsOutSearchStore.resetFilter(queryParams);
|
||||
this._initSettings();
|
||||
this._cdr.markForCheck();
|
||||
}
|
||||
|
||||
async applyFilter() {
|
||||
async applyFilter(filter: UiFilter) {
|
||||
this.uiFilter?.cancelAutocomplete();
|
||||
this._goodsOutSearchStore.setFilter(this.filter);
|
||||
this._goodsOutSearchStore.setFilter(filter);
|
||||
this.message = undefined;
|
||||
|
||||
await this.updateQueryParams();
|
||||
@@ -84,6 +134,7 @@ export class CustomerOrderSearchFilterComponent implements OnInit, OnDestroy {
|
||||
if (result.results.error) {
|
||||
} else {
|
||||
if (result.results.hits > 0) {
|
||||
// if (this.isTablet) {
|
||||
if (result.results.hits === 1) {
|
||||
const orderItem = result.results.result[0];
|
||||
this._router.navigate([this.getDetailsPath(orderItem)]);
|
||||
@@ -92,6 +143,18 @@ export class CustomerOrderSearchFilterComponent implements OnInit, OnDestroy {
|
||||
queryParams: this._goodsOutSearchStore.filter.getQueryParams(),
|
||||
});
|
||||
}
|
||||
// } else {
|
||||
// const orderItem = result.results.result[0];
|
||||
// if (result.results.hits === 1) {
|
||||
// this._router.navigate(this.getDetailsPathDesktop(orderItem, this.processId), {
|
||||
// queryParams: this._goodsOutSearchStore.filter.getQueryParams(),
|
||||
// });
|
||||
// } else {
|
||||
// this._router.navigate(this.getDetailsPathDesktop(orderItem, this.processId), {
|
||||
// queryParams: this._goodsOutSearchStore.filter.getQueryParams(),
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
||||
this.close.emit();
|
||||
} else {
|
||||
@@ -126,4 +189,32 @@ export class CustomerOrderSearchFilterComponent implements OnInit, OnDestroy {
|
||||
? `/kunde/${this.processId}/order/details/compartment/${encodeURIComponent(item?.compartmentCode)}/${item?.processingStatus}`
|
||||
: `/kunde/${this.processId}/order/details/order/${encodeURIComponent(item?.orderNumber)}/${item?.processingStatus}`;
|
||||
}
|
||||
|
||||
// getDetailsPathDesktop(item: OrderItemListItemDTO, processId: number) {
|
||||
// return item?.compartmentCode
|
||||
// ? [
|
||||
// '/kunde',
|
||||
// processId,
|
||||
// 'order',
|
||||
// {
|
||||
// outlets: {
|
||||
// main: null,
|
||||
// left: 'results',
|
||||
// right: ['details', 'compartment', encodeURIComponent(item?.compartmentCode), item?.processingStatus],
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
// : [
|
||||
// '/kunde',
|
||||
// processId,
|
||||
// 'order',
|
||||
// {
|
||||
// outlets: {
|
||||
// main: null,
|
||||
// left: 'results',
|
||||
// right: ['details', 'order', encodeURIComponent(item?.orderNumber), item?.processingStatus],
|
||||
// },
|
||||
// },
|
||||
// ];
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
::ng-deep page-order-branch-id-input shared-branch-selector .shared-branch-selector-input-container {
|
||||
@apply border border-solid border-[#AEB7C1] rounded-card;
|
||||
@apply border border-solid border-[#AEB7C1] rounded;
|
||||
}
|
||||
|
||||
::ng-deep page-order-branch-id-input shared-branch-selector.shared-branch-selector-opend .shared-branch-selector-input-container {
|
||||
|
||||
@@ -25,18 +25,31 @@ export class OrderBranchIdInputComponent extends AbstractUiFilterInputDirective
|
||||
ngOnInit() {
|
||||
this.control.setValue({ id: Number(this.value) });
|
||||
|
||||
const uiInputChangesSub = this.uiInput?.changes?.subscribe((changes) => {
|
||||
const controlValue = this.control?.value?.id;
|
||||
const changesValue = Number(changes?.target?.value);
|
||||
if (controlValue !== changesValue) {
|
||||
this.control.setValue(changesValue && !isNaN(changesValue) ? { id: changesValue } : undefined);
|
||||
}
|
||||
});
|
||||
|
||||
const onInputChangeSub = this.onUiInputChange$.subscribe((input) => {
|
||||
if (this.control.value !== input.value) {
|
||||
this.control.setValue(input.value ? { id: Number(input.value) } : undefined);
|
||||
const controlValue = this.control?.value?.id;
|
||||
const inputValue = Number(input?.value);
|
||||
if (controlValue !== inputValue) {
|
||||
this.control.setValue(inputValue && !isNaN(inputValue) ? { id: inputValue } : undefined);
|
||||
}
|
||||
});
|
||||
|
||||
const onControlValueChangeSub = this.control.valueChanges.subscribe((value) => {
|
||||
if (this.value !== value) {
|
||||
this.setValue(value ? String(value?.id) : undefined);
|
||||
if (!value) {
|
||||
this.setValue(undefined);
|
||||
} else if (this.value !== String(value?.id)) {
|
||||
this.setValue(String(value?.id));
|
||||
}
|
||||
});
|
||||
|
||||
this._subscriptions.add(uiInputChangesSub);
|
||||
this._subscriptions.add(onInputChangeSub);
|
||||
this._subscriptions.add(onControlValueChangeSub);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
<div class="flex flex-row justify-end mb-4">
|
||||
<button class="filter" [class.active]="hasFilter$ | async" (click)="shellFilterOverlay.open()">
|
||||
<ui-icon size="20px" icon="filter_alit"></ui-icon>
|
||||
<span class="label">Filter</span>
|
||||
</button>
|
||||
<div class="page-customer-order-search__header bg-background-liste flex flex-col items-end pb-4">
|
||||
<a
|
||||
[class.active]="hasFilter$ | async"
|
||||
class="page-customer-order-search__filter h-14 rounded font-bold px-5 mb-4 text-lg bg-cadet-blue flex flex-row flex-nowrap items-center justify-center"
|
||||
[routerLink]="filterRoute"
|
||||
queryParamsHandling="preserve"
|
||||
>
|
||||
<ui-svg-icon class="mr-2" icon="filter-variant"></ui-svg-icon>
|
||||
Filter
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
}
|
||||
|
||||
.filter {
|
||||
@apply font-sans flex items-center font-bold bg-wild-blue-yonder border-0 text-regular py-px-8 px-px-15 rounded-filter justify-center;
|
||||
@apply font-sans flex items-center font-bold bg-wild-blue-yonder border-0 text-p2 py-px-8 px-px-15 rounded-filter justify-center;
|
||||
min-width: 106px;
|
||||
|
||||
.label {
|
||||
|
||||
@@ -8,6 +8,7 @@ import { combineLatest, Subject } from 'rxjs';
|
||||
import { map, takeUntil, withLatestFrom } from 'rxjs/operators';
|
||||
import { CustomerOrderSearchStore } from './customer-order-search.store';
|
||||
import { CustomerOrderSearchMainAutocompleteProvider } from './providers/customer-order-search-main-autocomplete.provider';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'page-customer-order-search',
|
||||
@@ -15,7 +16,6 @@ import { CustomerOrderSearchMainAutocompleteProvider } from './providers/custome
|
||||
styleUrls: ['customer-order-search.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [
|
||||
CustomerOrderSearchStore,
|
||||
{
|
||||
provide: UiFilterAutocompleteProvider,
|
||||
useClass: CustomerOrderSearchMainAutocompleteProvider,
|
||||
@@ -32,28 +32,30 @@ import { CustomerOrderSearchMainAutocompleteProvider } from './providers/custome
|
||||
export class CustomerOrderSearchComponent implements OnInit, OnDestroy {
|
||||
private _onDestroy$ = new Subject();
|
||||
|
||||
get isTablet() {
|
||||
return this._environment.matchTablet();
|
||||
}
|
||||
|
||||
hasFilter$ = combineLatest([this._goodsOutSearchStore.filter$, this._goodsOutSearchStore.defaultSettings$]).pipe(
|
||||
map(([filter, defaultFilter]) => !isEqual(filter?.getQueryParams(), UiFilter.create(defaultFilter).getQueryParams()))
|
||||
);
|
||||
|
||||
processId$ = this._activatedRoute.data.pipe(map((data) => +data.processId));
|
||||
processId$ = this._activatedRoute.parent.data.pipe(map((data) => +data.processId));
|
||||
|
||||
get filterRoute() {
|
||||
const processId = this._activatedRoute?.parent?.snapshot?.data?.processId;
|
||||
return ['/kunde', processId, 'order', 'filter'];
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _goodsOutSearchStore: CustomerOrderSearchStore,
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
private _activatedRoute: ActivatedRoute
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _environment: EnvironmentService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.processId$.pipe(takeUntil(this._onDestroy$), withLatestFrom(this._activatedRoute.queryParams)).subscribe(([processId]) => {
|
||||
// if (params && Object.keys(params).length === 0) {
|
||||
// console.log('params is empty');
|
||||
// this._goodsOutSearchStore.setQueryParams(params);
|
||||
// this._goodsOutSearchStore.loadSettings();
|
||||
// } else {
|
||||
// // this._goodsOutSearchStore.resetFilter(params);
|
||||
// }
|
||||
|
||||
this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
|
||||
key: processId,
|
||||
name: 'Kundenbestellung',
|
||||
|
||||
@@ -8,6 +8,7 @@ import { RouterModule } from '@angular/router';
|
||||
import { UiFilterNextModule } from '@ui/filter';
|
||||
import { SharedFilterOverlayModule } from '@shared/components/filter-overlay';
|
||||
import { UiSpinnerModule } from '@ui/spinner';
|
||||
import { CustomerOrderSearchStore } from './customer-order-search.store';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -20,6 +21,7 @@ import { UiSpinnerModule } from '@ui/spinner';
|
||||
OrderBranchIdInputComponent,
|
||||
],
|
||||
exports: [CustomerOrderSearchComponent],
|
||||
providers: [CustomerOrderSearchStore],
|
||||
declarations: [CustomerOrderSearchComponent, CustomerOrderSearchFilterComponent],
|
||||
})
|
||||
export class CustomerOrderSearchModule {}
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
}
|
||||
|
||||
.goods-out-list-navigation {
|
||||
@apply text-center text-2xl text-active-branch block bg-white rounded-t-card font-bold no-underline py-5;
|
||||
@apply text-center text-h3 text-active-branch block bg-white rounded-t font-bold no-underline py-5;
|
||||
}
|
||||
|
||||
.search-main {
|
||||
@apply bg-white text-center rounded-t-card py-5 shadow-card;
|
||||
@apply bg-white text-center rounded-t p-5 shadow-card;
|
||||
height: calc(100vh - 380px);
|
||||
|
||||
.search-main-title {
|
||||
@apply text-2xl font-bold;
|
||||
@apply text-h3 font-bold;
|
||||
}
|
||||
|
||||
.search-main-paragraph {
|
||||
@apply text-2xl mb-12 mt-6;
|
||||
@apply text-h3 mb-12 mt-6;
|
||||
}
|
||||
|
||||
ui-filter-input-group-main {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { debounce, isEqual } from 'lodash';
|
||||
import { BehaviorSubject, combineLatest, Subscription } from 'rxjs';
|
||||
import { debounceTime, first, map, withLatestFrom } from 'rxjs/operators';
|
||||
import { CustomerOrderSearchStore } from '../customer-order-search.store';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'page-customer-order-search-main',
|
||||
@@ -28,10 +29,14 @@ export class CustomerOrderSearchMainComponent implements OnInit, OnDestroy {
|
||||
private _subscriptions = new Subscription();
|
||||
|
||||
get processId() {
|
||||
return +this._activatedRoute.snapshot.data.processId;
|
||||
return +this._activatedRoute.parent.parent.snapshot.data.processId;
|
||||
}
|
||||
|
||||
processId$ = this._activatedRoute.data.pipe(map((data) => +data.processId));
|
||||
processId$ = this._activatedRoute.parent.parent.data.pipe(map((data) => +data.processId));
|
||||
|
||||
get isTablet() {
|
||||
return this._environment.matchTablet();
|
||||
}
|
||||
|
||||
@ViewChild(UiFilterInputGroupMainComponent, { static: false })
|
||||
filterInputGroup: UiFilterInputGroupMainComponent;
|
||||
@@ -41,7 +46,8 @@ export class CustomerOrderSearchMainComponent implements OnInit, OnDestroy {
|
||||
private _cdr: ChangeDetectorRef,
|
||||
private _router: Router,
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _breadcrumb: BreadcrumbService
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
private _environment: EnvironmentService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -106,14 +112,29 @@ export class CustomerOrderSearchMainComponent implements OnInit, OnDestroy {
|
||||
if (result.results.error) {
|
||||
} else {
|
||||
if (result.results.hits > 0) {
|
||||
// if (this.isTablet) {
|
||||
if (result.results.hits === 1) {
|
||||
const orderItem = result.results.result[0];
|
||||
this._router.navigate([this.getDetailsPath(orderItem, this.processId)]);
|
||||
this._router.navigate([this.getDetailsPath(orderItem, this.processId)], {
|
||||
queryParams: this._goodsOutSearchStore.filter.getQueryParams(),
|
||||
});
|
||||
} else {
|
||||
this._router.navigate(['/kunde', this.processId, 'order', 'results'], {
|
||||
queryParams: this._goodsOutSearchStore.filter.getQueryParams(),
|
||||
});
|
||||
}
|
||||
// } else {
|
||||
// const orderItem = result.results.result[0];
|
||||
// if (result.results.hits === 1) {
|
||||
// this._router.navigate(this.getDetailsPathDesktop(orderItem, this.processId), {
|
||||
// queryParams: this._goodsOutSearchStore.filter.getQueryParams(),
|
||||
// });
|
||||
// } else {
|
||||
// this._router.navigate(this.getDetailsPathDesktop(orderItem, this.processId), {
|
||||
// queryParams: this._goodsOutSearchStore.filter.getQueryParams(),
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
} else {
|
||||
this.message = 'keine Suchergebnisse';
|
||||
}
|
||||
@@ -149,6 +170,34 @@ export class CustomerOrderSearchMainComponent implements OnInit, OnDestroy {
|
||||
: `/kunde/${processId}/order/details/order/${encodeURIComponent(item?.orderNumber)}/${item?.processingStatus}`;
|
||||
}
|
||||
|
||||
// getDetailsPathDesktop(item: OrderItemListItemDTO, processId: number) {
|
||||
// return item?.compartmentCode
|
||||
// ? [
|
||||
// '/kunde',
|
||||
// processId,
|
||||
// 'order',
|
||||
// {
|
||||
// outlets: {
|
||||
// main: null,
|
||||
// left: 'results',
|
||||
// right: ['details', 'compartment', encodeURIComponent(item?.compartmentCode), item?.processingStatus],
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
// : [
|
||||
// '/kunde',
|
||||
// processId,
|
||||
// 'order',
|
||||
// {
|
||||
// outlets: {
|
||||
// main: null,
|
||||
// left: 'results',
|
||||
// right: ['details', 'order', encodeURIComponent(item?.orderNumber), item?.processingStatus],
|
||||
// },
|
||||
// },
|
||||
// ];
|
||||
// }
|
||||
|
||||
queryChangeDebounce = debounce(async () => {
|
||||
this.queryChanged$.next(true);
|
||||
await this.updateQueryParams(this.processId);
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<a
|
||||
class="page-customer-order-item__item-card p-5 desktop:p-px-10 h-[212px] desktop:h-[181px] bg-white rounded"
|
||||
[routerLink]="detailsLink"
|
||||
[queryParams]="queryParams"
|
||||
[queryParamsHandling]="!isTablet ? 'preserve' : ''"
|
||||
>
|
||||
{{ item?.product?.name }}
|
||||
<!-- <div class="page-search-result-item__item-thumbnail text-center mr-4 w-[50px] h-[79px]">
|
||||
<img
|
||||
class="page-search-result-item__item-image w-[50px] h-[79px]"
|
||||
loading="lazy"
|
||||
*ngIf="item?.imageId | thumbnailUrl; let thumbnailUrl"
|
||||
[src]="thumbnailUrl"
|
||||
[alt]="item?.product?.name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="grid-container-test">
|
||||
<div
|
||||
class="page-search-result-item__item-title font-bold text-h3"
|
||||
[class.text-xl]="item?.product?.name?.length >= 35"
|
||||
[class.text-lg]="item?.product?.name?.length >= 40"
|
||||
[class.text-md]="item?.product?.name?.length >= 50"
|
||||
[class.text-p3]="item?.product?.name?.length >= 60 || !isTablet"
|
||||
[class.text-xs]="item?.product?.name?.length >= 100 || (!isTablet && item?.product?.name?.length >= 70)"
|
||||
>
|
||||
{{ item?.product?.name }}
|
||||
</div>
|
||||
|
||||
<div class="page-search-result-item__item-special-comment font-bold text-p3">
|
||||
{{ item?.specialComment }}
|
||||
</div>
|
||||
|
||||
<div class="page-search-result-item__item-select-bullet justify-self-end">
|
||||
<input
|
||||
*ngIf="selectable"
|
||||
(click)="$event.stopPropagation()"
|
||||
[ngModel]="selected$ | async"
|
||||
(ngModelChange)="setSelected()"
|
||||
class="isa-select-bullet"
|
||||
type="checkbox"
|
||||
/>
|
||||
</div>
|
||||
</div> -->
|
||||
</a>
|
||||
@@ -0,0 +1,3 @@
|
||||
:host {
|
||||
@apply flex flex-col w-full h-[212px] desktop:h-[181px] bg-white;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { ComponentStore } from '@ngrx/component-store';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
||||
import { isEqual } from 'lodash';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { CustomerOrderSearchStore } from '../customer-order-search.store';
|
||||
|
||||
export interface CustomerOrderItemComponentState {
|
||||
item?: OrderItemListItemDTO;
|
||||
selected: boolean;
|
||||
selectable: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'page-customer-order-item',
|
||||
templateUrl: 'customer-order-item.component.html',
|
||||
styleUrls: ['customer-order-item.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class CustomerOrderItemComponent extends ComponentStore<CustomerOrderItemComponentState> implements OnInit {
|
||||
@Input()
|
||||
get item() {
|
||||
return this.get((s) => s.item);
|
||||
}
|
||||
set item(item: OrderItemListItemDTO) {
|
||||
if (!isEqual(this.item, item)) {
|
||||
this.patchState({ item });
|
||||
}
|
||||
}
|
||||
|
||||
readonly item$ = this.select((s) => s.item);
|
||||
|
||||
// selected$ = this._articleSearchService.selectedItemIds$.pipe(map((selectedItemIds) => selectedItemIds.includes(this.item?.id)));
|
||||
|
||||
@Input()
|
||||
selected: boolean;
|
||||
|
||||
@Input()
|
||||
get selectable() {
|
||||
return this.get((s) => s.selectable);
|
||||
}
|
||||
set selectable(selectable: boolean) {
|
||||
if (this.selectable !== selectable) {
|
||||
this.patchState({ selectable });
|
||||
}
|
||||
}
|
||||
|
||||
@Output()
|
||||
selectedChange = new EventEmitter<boolean>();
|
||||
|
||||
get isTablet() {
|
||||
return this._environment.matchTablet();
|
||||
}
|
||||
|
||||
get queryParams() {
|
||||
const compartmentCode = this.item?.compartmentCode;
|
||||
const archive = !!this._customerOrderStore.filter?.getQueryParams()?.main_archive || false;
|
||||
|
||||
if (compartmentCode) {
|
||||
return {
|
||||
buyerNumber: this.item?.buyerNumber,
|
||||
archive,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
archive,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
get detailsLink() {
|
||||
const orderNumber = this.item?.orderNumber;
|
||||
const processingStatus = this.item?.processingStatus;
|
||||
const compartmentCode = this.item?.compartmentCode;
|
||||
// if (this.isTablet) {
|
||||
if (compartmentCode) {
|
||||
return [
|
||||
`/kunde/${this._applicationService.activatedProcessId}/order/details/compartment/${encodeURIComponent(
|
||||
compartmentCode
|
||||
)}/${processingStatus}`,
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
`/kunde/${this._applicationService.activatedProcessId}/order/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}`,
|
||||
];
|
||||
}
|
||||
// } else {
|
||||
// if (compartmentCode) {
|
||||
// return [
|
||||
// '/kunde',
|
||||
// this._applicationService.activatedProcessId,
|
||||
// 'order',
|
||||
// {
|
||||
// outlets: {
|
||||
// main: null,
|
||||
// left: 'results',
|
||||
// right: ['details', 'compartment', encodeURIComponent(compartmentCode), processingStatus],
|
||||
// },
|
||||
// },
|
||||
// ];
|
||||
// } else {
|
||||
// return [
|
||||
// '/kunde',
|
||||
// this._applicationService.activatedProcessId,
|
||||
// 'order',
|
||||
// { outlets: { main: null, left: 'results', right: ['details', 'order', encodeURIComponent(orderNumber), processingStatus] } },
|
||||
// ];
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _environment: EnvironmentService,
|
||||
private _customerOrderStore: CustomerOrderSearchStore,
|
||||
private _applicationService: ApplicationService
|
||||
) {
|
||||
super({ selected: false, selectable: false });
|
||||
}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
||||
@@ -1,7 +1,28 @@
|
||||
<div class="hits">{{ hits$ | async }} Titel</div>
|
||||
<div class="page-customer-order-search-results__header bg-background-liste flex flex-col items-end pb-4">
|
||||
<!-- <a
|
||||
[class.active]="hasFilter$ | async"
|
||||
class="page-customer-order-search-results__filter h-14 rounded font-bold px-5 mb-4 text-lg bg-cadet-blue flex flex-row flex-nowrap items-center justify-center"
|
||||
[routerLink]="filterRoute"
|
||||
queryParamsHandling="preserve"
|
||||
>
|
||||
<ui-svg-icon class="mr-2" icon="filter-variant"></ui-svg-icon>
|
||||
Filter
|
||||
</a> -->
|
||||
|
||||
<div
|
||||
*ngIf="hits$ | async; let hits"
|
||||
class="page-customer-order-search-results__items-count inline-flex flex-row items-center pr-5 text-p3"
|
||||
>
|
||||
{{ hits ??
|
||||
0 }}
|
||||
Titel
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ui-scroll-container
|
||||
*ngIf="!(listEmpty$ | async); else emptyMessage"
|
||||
[loading]="loading$ | async"
|
||||
[showScrollbar]="false"
|
||||
[showScrollArrow]="false"
|
||||
(reachEnd)="loadMore()"
|
||||
[deltaEnd]="150"
|
||||
[itemLength]="itemLength$ | async"
|
||||
@@ -10,6 +31,22 @@
|
||||
>
|
||||
<ng-container *ngIf="processId$ | async; let processId">
|
||||
<shared-goods-in-out-order-group *ngFor="let bueryNumberGroup of items$ | async | groupBy: byBuyerNumberFn">
|
||||
<!-- <div class="page-customer-order-search__items-list" *ngFor="let bueryNumberGroup of items$ | async | groupBy: byBuyerNumberFn">
|
||||
<ng-container *ngIf="bueryNumberGroup.items[0]; let firstItem">
|
||||
<div class="page-customer-order-search__item-header-group bg-white text-xl rounded-t p-4 font-bold mb-px-2">
|
||||
<h3 class="mt-0 mb-4">
|
||||
{{ firstItem?.organisation }}
|
||||
<ng-container *ngIf="!!firstItem?.organisation && (!!firstItem?.firstName || !!firstItem?.lastName)"> - </ng-container>
|
||||
{{ firstItem?.lastName }}
|
||||
{{ firstItem?.firstName }}
|
||||
</h3>
|
||||
<h4 class="mt-0 mb-0">
|
||||
{{ firstItem?.buyerNumber }}
|
||||
ans lager (nicht abgeholt) bezahlt
|
||||
</h4>
|
||||
</div>
|
||||
</ng-container> -->
|
||||
|
||||
<ng-container *ngFor="let orderNumberGroup of bueryNumberGroup.items | groupBy: byOrderNumberFn; let lastOrderNumber = last">
|
||||
<ng-container
|
||||
*ngFor="let processingStatusGroup of orderNumberGroup.items | groupBy: byProcessingStatusFn; let lastProcessingStatus = last"
|
||||
@@ -26,6 +63,17 @@
|
||||
[selected]="item | goodsOutItemSelected: selectedOrderItemSubsetIds"
|
||||
(selectedChange)="setSelectedItem(item, $event)"
|
||||
></shared-goods-in-out-order-group-item>
|
||||
|
||||
<!-- <page-customer-order-item
|
||||
*ngFor="let item of compartmentCodeGroup.items; let firstItem = first; trackBy: trackByFn"
|
||||
class="mb-px-10"
|
||||
[selectable]="item | goodsOutItemSelectable: selectionRules:selectedItems"
|
||||
[selected]="item | goodsOutItemSelected: selectedOrderItemSubsetIds"
|
||||
[item]="item"
|
||||
(click)="navigateToDetails(processId, item)"
|
||||
(selectedChange)="setSelectedItem(item, $event)"
|
||||
></page-customer-order-item> -->
|
||||
|
||||
<div class="divider" *ngIf="!lastCompartmentCode"></div>
|
||||
</ng-container>
|
||||
<div class="divider" *ngIf="!lastProcessingStatus"></div>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// :host {
|
||||
// @apply box-border block h-[100vh] max-h-[calc(100vh-364px)] desktop:max-h-[calc(100vh-300px)];
|
||||
// }
|
||||
|
||||
:host {
|
||||
@apply block relative;
|
||||
}
|
||||
|
||||
.hits {
|
||||
@apply text-active-customer text-right mb-3 font-semibold text-base;
|
||||
}
|
||||
|
||||
.empty-message {
|
||||
@apply bg-white text-center font-semibold text-inactive-customer py-10 rounded-card;
|
||||
@apply bg-white text-center font-semibold text-inactive-customer py-10 rounded;
|
||||
}
|
||||
|
||||
.divider {
|
||||
@@ -18,6 +18,10 @@ shared-goods-in-out-order-group-item {
|
||||
@apply cursor-pointer;
|
||||
}
|
||||
|
||||
// page-customer-order-item {
|
||||
// @apply cursor-pointer;
|
||||
// }
|
||||
|
||||
.actions {
|
||||
@apply fixed bottom-28 inline-grid grid-flow-col gap-7;
|
||||
left: 50%;
|
||||
@@ -40,6 +44,10 @@ shared-goods-in-out-order-group-item {
|
||||
}
|
||||
}
|
||||
|
||||
// ::ng-deep page-customer-order-search-results ui-scroll-container .scroll-container {
|
||||
// max-height: calc(100vh - 25.5rem) !important;
|
||||
// }
|
||||
|
||||
::ng-deep .desktop page-goods-out-search-results ui-scroll-container {
|
||||
.scrollbar-gap::-webkit-scrollbar-track {
|
||||
margin-bottom: 7.25rem;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, ViewChild, TrackByFunction } from '@angular/core';
|
||||
import { debounceTime, first, map, shareReplay, takeUntil, withLatestFrom } from 'rxjs/operators';
|
||||
import { debounceTime, filter, first, map, shareReplay, takeUntil, withLatestFrom } from 'rxjs/operators';
|
||||
import { KeyValueDTOOfStringAndString, OrderItemListItemDTO } from '@swagger/oms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ActivatedRoute, ChildrenOutletContexts, Params, Router } from '@angular/router';
|
||||
import { CustomerOrderSearchStore } from '../customer-order-search.store';
|
||||
import { BehaviorSubject, combineLatest, Observable, Subject, Subscription } from 'rxjs';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
@@ -11,6 +11,8 @@ import { OrderItemsContext } from '@domain/oms';
|
||||
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
|
||||
import { UiScrollContainerComponent } from '@ui/scroll-container';
|
||||
import { UiFilter } from '@ui/filter';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
export interface CustomerOrderSearchResultsState {
|
||||
selectedOrderItemSubsetIds: number[];
|
||||
@@ -80,13 +82,51 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
|
||||
|
||||
scrollTo: number;
|
||||
|
||||
filter$ = this._goodsOutSearchStore.filter$;
|
||||
|
||||
initialFilter$ = this.filter$.pipe(
|
||||
filter((filter) => !!filter),
|
||||
first()
|
||||
);
|
||||
|
||||
hasFilter$ = this.filter$.pipe(
|
||||
withLatestFrom(this.initialFilter$),
|
||||
map(([filter, initialFilter]) => !isEqual(filter?.getQueryParams(), initialFilter?.getQueryParams()))
|
||||
);
|
||||
|
||||
get isTablet() {
|
||||
return this._environment.matchTablet();
|
||||
}
|
||||
|
||||
get rightOutletParams(): Params {
|
||||
return this._activatedRoute?.parent?.children?.find((childRoute) => childRoute?.outlet === 'right')?.snapshot?.params;
|
||||
}
|
||||
|
||||
get filterRoute() {
|
||||
const processId = this._activatedRoute?.parent?.snapshot?.data?.processId;
|
||||
// if (!this.isTablet) {
|
||||
// const orderNumber = this.rightOutletParams?.orderNumber;
|
||||
// const compartmentCode = this.rightOutletParams?.compartmentCode;
|
||||
// const processingStatus = this.rightOutletParams?.processingStatus;
|
||||
// return [
|
||||
// '/kunde',
|
||||
// processId,
|
||||
// 'order',
|
||||
// { outlets: { main: null, left: 'results', right: ['filter', orderNumber ?? compartmentCode, processingStatus] } },
|
||||
// ];
|
||||
// } else {
|
||||
return ['/kunde', processId, 'order', 'filter'];
|
||||
// }
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _goodsOutSearchStore: CustomerOrderSearchStore,
|
||||
private _router: Router,
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
private _commandService: CommandService,
|
||||
private _modal: UiModalService
|
||||
private _modal: UiModalService,
|
||||
private _environment: EnvironmentService
|
||||
) {
|
||||
super({
|
||||
selectedOrderItemSubsetIds: [],
|
||||
@@ -263,6 +303,7 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
|
||||
const compartmentCode = orderItem.compartmentCode;
|
||||
const archive = !!this._goodsOutSearchStore.filter?.getQueryParams()?.main_archive || false;
|
||||
|
||||
// if (this.isTablet) {
|
||||
if (compartmentCode) {
|
||||
this._router.navigate([`/kunde/${processId}/order/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}`], {
|
||||
queryParams: {
|
||||
@@ -277,6 +318,46 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
|
||||
},
|
||||
});
|
||||
}
|
||||
// } else {
|
||||
// if (compartmentCode) {
|
||||
// this._router.navigate(
|
||||
// [
|
||||
// '/kunde',
|
||||
// processId,
|
||||
// 'order',
|
||||
// {
|
||||
// outlets: {
|
||||
// main: null,
|
||||
// left: 'results',
|
||||
// right: ['details', 'compartment', encodeURIComponent(compartmentCode), processingStatus],
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// {
|
||||
// queryParamsHandling: 'preserve',
|
||||
// queryParams: {
|
||||
// buyerNumber: orderItem.buyerNumber,
|
||||
// archive,
|
||||
// },
|
||||
// }
|
||||
// );
|
||||
// } else {
|
||||
// this._router.navigate(
|
||||
// [
|
||||
// '/kunde',
|
||||
// processId,
|
||||
// 'order',
|
||||
// { outlets: { main: null, left: 'results', right: ['details', 'order', encodeURIComponent(orderNumber), processingStatus] } },
|
||||
// ],
|
||||
// {
|
||||
// queryParamsHandling: 'preserve',
|
||||
// queryParams: {
|
||||
// archive,
|
||||
// },
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
setSelectedItem(item: OrderItemListItemDTO, selected: boolean) {
|
||||
|
||||
@@ -8,10 +8,18 @@ import { CustomerOrderItemSelectablePipe } from './customer-order-item-selectabl
|
||||
import { CustomerOrderItemSelectedPipe } from './customer-order-item-selectede.pipe';
|
||||
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
|
||||
import { UiScrollContainerModule } from '@ui/scroll-container';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { CustomerOrderItemComponent } from './customer-order-item.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, GoodsInOutOrderGroupModule, UiCommonModule, UiSpinnerModule, UiScrollContainerModule],
|
||||
exports: [CustomerOrderSearchResultsComponent],
|
||||
declarations: [CustomerOrderSearchResultsComponent, CustomerOrderItemSelectablePipe, CustomerOrderItemSelectedPipe],
|
||||
imports: [CommonModule, RouterModule, GoodsInOutOrderGroupModule, UiCommonModule, UiIconModule, UiSpinnerModule, UiScrollContainerModule],
|
||||
exports: [CustomerOrderSearchResultsComponent, CustomerOrderItemComponent],
|
||||
declarations: [
|
||||
CustomerOrderSearchResultsComponent,
|
||||
CustomerOrderItemSelectablePipe,
|
||||
CustomerOrderItemSelectedPipe,
|
||||
CustomerOrderItemComponent,
|
||||
],
|
||||
})
|
||||
export class CustomerOrderSearchResultsModule {}
|
||||
|
||||
@@ -2,3 +2,4 @@ export * from './customer-order-item-selectable.pipe';
|
||||
export * from './customer-order-item-selectede.pipe';
|
||||
export * from './customer-order-search-results.component';
|
||||
export * from './customer-order-search-results.module';
|
||||
export * from './customer-order-item.component';
|
||||
|
||||
@@ -8,4 +8,19 @@
|
||||
</shared-branch-selector>
|
||||
</shared-breadcrumb>
|
||||
|
||||
<!-- <ng-container *ngIf="isTablet; else desktop"> -->
|
||||
<router-outlet></router-outlet>
|
||||
<!-- </ng-container>
|
||||
|
||||
<ng-template #desktop>
|
||||
<router-outlet name="main"></router-outlet>
|
||||
<div class="grid desktop:grid-cols-[31rem_auto]">
|
||||
<div class="mr-6 hidden desktop:block">
|
||||
<router-outlet name="left"></router-outlet>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<router-outlet name="right"></router-outlet>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template> -->
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ActivatedRoute } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { AuthService } from '@core/auth';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { BranchDTO } from '@swagger/checkout';
|
||||
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
|
||||
import { Observable } from 'rxjs';
|
||||
@@ -19,6 +20,10 @@ export class CustomerOrderComponent implements OnInit {
|
||||
|
||||
selectedBranch$: Observable<BranchDTO>;
|
||||
|
||||
get isTablet() {
|
||||
return this._environmentService.matchTablet();
|
||||
}
|
||||
|
||||
onCustomerOrderDetailsPage$: Observable<boolean>;
|
||||
|
||||
constructor(
|
||||
@@ -26,6 +31,7 @@ export class CustomerOrderComponent implements OnInit {
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _uiModal: UiModalService,
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
private _environmentService: EnvironmentService,
|
||||
public auth: AuthService
|
||||
) {}
|
||||
|
||||
@@ -40,8 +46,6 @@ export class CustomerOrderComponent implements OnInit {
|
||||
this.selectedBranch$ = this.application.activatedProcessId$.pipe(
|
||||
switchMap((processId) => this.application.getSelectedBranch$(Number(processId)))
|
||||
);
|
||||
|
||||
this.application.setTitle('Kundenbestellung');
|
||||
}
|
||||
|
||||
async patchProcessData(selectedBranch: BranchDTO) {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
:host {
|
||||
@apply block bg-white rounded-card px-20 py-10;
|
||||
@apply block bg-white rounded px-20 py-10;
|
||||
}
|
||||
|
||||
h1.title {
|
||||
@apply text-2xl font-bold text-center mb-6;
|
||||
@apply text-h3 font-bold text-center mb-6;
|
||||
}
|
||||
|
||||
p.description {
|
||||
@@ -19,7 +19,7 @@ form {
|
||||
}
|
||||
|
||||
button.cta-submit {
|
||||
@apply fixed left-1/2 bottom-28 text-center bg-brand text-cta-l text-white font-bold px-7 py-3 rounded-full transform -translate-x-1/2 transition-all duration-200 ease-in-out;
|
||||
@apply fixed left-1/2 bottom-28 text-center bg-brand text-p1 text-white font-bold px-7 py-3 rounded-full transform -translate-x-1/2 transition-all duration-200 ease-in-out;
|
||||
|
||||
&:disabled {
|
||||
@apply bg-active-branch cursor-not-allowed;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
}
|
||||
|
||||
.card {
|
||||
@apply bg-white rounded-card p-card;
|
||||
@apply bg-white rounded p-card;
|
||||
}
|
||||
|
||||
form {
|
||||
@@ -32,15 +32,15 @@ h1 {
|
||||
}
|
||||
|
||||
.default-address {
|
||||
@apply flex-col justify-around text-cta-l mt-8;
|
||||
@apply flex-col justify-around text-p1 mt-8;
|
||||
|
||||
input {
|
||||
@apply text-cta-l;
|
||||
@apply text-p1;
|
||||
}
|
||||
}
|
||||
|
||||
.create-customer-submit {
|
||||
@apply border-none outline-none bg-brand text-white font-bold text-cta-l px-px-25 py-px-15 rounded-full mt-8 my-4;
|
||||
@apply border-none outline-none bg-brand text-white font-bold text-p1 px-px-25 py-px-15 rounded-full mt-8 my-4;
|
||||
|
||||
&:disabled {
|
||||
@apply bg-inactive-branch;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
}
|
||||
|
||||
.title {
|
||||
@apply text-page-heading font-bold;
|
||||
@apply text-h2 font-bold;
|
||||
}
|
||||
|
||||
.card-customer-orders,
|
||||
@@ -35,7 +35,7 @@ a {
|
||||
}
|
||||
|
||||
.info {
|
||||
@apply text-2xl mb-px-35;
|
||||
@apply text-h3 mb-px-35;
|
||||
padding-top: 70px;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ a {
|
||||
}
|
||||
|
||||
.cancel-message {
|
||||
@apply text-card-sub bg-transparent text-brand border-none font-bold pr-0 no-underline;
|
||||
@apply text-xl bg-transparent text-brand border-none font-bold pr-0 no-underline;
|
||||
}
|
||||
|
||||
.customer-card,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
:host {
|
||||
@apply flex flex-col box-border shadow-card rounded-card;
|
||||
@apply flex flex-col box-border shadow-card rounded;
|
||||
}
|
||||
|
||||
.header {
|
||||
@apply bg-white;
|
||||
|
||||
h1 {
|
||||
@apply text-center text-card-heading my-16 font-bold;
|
||||
@apply text-center text-h3 my-16 font-bold;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ form {
|
||||
@apply text-center my-8;
|
||||
|
||||
button {
|
||||
@apply rounded-full outline-none p-4 text-cta-l border-brand border-solid border-2 px-px-25 py-px-15 mx-4 font-bold;
|
||||
@apply rounded-full outline-none p-4 text-p1 border-brand border-solid border-2 px-px-25 py-px-15 mx-4 font-bold;
|
||||
|
||||
&.btn-cancel {
|
||||
@apply text-brand bg-white;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
}
|
||||
|
||||
.field {
|
||||
@apply grid justify-items-start grid-flow-col flex-row gap-8 text-regular p-4 bg-white;
|
||||
@apply grid justify-items-start grid-flow-col flex-row gap-8 text-p2 p-4 bg-white;
|
||||
grid-template-columns: max-content;
|
||||
.name {
|
||||
}
|
||||
|
||||
@@ -4,17 +4,17 @@
|
||||
}
|
||||
|
||||
.title {
|
||||
@apply text-page-heading font-bold;
|
||||
@apply text-h2 font-bold;
|
||||
}
|
||||
|
||||
.info {
|
||||
@apply text-2xl mt-1 mb-px-40;
|
||||
@apply text-h3 mt-1 mb-px-40;
|
||||
}
|
||||
|
||||
.card-customer-orders,
|
||||
.card-customer-card,
|
||||
.card-customer-details {
|
||||
@apply bg-white rounded-t-card p-4 text-center;
|
||||
@apply bg-white rounded-t p-4 text-center;
|
||||
|
||||
box-shadow: 0 -2px 24px 0 #dce2e9;
|
||||
}
|
||||
@@ -45,7 +45,7 @@ ui-radio-button {
|
||||
}
|
||||
|
||||
.tags {
|
||||
@apply grid grid-flow-col flex-row gap-4 justify-center items-center text-ucla-blue font-bold text-regular mb-px-40;
|
||||
@apply grid grid-flow-col flex-row gap-4 justify-center items-center text-ucla-blue font-bold text-p2 mb-px-40;
|
||||
}
|
||||
|
||||
.tag {
|
||||
@@ -53,7 +53,7 @@ ui-radio-button {
|
||||
}
|
||||
|
||||
.details {
|
||||
@apply grid flex-col text-regular gap-4;
|
||||
@apply grid flex-col text-p2 gap-4;
|
||||
|
||||
.detail {
|
||||
@apply grid grid-flow-col justify-items-start flex-row gap-8;
|
||||
@@ -71,7 +71,7 @@ ui-radio-button {
|
||||
}
|
||||
|
||||
.edit-details {
|
||||
@apply justify-self-end text-card-sub bg-transparent text-brand border-none font-bold rounded-full pr-0 no-underline;
|
||||
@apply justify-self-end text-xl bg-transparent text-brand border-none font-bold rounded-full pr-0 no-underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,20 +84,20 @@ ui-inline-input {
|
||||
@apply bg-white flex flex-row justify-between p-4 items-center pt-px-40 pb-px-20;
|
||||
|
||||
h3 {
|
||||
@apply m-0 text-card-sub font-bold;
|
||||
@apply m-0 text-xl font-bold;
|
||||
}
|
||||
}
|
||||
|
||||
.button-add-address,
|
||||
.button-edit-address {
|
||||
@apply p-0 text-card-sub bg-transparent text-brand border-none font-bold no-underline;
|
||||
@apply p-0 text-xl bg-transparent text-brand border-none font-bold no-underline;
|
||||
}
|
||||
|
||||
.card-customer-footer {
|
||||
@apply p-4 py-px-25 sticky bottom-0 text-center rounded-b-card mt-px-2;
|
||||
@apply p-4 py-px-25 sticky bottom-0 text-center rounded-b mt-px-2;
|
||||
|
||||
button.cta-to-cart {
|
||||
@apply px-px-20 py-px-15 text-card-sub bg-brand text-white border-none font-bold rounded-full;
|
||||
@apply px-px-20 py-px-15 text-xl bg-brand text-white border-none font-bold rounded-full;
|
||||
|
||||
&:disabled {
|
||||
@apply bg-inactive-branch;
|
||||
@@ -110,9 +110,9 @@ ui-inline-input {
|
||||
}
|
||||
|
||||
.button-customer-history {
|
||||
@apply text-card-sub bg-transparent text-brand border-none font-bold rounded-full absolute right-0 top-0 py-px-5;
|
||||
@apply text-xl bg-transparent text-brand border-none font-bold rounded-full absolute right-0 top-0 py-px-5;
|
||||
}
|
||||
|
||||
input[type='radio'] {
|
||||
@apply text-cta-l;
|
||||
@apply text-p1;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
}
|
||||
|
||||
.title {
|
||||
@apply text-page-heading font-bold justify-between mb-2;
|
||||
@apply text-h2 font-bold justify-between mb-2;
|
||||
}
|
||||
|
||||
.label {
|
||||
@@ -62,7 +62,7 @@
|
||||
@apply mx-10;
|
||||
|
||||
h2 {
|
||||
@apply text-card-sub;
|
||||
@apply text-xl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
}
|
||||
|
||||
.arrow-button {
|
||||
@apply border-none bg-transparent outline-none text-regular text-ucla-blue font-bold;
|
||||
@apply border-none bg-transparent outline-none text-p2 text-ucla-blue font-bold;
|
||||
|
||||
ui-icon {
|
||||
@apply inline mx-1 align-middle;
|
||||
@@ -65,7 +65,7 @@
|
||||
}
|
||||
|
||||
.cta-history {
|
||||
@apply text-base font-bold text-brand outline-none border-none bg-transparent mr-1;
|
||||
@apply text-p2 font-bold text-brand outline-none border-none bg-transparent mr-1;
|
||||
}
|
||||
|
||||
.item-format {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
}
|
||||
|
||||
.title {
|
||||
@apply text-page-heading font-bold;
|
||||
@apply text-h2 font-bold;
|
||||
}
|
||||
|
||||
.card-customer-card,
|
||||
@@ -22,7 +22,7 @@
|
||||
}
|
||||
|
||||
.header {
|
||||
@apply bg-white rounded-card p-card;
|
||||
@apply bg-white rounded p-card;
|
||||
box-shadow: 0px 19px 25px -10px white;
|
||||
height: 180px;
|
||||
}
|
||||
@@ -32,15 +32,15 @@ a {
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply text-center text-page-heading;
|
||||
@apply text-center text-h2;
|
||||
}
|
||||
|
||||
.desc {
|
||||
@apply text-center text-card-heading;
|
||||
@apply text-center text-h3;
|
||||
}
|
||||
|
||||
.desc-empty {
|
||||
@apply text-center text-regular;
|
||||
@apply text-center text-p2;
|
||||
}
|
||||
|
||||
.orders {
|
||||
@@ -77,7 +77,7 @@ h1 {
|
||||
}
|
||||
|
||||
.details {
|
||||
@apply text-brand text-cta-l font-bold no-underline;
|
||||
@apply text-brand text-p1 font-bold no-underline;
|
||||
width: 8%;
|
||||
text-align: end;
|
||||
}
|
||||
@@ -103,7 +103,7 @@ h1 {
|
||||
}
|
||||
|
||||
.spin-text {
|
||||
@apply fixed text-regular;
|
||||
@apply fixed text-p2;
|
||||
top: 66%;
|
||||
left: 42%;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ ui-icon {
|
||||
}
|
||||
|
||||
.headline {
|
||||
@apply text-wild-blue-yonder mt-px-15 text-sm font-bold;
|
||||
@apply text-wild-blue-yonder mt-px-15 text-p3 font-bold;
|
||||
}
|
||||
|
||||
.card-number,
|
||||
@@ -32,7 +32,7 @@ ui-icon {
|
||||
}
|
||||
|
||||
.button {
|
||||
@apply border-none outline-none bg-brand text-white font-bold text-cta-l px-px-25 py-px-15 rounded-full mt-px-15;
|
||||
@apply border-none outline-none bg-brand text-white font-bold text-p1 px-px-25 py-px-15 rounded-full mt-px-15;
|
||||
}
|
||||
|
||||
.barcode-field {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
}
|
||||
|
||||
.filter {
|
||||
@apply absolute font-sans flex items-center font-bold bg-wild-blue-yonder border-0 text-regular -top-12 right-0 py-px-8 px-px-15 rounded-filter justify-center z-sticky;
|
||||
@apply absolute font-sans flex items-center font-bold bg-wild-blue-yonder border-0 text-p2 -top-12 right-0 py-px-8 px-px-15 rounded-filter justify-center z-sticky;
|
||||
|
||||
min-width: 106px;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
button.apply-filter,
|
||||
.cta-reset-filter {
|
||||
@apply border-none bg-brand text-white rounded-full py-4 px-cta-x-l text-cta-l font-bold;
|
||||
@apply border-none bg-brand text-white rounded-full py-4 px-cta-x-l text-p1 font-bold;
|
||||
min-width: 201px;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
}
|
||||
|
||||
.title {
|
||||
@apply text-page-heading font-bold;
|
||||
@apply text-h2 font-bold;
|
||||
}
|
||||
|
||||
.info {
|
||||
@apply text-2xl mt-5 mb-px-50;
|
||||
@apply text-h3 mt-5 mb-px-50;
|
||||
}
|
||||
|
||||
.card-create-customer,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
:host {
|
||||
@apply box-border flex flex-col p-card bg-white text-black rounded-card shadow-card text-regular;
|
||||
@apply box-border flex flex-col p-card bg-white text-black rounded shadow-card text-p2;
|
||||
}
|
||||
|
||||
.header {
|
||||
@apply flex justify-between items-center;
|
||||
|
||||
.heading {
|
||||
@apply text-card-heading font-bold p-0 m-0;
|
||||
@apply text-h3 font-bold p-0 m-0;
|
||||
}
|
||||
|
||||
.date {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
}
|
||||
|
||||
.hits {
|
||||
@apply text-right bg-transparent text-regular font-semibold text-inactive-customer my-3;
|
||||
@apply text-right bg-transparent text-p2 font-semibold text-inactive-customer my-3;
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -11,7 +11,7 @@ a {
|
||||
}
|
||||
|
||||
.scroll-container-footer {
|
||||
@apply text-sm mx-auto mt-8 w-1/3 text-center text-ucla-blue font-semibold;
|
||||
@apply text-p3 mx-auto mt-8 w-1/3 text-center text-ucla-blue font-semibold;
|
||||
min-height: 200px;
|
||||
|
||||
a {
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
|
||||
h2,
|
||||
p {
|
||||
@apply text-center text-regular;
|
||||
@apply text-center text-p2;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply font-bold text-card-sub;
|
||||
@apply font-bold text-xl;
|
||||
}
|
||||
|
||||
ul {
|
||||
@apply list-none text-regular -mx-4 p-0 mt-px-35;
|
||||
@apply list-none text-p2 -mx-4 p-0 mt-px-35;
|
||||
|
||||
li {
|
||||
@apply flex flex-row items-center justify-between border-glitter border-t-4 border-b-0 border-solid border-r-0 border-l-0 py-px-15 px-px-25;
|
||||
@@ -22,7 +22,7 @@ ul {
|
||||
}
|
||||
|
||||
button {
|
||||
@apply border-none outline-none bg-transparent text-brand text-cta-l text-right font-bold;
|
||||
@apply border-none outline-none bg-transparent text-brand text-p1 text-right font-bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,5 +32,5 @@ ul {
|
||||
}
|
||||
|
||||
.select-btn {
|
||||
@apply border-none outline-none bg-brand text-white font-bold text-cta-l px-px-25 py-px-15 rounded-full my-8;
|
||||
@apply border-none outline-none bg-brand text-white font-bold text-p1 px-px-25 py-px-15 rounded-full my-8;
|
||||
}
|
||||
|
||||
@@ -8,11 +8,11 @@ h2 {
|
||||
|
||||
h2,
|
||||
p {
|
||||
@apply text-center text-card-sub font-bold;
|
||||
@apply text-center text-xl font-bold;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply font-bold text-card-sub;
|
||||
@apply font-bold text-xl;
|
||||
}
|
||||
|
||||
p {
|
||||
@@ -24,9 +24,9 @@ p {
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
@apply border-4 border-solid border-brand outline-none bg-white text-brand font-bold text-cta-l px-px-25 py-px-15 rounded-full no-underline;
|
||||
@apply border-4 border-solid border-brand outline-none bg-white text-brand font-bold text-p1 px-px-25 py-px-15 rounded-full no-underline;
|
||||
}
|
||||
|
||||
.create-btn {
|
||||
@apply border-none outline-none bg-brand text-white font-bold text-cta-l px-px-25 py-px-15 rounded-full no-underline;
|
||||
@apply border-none outline-none bg-brand text-white font-bold text-p1 px-px-25 py-px-15 rounded-full no-underline;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user