Skip to content

Commit

Permalink
fix(atomic): fix grid system for commerce when no results or error (#…
Browse files Browse the repository at this point in the history
…4058)

Grid system (search-layout/commerce-layout) relies on specific css
classes being toggled on the container interface when there are no
products/results or when there is an error, in order to align the
columns properly.


https://coveord.atlassian.net/browse/KIT-3239
  • Loading branch information
olamothe authored Jun 7, 2024
1 parent 8bb77af commit 7d0bddc
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import {
ProductListing,
Context,
buildContext,
buildSearchSummary,
buildListingSummary,
SearchSummary,
ListingSummary,
} from '@coveo/headless/commerce';
import {
Component,
Expand All @@ -36,6 +40,11 @@ import {
BaseAtomicInterface,
CommonAtomicInterfaceHelper,
} from '../../common/interface/interface-common';
import {
errorSelector,
firstSearchExecutedSelector,
noProductsSelector,
} from '../atomic-commerce-layout/commerce-layout';
import {getAnalyticsConfig} from './analytics-config';
import {AtomicCommerceStore, createAtomicCommerceStore} from './store';

Expand Down Expand Up @@ -66,10 +75,12 @@ export class AtomicCommerceInterface
implements BaseAtomicInterface<CommerceEngine>
{
private urlManager!: UrlManager;
private searchStatus!: Search | ProductListing;
private searchOrListing!: Search | ProductListing;
private summary!: SearchSummary | ListingSummary;
private context!: Context;
private unsubscribeUrlManager: Unsubscribe = () => {};
private unsubscribeSearchStatus: Unsubscribe = () => {};
private unsubscribeSummary: Unsubscribe = () => {};
private initialized = false;
private store: AtomicCommerceStore;
private commonInterfaceHelper: CommonAtomicInterfaceHelper<CommerceEngine>;
Expand Down Expand Up @@ -210,6 +221,7 @@ export class AtomicCommerceInterface
public disconnectedCallback() {
this.unsubscribeUrlManager();
this.unsubscribeSearchStatus();
this.unsubscribeSummary();
window.removeEventListener('hashchange', this.onHashChange);
}

Expand Down Expand Up @@ -339,7 +351,7 @@ export class AtomicCommerceInterface
}

private initUrlManager() {
this.urlManager = this.searchStatus.urlManager({
this.urlManager = this.searchOrListing.urlManager({
initialState: {fragment: this.fragment},
});

Expand All @@ -351,29 +363,54 @@ export class AtomicCommerceInterface
}

private initSearchStatus() {
if (this.type === 'product-listing') {
this.searchStatus = buildProductListing(this.engine!);
} else {
this.searchStatus = buildSearch(this.engine!);
}
this.unsubscribeSearchStatus = this.searchStatus.subscribe(() => {
this.searchOrListing =
this.type === 'product-listing'
? buildProductListing(this.engine!)
: buildSearch(this.engine!);

this.unsubscribeSearchStatus = this.searchOrListing.subscribe(() => {
if (
!this.searchStatus.state.isLoading &&
!this.searchOrListing.state.isLoading &&
this.store.hasLoadingFlag(FirstSearchExecutedFlag)
) {
this.store.unsetLoadingFlag(FirstSearchExecutedFlag);
}
});
}

private initSummary() {
this.summary =
this.type === 'product-listing'
? buildListingSummary(this.engine!)
: buildSearchSummary(this.engine!);

this.unsubscribeSummary = this.summary.subscribe(() => {
const {firstSearchExecuted, hasProducts, hasError} = this.summary.state;
const hasNoProductsAfterInitialSearch =
firstSearchExecuted && !hasError && !hasProducts;

this.host.classList.toggle(
noProductsSelector,
hasNoProductsAfterInitialSearch
);

this.host.classList.toggle(errorSelector, hasError);

this.host.classList.toggle(
firstSearchExecutedSelector,
firstSearchExecuted
);
});
}

private initContext() {
this.context = buildContext(this.engine!);
}

private updateHash() {
const newFragment = this.urlManager.state.fragment;

if (!this.searchStatus.state.isLoading) {
if (!this.searchOrListing.state.isLoading) {
history.replaceState(null, document.title, `#${newFragment}`);
this.bindings.engine.logger.info(`History replaceState #${newFragment}`);

Expand All @@ -392,6 +429,7 @@ export class AtomicCommerceInterface
await this.commonInterfaceHelper.onInitialization(initEngine);

this.initSearchStatus();
this.initSummary();
this.initUrlManager();
this.initContext();
this.initialized = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import {buildSearchLayoutCommon} from '../../common/atomic-layout-section/search-layout';

export const layoutWebComponentTagName = 'atomic-commerce-layout';
export const containerWebComponentTagName = 'atomic-commerce-interface';
export const noProductsSelector = `${containerWebComponentTagName}-no-results`;
export const errorSelector = `${containerWebComponentTagName}-error`;
export const firstSearchExecutedSelector = `${containerWebComponentTagName}-search-executed`;

export function makeDesktopQuery(mobileBreakpoint: string) {
return `only screen and (min-width: ${mobileBreakpoint})`;
}
Expand All @@ -10,7 +16,9 @@ export function buildCommerceLayout(
return buildSearchLayoutCommon(
element,
mobileBreakpoint,
'atomic-commerce-layout',
'atomic-commerce-interface'
layoutWebComponentTagName,
containerWebComponentTagName,
noProductsSelector,
errorSelector
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ export function buildSearchLayoutCommon(
element: HTMLElement,
mobileBreakpoint: string,
layoutWebComponentTagName: string,
containerWebComponentTagName: string
containerWebComponentTagName: string,
noItemsSelector: string,
errorSelector: string
) {
const id = element.id;
const layoutSelector = `${layoutWebComponentTagName}#${id}`;
const cleanStatusSelector = `${containerWebComponentTagName}:not(.${containerWebComponentTagName}-no-results, .${containerWebComponentTagName}-error)`;
const cleanStatusSelector = `${containerWebComponentTagName}:not(.${noItemsSelector}, .${errorSelector})`;
const mediaQuerySelector = `@media ${makeDesktopQuery(mobileBreakpoint)}`;

const display = `${layoutSelector} { display: grid }`;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import {buildSearchLayoutCommon} from '../../common/atomic-layout-section/search-layout';

export const layoutWebComponentTagName = 'atomic-search-layout';
export const containerWebComponentTagName = 'atomic-search-interface';
export const noResultsSelector = `${containerWebComponentTagName}-no-results`;
export const errorSelector = `${containerWebComponentTagName}-error`;
export const firstSearchExecutedSelector = `${containerWebComponentTagName}-search-executed`;

export function makeDesktopQuery(mobileBreakpoint: string) {
return `only screen and (min-width: ${mobileBreakpoint})`;
}
Expand All @@ -10,7 +16,9 @@ export function buildSearchLayout(
return buildSearchLayoutCommon(
element,
mobileBreakpoint,
'atomic-search-layout',
'atomic-search-interface'
layoutWebComponentTagName,
containerWebComponentTagName,
noResultsSelector,
errorSelector
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ import {
CommonAtomicInterfaceHelper,
mismatchedInterfaceAndEnginePropError,
} from '../../common/interface/interface-common';
import {
errorSelector,
firstSearchExecutedSelector,
noResultsSelector,
} from '../atomic-layout/search-layout';
import {getAnalyticsConfig} from './analytics-config';
import {AtomicStore, createAtomicStore} from './store';

Expand Down Expand Up @@ -538,17 +543,17 @@ export class AtomicSearchInterface
!this.searchStatus.state.hasError;

this.host.classList.toggle(
'atomic-search-interface-no-results',
noResultsSelector,
hasNoResultsAfterInitialSearch
);

this.host.classList.toggle(
'atomic-search-interface-error',
errorSelector,
this.searchStatus.state.hasError
);

this.host.classList.toggle(
'atomic-search-interface-search-executed',
firstSearchExecutedSelector,
this.searchStatus.state.firstSearchExecuted
);

Expand Down

0 comments on commit 7d0bddc

Please sign in to comment.