mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
Merge Store Changes from Main Branch
This commit is contained in:
@@ -13,7 +13,7 @@ export class BranchService {
|
||||
constructor(private checkoutService: StoreCheckoutService, private orderService: OrderService, private ssoService: SsoService) {}
|
||||
|
||||
getCurrentBranchNumber() {
|
||||
this.ssoService.getClaimByKey('branch_no');
|
||||
return this.ssoService.getClaimByKey('branch_no');
|
||||
}
|
||||
|
||||
searchBranches(input: string, skip: number, take: number): Observable<BranchDTO[]> {
|
||||
|
||||
@@ -1,22 +1,15 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import {
|
||||
map,
|
||||
switchMap,
|
||||
filter,
|
||||
startWith,
|
||||
shareReplay,
|
||||
withLatestFrom,
|
||||
share,
|
||||
} from 'rxjs/operators';
|
||||
import { map, switchMap, filter, startWith } from 'rxjs/operators';
|
||||
import { LocationService } from './location-service';
|
||||
import { RemissionOverlayService } from '../../modules/remission/services';
|
||||
import { Select } from '@ngxs/store';
|
||||
import { RemissionSelectors } from '../store/selectors/remission.selectors';
|
||||
import { SearchStateFacade } from '../../store/customer';
|
||||
|
||||
import { isNullOrUndefined } from 'util';
|
||||
import { SharedSelectors } from '../store/selectors/shared.selectors';
|
||||
import { ShelfOverlayService } from '../../modules/shelf/services';
|
||||
import { RemissionSelectors } from '../store/selectors/remission.selectors';
|
||||
import { SharedSelectors } from '../store/selectors/shared.selectors';
|
||||
import { SearchStateFacade } from 'apps/sales/src/app/store/customer';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ContentHeaderService {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export interface GroupedByCustomer<T> {
|
||||
buyerNumber?: string;
|
||||
fullName?: string;
|
||||
items?: T[];
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
export * from './search-process';
|
||||
export * from './grouped-by-customer';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ShelfPrimaryFilterOptions } from 'apps/sales/src/app/modules/shelf/defs';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
||||
|
||||
export interface SearchProcess {
|
||||
id: number; // Prozess ID;
|
||||
@@ -7,4 +8,7 @@ export interface SearchProcess {
|
||||
selectedFilters?: { [key: string]: string[] };
|
||||
primaryFilters?: ShelfPrimaryFilterOptions;
|
||||
};
|
||||
result: OrderItemListItemDTO[];
|
||||
hits?: number;
|
||||
fetching: boolean;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { createAction, props } from '@ngrx/store';
|
||||
import { ShelfPrimaryFilterOptions } from 'apps/sales/src/app/modules/shelf/defs';
|
||||
import {
|
||||
OrderItemListItemDTO,
|
||||
StrictHttpResponse,
|
||||
ListResponseArgsOfOrderItemListItemDTO,
|
||||
} from '@swagger/oms';
|
||||
|
||||
const prefix = '[CUSTOMER] [SHELF] [SEARCH]';
|
||||
|
||||
@@ -13,11 +18,6 @@ export const removeSearchProcess = createAction(
|
||||
props<{ id: number }>()
|
||||
);
|
||||
|
||||
export const setInput = createAction(
|
||||
`${prefix} Set Input`,
|
||||
props<{ id: number; input: string }>()
|
||||
);
|
||||
|
||||
export const setSelectedFilters = createAction(
|
||||
`${prefix} Set Selected Filters`,
|
||||
props<{ id: number; filters: { [key: string]: string[] } }>()
|
||||
@@ -32,3 +32,41 @@ export const setPrimaryFilters = createAction(
|
||||
`${prefix} Set Primary Filters`,
|
||||
props<{ id: number; filters: ShelfPrimaryFilterOptions }>()
|
||||
);
|
||||
|
||||
export const setInput = createAction(
|
||||
`${prefix} Search Input`,
|
||||
props<{ id: number; input: string }>()
|
||||
);
|
||||
|
||||
export const clearResults = createAction(
|
||||
`${prefix} Clear Results`,
|
||||
props<{ id: number }>()
|
||||
);
|
||||
|
||||
export const addResult = createAction(
|
||||
`${prefix} Add Result`,
|
||||
props<{ id: number; result: OrderItemListItemDTO[] }>()
|
||||
);
|
||||
|
||||
export const clearHits = createAction(
|
||||
`${prefix} Clear Hits`,
|
||||
props<{ id: number }>()
|
||||
);
|
||||
|
||||
export const setHits = createAction(
|
||||
`${prefix} Set Hits`,
|
||||
props<{ id: number; hits: number }>()
|
||||
);
|
||||
|
||||
export const fetchResult = createAction(
|
||||
`${prefix} Fetch Result`,
|
||||
props<{ id: number }>()
|
||||
);
|
||||
|
||||
export const fetchResultDone = createAction(
|
||||
`${prefix} Fetch Result Done`,
|
||||
props<{
|
||||
id: number;
|
||||
response: StrictHttpResponse<ListResponseArgsOfOrderItemListItemDTO>;
|
||||
}>()
|
||||
);
|
||||
|
||||
@@ -1,16 +1,66 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Actions, createEffect, ofType } from '@ngrx/effects';
|
||||
import { Actions as NgxsActions, ofActionDispatched } from '@ngxs/store';
|
||||
import { AddProcess, DeleteProcess } from 'apps/sales/src/app/core/store/actions/process.actions';
|
||||
import * as actions from './search.actions';
|
||||
import { switchMap, withLatestFrom, catchError, map, flatMap } from 'rxjs/operators';
|
||||
import { OrderService, StrictHttpResponse, ListResponseArgsOfOrderItemListItemDTO } from '@swagger/oms';
|
||||
import { BranchService } from '@sales/core-services';
|
||||
import { SearchStateFacade } from './search.facade';
|
||||
import { of, NEVER } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class SearchEffects {
|
||||
constructor(private ngxsActions$: NgxsActions, private store: Store<any>) {
|
||||
constructor(
|
||||
private actions$: Actions,
|
||||
private ngxsActions$: NgxsActions,
|
||||
private store: Store<any>,
|
||||
private searchStateFacade: SearchStateFacade,
|
||||
private orderService: OrderService,
|
||||
private branchService: BranchService
|
||||
) {
|
||||
this.initAddProcess();
|
||||
this.initRemoveProcess();
|
||||
}
|
||||
|
||||
fetchResults$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(actions.fetchResult),
|
||||
switchMap((a) =>
|
||||
of(a).pipe(
|
||||
withLatestFrom(this.searchStateFacade.getProcess$(a.id)),
|
||||
flatMap(([_, process]) =>
|
||||
this.orderService
|
||||
.OrderWarenausgabeResponse({
|
||||
branchNumber: this.branchService.getCurrentBranchNumber(),
|
||||
input: process.input,
|
||||
skip: process.result.length || 0,
|
||||
take: 20,
|
||||
})
|
||||
.pipe(
|
||||
catchError((err) => of<StrictHttpResponse<ListResponseArgsOfOrderItemListItemDTO>>(err)),
|
||||
map((response) => actions.fetchResultDone({ id: a.id, response }))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
fetchResultDone$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(actions.fetchResultDone),
|
||||
flatMap((action) => {
|
||||
if (action.response.ok) {
|
||||
const result = action.response.body;
|
||||
return [actions.setHits({ id: action.id, hits: result.hits }), actions.addResult({ id: action.id, result: result.result })];
|
||||
}
|
||||
return NEVER;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
initAddProcess() {
|
||||
this.ngxsActions$.pipe(ofActionDispatched(AddProcess)).subscribe((action) => {
|
||||
if (action instanceof AddProcess) {
|
||||
|
||||
@@ -2,37 +2,109 @@ import { Injectable } from '@angular/core';
|
||||
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 { SharedSelectors } from 'apps/sales/src/app/core/store/selectors/shared.selectors';
|
||||
import { map, first, take, switchMap, filter } from 'rxjs/operators';
|
||||
import { from, Observable } from 'rxjs';
|
||||
import {
|
||||
selectSearchProcessById,
|
||||
selectProcessPrimaryFiltersById,
|
||||
} from './search.selectors';
|
||||
import { SearchProcess } from './defs';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
import { ShelfPrimaryFilterOptions } from 'apps/sales/src/app/modules/shelf/defs';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
||||
import { GroupedByCustomer } from './defs';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class SearchStateFacade {
|
||||
get process$() {
|
||||
return this.getProcessId$().pipe(switchMap((id) => this.getProcess$(id)));
|
||||
}
|
||||
|
||||
get input$() {
|
||||
return this.getProcessId$().pipe(switchMap((id) => this.getInput$(id)));
|
||||
}
|
||||
|
||||
get result$() {
|
||||
return this.getProcessId$().pipe(switchMap((id) => this.getResult$(id)));
|
||||
}
|
||||
|
||||
get resultGroupedByCustomer$() {
|
||||
return this.getProcessId$().pipe(
|
||||
switchMap((id) => this.getResultGroupedByCustomer$(id))
|
||||
);
|
||||
}
|
||||
|
||||
get hits$() {
|
||||
return this.getProcessId$().pipe(switchMap((id) => this.getHits$(id)));
|
||||
}
|
||||
|
||||
get fetching$() {
|
||||
return this.getProcessId$().pipe(switchMap((id) => this.getFetching$(id)));
|
||||
}
|
||||
|
||||
constructor(private store: Store<any>, private ngxsStore: NgxsStore) {}
|
||||
|
||||
getProcessId$() {
|
||||
return this.ngxsStore.select(SharedSelectors.getCurrentProcess).pipe(
|
||||
filter((process) => !!process && !!process.id),
|
||||
map((currentProcess) => currentProcess.id)
|
||||
);
|
||||
}
|
||||
|
||||
getProcessId() {
|
||||
return this.ngxsStore
|
||||
.select(SharedSelectors.getCurrentProcess)
|
||||
.pipe(
|
||||
filter((currentProcess) => !isNullOrUndefined(currentProcess)),
|
||||
map((currentProcess) => currentProcess.id),
|
||||
first()
|
||||
return this.getProcessId$().pipe(first()).toPromise();
|
||||
}
|
||||
|
||||
getProcess$(id: number) {
|
||||
return this.store.select(selectors.selectProcess, id);
|
||||
}
|
||||
|
||||
getInput$(id: number) {
|
||||
return this.store.select(selectors.selectInput, id);
|
||||
}
|
||||
|
||||
getResult$(id: number) {
|
||||
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>[])
|
||||
)
|
||||
.toPromise();
|
||||
);
|
||||
}
|
||||
|
||||
getHits$(id: number) {
|
||||
return this.store.select(selectors.selectHits, id);
|
||||
}
|
||||
|
||||
getFetching$(id: number) {
|
||||
return this.store.select(selectors.selectFetching, id);
|
||||
}
|
||||
|
||||
get currentSearchProcess$(): Observable<SearchProcess> {
|
||||
return from(this.getProcessId()).pipe(
|
||||
take(1),
|
||||
switchMap((processId) =>
|
||||
this.store.select(selectSearchProcessById, processId)
|
||||
this.store.select(selectors.selectProcess, processId)
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -105,6 +177,22 @@ export class SearchStateFacade {
|
||||
private getCurrentPrimaryFilters(
|
||||
processId: number
|
||||
): Observable<ShelfPrimaryFilterOptions> {
|
||||
return this.store.select(selectProcessPrimaryFiltersById, processId);
|
||||
return this.store.select(selectors.selectPrimaryFilters, processId);
|
||||
}
|
||||
|
||||
async fetchResult(id?: number) {
|
||||
let processId = id;
|
||||
if (typeof processId !== 'number') {
|
||||
processId = await this.getProcessId();
|
||||
}
|
||||
this.store.dispatch(actions.fetchResult({ id: processId }));
|
||||
}
|
||||
|
||||
async clearResult(id?: number) {
|
||||
let processId = id;
|
||||
if (typeof processId !== 'number') {
|
||||
processId = await this.getProcessId();
|
||||
}
|
||||
this.store.dispatch(actions.clearResults({ id: processId }));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,14 @@ import {
|
||||
INITIAL_SEARCH_STATE,
|
||||
SearchState,
|
||||
searchStateAdapter,
|
||||
INITIAL_FILTERS,
|
||||
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, filters: INITIAL_FILTERS }, s)
|
||||
searchStateAdapter.addOne({ id: a.id, ...INITIAL_SEARCH_PROCESS }, s)
|
||||
),
|
||||
on(actions.removeSearchProcess, (s, a) =>
|
||||
searchStateAdapter.removeOne(a.id, s)
|
||||
@@ -42,6 +42,36 @@ const _searchReducer = createReducer(
|
||||
{ id: a.id, changes: { filters: { primaryFilters: a.filters } } },
|
||||
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.addResult, (s, a) =>
|
||||
searchStateAdapter.updateOne(
|
||||
{
|
||||
id: a.id,
|
||||
changes: { result: [...s.entities[a.id].result, ...a.result] },
|
||||
},
|
||||
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)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -1,55 +1,60 @@
|
||||
import { createSelector } from '@ngrx/store';
|
||||
import { selectShelfState } from '../shelf.selectors';
|
||||
import { searchStateAdapter } from './search.state';
|
||||
import { Dictionary } from '@ngrx/entity';
|
||||
import { SearchProcess } from './defs';
|
||||
import { ShelfPrimaryFilterOptions } from 'apps/sales/src/app/modules/shelf/defs';
|
||||
|
||||
export const selectSearchState = createSelector(
|
||||
selectShelfState,
|
||||
(s) => s.search
|
||||
);
|
||||
|
||||
export const { selectAll } = searchStateAdapter.getSelectors();
|
||||
export const { selectAll, selectEntities } = searchStateAdapter.getSelectors();
|
||||
|
||||
export const selectAllSearchProcesses = createSelector(
|
||||
selectSearchState,
|
||||
selectAll
|
||||
);
|
||||
|
||||
export const selectSearchProcessById = createSelector(
|
||||
selectAllSearchProcesses,
|
||||
(s: SearchProcess[], processId: number) =>
|
||||
s.find((searchProcess) => searchProcess.id === processId)
|
||||
export const selectProcess = createSelector(
|
||||
selectEntities,
|
||||
(entities: Dictionary<SearchProcess>, id: number) => entities[id]
|
||||
);
|
||||
|
||||
export const selectSearchProcessFiltersById = createSelector(
|
||||
selectAllSearchProcesses,
|
||||
(s: SearchProcess[], processId: number) => {
|
||||
const searchProcess = s.find((p) => p.id === processId);
|
||||
|
||||
if (searchProcess) {
|
||||
return searchProcess.filters;
|
||||
}
|
||||
}
|
||||
export const selectInput = createSelector(
|
||||
selectEntities,
|
||||
(entities: Dictionary<SearchProcess>, id: number) => entities[id].input
|
||||
);
|
||||
|
||||
export const selectProcessSelectedFiltersById = createSelector(
|
||||
selectAllSearchProcesses,
|
||||
(s: SearchProcess[], processId: number) => {
|
||||
const searchProcess = s.find((p) => p.id === processId);
|
||||
|
||||
if (searchProcess && searchProcess.filters) {
|
||||
return searchProcess.filters.selectedFilters;
|
||||
}
|
||||
}
|
||||
export const selectResult = createSelector(
|
||||
selectEntities,
|
||||
(entities: Dictionary<SearchProcess>, id: number) => entities[id].result
|
||||
);
|
||||
|
||||
export const selectProcessPrimaryFiltersById = createSelector(
|
||||
selectAllSearchProcesses,
|
||||
(s: SearchProcess[], processId: number) => {
|
||||
const searchProcess = s.find((p) => p.id === processId);
|
||||
|
||||
if (searchProcess && searchProcess.filters) {
|
||||
return searchProcess.filters.primaryFilters;
|
||||
}
|
||||
}
|
||||
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 selectSelectedFilters = createSelector(
|
||||
selectEntities,
|
||||
(entities: Dictionary<SearchProcess>, id: number) =>
|
||||
entities[id].filters.selectedFilters
|
||||
);
|
||||
|
||||
export const selectPrimaryFilters = createSelector(
|
||||
selectEntities,
|
||||
(entities: Dictionary<SearchProcess>, id: number) =>
|
||||
entities[id].filters.primaryFilters
|
||||
);
|
||||
|
||||
@@ -24,3 +24,11 @@ export const INITIAL_FILTERS: {
|
||||
selectedFilters: {},
|
||||
primaryFilters: INITIAL_PRIMARY_FILTERS,
|
||||
};
|
||||
|
||||
export const INITIAL_SEARCH_PROCESS: SearchProcess = {
|
||||
id: undefined,
|
||||
result: [],
|
||||
input: 'Müller',
|
||||
fetching: false,
|
||||
filters: INITIAL_FILTERS,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user