From 8f29dcde4246d67fbe8013f075d1b1369f51cbaf Mon Sep 17 00:00:00 2001 From: "aliaksei.bykau" Date: Fri, 24 Nov 2023 12:25:41 +0100 Subject: [PATCH 1/3] [CST-12624] updated the logic of the suggestion-targets feature. --- .../openaire/reciter-suggestions/selectors.ts | 66 +++++---- .../suggestion-targets.component.html | 4 +- .../suggestion-targets.component.ts | 12 +- .../suggestion-targets.reducer.ts | 128 +++++++++++++----- .../suggestion-targets.state.service.ts | 28 ++-- 5 files changed, 156 insertions(+), 82 deletions(-) diff --git a/src/app/openaire/reciter-suggestions/selectors.ts b/src/app/openaire/reciter-suggestions/selectors.ts index d5db946817b..057d0d3a692 100644 --- a/src/app/openaire/reciter-suggestions/selectors.ts +++ b/src/app/openaire/reciter-suggestions/selectors.ts @@ -1,8 +1,10 @@ -import { createFeatureSelector, createSelector, MemoizedSelector } from '@ngrx/store'; -import { subStateSelector } from '../../shared/selector.util'; -import { openaireSelector, OpenaireState } from '../openaire.reducer'; -import { OpenaireSuggestionTarget } from '../../core/openaire/reciter-suggestions/models/openaire-suggestion-target.model'; -import { SuggestionTargetState } from './suggestion-targets/suggestion-targets.reducer'; +import {createFeatureSelector, createSelector, MemoizedSelector} from '@ngrx/store'; +import {subStateSelector} from '../../shared/selector.util'; +import {openaireSelector, OpenaireState} from '../openaire.reducer'; +import { + OpenaireSuggestionTarget +} from '../../core/openaire/reciter-suggestions/models/openaire-suggestion-target.model'; +import {SuggestionTargetState} from './suggestion-targets/suggestion-targets.reducer'; /** * Returns the Reciter Suggestion Target state. @@ -29,8 +31,9 @@ export function reciterSuggestionTargetStateSelector(): MemoizedSelector { - return subStateSelector(reciterSuggestionTargetStateSelector(), 'targets'); +export function reciterSuggestionTargetObjectSelector(source: string): MemoizedSelector { + return createSelector(reciterSuggestionTargetStateSelector(), + (state: SuggestionTargetState) => state[source]?.targets); } /** @@ -38,45 +41,51 @@ export function reciterSuggestionTargetObjectSelector(): MemoizedSelector state.suggestionTarget.loaded -); +export const isReciterSuggestionTargetLoadedSelector = (source: string) => { + return createSelector(_getReciterSuggestionTargetState, (state: OpenaireState) => { + const loaded = state.suggestionTarget[source]?.loaded; + return loaded || false; + }); +}; /** * Returns true if the deduplication sets are processing. * @function isDeduplicationSetsProcessingSelector * @return {boolean} */ -export const isreciterSuggestionTargetProcessingSelector = createSelector(_getReciterSuggestionTargetState, - (state: OpenaireState) => state.suggestionTarget.processing -); +export const isreciterSuggestionTargetProcessingSelector = (source: string) => { + return createSelector(_getReciterSuggestionTargetState, (state: OpenaireState) => { + const processing = state.suggestionTarget[source]?.processing; + return processing || false; + }); +}; /** * Returns the total available pages of Reciter Suggestion Targets. * @function getreciterSuggestionTargetTotalPagesSelector * @return {number} */ -export const getreciterSuggestionTargetTotalPagesSelector = createSelector(_getReciterSuggestionTargetState, - (state: OpenaireState) => state.suggestionTarget.totalPages -); +export const getreciterSuggestionTargetTotalPagesSelector = (source: string) => { + return createSelector(_getReciterSuggestionTargetState, (state: OpenaireState) => state.suggestionTarget[source]?.totalPages); +}; /** * Returns the current page of Reciter Suggestion Targets. * @function getreciterSuggestionTargetCurrentPageSelector * @return {number} */ -export const getreciterSuggestionTargetCurrentPageSelector = createSelector(_getReciterSuggestionTargetState, - (state: OpenaireState) => state.suggestionTarget.currentPage -); +export const getreciterSuggestionTargetCurrentPageSelector = (source: string) => { + return createSelector(_getReciterSuggestionTargetState, (state: OpenaireState) => state.suggestionTarget[source]?.currentPage); +}; /** * Returns the total number of Reciter Suggestion Targets. * @function getreciterSuggestionTargetTotalsSelector * @return {number} */ -export const getreciterSuggestionTargetTotalsSelector = createSelector(_getReciterSuggestionTargetState, - (state: OpenaireState) => state.suggestionTarget.totalElements -); +export const getreciterSuggestionTargetTotalsSelector = (source: string) => { + return createSelector(_getReciterSuggestionTargetState, (state: OpenaireState) => state.suggestionTarget[source]?.totalElements); +}; /** * Returns Suggestion Targets for the current user. @@ -84,7 +93,12 @@ export const getreciterSuggestionTargetTotalsSelector = createSelector(_getRecit * @return {OpenaireSuggestionTarget[]} */ export const getCurrentUserSuggestionTargetsSelector = createSelector(_getReciterSuggestionTargetState, - (state: OpenaireState) => state.suggestionTarget.currentUserTargets + (state: OpenaireState) => { + const suggestionTargetValues = Object.values(state.suggestionTarget); + return suggestionTargetValues.reduce( + (acc, entry) => acc.concat(entry?.currentUserTargets || []), + []); + } ); /** @@ -93,5 +107,9 @@ export const getCurrentUserSuggestionTargetsSelector = createSelector(_getRecite * @return {boolean} */ export const getCurrentUserSuggestionTargetsVisitedSelector = createSelector(_getReciterSuggestionTargetState, - (state: OpenaireState) => state.suggestionTarget.currentUserTargetsVisited + (state: OpenaireState) => { + const suggestionTargetValues = Object.values(state.suggestionTarget); + return suggestionTargetValues.some( + (entry) => entry?.currentUserTargetsVisited === true); + } ); diff --git a/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.component.html b/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.component.html index 791e694ba90..d7e669051b0 100644 --- a/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.component.html +++ b/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.component.html @@ -3,8 +3,8 @@
- - + { this.getSuggestionTargets(); @@ -95,8 +95,8 @@ export class SuggestionTargetsComponent implements OnInit { * @return Observable * 'true' if the targets are loading, 'false' otherwise. */ - public isTargetsLoading(): Observable { - return this.suggestionTargetsStateService.isReciterSuggestionTargetsLoading(); + public isTargetsLoading(source: string): Observable { + return this.suggestionTargetsStateService.isReciterSuggestionTargetsLoading(source); } /** @@ -106,7 +106,7 @@ export class SuggestionTargetsComponent implements OnInit { * 'true' if there are operations running on the targets (ex.: a REST call), 'false' otherwise. */ public isTargetsProcessing(): Observable { - return this.suggestionTargetsStateService.isReciterSuggestionTargetsProcessing(); + return this.suggestionTargetsStateService.isReciterSuggestionTargetsProcessing(this.source); } /** diff --git a/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.reducer.ts b/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.reducer.ts index f8bd53ec050..e5ce049bba6 100644 --- a/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.reducer.ts +++ b/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.reducer.ts @@ -4,7 +4,7 @@ import { OpenaireSuggestionTarget } from '../../../core/openaire/reciter-suggest /** * The interface representing the OpenAIRE suggestion targets state. */ -export interface SuggestionTargetState { +export interface SuggestionTargetEntry { targets: OpenaireSuggestionTarget[]; processing: boolean; loaded: boolean; @@ -15,10 +15,14 @@ export interface SuggestionTargetState { currentUserTargetsVisited: boolean; } +export interface SuggestionTargetState { + [source: string]: SuggestionTargetEntry; +} + /** * Used for the OpenAIRE Suggestion Target state initialization. */ -const SuggestionTargetInitialState: SuggestionTargetState = { +const SuggestionTargetInitialEntity: SuggestionTargetEntry = { targets: [], processing: false, loaded: false, @@ -29,6 +33,10 @@ const SuggestionTargetInitialState: SuggestionTargetState = { currentUserTargetsVisited: false }; +const SuggestionTargetInitialState: SuggestionTargetState = { + 'oaire' : SuggestionTargetInitialEntity +}; + /** * The OpenAIRE Broker Topic Reducer * @@ -42,55 +50,103 @@ const SuggestionTargetInitialState: SuggestionTargetState = { export function SuggestionTargetsReducer(state = SuggestionTargetInitialState, action: SuggestionTargetsActions): SuggestionTargetState { switch (action.type) { case SuggestionTargetActionTypes.RETRIEVE_TARGETS_BY_SOURCE: { - return Object.assign({}, state, { - targets: [], - processing: true - }); + const updatedSuggestion = {}; + + for (const key in state) { + if (state.hasOwnProperty(key)) { + if (key === action.payload.source) { + updatedSuggestion[key] = { + targets: [], + processing: true + }; + } else { + updatedSuggestion[key] = state[key]; + } + } + } + return Object.assign({}, state, updatedSuggestion); } case SuggestionTargetActionTypes.ADD_TARGETS: { - return Object.assign({}, state, { - targets: state.targets.concat(action.payload.targets), - processing: false, - loaded: true, - totalPages: action.payload.totalPages, - currentPage: state.currentPage, - totalElements: action.payload.totalElements - }); + const updatedSuggestion = {}; + + for (const key in state) { + if (state.hasOwnProperty(key)) { + updatedSuggestion[key] = { + targets: state[key].targets.concat(action.payload.targets + .filter(target => target.source === key)), + processing: false, + loaded: true, + totalPages: action.payload.totalPages, + currentPage: state[key].currentPage, + totalElements: action.payload.totalElements, + }; + } + } + return Object.assign({}, state, updatedSuggestion); } case SuggestionTargetActionTypes.RETRIEVE_TARGETS_BY_SOURCE_ERROR: { - return Object.assign({}, state, { - targets: [], - processing: false, - loaded: true, - totalPages: 0, - currentPage: 0, - totalElements: 0, - }); + const updatedSuggestion = {}; + + for (const key in state) { + if (state.hasOwnProperty(key)) { + updatedSuggestion[key] = { + targets: [], + processing: false, + loaded: true, + totalPages: 0, + currentPage: 0, + totalElements: 0, + }; + } + } + return Object.assign({}, state, updatedSuggestion); } case SuggestionTargetActionTypes.ADD_USER_SUGGESTIONS: { - return Object.assign({}, state, { - currentUserTargets: action.payload.suggestionTargets - }); + const updatedSuggestion = {}; + + for (const key in state) { + if (state.hasOwnProperty(key)) { + updatedSuggestion[key] = { + targets: state[key].targets.concat(action.payload.suggestionTargets + .filter(target => target.source === key)), + }; + } + } + return Object.assign({}, state, updatedSuggestion); } case SuggestionTargetActionTypes.MARK_USER_SUGGESTIONS_AS_VISITED: { - return Object.assign({}, state, { - currentUserTargetsVisited: true - }); + const updatedSuggestion = {}; + + for (const key in state) { + if (state.hasOwnProperty(key)) { + updatedSuggestion[key] = { + currentUserTargetsVisited: true + }; + } + } + return Object.assign({}, state, updatedSuggestion); } case SuggestionTargetActionTypes.CLEAR_TARGETS: { - return Object.assign({}, state, { - targets: [], - processing: false, - loaded: false, - totalPages: 0, - currentPage: 0, - totalElements: 0, - }); + const updatedSuggestion = {}; + + for (const key in state) { + if (state.hasOwnProperty(key)) { + updatedSuggestion[key] = { + targets: [], + processing: false, + loaded: false, + totalPages: 0, + currentPage: 0, + totalElements: 0, + }; + } + } + return Object.assign({}, state, updatedSuggestion); } default: { diff --git a/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.state.service.ts b/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.state.service.ts index 2e05bce0a9b..b0cece0a786 100644 --- a/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.state.service.ts +++ b/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.state.service.ts @@ -40,8 +40,8 @@ export class SuggestionTargetsStateService { * @return Observable * The list of Reciter Suggestion Targets. */ - public getReciterSuggestionTargets(): Observable { - return this.store.pipe(select(reciterSuggestionTargetObjectSelector())); + public getReciterSuggestionTargets(source: string): Observable { + return this.store.pipe(select(reciterSuggestionTargetObjectSelector(source))); } /** @@ -50,9 +50,9 @@ export class SuggestionTargetsStateService { * @return Observable * 'true' if the targets are loading, 'false' otherwise. */ - public isReciterSuggestionTargetsLoading(): Observable { + public isReciterSuggestionTargetsLoading(source: string): Observable { return this.store.pipe( - select(isReciterSuggestionTargetLoadedSelector), + select(isReciterSuggestionTargetLoadedSelector(source)), map((loaded: boolean) => !loaded) ); } @@ -63,8 +63,8 @@ export class SuggestionTargetsStateService { * @return Observable * 'true' if the targets are loaded, 'false' otherwise. */ - public isReciterSuggestionTargetsLoaded(): Observable { - return this.store.pipe(select(isReciterSuggestionTargetLoadedSelector)); + public isReciterSuggestionTargetsLoaded(source: string): Observable { + return this.store.pipe(select(isReciterSuggestionTargetLoadedSelector(source))); } /** @@ -73,8 +73,8 @@ export class SuggestionTargetsStateService { * @return Observable * 'true' if there are operations running on the targets (ex.: a REST call), 'false' otherwise. */ - public isReciterSuggestionTargetsProcessing(): Observable { - return this.store.pipe(select(isreciterSuggestionTargetProcessingSelector)); + public isReciterSuggestionTargetsProcessing(source: string): Observable { + return this.store.pipe(select(isreciterSuggestionTargetProcessingSelector(source))); } /** @@ -83,8 +83,8 @@ export class SuggestionTargetsStateService { * @return Observable * The number of the Reciter Suggestion Targets pages. */ - public getReciterSuggestionTargetsTotalPages(): Observable { - return this.store.pipe(select(getreciterSuggestionTargetTotalsSelector)); + public getReciterSuggestionTargetsTotalPages(source: string): Observable { + return this.store.pipe(select(getreciterSuggestionTargetTotalsSelector(source))); } /** @@ -93,8 +93,8 @@ export class SuggestionTargetsStateService { * @return Observable * The number of the current Reciter Suggestion Targets page. */ - public getReciterSuggestionTargetsCurrentPage(): Observable { - return this.store.pipe(select(getreciterSuggestionTargetCurrentPageSelector)); + public getReciterSuggestionTargetsCurrentPage(source: string): Observable { + return this.store.pipe(select(getreciterSuggestionTargetCurrentPageSelector(source))); } /** @@ -103,8 +103,8 @@ export class SuggestionTargetsStateService { * @return Observable * The number of the Reciter Suggestion Targets. */ - public getReciterSuggestionTargetsTotals(): Observable { - return this.store.pipe(select(getreciterSuggestionTargetTotalsSelector)); + public getReciterSuggestionTargetsTotals(source: string): Observable { + return this.store.pipe(select(getreciterSuggestionTargetTotalsSelector(source))); } /** From be89bc64bfe388861371876952437010e378a62e Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 29 Nov 2023 18:40:38 +0100 Subject: [PATCH 2/3] [DSC-1400] Add store support for multiple source --- .../openaire/reciter-suggestions/selectors.ts | 83 ++++----- .../suggestion-targets.actions.ts | 60 ++++-- .../suggestion-targets.component.ts | 10 +- .../suggestion-targets.effects.ts | 6 +- .../suggestion-targets.reducer.ts | 171 +++++++++--------- .../suggestion-targets.state.service.ts | 25 ++- 6 files changed, 187 insertions(+), 168 deletions(-) diff --git a/src/app/openaire/reciter-suggestions/selectors.ts b/src/app/openaire/reciter-suggestions/selectors.ts index 057d0d3a692..6b4b97cdd8b 100644 --- a/src/app/openaire/reciter-suggestions/selectors.ts +++ b/src/app/openaire/reciter-suggestions/selectors.ts @@ -1,18 +1,10 @@ -import {createFeatureSelector, createSelector, MemoizedSelector} from '@ngrx/store'; -import {subStateSelector} from '../../shared/selector.util'; -import {openaireSelector, OpenaireState} from '../openaire.reducer'; +import { createSelector, MemoizedSelector } from '@ngrx/store'; +import { subStateSelector } from '../../shared/selector.util'; +import { openaireSelector, OpenaireState } from '../openaire.reducer'; import { - OpenaireSuggestionTarget + OpenaireSuggestionTarget } from '../../core/openaire/reciter-suggestions/models/openaire-suggestion-target.model'; -import {SuggestionTargetState} from './suggestion-targets/suggestion-targets.reducer'; - -/** - * Returns the Reciter Suggestion Target state. - * @function _getReciterSuggestionTargetState - * @param {AppState} state Top level state. - * @return {OpenaireState} - */ -const _getReciterSuggestionTargetState = createFeatureSelector('openaire'); +import { SuggestionTargetEntry, SuggestionTargetState } from './suggestion-targets/suggestion-targets.reducer'; // Reciter Suggestion Targets // ---------------------------------------------------------------------------- @@ -27,13 +19,21 @@ export function reciterSuggestionTargetStateSelector(): MemoizedSelector { + return createSelector(reciterSuggestionTargetStateSelector(),(state: SuggestionTargetState) => state.sources[source]); +} + +/** + * Returns the Reciter Suggestion Targets list by source. * @function reciterSuggestionTargetObjectSelector - * @return {OpenaireReciterSuggestionTarget[]} + * @return {OpenaireSuggestionTarget[]} */ export function reciterSuggestionTargetObjectSelector(source: string): MemoizedSelector { - return createSelector(reciterSuggestionTargetStateSelector(), - (state: SuggestionTargetState) => state[source]?.targets); + return createSelector(reciterSuggestionSourceSelector(source), (state: SuggestionTargetEntry) => state.targets); } /** @@ -42,10 +42,7 @@ export function reciterSuggestionTargetObjectSelector(source: string): MemoizedS * @return {boolean} */ export const isReciterSuggestionTargetLoadedSelector = (source: string) => { - return createSelector(_getReciterSuggestionTargetState, (state: OpenaireState) => { - const loaded = state.suggestionTarget[source]?.loaded; - return loaded || false; - }); + return createSelector(reciterSuggestionSourceSelector(source), (state: SuggestionTargetEntry) => state?.loaded || false); }; /** @@ -54,10 +51,7 @@ export const isReciterSuggestionTargetLoadedSelector = (source: string) => { * @return {boolean} */ export const isreciterSuggestionTargetProcessingSelector = (source: string) => { - return createSelector(_getReciterSuggestionTargetState, (state: OpenaireState) => { - const processing = state.suggestionTarget[source]?.processing; - return processing || false; - }); + return createSelector(reciterSuggestionSourceSelector(source), (state: SuggestionTargetEntry) => state?.processing || false); }; /** @@ -65,26 +59,26 @@ export const isreciterSuggestionTargetProcessingSelector = (source: string) => { * @function getreciterSuggestionTargetTotalPagesSelector * @return {number} */ -export const getreciterSuggestionTargetTotalPagesSelector = (source: string) => { - return createSelector(_getReciterSuggestionTargetState, (state: OpenaireState) => state.suggestionTarget[source]?.totalPages); +export const getReciterSuggestionTargetTotalPagesSelector = (source: string) => { + return createSelector(reciterSuggestionSourceSelector(source), (state: SuggestionTargetEntry) => state?.totalPages || 0); }; /** * Returns the current page of Reciter Suggestion Targets. - * @function getreciterSuggestionTargetCurrentPageSelector + * @function getReciterSuggestionTargetCurrentPageSelector * @return {number} */ -export const getreciterSuggestionTargetCurrentPageSelector = (source: string) => { - return createSelector(_getReciterSuggestionTargetState, (state: OpenaireState) => state.suggestionTarget[source]?.currentPage); +export const getReciterSuggestionTargetCurrentPageSelector = (source: string) => { + return createSelector(reciterSuggestionSourceSelector(source), (state: SuggestionTargetEntry) => state?.currentPage || 0); }; /** * Returns the total number of Reciter Suggestion Targets. - * @function getreciterSuggestionTargetTotalsSelector + * @function getReciterSuggestionTargetTotalsSelector * @return {number} */ -export const getreciterSuggestionTargetTotalsSelector = (source: string) => { - return createSelector(_getReciterSuggestionTargetState, (state: OpenaireState) => state.suggestionTarget[source]?.totalElements); +export const getReciterSuggestionTargetTotalsSelector = (source: string) => { + return createSelector(reciterSuggestionSourceSelector(source), (state: SuggestionTargetEntry) => state?.totalElements || 0); }; /** @@ -92,24 +86,15 @@ export const getreciterSuggestionTargetTotalsSelector = (source: string) => { * @function getCurrentUserReciterSuggestionTargetSelector * @return {OpenaireSuggestionTarget[]} */ -export const getCurrentUserSuggestionTargetsSelector = createSelector(_getReciterSuggestionTargetState, - (state: OpenaireState) => { - const suggestionTargetValues = Object.values(state.suggestionTarget); - return suggestionTargetValues.reduce( - (acc, entry) => acc.concat(entry?.currentUserTargets || []), - []); - } -); +export const getCurrentUserSuggestionTargetsSelector = () => { + return createSelector(reciterSuggestionTargetStateSelector(), (state: SuggestionTargetState) => state?.currentUserTargets || []); +}; /** - * Returns whether or not the user has consulted their suggestions + * Returns whether the user has consulted their suggestions * @function getCurrentUserReciterSuggestionTargetSelector * @return {boolean} */ -export const getCurrentUserSuggestionTargetsVisitedSelector = createSelector(_getReciterSuggestionTargetState, - (state: OpenaireState) => { - const suggestionTargetValues = Object.values(state.suggestionTarget); - return suggestionTargetValues.some( - (entry) => entry?.currentUserTargetsVisited === true); - } -); +export const getCurrentUserSuggestionTargetsVisitedSelector = () => { + return createSelector(reciterSuggestionTargetStateSelector(), (state: SuggestionTargetState) => state?.currentUserTargetsVisited || false); +}; diff --git a/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.actions.ts b/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.actions.ts index 40bc204b7cc..c2d3e800dcb 100644 --- a/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.actions.ts +++ b/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.actions.ts @@ -2,10 +2,12 @@ import { Action } from '@ngrx/store'; import { type } from '../../../shared/ngrx/type'; -import { OpenaireSuggestionTarget } from '../../../core/openaire/reciter-suggestions/models/openaire-suggestion-target.model'; +import { + OpenaireSuggestionTarget +} from '../../../core/openaire/reciter-suggestions/models/openaire-suggestion-target.model'; /** - * For each action type in an action group, make a simple + * For each action type in A action group, make a simple * enum object for all of this group's action types. * * The 'type' utility function coerces strings into string @@ -23,7 +25,7 @@ export const SuggestionTargetActionTypes = { }; /** - * An ngrx action to retrieve all the Suggestion Targets. + * A ngrx action to retrieve all the Suggestion Targets. */ export class RetrieveTargetsBySourceAction implements Action { type = SuggestionTargetActionTypes.RETRIEVE_TARGETS_BY_SOURCE; @@ -53,18 +55,34 @@ export class RetrieveTargetsBySourceAction implements Action { } /** - * An ngrx action for retrieving 'all Suggestion Targets' error. + * A ngrx action for notifying error. */ -export class RetrieveAllTargetsErrorAction implements Action { +export class RetrieveTargetsBySourceErrorAction implements Action { type = SuggestionTargetActionTypes.RETRIEVE_TARGETS_BY_SOURCE_ERROR; + payload: { + source: string; + }; + + /** + * Create a new RetrieveTargetsBySourceAction. + * + * @param source + * the source for which to retrieve suggestion targets + */ + constructor(source: string) { + this.payload = { + source + }; + } } /** - * An ngrx action to load the Suggestion Target objects. + * A ngrx action to load the Suggestion Target objects. */ export class AddTargetAction implements Action { type = SuggestionTargetActionTypes.ADD_TARGETS; payload: { + source: string; targets: OpenaireSuggestionTarget[]; totalPages: number; currentPage: number; @@ -74,6 +92,8 @@ export class AddTargetAction implements Action { /** * Create a new AddTargetAction. * + * @param source + * the source of suggestion targets * @param targets * the list of targets * @param totalPages @@ -83,8 +103,9 @@ export class AddTargetAction implements Action { * @param totalElements * the total available Suggestion Targets */ - constructor(targets: OpenaireSuggestionTarget[], totalPages: number, currentPage: number, totalElements: number) { + constructor(source: string, targets: OpenaireSuggestionTarget[], totalPages: number, currentPage: number, totalElements: number) { this.payload = { + source, targets, totalPages, currentPage, @@ -95,7 +116,7 @@ export class AddTargetAction implements Action { } /** - * An ngrx action to load the user Suggestion Target object. + * A ngrx action to load the user Suggestion Target object. * Called by the ??? effect. */ export class AddUserSuggestionsAction implements Action { @@ -117,7 +138,7 @@ export class AddUserSuggestionsAction implements Action { } /** - * An ngrx action to reload the user Suggestion Target object. + * A ngrx action to reload the user Suggestion Target object. * Called by the ??? effect. */ export class RefreshUserSuggestionsAction implements Action { @@ -125,7 +146,7 @@ export class RefreshUserSuggestionsAction implements Action { } /** - * An ngrx action to Mark User Suggestions As Visited. + * A ngrx action to Mark User Suggestions As Visited. * Called by the ??? effect. */ export class MarkUserSuggestionsAsVisitedAction implements Action { @@ -133,10 +154,25 @@ export class MarkUserSuggestionsAsVisitedAction implements Action { } /** - * An ngrx action to clear targets state. + * A ngrx action to clear targets state. */ export class ClearSuggestionTargetsAction implements Action { type = SuggestionTargetActionTypes.CLEAR_TARGETS; + payload: { + source: string; + }; + + /** + * Create a new ClearSuggestionTargetsAction. + * + * @param source + * the source of suggestion targets + */ + constructor(source: string) { + this.payload = { + source + }; + } } /** @@ -149,4 +185,4 @@ export type SuggestionTargetsActions | ClearSuggestionTargetsAction | MarkUserSuggestionsAsVisitedAction | RetrieveTargetsBySourceAction - | RetrieveAllTargetsErrorAction; + | RetrieveTargetsBySourceErrorAction; diff --git a/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.component.ts b/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.component.ts index ceadc323ace..6c71dcaf464 100644 --- a/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.component.ts +++ b/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.component.ts @@ -1,10 +1,12 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { AfterViewInit, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; import { distinctUntilChanged, take } from 'rxjs/operators'; -import { OpenaireSuggestionTarget } from '../../../core/openaire/reciter-suggestions/models/openaire-suggestion-target.model'; +import { + OpenaireSuggestionTarget +} from '../../../core/openaire/reciter-suggestions/models/openaire-suggestion-target.model'; import { hasValue } from '../../../shared/empty.util'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { SuggestionTargetsStateService } from './suggestion-targets.state.service'; @@ -21,7 +23,7 @@ import { UUIDService } from '../../../core/shared/uuid.service'; templateUrl: './suggestion-targets.component.html', styleUrls: ['./suggestion-targets.component.scss'], }) -export class SuggestionTargetsComponent implements OnInit { +export class SuggestionTargetsComponent implements AfterViewInit, OnInit, OnDestroy { /** * The source for which to list targets @@ -125,7 +127,7 @@ export class SuggestionTargetsComponent implements OnInit { * Unsubscribe from all subscriptions. */ ngOnDestroy(): void { - this.suggestionTargetsStateService.dispatchClearSuggestionTargetsAction(); + this.suggestionTargetsStateService.dispatchClearSuggestionTargetsAction(this.source); this.subs .filter((sub) => hasValue(sub)) .forEach((sub) => sub.unsubscribe()); diff --git a/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.effects.ts b/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.effects.ts index fe9311b5412..3f3db5373e2 100644 --- a/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.effects.ts +++ b/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.effects.ts @@ -10,8 +10,8 @@ import { AddTargetAction, AddUserSuggestionsAction, RefreshUserSuggestionsAction, - RetrieveAllTargetsErrorAction, RetrieveTargetsBySourceAction, + RetrieveTargetsBySourceErrorAction, SuggestionTargetActionTypes, } from './suggestion-targets.actions'; import { PaginatedList } from '../../../core/data/paginated-list.model'; @@ -41,13 +41,13 @@ export class SuggestionTargetsEffects { action.payload.currentPage ).pipe( map((targets: PaginatedList) => - new AddTargetAction(targets.page, targets.totalPages, targets.currentPage, targets.totalElements) + new AddTargetAction(action.payload.source, targets.page, targets.totalPages, targets.currentPage, targets.totalElements) ), catchError((error: Error) => { if (error) { console.error(error.message); } - return of(new RetrieveAllTargetsErrorAction()); + return of(new RetrieveTargetsBySourceErrorAction(action.payload.source)); }) ); }) diff --git a/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.reducer.ts b/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.reducer.ts index e5ce049bba6..0df541974d4 100644 --- a/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.reducer.ts +++ b/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.reducer.ts @@ -1,5 +1,7 @@ import { SuggestionTargetActionTypes, SuggestionTargetsActions } from './suggestion-targets.actions'; -import { OpenaireSuggestionTarget } from '../../../core/openaire/reciter-suggestions/models/openaire-suggestion-target.model'; +import { + OpenaireSuggestionTarget +} from '../../../core/openaire/reciter-suggestions/models/openaire-suggestion-target.model'; /** * The interface representing the OpenAIRE suggestion targets state. @@ -11,30 +13,35 @@ export interface SuggestionTargetEntry { totalPages: number; currentPage: number; totalElements: number; - currentUserTargets: OpenaireSuggestionTarget[]; - currentUserTargetsVisited: boolean; + } -export interface SuggestionTargetState { +export interface SuggestionSourcesState { [source: string]: SuggestionTargetEntry; } +export interface SuggestionTargetState { + sources: SuggestionSourcesState; + currentUserTargets: OpenaireSuggestionTarget[]; + currentUserTargetsVisited: boolean; +} + /** * Used for the OpenAIRE Suggestion Target state initialization. */ -const SuggestionTargetInitialEntity: SuggestionTargetEntry = { +const suggestionSourceTargetsInitialState: SuggestionTargetEntry = { targets: [], processing: false, loaded: false, totalPages: 0, currentPage: 0, totalElements: 0, - currentUserTargets: null, - currentUserTargetsVisited: false }; const SuggestionTargetInitialState: SuggestionTargetState = { - 'oaire' : SuggestionTargetInitialEntity + sources: {}, + currentUserTargets: null, + currentUserTargetsVisited: false }; /** @@ -50,103 +57,87 @@ const SuggestionTargetInitialState: SuggestionTargetState = { export function SuggestionTargetsReducer(state = SuggestionTargetInitialState, action: SuggestionTargetsActions): SuggestionTargetState { switch (action.type) { case SuggestionTargetActionTypes.RETRIEVE_TARGETS_BY_SOURCE: { - const updatedSuggestion = {}; - - for (const key in state) { - if (state.hasOwnProperty(key)) { - if (key === action.payload.source) { - updatedSuggestion[key] = { - targets: [], - processing: true - }; - } else { - updatedSuggestion[key] = state[key]; - } - } - } - return Object.assign({}, state, updatedSuggestion); + const sourceState = state.sources[action.payload.source] || Object.assign({}, suggestionSourceTargetsInitialState); + const newSourceState = Object.assign({}, sourceState, { + targets: [], + processing: true, + }); + + return Object.assign({}, state, { + sources: + Object.assign({}, state.sources, { + [action.payload.source]: newSourceState + }) + }); } case SuggestionTargetActionTypes.ADD_TARGETS: { - const updatedSuggestion = {}; - - for (const key in state) { - if (state.hasOwnProperty(key)) { - updatedSuggestion[key] = { - targets: state[key].targets.concat(action.payload.targets - .filter(target => target.source === key)), - processing: false, - loaded: true, - totalPages: action.payload.totalPages, - currentPage: state[key].currentPage, - totalElements: action.payload.totalElements, - }; - } - } - return Object.assign({}, state, updatedSuggestion); + const sourceState = state.sources[action.payload.source] || Object.assign({}, suggestionSourceTargetsInitialState); + const newSourceState = Object.assign({}, sourceState, { + targets: sourceState.targets.concat(action.payload.targets), + processing: false, + loaded: true, + totalPages: action.payload.totalPages, + currentPage: action.payload.currentPage, + totalElements: action.payload.totalElements + }); + + return Object.assign({}, state, { + sources: + Object.assign({}, state.sources, { + [action.payload.source]: newSourceState + }) + }); } case SuggestionTargetActionTypes.RETRIEVE_TARGETS_BY_SOURCE_ERROR: { - const updatedSuggestion = {}; - - for (const key in state) { - if (state.hasOwnProperty(key)) { - updatedSuggestion[key] = { - targets: [], - processing: false, - loaded: true, - totalPages: 0, - currentPage: 0, - totalElements: 0, - }; - } - } - return Object.assign({}, state, updatedSuggestion); + const sourceState = state.sources[action.payload.source] || Object.assign({}, suggestionSourceTargetsInitialState); + const newSourceState = Object.assign({}, sourceState, { + targets: [], + processing: false, + loaded: true, + totalPages: 0, + currentPage: 0, + totalElements: 0, + }); + + return Object.assign({}, state, { + sources: + Object.assign({}, state.sources, { + [action.payload.source]: newSourceState + }) + }); } case SuggestionTargetActionTypes.ADD_USER_SUGGESTIONS: { - const updatedSuggestion = {}; - - for (const key in state) { - if (state.hasOwnProperty(key)) { - updatedSuggestion[key] = { - targets: state[key].targets.concat(action.payload.suggestionTargets - .filter(target => target.source === key)), - }; - } - } - return Object.assign({}, state, updatedSuggestion); + return Object.assign({}, state, { + currentUserTargets: action.payload.suggestionTargets + }); } case SuggestionTargetActionTypes.MARK_USER_SUGGESTIONS_AS_VISITED: { - const updatedSuggestion = {}; - - for (const key in state) { - if (state.hasOwnProperty(key)) { - updatedSuggestion[key] = { - currentUserTargetsVisited: true - }; - } - } - return Object.assign({}, state, updatedSuggestion); + return Object.assign({}, state, { + currentUserTargetsVisited: true + }); } case SuggestionTargetActionTypes.CLEAR_TARGETS: { - const updatedSuggestion = {}; - - for (const key in state) { - if (state.hasOwnProperty(key)) { - updatedSuggestion[key] = { - targets: [], - processing: false, - loaded: false, - totalPages: 0, - currentPage: 0, - totalElements: 0, - }; - } - } - return Object.assign({}, state, updatedSuggestion); + const sourceState = state.sources[action.payload.source] || Object.assign({}, suggestionSourceTargetsInitialState); + const newSourceState = Object.assign({}, sourceState, { + targets: [], + processing: false, + loaded: true, + totalPages: 0, + currentPage: 0, + totalElements: 0, + }); + + return Object.assign({}, state, { + sources: + Object.assign({}, state.sources, { + [action.payload.source]: newSourceState + }) + }); } default: { diff --git a/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.state.service.ts b/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.state.service.ts index b0cece0a786..92cf1dba3b0 100644 --- a/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.state.service.ts +++ b/src/app/openaire/reciter-suggestions/suggestion-targets/suggestion-targets.state.service.ts @@ -7,13 +7,15 @@ import { map } from 'rxjs/operators'; import { getCurrentUserSuggestionTargetsSelector, getCurrentUserSuggestionTargetsVisitedSelector, - getreciterSuggestionTargetCurrentPageSelector, - getreciterSuggestionTargetTotalsSelector, + getReciterSuggestionTargetCurrentPageSelector, + getReciterSuggestionTargetTotalsSelector, isReciterSuggestionTargetLoadedSelector, isreciterSuggestionTargetProcessingSelector, reciterSuggestionTargetObjectSelector } from '../selectors'; -import { OpenaireSuggestionTarget } from '../../../core/openaire/reciter-suggestions/models/openaire-suggestion-target.model'; +import { + OpenaireSuggestionTarget +} from '../../../core/openaire/reciter-suggestions/models/openaire-suggestion-target.model'; import { ClearSuggestionTargetsAction, MarkUserSuggestionsAsVisitedAction, @@ -84,7 +86,7 @@ export class SuggestionTargetsStateService { * The number of the Reciter Suggestion Targets pages. */ public getReciterSuggestionTargetsTotalPages(source: string): Observable { - return this.store.pipe(select(getreciterSuggestionTargetTotalsSelector(source))); + return this.store.pipe(select(getReciterSuggestionTargetTotalsSelector(source))); } /** @@ -94,7 +96,7 @@ export class SuggestionTargetsStateService { * The number of the current Reciter Suggestion Targets page. */ public getReciterSuggestionTargetsCurrentPage(source: string): Observable { - return this.store.pipe(select(getreciterSuggestionTargetCurrentPageSelector(source))); + return this.store.pipe(select(getReciterSuggestionTargetCurrentPageSelector(source))); } /** @@ -104,7 +106,7 @@ export class SuggestionTargetsStateService { * The number of the Reciter Suggestion Targets. */ public getReciterSuggestionTargetsTotals(source: string): Observable { - return this.store.pipe(select(getreciterSuggestionTargetTotalsSelector(source))); + return this.store.pipe(select(getReciterSuggestionTargetTotalsSelector(source))); } /** @@ -128,7 +130,7 @@ export class SuggestionTargetsStateService { * The Reciter Suggestion Targets object. */ public getCurrentUserSuggestionTargets(): Observable { - return this.store.pipe(select(getCurrentUserSuggestionTargetsSelector)); + return this.store.pipe(select(getCurrentUserSuggestionTargetsSelector())); } /** @@ -138,7 +140,7 @@ export class SuggestionTargetsStateService { * True if user already visited, false otherwise. */ public hasUserVisitedSuggestions(): Observable { - return this.store.pipe(select(getCurrentUserSuggestionTargetsVisitedSelector)); + return this.store.pipe(select(getCurrentUserSuggestionTargetsVisitedSelector())); } /** @@ -150,9 +152,12 @@ export class SuggestionTargetsStateService { /** * Dispatch an action to clear the Reciter Suggestion Targets state. + * + * @param source + * the source of suggestion targets */ - public dispatchClearSuggestionTargetsAction(): void { - this.store.dispatch(new ClearSuggestionTargetsAction()); + public dispatchClearSuggestionTargetsAction(source: string): void { + this.store.dispatch(new ClearSuggestionTargetsAction(source)); } /** From de56ad495ee23497ab272e72f9645d9ed10f2493 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 29 Nov 2023 18:41:33 +0100 Subject: [PATCH 3/3] [DSC-1400] Fix issue with user's suggestion notifications --- src/app/openaire/openaire.module.ts | 7 ++----- .../suggestions-notification.component.ts | 1 + src/app/root.module.ts | 4 +++- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/openaire/openaire.module.ts b/src/app/openaire/openaire.module.ts index b3a9dcd8ff4..91767a51439 100644 --- a/src/app/openaire/openaire.module.ts +++ b/src/app/openaire/openaire.module.ts @@ -51,7 +51,8 @@ const MODULES = [ CoreModule.forRoot(), StoreModule.forFeature('openaire', openaireReducers, storeModuleConfig as StoreConfig), EffectsModule.forFeature(openaireEffects), - TranslateModule + TranslateModule, + SearchModule ]; const COMPONENTS = [ @@ -86,7 +87,6 @@ const PROVIDERS = [ @NgModule({ imports: [ ...MODULES, - SearchModule ], declarations: [ ...COMPONENTS, @@ -96,9 +96,6 @@ const PROVIDERS = [ providers: [ ...PROVIDERS ], - entryComponents: [ - ...ENTRY_COMPONENTS - ], exports: [ ...COMPONENTS, ...DIRECTIVES diff --git a/src/app/openaire/reciter-suggestions/suggestions-notification/suggestions-notification.component.ts b/src/app/openaire/reciter-suggestions/suggestions-notification/suggestions-notification.component.ts index 094dfab0174..923c25ecf41 100644 --- a/src/app/openaire/reciter-suggestions/suggestions-notification/suggestions-notification.component.ts +++ b/src/app/openaire/reciter-suggestions/suggestions-notification/suggestions-notification.component.ts @@ -29,6 +29,7 @@ export class SuggestionsNotificationComponent implements OnInit { ngOnInit() { this.suggestionsRD$ = this.reciterSuggestionStateService.getCurrentUserSuggestionTargets(); + this.reciterSuggestionStateService.dispatchMarkUserSuggestionsAsVisitedAction(); } /** diff --git a/src/app/root.module.ts b/src/app/root.module.ts index a4edec2a914..8f659ad9fe6 100644 --- a/src/app/root.module.ts +++ b/src/app/root.module.ts @@ -46,6 +46,7 @@ import { BreadcrumbTooltipPipe } from './breadcrumbs/breadcrumb/breadcrumb-toolt import { TruncateBreadcrumbItemCharactersPipe } from './breadcrumbs/breadcrumb/truncate-breadcrumb-item-characters.pipe'; +import { OpenaireModule } from './openaire/openaire.module'; const IMPORTS = [ CommonModule, @@ -55,7 +56,8 @@ const IMPORTS = [ NgbModule, ExploreModule, FooterModule, - SocialModule + SocialModule, + OpenaireModule ]; const PROVIDERS = [