Merge branch 'feature/189-Warenausgabe/main' of ssh.dev.azure.com:v3/hugendubel/ISA/ISA-Frontend into feature/189-Warenausgabe/main
@@ -1,11 +1,6 @@
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import {
|
||||
NgModule,
|
||||
ErrorHandler,
|
||||
LOCALE_ID,
|
||||
APP_INITIALIZER,
|
||||
} from '@angular/core';
|
||||
import { NgModule, ErrorHandler, LOCALE_ID, APP_INITIALIZER } from '@angular/core';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
@@ -32,10 +27,7 @@ import { AppState } from './core/store/state/app.state';
|
||||
import { CartEntryState } from './core/store/state/cart-entry.state';
|
||||
import { BranchState } from './core/store/state/branches.state';
|
||||
import { SsoModule, SsoInterface } from 'sso';
|
||||
import {
|
||||
SsoAuthorizationInterceptor,
|
||||
HttpErrorHandlerInterceptor,
|
||||
} from './core/interceptors';
|
||||
import { SsoAuthorizationInterceptor, HttpErrorHandlerInterceptor } from './core/interceptors';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { CountryState } from './core/store/state/countries.state';
|
||||
import { HimaSalesErrorHandler } from './core/error/hima-sales.error-handler';
|
||||
@@ -64,6 +56,7 @@ import { ModalDialogueModule } from './core/overlay/component';
|
||||
import { AppModalModule } from './app-modal.module';
|
||||
import { OverlaysModule } from './core/overlay/overlays.module';
|
||||
registerLocaleData(localeDe, localeDeExtra);
|
||||
registerLocaleData(localeDe, 'de', localeDeExtra);
|
||||
|
||||
const states = [
|
||||
AppState,
|
||||
@@ -91,9 +84,7 @@ export function noop() {
|
||||
return function () {};
|
||||
}
|
||||
|
||||
export function remissionModuleOptionsFactory(
|
||||
config: AppConfiguration
|
||||
): RemissionModuleOptions {
|
||||
export function remissionModuleOptionsFactory(config: AppConfiguration): RemissionModuleOptions {
|
||||
return config.remissionModuleOptions;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,10 +50,8 @@ export class ContentHeaderService {
|
||||
break;
|
||||
|
||||
case 'shelf':
|
||||
filters$ = this.searchStore.selectedSearchProcessFilters$.pipe(
|
||||
filter(
|
||||
(filters) => !isNullOrUndefined(filters) && !filters.length
|
||||
),
|
||||
filters$ = this.searchStore.selectedFilter$.pipe(
|
||||
filter((filters) => !isNullOrUndefined(filters) && !filters.length),
|
||||
// To ensure if no filter is set on process that filter is inactive
|
||||
startWith([])
|
||||
);
|
||||
@@ -63,12 +61,7 @@ export class ContentHeaderService {
|
||||
return of(false);
|
||||
}
|
||||
|
||||
return filters$.pipe(
|
||||
map(
|
||||
(selectedFilters) =>
|
||||
selectedFilters && !!Object.entries(selectedFilters).length
|
||||
)
|
||||
);
|
||||
return filters$.pipe(map((selectedFilters) => selectedFilters && !!Object.entries(selectedFilters).length));
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -122,18 +115,12 @@ export class ContentHeaderService {
|
||||
const applicableBlacklist = this.blackList[type];
|
||||
|
||||
if (type === 'filter') {
|
||||
const isOnWhiteList = !!applicableWhitelist.find(
|
||||
(whitelistetUrl) =>
|
||||
whitelistetUrl.includes(url) || url.includes(whitelistetUrl)
|
||||
);
|
||||
const isOnWhiteList = !!applicableWhitelist.find((whitelistetUrl) => whitelistetUrl.includes(url) || url.includes(whitelistetUrl));
|
||||
return isOnWhiteList;
|
||||
}
|
||||
|
||||
if (type === 'breadcrumbs') {
|
||||
const isOnBlackList = !!applicableBlacklist.find(
|
||||
(blacklistetUrl) =>
|
||||
blacklistetUrl.includes(url) || url.includes(blacklistetUrl)
|
||||
);
|
||||
const isOnBlackList = !!applicableBlacklist.find((blacklistetUrl) => blacklistetUrl.includes(url) || url.includes(blacklistetUrl));
|
||||
return !isOnBlackList;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,7 @@ import {
|
||||
import { LoadBranches, LoadUserBranch } from '../actions/branch.actions';
|
||||
import { BranchSelectors } from '../selectors/branch.selector';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
import {
|
||||
RemoveProcessNewState,
|
||||
ReloadProcessData,
|
||||
} from '../actions/process.actions';
|
||||
import { RemoveProcessNewState, ReloadProcessData } from '../actions/process.actions';
|
||||
import { UserStateService } from '../../services/user-state.service';
|
||||
import { UserStateSyncData } from '../../models/user-state-sync.model';
|
||||
import { ReloadCustomersData } from '../actions/customer.actions';
|
||||
@@ -23,12 +20,7 @@ import { ReloadProductsData } from '../actions/product.actions';
|
||||
import { ReloadBreadcrumbsData } from '../actions/breadcrumb.actions';
|
||||
import { Router } from '@angular/router';
|
||||
import { Subject } from 'rxjs';
|
||||
import {
|
||||
debounceTime,
|
||||
distinctUntilChanged,
|
||||
switchMap,
|
||||
tap,
|
||||
} from 'rxjs/operators';
|
||||
import { debounceTime, distinctUntilChanged, switchMap, tap } from 'rxjs/operators';
|
||||
import { ModuleSwitcher } from '../../models/app-switcher.enum';
|
||||
import { ModuleSwitcherService } from '../../services/module-switcher.service';
|
||||
import { ReloadFiltersData } from '../actions/filter.actions';
|
||||
@@ -39,7 +31,7 @@ import { ReloadRemission } from '../actions/remission.actions';
|
||||
import { ReloadFormState } from '../actions/forms.actions';
|
||||
import { FILIALE_LANDING_PAGE } from '../../utils/app.constants';
|
||||
|
||||
export const SYNC_DATA_VERSION = 209;
|
||||
export const SYNC_DATA_VERSION = 210;
|
||||
|
||||
export class AppStateModel {
|
||||
currentProcesssId: number;
|
||||
@@ -109,13 +101,9 @@ export class AppState {
|
||||
}
|
||||
|
||||
@Action(AppSetCurrentProcess)
|
||||
appSetCurrentProcess(
|
||||
ctx: StateContext<AppStateModel>,
|
||||
{ payload }: AppSetCurrentProcess
|
||||
) {
|
||||
appSetCurrentProcess(ctx: StateContext<AppStateModel>, { payload }: AppSetCurrentProcess) {
|
||||
const state = ctx.getState();
|
||||
const processExists =
|
||||
state.processIds.findIndex((t) => t === payload) !== -1;
|
||||
const processExists = state.processIds.findIndex((t) => t === payload) !== -1;
|
||||
if (processExists) {
|
||||
ctx.patchState({
|
||||
currentProcesssId: payload,
|
||||
@@ -127,23 +115,18 @@ export class AppState {
|
||||
@Action(AppAddProcess)
|
||||
appAddProcess(ctx: StateContext<AppStateModel>, { payload }: AppAddProcess) {
|
||||
const state = ctx.getState();
|
||||
const processExists =
|
||||
state.processIds.findIndex((t) => t === payload) !== -1;
|
||||
const processExists = state.processIds.findIndex((t) => t === payload) !== -1;
|
||||
if (!processExists) {
|
||||
const processIds = [...state.processIds, payload];
|
||||
const currentProcesssId = payload;
|
||||
ctx.patchState({ currentProcesssId, processIds });
|
||||
|
||||
const branchesLoaded = this.store.selectSnapshot(
|
||||
BranchSelectors.getBranches
|
||||
);
|
||||
const branchesLoaded = this.store.selectSnapshot(BranchSelectors.getBranches);
|
||||
if (!branchesLoaded || Object.keys(branchesLoaded).length === 0) {
|
||||
this.store.dispatch(new LoadBranches());
|
||||
}
|
||||
|
||||
const userBranch = this.store.selectSnapshot(
|
||||
BranchSelectors.getUserBranch
|
||||
);
|
||||
const userBranch = this.store.selectSnapshot(BranchSelectors.getUserBranch);
|
||||
if (isNullOrUndefined(userBranch)) {
|
||||
this.store.dispatch(new LoadUserBranch());
|
||||
}
|
||||
@@ -153,10 +136,7 @@ export class AppState {
|
||||
}
|
||||
|
||||
@Action(AppDeleteProcess)
|
||||
appDeleteProcess(
|
||||
ctx: StateContext<AppStateModel>,
|
||||
{ payload }: AppDeleteProcess
|
||||
) {
|
||||
appDeleteProcess(ctx: StateContext<AppStateModel>, { payload }: AppDeleteProcess) {
|
||||
const state = ctx.getState();
|
||||
const currentIds = state.processIds;
|
||||
if (currentIds) {
|
||||
@@ -167,10 +147,7 @@ export class AppState {
|
||||
}
|
||||
|
||||
@Action(AppSwitchModule)
|
||||
appSwitchModule(
|
||||
ctx: StateContext<AppStateModel>,
|
||||
{ payload }: AppSwitchModule
|
||||
) {
|
||||
appSwitchModule(ctx: StateContext<AppStateModel>, { payload }: AppSwitchModule) {
|
||||
const state = ctx.getState();
|
||||
ctx.patchState({ activeModule: payload });
|
||||
this.syncApiState(state.processIds, payload);
|
||||
@@ -180,10 +157,7 @@ export class AppState {
|
||||
* Save store data on backend
|
||||
*/
|
||||
@Action(AppUserDataSync)
|
||||
appUserDataSynced(
|
||||
ctx: StateContext<AppStateModel>,
|
||||
{ data, sync }: AppUserDataSync
|
||||
) {
|
||||
appUserDataSynced(ctx: StateContext<AppStateModel>, { data, sync }: AppUserDataSync) {
|
||||
const state = ctx.getState();
|
||||
|
||||
let currentUserData: UserStateSyncData = {};
|
||||
@@ -210,10 +184,7 @@ export class AppState {
|
||||
* Initial store loading from API, triggered once on page load
|
||||
*/
|
||||
@Action(ReloadSavedState)
|
||||
reloadSavedState(
|
||||
ctx: StateContext<AppStateModel>,
|
||||
{ data, sync }: ReloadSavedState
|
||||
) {
|
||||
reloadSavedState(ctx: StateContext<AppStateModel>, { data, sync }: ReloadSavedState) {
|
||||
const state = ctx.getState();
|
||||
|
||||
let currentUserData: UserStateSyncData = {};
|
||||
@@ -237,10 +208,7 @@ export class AppState {
|
||||
if (sync && syncedData.version === SYNC_DATA_VERSION) {
|
||||
this.reloadDataFromAPI(syncedData);
|
||||
|
||||
if (
|
||||
syncedData.currentProcesssId ||
|
||||
syncedData.activeModule === ModuleSwitcher.Branch
|
||||
) {
|
||||
if (syncedData.currentProcesssId || syncedData.activeModule === ModuleSwitcher.Branch) {
|
||||
ctx.patchState({
|
||||
...state,
|
||||
synced: true,
|
||||
@@ -267,19 +235,11 @@ export class AppState {
|
||||
return;
|
||||
}
|
||||
if (data.customers) {
|
||||
this.store.dispatch(
|
||||
new ReloadCustomersData(
|
||||
data.customers,
|
||||
data.lastCreatedCustomerId,
|
||||
data.cachedCustomerSearch
|
||||
)
|
||||
);
|
||||
this.store.dispatch(new ReloadCustomersData(data.customers, data.lastCreatedCustomerId, data.cachedCustomerSearch));
|
||||
}
|
||||
|
||||
if (data.products) {
|
||||
this.store.dispatch(
|
||||
new ReloadProductsData(data.products, data.cachedProductResults)
|
||||
);
|
||||
this.store.dispatch(new ReloadProductsData(data.products, data.cachedProductResults));
|
||||
}
|
||||
|
||||
if (data.carts) {
|
||||
@@ -299,9 +259,7 @@ export class AppState {
|
||||
}
|
||||
|
||||
if (data.processes) {
|
||||
this.store.dispatch(
|
||||
new ReloadProcessData(data.processes, data.recentArticles)
|
||||
);
|
||||
this.store.dispatch(new ReloadProcessData(data.processes, data.recentArticles));
|
||||
}
|
||||
|
||||
if (data.formsState) {
|
||||
@@ -309,20 +267,11 @@ export class AppState {
|
||||
}
|
||||
|
||||
if (data.activeModule === ModuleSwitcher.Customer) {
|
||||
if (
|
||||
data.processes &&
|
||||
data.currentProcesssId &&
|
||||
data.processes[data.currentProcesssId]
|
||||
) {
|
||||
if (data.processes && data.currentProcesssId && data.processes[data.currentProcesssId]) {
|
||||
const currentProcesssId = data.currentProcesssId;
|
||||
const currentRoute = data.processes[currentProcesssId].currentRoute;
|
||||
if (currentRoute && currentRoute.length > 0) {
|
||||
this.routingAvailableAction(
|
||||
data,
|
||||
currentProcesssId,
|
||||
currentRoute,
|
||||
data.activeModule
|
||||
);
|
||||
this.routingAvailableAction(data, currentProcesssId, currentRoute, data.activeModule);
|
||||
} else {
|
||||
this.router.navigate(['/dashboard']);
|
||||
}
|
||||
@@ -334,12 +283,7 @@ export class AppState {
|
||||
const currentProcesssId = -1;
|
||||
const currentRoute = data.branchProcess.currentRoute;
|
||||
if (currentRoute && currentRoute.length > 0) {
|
||||
this.routingAvailableAction(
|
||||
data,
|
||||
currentProcesssId,
|
||||
currentRoute,
|
||||
data.activeModule
|
||||
);
|
||||
this.routingAvailableAction(data, currentProcesssId, currentRoute, data.activeModule);
|
||||
} else {
|
||||
this.router.navigate([FILIALE_LANDING_PAGE]);
|
||||
}
|
||||
@@ -353,24 +297,11 @@ export class AppState {
|
||||
}
|
||||
|
||||
if (data.activeModule === ModuleSwitcher.Branch) {
|
||||
this.moduleSwitcherService.switch(
|
||||
ModuleSwitcher.Branch,
|
||||
data.branchProcess
|
||||
);
|
||||
this.moduleSwitcherService.switch(ModuleSwitcher.Branch, data.branchProcess);
|
||||
}
|
||||
|
||||
if (
|
||||
data.processesBreadcrumbs &&
|
||||
data.activeCrumbs &&
|
||||
(data.currentProcesssId || data.activeModule === ModuleSwitcher.Branch)
|
||||
) {
|
||||
this.store.dispatch(
|
||||
new ReloadBreadcrumbsData(
|
||||
data.processesBreadcrumbs,
|
||||
data.activeCrumbs,
|
||||
data.previusMenuPath
|
||||
)
|
||||
);
|
||||
if (data.processesBreadcrumbs && data.activeCrumbs && (data.currentProcesssId || data.activeModule === ModuleSwitcher.Branch)) {
|
||||
this.store.dispatch(new ReloadBreadcrumbsData(data.processesBreadcrumbs, data.activeCrumbs, data.previusMenuPath));
|
||||
}
|
||||
|
||||
if (data.filters && data.processesSelectedFilters && data.dropdownFilters) {
|
||||
@@ -396,28 +327,16 @@ export class AppState {
|
||||
);
|
||||
}
|
||||
|
||||
private routingAvailableAction(
|
||||
data: UserStateSyncData,
|
||||
currentProcesssId: number,
|
||||
currentRoute: string,
|
||||
module: ModuleSwitcher
|
||||
) {
|
||||
const hasActiveCrumbsAvailableForProcess =
|
||||
data.activeCrumbs && data.activeCrumbs[currentProcesssId];
|
||||
private routingAvailableAction(data: UserStateSyncData, currentProcesssId: number, currentRoute: string, module: ModuleSwitcher) {
|
||||
const hasActiveCrumbsAvailableForProcess = data.activeCrumbs && data.activeCrumbs[currentProcesssId];
|
||||
const activeCrumbs = data.activeCrumbs[currentProcesssId];
|
||||
const hasProcessBreadcrumbsAvailableForProcess =
|
||||
data.processesBreadcrumbs && data.processesBreadcrumbs[activeCrumbs];
|
||||
const hasProcessBreadcrumbsAvailableForProcess = data.processesBreadcrumbs && data.processesBreadcrumbs[activeCrumbs];
|
||||
|
||||
const breadcrumb = hasProcessBreadcrumbsAvailableForProcess
|
||||
? data.processesBreadcrumbs[activeCrumbs].find(
|
||||
(t) => t.processId === currentProcesssId
|
||||
)
|
||||
? data.processesBreadcrumbs[activeCrumbs].find((t) => t.processId === currentProcesssId)
|
||||
: null;
|
||||
|
||||
const breadcrumbPath =
|
||||
breadcrumb && breadcrumb.breadcrumbs
|
||||
? breadcrumb.breadcrumbs.find((t) => t && t.path === currentRoute)
|
||||
: null;
|
||||
const breadcrumbPath = breadcrumb && breadcrumb.breadcrumbs ? breadcrumb.breadcrumbs.find((t) => t && t.path === currentRoute) : null;
|
||||
|
||||
if (
|
||||
hasActiveCrumbsAvailableForProcess &&
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './search-result-group.component';
|
||||
export * from './search-result-group.module';
|
||||
@@ -0,0 +1,50 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { OrderItemProcessingStatusValue } from '@swagger/oms';
|
||||
|
||||
@Pipe({
|
||||
name: 'processingStatus',
|
||||
})
|
||||
export class ProcessingStatusPipe implements PipeTransform {
|
||||
map = {
|
||||
0: '',
|
||||
1: 'bestellt',
|
||||
2: 'Placed',
|
||||
4: 'Accepted',
|
||||
8: 'Parked',
|
||||
16: 'in Bearbeitung',
|
||||
32: 'Vorbereitung Versand',
|
||||
64: 'versendet',
|
||||
128: 'eingetroffen',
|
||||
256: 'abgeholt',
|
||||
512: 'storniert (Kunde)',
|
||||
1024: 'storniert',
|
||||
2048: 'storniert (Lieferant)',
|
||||
4096: 'NotAvailable',
|
||||
8192: 'nachbestellt ',
|
||||
16384: 'ReturnedByBuyer',
|
||||
32768: 'AvailableForDownload',
|
||||
65536: 'Downloaded',
|
||||
131072: 'NotFetched',
|
||||
262144: 'Zurück zum Lager',
|
||||
524288: 'angefragt',
|
||||
1048576: 'RedirectedInternally',
|
||||
2097152: 'Overdue',
|
||||
4194304: 'Delivered',
|
||||
8388608: 'DetermineSupplier',
|
||||
16777216: 'SupplierTemporarilyOutOfStock',
|
||||
33554432: 'Reserved',
|
||||
67108864: 'Assembled',
|
||||
134217728: 'Packed',
|
||||
};
|
||||
|
||||
icon = {
|
||||
128: 'Check',
|
||||
512: 'close',
|
||||
1024: 'close',
|
||||
2048: 'close',
|
||||
};
|
||||
|
||||
transform(value: OrderItemProcessingStatusValue, type: 'icon' | 'text' = 'text'): string {
|
||||
return (type === 'icon' ? this.icon[value] : this.map[value]) || '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<div class="tags" *ngIf="item.features?.prebooked">
|
||||
<lib-icon name="tag_icon_preorder" width="30px"></lib-icon>
|
||||
</div>
|
||||
<div class="isa-text-right isa-mb-9" *ngIf="item.compartmentCode">
|
||||
<strong>{{ item.compartmentCode }} {{ item.compartmentInfo }} </strong>
|
||||
</div>
|
||||
<div class="paid isa-mt-9 isa-mb-9" *ngIf="item.features?.paid">
|
||||
<lib-icon height="24px" width="24px" name="Check_green_circle" class="isa-mr-10"></lib-icon>
|
||||
<strong> {{ item.features?.paid }} </strong>
|
||||
</div>
|
||||
<div class="grid-container">
|
||||
<div class="cover">
|
||||
<img class="thumbnail" src="https://produktbilder.ihugendubel.de/{{item.product.ean}}.jpg?showDummy=true"
|
||||
alt="item.product.name">
|
||||
</div>
|
||||
<div class="title">
|
||||
<strong class="product-name"> {{ [ item.product.contributors, item.product.name] | title }}</strong>
|
||||
<strong class="processing-status">
|
||||
<lib-icon *ngIf="item.processingStatus | processingStatus:'icon'; let icon" [name]="icon"></lib-icon>
|
||||
{{ item.processingStatus | processingStatus }}
|
||||
</strong>
|
||||
</div>
|
||||
<div class="details">
|
||||
<div class="item-type">
|
||||
<lib-icon name="Icon_{{item.product.format}}"></lib-icon>
|
||||
<strong>{{ item.product.formatDetail }}</strong>
|
||||
</div>
|
||||
<div class="order-date spec">
|
||||
<span>Bestelldatum</span>
|
||||
<strong>{{ item.orderDate | date }}</strong>
|
||||
</div>
|
||||
<div class="item-number">
|
||||
<strong>{{ item.product.ean }}</strong>
|
||||
</div>
|
||||
<div class="quantity spec">
|
||||
<span>Menge</span>
|
||||
<strong>{{ item.quantity }}x</strong>
|
||||
</div>
|
||||
<div class="price">
|
||||
<strong>{{ item.price | currency:'EUR':'code' }}</strong>
|
||||
</div>
|
||||
<div class="target-branch spec">
|
||||
<span>Zielfiliale</span>
|
||||
<strong>{{ item.targetBranch }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,97 @@
|
||||
:host {
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: 100px 1fr;
|
||||
grid-template-rows: auto 1fr;
|
||||
grid-template-areas: 'cover title' 'cover details';
|
||||
}
|
||||
|
||||
.cover {
|
||||
grid-area: cover;
|
||||
|
||||
.thumbnail {
|
||||
max-width: 59px;
|
||||
max-height: 111px;
|
||||
box-shadow: 0 0 18px 0 #b8b3b7;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
grid-area: title;
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
margin-bottom: 18px;
|
||||
|
||||
.product-name {
|
||||
}
|
||||
|
||||
.processing-status {
|
||||
color: #557596;
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 340px;
|
||||
grid-template-rows: 1fr 1fr 1fr;
|
||||
grid-template-areas: 'item-type order-date' 'item-number quantity' 'price target-branch';
|
||||
grid-area: details;
|
||||
}
|
||||
|
||||
.item-type {
|
||||
grid-area: item-type;
|
||||
}
|
||||
|
||||
.order-date {
|
||||
grid-area: order-date;
|
||||
}
|
||||
|
||||
.item-number {
|
||||
grid-area: item-number;
|
||||
}
|
||||
|
||||
.quantity {
|
||||
grid-area: quantity;
|
||||
}
|
||||
|
||||
.price {
|
||||
grid-area: price;
|
||||
}
|
||||
|
||||
.target-branch {
|
||||
grid-area: target-branch;
|
||||
}
|
||||
|
||||
.spec {
|
||||
display: flex;
|
||||
|
||||
*:nth-child(1) {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
// *:nth-child(2) {
|
||||
// }
|
||||
}
|
||||
|
||||
.paid {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
|
||||
lib-icon {
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.tags {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 150px;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Component, OnInit, ChangeDetectionStrategy, Input } from '@angular/core';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-search-result-group-item',
|
||||
templateUrl: 'search-result-group-item.component.html',
|
||||
styleUrls: ['search-result-group-item.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class SearchResultGroupItemComponent implements OnInit {
|
||||
@Input()
|
||||
item: OrderItemListItemDTO;
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<div class="isa-card">
|
||||
<h3 class="heading">{{ group.fullName }}</h3>
|
||||
<ng-container *ngFor="let customer of group.items; let last = last">
|
||||
<div class="isa-mb-12 isa-mt-12">
|
||||
<div class="isa-text-right isa-mb-9">
|
||||
<strong>{{ customer.orderNumber }}</strong>
|
||||
</div>
|
||||
<app-search-result-group-item *ngFor="let item of customer.items; let lastItem = last" [item]="item"
|
||||
[class.group-item-bottom-space]="!lastItem">
|
||||
</app-search-result-group-item>
|
||||
</div>
|
||||
<div class="divider" *ngIf="!last"></div>
|
||||
</ng-container>
|
||||
</div>
|
||||
@@ -0,0 +1,24 @@
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.isa-card {
|
||||
padding: 20px 24px;
|
||||
|
||||
.heading {
|
||||
margin: 0;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
display: block;
|
||||
height: 2px;
|
||||
background-color: #e6eff9;
|
||||
margin-left: -24px;
|
||||
margin-right: -24px;
|
||||
}
|
||||
|
||||
.group-item-bottom-space {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Component, OnInit, ChangeDetectionStrategy, Input } from '@angular/core';
|
||||
import { GroupedByCustomer } from 'apps/sales/src/app/store/customer';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-search-result-group',
|
||||
templateUrl: 'search-result-group.component.html',
|
||||
styleUrls: ['search-result-group.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class SearchResultGroupComponent implements OnInit {
|
||||
@Input()
|
||||
group: GroupedByCustomer;
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { SearchResultGroupComponent } from './search-result-group.component';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SearchResultGroupItemComponent } from './search-result-group-item.component';
|
||||
import { ProcessingStatusPipe } from './processing-status.pipe';
|
||||
import { TitlePipe } from './title.pipe';
|
||||
import { IconModule } from '@libs/ui';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, IconModule],
|
||||
exports: [SearchResultGroupComponent],
|
||||
declarations: [SearchResultGroupComponent, SearchResultGroupItemComponent, ProcessingStatusPipe, TitlePipe],
|
||||
providers: [],
|
||||
})
|
||||
export class SearchResultGroupModule {}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
@Pipe({
|
||||
name: 'title',
|
||||
})
|
||||
export class TitlePipe implements PipeTransform {
|
||||
readonly placeholder = '...';
|
||||
readonly seperator = '-';
|
||||
|
||||
transform(value: [string, string] = ['', ''], max: [number, number] = [24, 24]): any {
|
||||
const maxAuthor = max[0];
|
||||
let author = (value[0] || '').trim();
|
||||
const restAuthor = Math.max(0, maxAuthor - author.length);
|
||||
|
||||
const maxTitle = max[1];
|
||||
let title = (value[1] || '').trim();
|
||||
const restTitle = Math.max(0, maxTitle - title.length);
|
||||
|
||||
if (author.length > maxAuthor + restTitle) {
|
||||
author = author.trim().substr(0, maxAuthor + restTitle - this.placeholder.length) + this.placeholder;
|
||||
}
|
||||
|
||||
if (title.length > maxTitle + restAuthor) {
|
||||
title = title.trim().substr(0, maxTitle + restAuthor - this.placeholder.length) + this.placeholder;
|
||||
}
|
||||
|
||||
let result = author;
|
||||
if (result.length > 0) {
|
||||
result += ` ${this.seperator} `;
|
||||
}
|
||||
result += title;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,4 @@
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
ChangeDetectionStrategy,
|
||||
Output,
|
||||
EventEmitter,
|
||||
} from '@angular/core';
|
||||
import { Component, OnInit, ChangeDetectionStrategy, Output, EventEmitter } from '@angular/core';
|
||||
import { ShelfPrimaryFilterOptions } from '../../../defs';
|
||||
import { Observable } from 'rxjs';
|
||||
import { SearchStateFacade } from 'apps/sales/src/app/store/customer';
|
||||
@@ -50,6 +44,6 @@ export class ShelfPrimaryFiltersComponent implements OnInit {
|
||||
}
|
||||
|
||||
private initFilters() {
|
||||
this.primaryFilters$ = this.searchStateFacade.getPrimaryFilters();
|
||||
this.primaryFilters$ = this.searchStateFacade.primaryFilters$;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,6 @@
|
||||
<div class="result-container">
|
||||
<ng-container>
|
||||
<cdk-virtual-scroll-viewport itemSize="300" #scroller
|
||||
[perfectScrollbar]="{minScrollbarLength: 20}">
|
||||
<div *cdkVirtualFor="let order of ds; let last = last; let index = index">
|
||||
<app-shelf-customer-order
|
||||
*ngIf="order != null; else loadingComponent"
|
||||
[index]="index"
|
||||
[last]="last"
|
||||
[order]="order"
|
||||
[processId]="id"
|
||||
></app-shelf-customer-order>
|
||||
</div>
|
||||
<ng-template #loadingComponent>
|
||||
<app-order-loading></app-order-loading>
|
||||
</ng-template>
|
||||
</cdk-virtual-scroll-viewport>
|
||||
</ng-container>
|
||||
|
||||
<app-loading
|
||||
*ngIf="!ds || ds.loading"
|
||||
[style.marginTop.px]="60"
|
||||
[style.marginBottom.px]="60"
|
||||
loading="true"
|
||||
text="Inhalte werden geladen"
|
||||
></app-loading>
|
||||
</div>
|
||||
<div class="result-container" #scroll>
|
||||
<app-search-result-group class="isa-mb-10" *ngFor="let group of grouped$ | async; let i = index" [group]="group">
|
||||
</app-search-result-group>
|
||||
<app-loading *ngIf="fetching$ | async" [style.marginTop.px]="60" [style.marginBottom.px]="60" loading="true"
|
||||
text="Inhalte werden geladen"></app-loading>
|
||||
</div>
|
||||
@@ -1,7 +1,12 @@
|
||||
.result-container {
|
||||
height: calc(100% - 30px);
|
||||
}
|
||||
cdk-virtual-scroll-viewport {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.result-container {
|
||||
height: calc(100% - 74px);
|
||||
overflow: auto;
|
||||
}
|
||||
.item {
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
@@ -1,101 +1,61 @@
|
||||
import { Subject } from 'rxjs';
|
||||
import { Subject, fromEvent, combineLatest } from 'rxjs';
|
||||
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
import { AfterViewInit, ChangeDetectionStrategy, Component, OnDestroy, OnInit, ViewChild, ChangeDetectorRef } from '@angular/core';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { ProcessSelectors } from 'apps/sales/src/app/core/store/selectors/process.selectors';
|
||||
import { ShelfSearch } from 'apps/sales/src/app/core/models/shelf-search.modal';
|
||||
import { ShelfSearchDataSource } from './shelf-search-results.datasource';
|
||||
import { CollectingShelfService } from 'apps/sales/src/app/core/services/collecting-shelf.service';
|
||||
import { takeUntil, distinct, distinctUntilChanged, take, filter } from 'rxjs/operators';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
import { Process } from 'apps/sales/src/app/core/models/process.model';
|
||||
import { ClearShelfOrdersForProcess, SetCollectingShelfCacheState } from 'apps/sales/src/app/core/store/actions/collecting-shelf.action';
|
||||
import { SHELF_SCROLL_INDEX } from 'apps/sales/src/app/core/utils/app.constants';
|
||||
import { ListRange } from '@angular/cdk/collections';
|
||||
import { CollectingShelfSelectors } from 'apps/sales/src/app/core/store/selectors/collecting-shelf.selector';
|
||||
import { Component, OnDestroy, OnInit, ChangeDetectorRef, ViewChild, ElementRef } from '@angular/core';
|
||||
import { SearchStateFacade } from 'apps/sales/src/app/store/customer';
|
||||
import { first, takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'app-shelf-search-results',
|
||||
templateUrl: './shelf-search-results.component.html',
|
||||
styleUrls: ['./shelf-search-results.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
// changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ShelfSearchResultsComponent implements OnInit, OnDestroy {
|
||||
@ViewChild('scroller', { static: true }) scroller: CdkVirtualScrollViewport;
|
||||
@ViewChild('scroll', { static: true })
|
||||
scrollContainer: ElementRef;
|
||||
|
||||
shelfSearch: ShelfSearch;
|
||||
ds: ShelfSearchDataSource;
|
||||
destroy$ = new Subject();
|
||||
id: number;
|
||||
currentProcess: Process;
|
||||
currentSearch: ShelfSearch;
|
||||
loading = true;
|
||||
doScroll = true;
|
||||
useCache = false;
|
||||
|
||||
constructor(private store: Store, private collectingShelf: CollectingShelfService, private cdr: ChangeDetectorRef) { }
|
||||
grouped$ = this.searchStateFacade.resultGroupedByCustomer$;
|
||||
|
||||
fetching$ = this.searchStateFacade.fetching$;
|
||||
|
||||
constructor(private searchStateFacade: SearchStateFacade) {
|
||||
this.searchStateFacade.clearResult();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.store.dispatch(new ClearShelfOrdersForProcess());
|
||||
this.store
|
||||
.select(ProcessSelectors.getCurrentProcess)
|
||||
.pipe(
|
||||
filter(data => !isNullOrUndefined(data) && data.id !== this.id),
|
||||
takeUntil(this.destroy$)
|
||||
)
|
||||
.subscribe((process: Process) => {
|
||||
this.currentProcess = process;
|
||||
this.currentSearch = process.shelfSearch;
|
||||
this.id = process.id;
|
||||
this.initScrollContainer();
|
||||
this.fetch(true);
|
||||
}
|
||||
|
||||
if (this.currentSearch) {
|
||||
this.useCache = this.store.selectSnapshot(CollectingShelfSelectors.getShelfCacheState);
|
||||
this.loadDataSource();
|
||||
this.store.dispatch(new SetCollectingShelfCacheState(false));
|
||||
initScrollContainer() {
|
||||
const scrollContainer: HTMLElement = this.scrollContainer.nativeElement;
|
||||
fromEvent(scrollContainer, 'scroll')
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(() => {
|
||||
if (this.reachedBottom()) {
|
||||
this.fetch();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.scroller.renderedRangeStream
|
||||
.pipe(
|
||||
takeUntil(this.destroy$),
|
||||
filter(data => !isNullOrUndefined(data))
|
||||
)
|
||||
.subscribe(range => {
|
||||
if (this.doScroll) {
|
||||
this.scrollToIndexCached(range);
|
||||
}
|
||||
});
|
||||
reachedBottom() {
|
||||
const scrollContainer: HTMLElement = this.scrollContainer.nativeElement;
|
||||
return scrollContainer.scrollHeight - (scrollContainer.scrollTop + scrollContainer.clientHeight) - 100 <= 0;
|
||||
}
|
||||
|
||||
async fetch(force = false) {
|
||||
const [hits, result, fetching] = await combineLatest([this.searchStateFacade.hits$, this.searchStateFacade.result$, this.fetching$])
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
if (force || (hits > result.length && !fetching)) {
|
||||
this.searchStateFacade.fetchResult();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
}
|
||||
|
||||
loadDataSource() {
|
||||
this.ds = new ShelfSearchDataSource(this.currentSearch, this.store, this.collectingShelf, this.useCache);
|
||||
this.loading = false;
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
scrollToIndexCached(range: ListRange) {
|
||||
setTimeout(() => {
|
||||
this.scroller.scrollToIndex(this.getIndex());
|
||||
if (range.start <= this.getIndex() && range.end >= this.getIndex()) {
|
||||
this.doScroll = false;
|
||||
sessionStorage.removeItem(SHELF_SCROLL_INDEX);
|
||||
}
|
||||
}, 1);
|
||||
}
|
||||
|
||||
getIndex() {
|
||||
const index = sessionStorage.getItem(SHELF_SCROLL_INDEX);
|
||||
if (!isNullOrUndefined(index)) {
|
||||
const ids = index.split(':');
|
||||
if (this.id === +ids[1]) {
|
||||
return +ids[0];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
import { DataSource, CollectionViewer } from '@angular/cdk/collections';
|
||||
import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { take, takeUntil, debounceTime } from 'rxjs/operators';
|
||||
import { SetShelfOrders } from 'apps/sales/src/app/core/store/actions/collecting-shelf.action';
|
||||
import { ShelfSearch } from 'apps/sales/src/app/core/models/shelf-search.modal';
|
||||
import { CollectingShelfService } from 'apps/sales/src/app/core/services/collecting-shelf.service';
|
||||
import { CollectingShelfOrder } from 'apps/sales/src/app/core/models/collecting-shelf-order.model';
|
||||
import { ShelfOrderItemLevel } from 'apps/sales/src/app/core/models/shelf-order-item-level.enum';
|
||||
import { SharedSelectors } from 'apps/sales/src/app/core/store/selectors/shared.selectors';
|
||||
|
||||
export class ShelfSearchDataSource extends DataSource<CollectingShelfOrder | undefined> {
|
||||
private pageSize = 10;
|
||||
private fetchedPages = new Set<number>();
|
||||
private cachedData = Array.from<CollectingShelfOrder>({ length: 10 });
|
||||
private dataStream = new BehaviorSubject<(CollectingShelfOrder | undefined)[]>(this.cachedData);
|
||||
destroy$ = new Subject();
|
||||
public loading = true;
|
||||
public results = false;
|
||||
public allHits = 0;
|
||||
public firstLoad = true;
|
||||
|
||||
constructor(
|
||||
private search: ShelfSearch,
|
||||
private store: Store,
|
||||
private collectingShelf: CollectingShelfService,
|
||||
private useCache: boolean
|
||||
) {
|
||||
super();
|
||||
}
|
||||
connect(collectionViewer: CollectionViewer): Observable<(CollectingShelfOrder | undefined)[]> {
|
||||
collectionViewer.viewChange.pipe(takeUntil(this.destroy$)).subscribe(range => {
|
||||
const startPage = this.getPageForIndex(range.start);
|
||||
const endPage = this.getPageForIndex(range.end - 1);
|
||||
for (let i = startPage; i <= endPage; i++) {
|
||||
if (this.firstLoad && i === 0) {
|
||||
return;
|
||||
}
|
||||
this.fetchPage(i);
|
||||
}
|
||||
});
|
||||
|
||||
this.dataStream
|
||||
.pipe(
|
||||
takeUntil(this.destroy$),
|
||||
debounceTime(1000)
|
||||
)
|
||||
.subscribe(i => {
|
||||
this.store.dispatch(new SetShelfOrders([...i]));
|
||||
});
|
||||
|
||||
this.fetchPage(0);
|
||||
return this.dataStream;
|
||||
}
|
||||
|
||||
disconnect(): void {
|
||||
this.destroy$.next();
|
||||
}
|
||||
|
||||
public getPageForIndex(index: number): number {
|
||||
return Math.floor(index / this.pageSize);
|
||||
}
|
||||
|
||||
private fetchPage(page: number): number {
|
||||
if (page === 0) {
|
||||
this.results = false;
|
||||
}
|
||||
if (this.fetchedPages.has(page)) {
|
||||
return;
|
||||
}
|
||||
this.fetchedPages.add(page);
|
||||
this.loading = true;
|
||||
|
||||
const shelfSearch$ =
|
||||
page === 0 && this.useCache
|
||||
? this.collectingShelf.searchShelfCached()
|
||||
: this.collectingShelf.searchShelf(this.search.input, this.search.branchnumber, page * this.pageSize, this.pageSize);
|
||||
|
||||
shelfSearch$.pipe(take(1)).subscribe(({ result, hits }: { result: CollectingShelfOrder[]; hits: number }) => {
|
||||
this.loading = false;
|
||||
this.results = true;
|
||||
|
||||
if (page === 0) {
|
||||
this.cachedData = Array.from<CollectingShelfOrder>({ length: hits });
|
||||
this.allHits = hits;
|
||||
}
|
||||
|
||||
const tempComperer = this.cachedData.filter(t => t && t.orderId);
|
||||
const updatedResult = result.map(or => {
|
||||
const updatedOrder = <CollectingShelfOrder>{
|
||||
...or,
|
||||
shelfOrderItemLevel: !this.cachedData
|
||||
? ShelfOrderItemLevel.Customer
|
||||
: this.defineOrderLevel(or.buyerNumber, or.orderId, or.processingStatus, or.orderItemId, or.compartmentCode, tempComperer),
|
||||
};
|
||||
tempComperer.push(updatedOrder);
|
||||
return updatedOrder;
|
||||
});
|
||||
|
||||
this.cachedData.splice(page * this.pageSize, this.pageSize, ...updatedResult);
|
||||
this.dataStream.next(this.cachedData);
|
||||
|
||||
if (page === 0) {
|
||||
// dispatch immediately on first page load
|
||||
this.firstLoad = false;
|
||||
this.store.dispatch(new SetShelfOrders(this.cachedData));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private defineOrderLevel(
|
||||
buyerNumber: string,
|
||||
orderId: number,
|
||||
processingStatus: number,
|
||||
itemId: number,
|
||||
compartmentCode: string,
|
||||
currentOrders: CollectingShelfOrder[]
|
||||
): ShelfOrderItemLevel {
|
||||
const customerFound = currentOrders.findIndex((or: CollectingShelfOrder) => or && or.buyerNumber === buyerNumber) !== -1;
|
||||
const orderFound = currentOrders.findIndex((or: CollectingShelfOrder) => or && or.orderId === orderId) !== -1;
|
||||
const compartmentCodeFound =
|
||||
currentOrders &&
|
||||
currentOrders[currentOrders.length - 1] &&
|
||||
currentOrders[currentOrders.length - 1].compartmentCode === compartmentCode;
|
||||
const orderByStatus =
|
||||
currentOrders &&
|
||||
currentOrders[currentOrders.length - 1] &&
|
||||
currentOrders[currentOrders.length - 1].processingStatus !== processingStatus;
|
||||
if (customerFound && !orderFound) {
|
||||
return ShelfOrderItemLevel.Order;
|
||||
} else if (customerFound && orderByStatus) {
|
||||
return ShelfOrderItemLevel.Order;
|
||||
} else if (customerFound && !compartmentCodeFound) {
|
||||
return ShelfOrderItemLevel.Order;
|
||||
} else if (!customerFound) {
|
||||
return ShelfOrderItemLevel.Customer;
|
||||
} else {
|
||||
return ShelfOrderItemLevel.Item;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { ShelfSearchResultsComponent } from './shelf-search-results.component';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { LoadingModule } from '@libs/ui';
|
||||
import { SearchResultGroupModule } from '../../components/search-result-group';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, LoadingModule, SearchResultGroupModule],
|
||||
exports: [ShelfSearchResultsComponent],
|
||||
declarations: [ShelfSearchResultsComponent],
|
||||
providers: [],
|
||||
})
|
||||
export class ShelfSearchResultsModule {}
|
||||
@@ -2,16 +2,7 @@ import { Injectable, OnDestroy } from '@angular/core';
|
||||
import { Observable, BehaviorSubject, of, Subject, combineLatest } from 'rxjs';
|
||||
import { SelectFilter, Filter, SelectFilterOption } from '../../filter';
|
||||
import { mockFilters } from '../shared/mockdata/filters.mock';
|
||||
import {
|
||||
tap,
|
||||
switchMap,
|
||||
startWith,
|
||||
map,
|
||||
withLatestFrom,
|
||||
debounceTime,
|
||||
filter,
|
||||
first,
|
||||
} from 'rxjs/operators';
|
||||
import { tap, switchMap, startWith, map, withLatestFrom, debounceTime, filter, first } from 'rxjs/operators';
|
||||
import { SearchStateFacade } from '../../../store/customer';
|
||||
import { flatten } from '../../../shared/utils';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
@@ -27,14 +18,12 @@ export class ShelfFilterService implements OnDestroy {
|
||||
public overlayClosed$ = new Subject<void>();
|
||||
|
||||
constructor(private searchStateFacade: SearchStateFacade) {
|
||||
this.filters$ = this.searchStateFacade.currentSearchProcessFilters$;
|
||||
this.filters$ = this.searchStateFacade.currentFilter$;
|
||||
this.initPendingFilters();
|
||||
}
|
||||
|
||||
get hasSelectedFilters$(): Observable<boolean> {
|
||||
return this.searchStateFacade.currentSearchProcessFilters$.pipe(
|
||||
map(this.computeHasSelectedFilters)
|
||||
);
|
||||
return this.searchStateFacade.currentFilter$.pipe(map(this.computeHasSelectedFilters));
|
||||
}
|
||||
|
||||
get hasSelectedPendingFilters$(): Observable<boolean> {
|
||||
@@ -75,10 +64,7 @@ export class ShelfFilterService implements OnDestroy {
|
||||
}
|
||||
|
||||
private computeHasSelectedFilters(filters: SelectFilter[]): boolean {
|
||||
const flattenedFilters = (flatten(
|
||||
filters,
|
||||
'options'
|
||||
) as unknown) as SelectFilterOption[];
|
||||
const flattenedFilters = (flatten(filters, 'options') as unknown) as SelectFilterOption[];
|
||||
|
||||
if (flattenedFilters.some((f) => !!f.selected)) {
|
||||
return true;
|
||||
|
||||
@@ -5,15 +5,7 @@ import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import {
|
||||
ButtonModule,
|
||||
CardModule,
|
||||
IconModule,
|
||||
InputModule,
|
||||
LoadingModule,
|
||||
SearchInputModule,
|
||||
DropdownModule,
|
||||
} from '@libs/ui';
|
||||
import { ButtonModule, CardModule, IconModule, InputModule, LoadingModule, SearchInputModule, DropdownModule } from '@libs/ui';
|
||||
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
import {
|
||||
@@ -23,7 +15,7 @@ import {
|
||||
ShelfOrderTagComponent,
|
||||
ShelfPartialCollectionModalComponent,
|
||||
} from './components';
|
||||
import { ShelfSearchResultsComponent } from './pages/shelf-search-results/shelf-search-results.component';
|
||||
|
||||
import { ShelfRoutingModule } from './shelf-routing.module';
|
||||
import { ShelfOrderDetailsComponent } from './pages/shelf-order-details/shelf-order-details.component';
|
||||
import { OrderStatusPipe } from '../../pipes/order-status.pipe';
|
||||
@@ -32,11 +24,11 @@ import { ShelfEditOrderComponent } from './pages/shelf-edit-order/shelf-edit-ord
|
||||
import { OrderItemEditComponent } from './components/order-item-edit/order-item-edit.component';
|
||||
import { OrderOverviewEditComponent } from './components/order-overview-edit/order-overview-edit.component';
|
||||
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
||||
import { ShelfSearchResultsModule } from './pages/shelf-search-results/shelf-search-results.module';
|
||||
import { ShelfSearchModule } from './pages/shelf-search';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
ShelfSearchResultsComponent,
|
||||
ShelfOrderItemComponent,
|
||||
ShelfOrderTagComponent,
|
||||
ShelfCustomerOrderComponent,
|
||||
@@ -68,6 +60,7 @@ import { ShelfSearchModule } from './pages/shelf-search';
|
||||
IconModule,
|
||||
LoadingModule,
|
||||
ButtonModule,
|
||||
ShelfSearchResultsModule,
|
||||
],
|
||||
})
|
||||
export class ShelfModule {}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
export interface GroupedByCustomer<T> {
|
||||
import { GroupedByOrder } from './grouped-by-order';
|
||||
|
||||
export interface GroupedByCustomer {
|
||||
buyerNumber?: string;
|
||||
fullName?: string;
|
||||
items?: T[];
|
||||
items?: GroupedByOrder[];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { OrderItemListItemDTO, OrderItemProcessingStatusValue } from '@swagger/oms';
|
||||
|
||||
export interface GroupedByOrder {
|
||||
orderNumber: string;
|
||||
items: OrderItemListItemDTO[];
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface Group<T> {
|
||||
group: string;
|
||||
items: T[];
|
||||
}
|
||||
@@ -1,2 +1,4 @@
|
||||
export * from './search-process';
|
||||
export * from './grouped-by-customer';
|
||||
export * from './grouped-by-order';
|
||||
export * from './grouped';
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { GroupedByCustomer } from '../defs';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
||||
import { addOrCreateOrderGroup } from './grouped-by-order.mapper';
|
||||
|
||||
export function addOrCreateCustomerGroup(list: GroupedByCustomer[], item: OrderItemListItemDTO): GroupedByCustomer[] {
|
||||
const customerGroupIndex = list.findIndex((ex) => ex.buyerNumber === item.buyerNumber);
|
||||
const customerGroupList = [...list];
|
||||
|
||||
if (customerGroupIndex === -1) {
|
||||
const customerGroup = {
|
||||
buyerNumber: item.buyerNumber,
|
||||
fullName: `${item.firstName} ${item.lastName}`,
|
||||
items: addOrCreateOrderGroup([], item),
|
||||
};
|
||||
customerGroupList.push(customerGroup);
|
||||
} else {
|
||||
const customerGroup = { ...customerGroupList[customerGroupIndex] };
|
||||
customerGroup.items = addOrCreateOrderGroup(customerGroup.items, item);
|
||||
customerGroupList[customerGroupIndex] = customerGroup;
|
||||
}
|
||||
|
||||
return customerGroupList;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { GroupedByOrder } from '../defs';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
||||
|
||||
export function addOrCreateOrderGroup(list: GroupedByOrder[], item: OrderItemListItemDTO): GroupedByOrder[] {
|
||||
const orderGroupIndex = list.findIndex((ex) => ex.orderNumber === item.orderNumber);
|
||||
const orderGroupList = [...list];
|
||||
|
||||
if (orderGroupIndex === -1) {
|
||||
const orderGroup = {
|
||||
orderNumber: item.orderNumber,
|
||||
items: [item],
|
||||
};
|
||||
orderGroupList.push(orderGroup);
|
||||
} else {
|
||||
const orderGroup = { ...orderGroupList[orderGroupIndex] };
|
||||
orderGroup.items = [...orderGroup.items, item];
|
||||
orderGroupList[orderGroupIndex] = orderGroup;
|
||||
}
|
||||
return orderGroupList;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './grouped-by-customer.mapper';
|
||||
export * from './grouped-by-order.mapper';
|
||||
@@ -3,20 +3,22 @@ import { Store } from '@ngrx/store';
|
||||
import { Store as NgxsStore } from '@ngxs/store';
|
||||
import * as actions from './search.actions';
|
||||
import * as selectors from './search.selectors';
|
||||
import { map, first, take, switchMap, filter, startWith } from 'rxjs/operators';
|
||||
import { from, Observable } from 'rxjs';
|
||||
import { SearchProcess } from './defs';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
||||
import { GroupedByCustomer } from './defs';
|
||||
import { switchMap, filter, map, first } from 'rxjs/operators';
|
||||
import { SharedSelectors } from 'apps/sales/src/app/core/store/selectors/shared.selectors';
|
||||
import { ShelfPrimaryFilterOptions } from 'apps/sales/src/app/modules/shelf/defs/shelf-primary-filter-options';
|
||||
import { Observable } from 'rxjs';
|
||||
import { GroupedByCustomer } from './defs';
|
||||
import { addOrCreateCustomerGroup } from './mappers';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
import { SelectFilter } from 'apps/sales/src/app/modules/filter';
|
||||
import { ShelfPrimaryFilterOptions } from 'apps/sales/src/app/modules/shelf/defs';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class SearchStateFacade {
|
||||
get process$() {
|
||||
return this.getProcessId$().pipe(switchMap((id) => this.getProcess$(id)));
|
||||
return this.getProcessId$().pipe(
|
||||
switchMap((id) => this.getProcess$(id)),
|
||||
filter((process) => !isNullOrUndefined(process))
|
||||
);
|
||||
}
|
||||
|
||||
get input$() {
|
||||
@@ -28,9 +30,7 @@ export class SearchStateFacade {
|
||||
}
|
||||
|
||||
get resultGroupedByCustomer$() {
|
||||
return this.getProcessId$().pipe(
|
||||
switchMap((id) => this.getResultGroupedByCustomer$(id))
|
||||
);
|
||||
return this.getProcessId$().pipe(switchMap((id) => this.getResultGroupedByCustomer$(id)));
|
||||
}
|
||||
|
||||
get hits$() {
|
||||
@@ -41,6 +41,26 @@ export class SearchStateFacade {
|
||||
return this.getProcessId$().pipe(switchMap((id) => this.getFetching$(id)));
|
||||
}
|
||||
|
||||
get primaryFilters$() {
|
||||
return this.process$.pipe(switchMap((process) => this.getPrimaryFilters(process.id)));
|
||||
}
|
||||
|
||||
get currentFilter$(): Observable<SelectFilter[]> {
|
||||
return this.process$.pipe(
|
||||
filter((process) => !isNullOrUndefined(process) && !isNullOrUndefined(process.filters)),
|
||||
map((process) => process.filters.selectedFilters)
|
||||
);
|
||||
}
|
||||
|
||||
get selectedFilter$(): Observable<string[]> {
|
||||
return this.currentFilter$.pipe(
|
||||
map(() => {
|
||||
// TODO extracting all selected filters possibly required for building search query
|
||||
return [];
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
constructor(private store: Store<any>, private ngxsStore: NgxsStore) {}
|
||||
|
||||
getProcessId$() {
|
||||
@@ -66,31 +86,8 @@ export class SearchStateFacade {
|
||||
return this.store.select(selectors.selectResult, id);
|
||||
}
|
||||
|
||||
getResultGroupedByCustomer$(
|
||||
id: number
|
||||
): Observable<GroupedByCustomer<OrderItemListItemDTO>[]> {
|
||||
return this.getResult$(id).pipe(
|
||||
map((result) =>
|
||||
result.reduce((acc, item) => {
|
||||
const existing = acc.findIndex(
|
||||
(ex) => ex.buyerNumber === item.buyerNumber
|
||||
);
|
||||
if (existing === -1) {
|
||||
return [
|
||||
...acc,
|
||||
{
|
||||
buyerNumber: item.buyerNumber,
|
||||
fullName: `${item.firstName} ${item.lastName}`,
|
||||
items: [item],
|
||||
},
|
||||
];
|
||||
} else {
|
||||
acc[existing].items.push(item);
|
||||
}
|
||||
return acc;
|
||||
}, [] as GroupedByCustomer<OrderItemListItemDTO>[])
|
||||
)
|
||||
);
|
||||
getResultGroupedByCustomer$(id: number): Observable<GroupedByCustomer[]> {
|
||||
return this.getResult$(id).pipe(map((result) => result.reduce(addOrCreateCustomerGroup, [])));
|
||||
}
|
||||
|
||||
getHits$(id: number) {
|
||||
@@ -101,32 +98,8 @@ export class SearchStateFacade {
|
||||
return this.store.select(selectors.selectFetching, id);
|
||||
}
|
||||
|
||||
get currentSearchProcess$(): Observable<SearchProcess> {
|
||||
return from(this.getProcessId()).pipe(
|
||||
take(1),
|
||||
switchMap((processId) =>
|
||||
this.store.select(selectors.selectProcess, processId)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
get currentSearchProcessFilters$(): Observable<SelectFilter[]> {
|
||||
return this.currentSearchProcess$.pipe(
|
||||
filter(
|
||||
(process) =>
|
||||
!isNullOrUndefined(process) && !isNullOrUndefined(process.filters)
|
||||
),
|
||||
map((process) => process.filters.selectedFilters)
|
||||
);
|
||||
}
|
||||
|
||||
get selectedSearchProcessFilters$(): Observable<string[]> {
|
||||
return this.currentSearchProcessFilters$.pipe(
|
||||
map((filters) => {
|
||||
// TODO extracting all selected filters possibly required for building search query
|
||||
return [];
|
||||
})
|
||||
);
|
||||
getPrimaryFilters(id: number): Observable<ShelfPrimaryFilterOptions> {
|
||||
return this.store.select(selectors.selectPrimaryFilters, id);
|
||||
}
|
||||
|
||||
async setInput(input: string, id?: number) {
|
||||
@@ -149,10 +122,7 @@ export class SearchStateFacade {
|
||||
this.store.dispatch(actions.setSelectedFilters({ filters, id: processId }));
|
||||
}
|
||||
|
||||
async setPrimaryFilters(
|
||||
filters: Partial<ShelfPrimaryFilterOptions>,
|
||||
id?: number
|
||||
) {
|
||||
async setPrimaryFilters(filters: Partial<ShelfPrimaryFilterOptions>, id?: number) {
|
||||
let updatedFilters: ShelfPrimaryFilterOptions;
|
||||
let processId = id;
|
||||
|
||||
@@ -160,34 +130,14 @@ export class SearchStateFacade {
|
||||
processId = await this.getProcessId();
|
||||
}
|
||||
|
||||
const currentPrimaryFilters = await this.getCurrentPrimaryFilters(processId)
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
const currentPrimaryFilters = await this.getPrimaryFilters(processId).pipe(first()).toPromise();
|
||||
|
||||
updatedFilters = {
|
||||
...currentPrimaryFilters,
|
||||
...filters,
|
||||
} as ShelfPrimaryFilterOptions;
|
||||
|
||||
return this.store.dispatch(
|
||||
actions.setPrimaryFilters({ filters: updatedFilters, id: processId })
|
||||
);
|
||||
}
|
||||
|
||||
getPrimaryFilters(id?: number): Observable<ShelfPrimaryFilterOptions> {
|
||||
if (id) {
|
||||
return this.getCurrentPrimaryFilters(id);
|
||||
}
|
||||
|
||||
return from(this.getProcessId()).pipe(
|
||||
switchMap((processId) => this.getCurrentPrimaryFilters(processId))
|
||||
);
|
||||
}
|
||||
|
||||
private getCurrentPrimaryFilters(
|
||||
processId: number
|
||||
): Observable<ShelfPrimaryFilterOptions> {
|
||||
return this.store.select(selectors.selectPrimaryFilters, processId);
|
||||
return this.store.dispatch(actions.setPrimaryFilters({ filters: updatedFilters, id: processId }));
|
||||
}
|
||||
|
||||
async fetchResult(id?: number) {
|
||||
|
||||
@@ -1,23 +1,12 @@
|
||||
import { createReducer, Action, on } from '@ngrx/store';
|
||||
import {
|
||||
INITIAL_SEARCH_STATE,
|
||||
SearchState,
|
||||
searchStateAdapter,
|
||||
INITIAL_SEARCH_PROCESS,
|
||||
} from './search.state';
|
||||
import { INITIAL_SEARCH_STATE, SearchState, searchStateAdapter, INITIAL_SEARCH_PROCESS } from './search.state';
|
||||
import * as actions from './search.actions';
|
||||
|
||||
const _searchReducer = createReducer(
|
||||
INITIAL_SEARCH_STATE,
|
||||
on(actions.addSearchProcess, (s, a) =>
|
||||
searchStateAdapter.addOne({ id: a.id, ...INITIAL_SEARCH_PROCESS }, s)
|
||||
),
|
||||
on(actions.removeSearchProcess, (s, a) =>
|
||||
searchStateAdapter.removeOne(a.id, s)
|
||||
),
|
||||
on(actions.setInput, (s, a) =>
|
||||
searchStateAdapter.updateOne({ id: a.id, changes: { input: a.input } }, s)
|
||||
),
|
||||
on(actions.addSearchProcess, (s, a) => searchStateAdapter.addOne({ ...INITIAL_SEARCH_PROCESS, id: a.id }, s)),
|
||||
on(actions.removeSearchProcess, (s, a) => searchStateAdapter.removeOne(a.id, s)),
|
||||
on(actions.setInput, (s, a) => searchStateAdapter.updateOne({ id: a.id, changes: { input: a.input } }, s)),
|
||||
on(actions.setSelectedFilters, (s, a) =>
|
||||
searchStateAdapter.updateOne(
|
||||
{
|
||||
@@ -43,15 +32,7 @@ const _searchReducer = createReducer(
|
||||
s
|
||||
)
|
||||
),
|
||||
on(actions.addSearchProcess, (s, a) =>
|
||||
searchStateAdapter.addOne({ ...INITIAL_SEARCH_PROCESS, id: a.id }, s)
|
||||
),
|
||||
on(actions.removeSearchProcess, (s, a) =>
|
||||
searchStateAdapter.removeOne(a.id, s)
|
||||
),
|
||||
on(actions.clearResults, (s, a) =>
|
||||
searchStateAdapter.updateOne({ id: a.id, changes: { result: [] } }, s)
|
||||
),
|
||||
on(actions.clearResults, (s, a) => searchStateAdapter.updateOne({ id: a.id, changes: { result: [] } }, s)),
|
||||
on(actions.addResult, (s, a) =>
|
||||
searchStateAdapter.updateOne(
|
||||
{
|
||||
@@ -61,18 +42,10 @@ const _searchReducer = createReducer(
|
||||
s
|
||||
)
|
||||
),
|
||||
on(actions.clearHits, (s, a) =>
|
||||
searchStateAdapter.updateOne({ id: a.id, changes: { hits: undefined } }, s)
|
||||
),
|
||||
on(actions.setHits, (s, a) =>
|
||||
searchStateAdapter.updateOne({ id: a.id, changes: { hits: a.hits } }, s)
|
||||
),
|
||||
on(actions.fetchResult, (s, a) =>
|
||||
searchStateAdapter.updateOne({ id: a.id, changes: { fetching: true } }, s)
|
||||
),
|
||||
on(actions.fetchResultDone, (s, a) =>
|
||||
searchStateAdapter.updateOne({ id: a.id, changes: { fetching: false } }, s)
|
||||
)
|
||||
on(actions.clearHits, (s, a) => searchStateAdapter.updateOne({ id: a.id, changes: { hits: undefined } }, s)),
|
||||
on(actions.setHits, (s, a) => searchStateAdapter.updateOne({ id: a.id, changes: { hits: a.hits } }, s)),
|
||||
on(actions.fetchResult, (s, a) => searchStateAdapter.updateOne({ id: a.id, changes: { fetching: true } }, s)),
|
||||
on(actions.fetchResultDone, (s, a) => searchStateAdapter.updateOne({ id: a.id, changes: { fetching: false } }, s))
|
||||
);
|
||||
|
||||
export function searchReducer(state: SearchState, action: Action) {
|
||||
|
||||
@@ -4,61 +4,28 @@ import { searchStateAdapter } from './search.state';
|
||||
import { Dictionary } from '@ngrx/entity';
|
||||
import { SearchProcess } from './defs';
|
||||
|
||||
export const selectSearchState = createSelector(
|
||||
selectShelfState,
|
||||
(s) => s.search
|
||||
);
|
||||
export const selectSearchState = createSelector(selectShelfState, (s) => s.search);
|
||||
|
||||
export const { selectAll, selectEntities } = searchStateAdapter.getSelectors();
|
||||
export const { selectAll, selectEntities } = searchStateAdapter.getSelectors(selectSearchState);
|
||||
|
||||
export const selectAllSearchProcesses = createSelector(
|
||||
selectSearchState,
|
||||
selectAll
|
||||
);
|
||||
export const selectProcess = createSelector(selectEntities, (entities: Dictionary<SearchProcess>, id: number) => entities[id]);
|
||||
|
||||
export const selectAllSearchProcessEntities = createSelector(
|
||||
selectSearchState,
|
||||
selectEntities
|
||||
);
|
||||
export const selectInput = createSelector(selectEntities, (entities: Dictionary<SearchProcess>, id: number) => entities[id].input);
|
||||
|
||||
export const selectProcess = createSelector(
|
||||
selectAllSearchProcessEntities,
|
||||
(entities: Dictionary<SearchProcess>, id: number) => entities[id]
|
||||
);
|
||||
export const selectResult = createSelector(selectEntities, (entities: Dictionary<SearchProcess>, id: number) => entities[id].result);
|
||||
|
||||
export const selectInput = createSelector(
|
||||
selectEntities,
|
||||
(entities: Dictionary<SearchProcess>, id: number) => entities[id].input
|
||||
);
|
||||
export const selectHits = createSelector(selectEntities, (entities: Dictionary<SearchProcess>, id: number) => entities[id].hits);
|
||||
|
||||
export const selectResult = createSelector(
|
||||
selectEntities,
|
||||
(entities: Dictionary<SearchProcess>, id: number) => entities[id].result
|
||||
);
|
||||
export const selectFetching = createSelector(selectEntities, (entities: Dictionary<SearchProcess>, id: number) => entities[id].fetching);
|
||||
|
||||
export const selectHits = createSelector(
|
||||
selectEntities,
|
||||
(entities: Dictionary<SearchProcess>, id: number) => entities[id].hits
|
||||
);
|
||||
|
||||
export const selectFetching = createSelector(
|
||||
selectEntities,
|
||||
(entities: Dictionary<SearchProcess>, id: number) => entities[id].fetching
|
||||
);
|
||||
|
||||
export const selectFilters = createSelector(
|
||||
selectEntities,
|
||||
(entities: Dictionary<SearchProcess>, id: number) => entities[id].filters
|
||||
);
|
||||
export const selectFilters = createSelector(selectEntities, (entities: Dictionary<SearchProcess>, id: number) => entities[id].filters);
|
||||
|
||||
export const selectSelectedFilters = createSelector(
|
||||
selectAllSearchProcessEntities,
|
||||
(entities: Dictionary<SearchProcess>, id: number) =>
|
||||
entities[id].filters.selectedFilters
|
||||
selectEntities,
|
||||
(entities: Dictionary<SearchProcess>, id: number) => entities[id].filters.selectedFilters
|
||||
);
|
||||
|
||||
export const selectPrimaryFilters = createSelector(
|
||||
selectAllSearchProcessEntities,
|
||||
(entities: Dictionary<SearchProcess>, id: number) =>
|
||||
entities[id].filters.primaryFilters
|
||||
selectEntities,
|
||||
(entities: Dictionary<SearchProcess>, id: number) => entities[id].filters.primaryFilters
|
||||
);
|
||||
|
||||
@@ -29,7 +29,7 @@ export const INITIAL_FILTERS: {
|
||||
export const INITIAL_SEARCH_PROCESS: SearchProcess = {
|
||||
id: undefined,
|
||||
result: [],
|
||||
input: 'Müller',
|
||||
input: '',
|
||||
fetching: false,
|
||||
filters: INITIAL_FILTERS,
|
||||
};
|
||||
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
BIN
apps/sales/src/assets/icons/icon-144x144.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
BIN
apps/sales/src/assets/icons/icon-192x192.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
BIN
apps/sales/src/assets/icons/icon-512x512.png
Normal file → Executable file
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 13 KiB |
BIN
apps/sales/src/assets/icons/icon-72x72.png
Normal file → Executable file
|
Before Width: | Height: | Size: 792 B After Width: | Height: | Size: 1.7 KiB |
BIN
apps/sales/src/assets/icons/icon-96x96.png
Normal file → Executable file
|
Before Width: | Height: | Size: 958 B After Width: | Height: | Size: 2.4 KiB |
@@ -6,6 +6,10 @@ import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
import 'hammerjs';
|
||||
import { AppConfiguration } from './app/app-configuration';
|
||||
import { registerLocaleData } from '@angular/common';
|
||||
|
||||
import localeDe from '@angular/common/locales/de';
|
||||
registerLocaleData(localeDe, 'de');
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
|
||||
@@ -12,6 +12,23 @@
|
||||
font-weight: $font-weight-emphasis;
|
||||
}
|
||||
|
||||
.isa-text-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.isa-text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.isa-text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
//TODO: _color.scss ausglagern
|
||||
.isa-font-color-customer {
|
||||
color: $isa-customer;
|
||||
}
|
||||
|
||||
.isa-font-grey {
|
||||
color: $text-grey;
|
||||
}
|
||||
@@ -19,7 +36,3 @@
|
||||
.isa-font-lightgrey {
|
||||
color: $text-lightgrey;
|
||||
}
|
||||
|
||||
.isa-font-color-customer {
|
||||
color: $isa-customer;
|
||||
}
|
||||
|
||||