Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(atomic): split the atomic store into composable parts #4806

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 18 additions & 14 deletions packages/atomic/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,20 @@ import { NumberInputType } from "./components/common/facets/facet-number-input/n
import { NumericFilter, NumericFilterState, RelativeDateUnit } from "./components/common/types";
import { InsightEngine, FacetSortCriterion as InsightFacetSortCriterion, FoldedResult as InsightFoldedResult, InteractiveResult as InsightInteractiveResult, LogLevel as InsightLogLevel, RangeFacetRangeAlgorithm as InsightRangeFacetRangeAlgorithm, RangeFacetSortCriterion as InsightRangeFacetSortCriterion, Result as InsightResult, ResultTemplate as InsightResultTemplate, ResultTemplateCondition as InsightResultTemplateCondition, UserAction as IUserAction } from "./components/insight";
import { InsightInitializationOptions } from "./components/insight/atomic-insight-interface/atomic-insight-interface";
import { AtomicInsightStore } from "./components/insight/atomic-insight-interface/store";
import { InsightStore } from "./components/insight/atomic-insight-interface/store";
import { InsightResultActionClickedEvent } from "./components/insight/atomic-insight-result-action/atomic-insight-result-action";
import { InsightResultAttachToCaseEvent } from "./components/insight/atomic-insight-result-attach-to-case-action/atomic-insight-result-attach-to-case-action";
import { Section } from "./components/common/atomic-layout-section/sections";
import { AtomicCommonStore, AtomicCommonStoreData } from "./components/common/interface/store";
import { CommerceStore } from "./components/commerce/atomic-commerce-interface/store";
import { CommerceRecommendationStore } from "./components/commerce/atomic-commerce-recommendation-interface/store";
import { SelectChildProductEventArgs } from "./components/commerce/product-template-components/atomic-product-children/atomic-product-children";
import { TruncateAfter } from "./components/common/expandable-text/expandable-text";
import { RecommendationEngine } from "@coveo/headless/recommendation";
import { InteractiveResult as RecsInteractiveResult, LogLevel as RecsLogLevel, Result as RecsResult, ResultTemplate as RecsResultTemplate, ResultTemplateCondition as RecsResultTemplateCondition } from "./components/recommendations";
import { RecsInitializationOptions } from "./components/recommendations/atomic-recs-interface/atomic-recs-interface";
import { AtomicRecsStore } from "./components/recommendations/atomic-recs-interface/store";
import { RecsStore } from "./components/recommendations/atomic-recs-interface/store";
import { Bindings as Bindings1 } from "./components/search/atomic-search-interface/atomic-search-interface";
import { SearchStore } from "./components/search/atomic-search-interface/store";
import { AriaLabelGenerator as AriaLabelGenerator1 } from "./components/search/search-box-suggestions/atomic-search-box-instant-results/atomic-search-box-instant-results";
import { InitializationOptions } from "./components/search/atomic-search-interface/atomic-search-interface";
export { AutomaticFacet, CategoryFacetSortCriterion, DateFilterRange, DateRangeRequest, FacetResultsMustMatch, FacetSortCriterion, FoldedResult, GeneratedAnswer, GeneratedAnswerCitation, InlineLink, InteractiveCitation, InteractiveResult, LogLevel as LogLevel1, RangeFacetRangeAlgorithm, RangeFacetSortCriterion, Result, ResultTemplate, ResultTemplateCondition, SearchEngine, SearchStatus } from "@coveo/headless";
Expand All @@ -55,18 +57,20 @@ export { NumberInputType } from "./components/common/facets/facet-number-input/n
export { NumericFilter, NumericFilterState, RelativeDateUnit } from "./components/common/types";
export { InsightEngine, FacetSortCriterion as InsightFacetSortCriterion, FoldedResult as InsightFoldedResult, InteractiveResult as InsightInteractiveResult, LogLevel as InsightLogLevel, RangeFacetRangeAlgorithm as InsightRangeFacetRangeAlgorithm, RangeFacetSortCriterion as InsightRangeFacetSortCriterion, Result as InsightResult, ResultTemplate as InsightResultTemplate, ResultTemplateCondition as InsightResultTemplateCondition, UserAction as IUserAction } from "./components/insight";
export { InsightInitializationOptions } from "./components/insight/atomic-insight-interface/atomic-insight-interface";
export { AtomicInsightStore } from "./components/insight/atomic-insight-interface/store";
export { InsightStore } from "./components/insight/atomic-insight-interface/store";
export { InsightResultActionClickedEvent } from "./components/insight/atomic-insight-result-action/atomic-insight-result-action";
export { InsightResultAttachToCaseEvent } from "./components/insight/atomic-insight-result-attach-to-case-action/atomic-insight-result-attach-to-case-action";
export { Section } from "./components/common/atomic-layout-section/sections";
export { AtomicCommonStore, AtomicCommonStoreData } from "./components/common/interface/store";
export { CommerceStore } from "./components/commerce/atomic-commerce-interface/store";
export { CommerceRecommendationStore } from "./components/commerce/atomic-commerce-recommendation-interface/store";
export { SelectChildProductEventArgs } from "./components/commerce/product-template-components/atomic-product-children/atomic-product-children";
export { TruncateAfter } from "./components/common/expandable-text/expandable-text";
export { RecommendationEngine } from "@coveo/headless/recommendation";
export { InteractiveResult as RecsInteractiveResult, LogLevel as RecsLogLevel, Result as RecsResult, ResultTemplate as RecsResultTemplate, ResultTemplateCondition as RecsResultTemplateCondition } from "./components/recommendations";
export { RecsInitializationOptions } from "./components/recommendations/atomic-recs-interface/atomic-recs-interface";
export { AtomicRecsStore } from "./components/recommendations/atomic-recs-interface/store";
export { RecsStore } from "./components/recommendations/atomic-recs-interface/store";
export { Bindings as Bindings1 } from "./components/search/atomic-search-interface/atomic-search-interface";
export { SearchStore } from "./components/search/atomic-search-interface/store";
export { AriaLabelGenerator as AriaLabelGenerator1 } from "./components/search/search-box-suggestions/atomic-search-box-instant-results/atomic-search-box-instant-results";
export { InitializationOptions } from "./components/search/atomic-search-interface/atomic-search-interface";
export namespace Components {
Expand Down Expand Up @@ -1409,7 +1413,7 @@ export namespace Components {
/**
* Global Atomic state.
*/
"store"?: AtomicInsightStore;
"store"?: InsightStore;
}
interface AtomicInsightResultAction {
/**
Expand Down Expand Up @@ -2052,7 +2056,7 @@ export namespace Components {
* Global Atomic state.
* @alpha
*/
"store"?: AtomicCommonStore<AtomicCommonStoreData>;
"store"?: CommerceStore | CommerceRecommendationStore;
}
/**
* @alpha The `atomic-product-children` component renders a section that allows the user to select a nested product (e.g., a color variant of a given product).
Expand Down Expand Up @@ -2696,7 +2700,7 @@ export namespace Components {
/**
* Global Atomic state.
*/
"store"?: AtomicRecsStore;
"store"?: RecsStore;
}
/**
* A [result template](https://docs.coveo.com/en/atomic/latest/usage/displaying-results#defining-a-result-template) determines the format of the query results, depending on the conditions that are defined for each template.
Expand Down Expand Up @@ -2818,7 +2822,7 @@ export namespace Components {
/**
* Global Atomic state.
*/
"store"?: AtomicCommonStore<AtomicCommonStoreData>;
"store"?: SearchStore;
}
/**
* The `atomic-result-badge` element renders a badge to highlight special features of a result.
Expand Down Expand Up @@ -7567,7 +7571,7 @@ declare namespace LocalJSX {
/**
* Global Atomic state.
*/
"store"?: AtomicInsightStore;
"store"?: InsightStore;
}
interface AtomicInsightResultAction {
/**
Expand Down Expand Up @@ -8185,7 +8189,7 @@ declare namespace LocalJSX {
* Global Atomic state.
* @alpha
*/
"store"?: AtomicCommonStore<AtomicCommonStoreData>;
"store"?: CommerceStore | CommerceRecommendationStore;
}
/**
* @alpha The `atomic-product-children` component renders a section that allows the user to select a nested product (e.g., a color variant of a given product).
Expand Down Expand Up @@ -8789,7 +8793,7 @@ declare namespace LocalJSX {
/**
* Global Atomic state.
*/
"store"?: AtomicRecsStore;
"store"?: RecsStore;
}
/**
* A [result template](https://docs.coveo.com/en/atomic/latest/usage/displaying-results#defining-a-result-template) determines the format of the query results, depending on the conditions that are defined for each template.
Expand Down Expand Up @@ -8908,7 +8912,7 @@ declare namespace LocalJSX {
/**
* Global Atomic state.
*/
"store"?: AtomicCommonStore<AtomicCommonStoreData>;
"store"?: SearchStore;
}
/**
* The `atomic-result-badge` element renders a badge to highlight special features of a result.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ import {
noProductsSelector,
} from '../atomic-commerce-layout/commerce-layout';
import {getAnalyticsConfig} from './analytics-config';
import {AtomicCommerceStore, createAtomicCommerceStore} from './store';
import {CommerceStore, createCommerceStore} from './store';

const FirstRequestExecutedFlag = 'firstRequestExecuted';

export type CommerceInitializationOptions = CommerceEngineConfiguration;
export type CommerceBindings = CommonBindings<
CommerceEngine,
AtomicCommerceStore,
CommerceStore,
HTMLAtomicCommerceInterfaceElement
> &
NonceBindings;
Expand Down Expand Up @@ -81,7 +81,7 @@ export class AtomicCommerceInterface
private unsubscribeUrlManager: Unsubscribe = () => {};
private unsubscribeSummary: Unsubscribe = () => {};
private initialized = false;
private store: AtomicCommerceStore;
private store: CommerceStore;
private commonInterfaceHelper: CommonAtomicInterfaceHelper<CommerceEngine>;

@Element() public host!: HTMLAtomicCommerceInterfaceElement;
Expand Down Expand Up @@ -178,7 +178,7 @@ export class AtomicCommerceInterface
this,
'CoveoAtomic'
);
this.store = createAtomicCommerceStore(this.type);
this.store = createCommerceStore(this.type);
}

public connectedCallback() {
Expand Down Expand Up @@ -220,7 +220,7 @@ export class AtomicCommerceInterface

@Watch('iconAssetsPath')
public updateIconAssetsPath() {
this.store.set('iconAssetsPath', this.iconAssetsPath);
this.store.state.iconAssetsPath = this.iconAssetsPath;
}

public disconnectedCallback() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,78 +1,63 @@
import {
CommerceEngine,
Selectors,
NumericFacetValue,
DateFacetValue,
SortCriterion,
ChildProduct,
} from '@coveo/headless/commerce';
import {DEFAULT_MOBILE_BREAKPOINT} from '../../../utils/replace-breakpoint';
import {
FacetInfo,
FacetStore,
FacetValueFormat,
} from '../../common/facets/facet-common-store';
import {
createAtomicCommonStore,
AtomicCommonStoreData,
AtomicCommonStore,
BaseStore,
createBaseStore,
ResultListInfo,
setLoadingFlag,
unsetLoadingFlag,
} from '../../common/interface/store';
import {makeDesktopQuery} from '../../search/atomic-layout/search-layout';

export interface SortDropdownOption {
expression: string;
criteria: SortCriterion[];
label: string;
}

export interface AtomicStoreData extends AtomicCommonStoreData {
facets: FacetStore<FacetInfo>;
numericFacets: FacetStore<FacetInfo & FacetValueFormat<NumericFacetValue>>;
dateFacets: FacetStore<FacetInfo & FacetValueFormat<DateFacetValue>>;
categoryFacets: FacetStore<FacetInfo>;
sortOptions: SortDropdownOption[];
interface Data {
loadingFlags: string[];
iconAssetsPath: string;
resultList: ResultListInfo | undefined;
mobileBreakpoint: string;
currentQuickviewPosition: number;
activeProductChild: ChildProduct | undefined;
}

export interface AtomicCommerceStore
extends AtomicCommonStore<AtomicStoreData> {
export type CommerceStore = BaseStore<Data> & {
isAppLoaded(): boolean;
unsetLoadingFlag(loadingFlag: string): void;
setLoadingFlag(flag: string): void;
isMobile(): boolean;
}

export interface FacetInfoMap {
[facetId: string]:
| FacetInfo
| (FacetInfo & FacetValueFormat<NumericFacetValue>)
| (FacetInfo & FacetValueFormat<DateFacetValue>);
}
getUniqueIDFromEngine(engine: CommerceEngine): string;
};

export function createAtomicCommerceStore(
export function createCommerceStore(
type: 'search' | 'product-listing'
): AtomicCommerceStore {
const commonStore = createAtomicCommonStore<AtomicStoreData>({
): CommerceStore {
const store = createBaseStore({
loadingFlags: [],
facets: {},
numericFacets: {},
dateFacets: {},
categoryFacets: {},
facetElements: [],
sortOptions: [],
iconAssetsPath: '',
resultList: undefined,
mobileBreakpoint: DEFAULT_MOBILE_BREAKPOINT,
fieldsToInclude: [],
currentQuickviewPosition: -1,
activeProductChild: undefined,
});

return {
...commonStore,
...store,

isAppLoaded() {
return !store.state.loadingFlags.length;
},

unsetLoadingFlag(loadingFlag: string) {
unsetLoadingFlag(store, loadingFlag);
},

setLoadingFlag(loadingFlag: string) {
setLoadingFlag(store, loadingFlag);
},

isMobile() {
return !window.matchMedia(
makeDesktopQuery(commonStore.state.mobileBreakpoint)
).matches;
return !window.matchMedia(makeDesktopQuery(store.state.mobileBreakpoint))
.matches;
},

getUniqueIDFromEngine(engine: CommerceEngine): string {
Expand All @@ -81,10 +66,6 @@ export function createAtomicCommerceStore(
return Selectors.Search.responseIdSelector(engine);
case 'product-listing':
return Selectors.ProductListing.responseIdSelector(engine);
default:
throw new Error(
`getUniqueIDFromEngine not implemented for this interface type, ${type}`
);
}
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ import {
CommonAtomicInterfaceHelper,
} from '../../common/interface/interface-common';
import {
AtomicCommerceRecommendationStore,
createAtomicCommerceRecommendationStore,
CommerceRecommendationStore,
createCommerceRecommendationStore,
} from './store';

export type CommerceInitializationOptions = CommerceEngineConfiguration;
export type CommerceBindings = CommonBindings<
CommerceEngine,
AtomicCommerceRecommendationStore,
CommerceRecommendationStore,
HTMLAtomicCommerceInterfaceElement
> &
NonceBindings;
Expand All @@ -48,7 +48,7 @@ export type CommerceBindings = CommonBindings<
export class AtomicCommerceRecommendationInterface
implements BaseAtomicInterface<CommerceEngine>
{
private store = createAtomicCommerceRecommendationStore();
private store = createCommerceRecommendationStore();
private commonInterfaceHelper: CommonAtomicInterfaceHelper<CommerceEngine>;

@Element() public host!: HTMLAtomicCommerceInterfaceElement;
Expand Down Expand Up @@ -168,7 +168,7 @@ export class AtomicCommerceRecommendationInterface

@Watch('iconAssetsPath')
public updateIconAssetsPath() {
this.store.set('iconAssetsPath', this.iconAssetsPath);
this.store.state.iconAssetsPath = this.iconAssetsPath;
}

@Listen('atomic/initializeComponent')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,43 @@
import {ChildProduct} from '@coveo/headless/commerce';
import {DEFAULT_MOBILE_BREAKPOINT} from '../../../utils/replace-breakpoint';
import {
AtomicCommonStore,
AtomicCommonStoreData,
createAtomicCommonStore,
BaseStore,
createBaseStore,
ResultListInfo,
setLoadingFlag,
unsetLoadingFlag,
} from '../../common/interface/store';
import {makeDesktopQuery} from '../atomic-commerce-layout/commerce-layout';

export interface AtomicStoreData extends AtomicCommonStoreData {
mobileBreakpoint: string;
currentQuickviewPosition: number;
activeProductChild: ChildProduct | undefined;
interface Data {
loadingFlags: string[];
iconAssetsPath: string;
resultList: ResultListInfo | undefined;
}

export interface AtomicCommerceRecommendationStore
extends AtomicCommonStore<AtomicStoreData> {
isMobile(): boolean;
}
export type CommerceRecommendationStore = BaseStore<Data> & {
isAppLoaded(): boolean;
unsetLoadingFlag(loadingFlag: string): void;
setLoadingFlag(flag: string): void;
};

export function createAtomicCommerceRecommendationStore(): AtomicCommerceRecommendationStore {
const commonStore = createAtomicCommonStore<AtomicStoreData>({
export function createCommerceRecommendationStore(): CommerceRecommendationStore {
const store = createBaseStore<Data>({
loadingFlags: [],
facets: {},
numericFacets: {},
dateFacets: {},
categoryFacets: {},
facetElements: [],
iconAssetsPath: '',
mobileBreakpoint: DEFAULT_MOBILE_BREAKPOINT,
fieldsToInclude: [],
currentQuickviewPosition: -1,
activeProductChild: undefined,
resultList: undefined,
});

return {
...commonStore,
...store,

isAppLoaded() {
return !store.state.loadingFlags.length;
},

unsetLoadingFlag(loadingFlag: string) {
unsetLoadingFlag(store, loadingFlag);
},

isMobile() {
return !window.matchMedia(
makeDesktopQuery(commonStore.state.mobileBreakpoint)
).matches;
setLoadingFlag(loadingFlag: string) {
setLoadingFlag(store, loadingFlag);
},
};
}
Loading
Loading