-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(atomic,headless): support for atomic-commerce-did-you-mean (#4029)
https://coveord.atlassian.net/browse/KIT-3167 --------- Co-authored-by: GitHub Actions Bot <>
- Loading branch information
Showing
19 changed files
with
505 additions
and
139 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
...ic/src/components/commerce/atomic-commerce-did-you-mean/atomic-commerce-did-you-mean.pcss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
@import '../../../global/global.pcss'; |
122 changes: 122 additions & 0 deletions
122
...mic/src/components/commerce/atomic-commerce-did-you-mean/atomic-commerce-did-you-mean.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import { | ||
DidYouMeanState, | ||
DidYouMean, | ||
buildSearch, | ||
QueryTrigger, | ||
buildQueryTrigger, | ||
QueryTriggerState, | ||
} from '@coveo/headless/commerce'; | ||
import {Component, State, h} from '@stencil/core'; | ||
import { | ||
BindStateToController, | ||
InitializableComponent, | ||
InitializeBindings, | ||
} from '../../../utils/initialization-utils'; | ||
import {AutoCorrection} from '../../common/query-correction/auto-correction'; | ||
import {Correction} from '../../common/query-correction/correction'; | ||
import {QueryCorrectionGuard} from '../../common/query-correction/guard'; | ||
import {TriggerCorrection} from '../../common/query-correction/trigger-correction'; | ||
import {CommerceBindings} from '../atomic-commerce-interface/atomic-commerce-interface'; | ||
|
||
/** | ||
* @internal | ||
* | ||
* The `atomic-commerce-query-correction` component is responsible for handling query corrections. When a query returns no products but finds a possible query correction, the component either suggests the correction or automatically triggers a new query with the suggested term. | ||
* | ||
* @part no-results - The text displayed when there are no results. | ||
* @part auto-corrected - The text displayed for the automatically corrected query. | ||
* @part showing-results-for - The first paragraph of the text displayed when a query trigger changes a query. | ||
* @part search-instead-for - The second paragraph of the text displayed when a query trigger changes a query. | ||
* @part did-you-mean - The text displayed around the button to manually correct a query. | ||
* @part correction-btn - The button used to manually correct a query. | ||
* @part undo-btn - The button used to undo a query changed by a query trigger. | ||
* @part highlight - The query highlights. | ||
*/ | ||
@Component({ | ||
tag: 'atomic-commerce-did-you-mean', | ||
styleUrl: 'atomic-commerce-did-you-mean.pcss', | ||
shadow: true, | ||
}) | ||
export class AtomicCommerceDidYouMean | ||
implements InitializableComponent<CommerceBindings> | ||
{ | ||
@InitializeBindings() public bindings!: CommerceBindings; | ||
didYouMean!: DidYouMean; | ||
queryTrigger!: QueryTrigger; | ||
|
||
@BindStateToController('didYouMean') | ||
@State() | ||
private didYouMeanState?: DidYouMeanState; | ||
@BindStateToController('queryTrigger') | ||
@State() | ||
private queryTriggerState?: QueryTriggerState; | ||
@State() | ||
public error!: Error; | ||
|
||
public initialize() { | ||
if (this.bindings.interfaceElement.type !== 'search') { | ||
this.error = new Error( | ||
'atomic-commerce-did-you-mean is only usable with an atomic-commerce-interface of type "search"' | ||
); | ||
} | ||
|
||
this.didYouMean = buildSearch(this.bindings.engine).didYouMean(); | ||
this.queryTrigger = buildQueryTrigger(this.bindings.engine); | ||
} | ||
|
||
private get content() { | ||
if (!this.didYouMeanState || !this.queryTriggerState) { | ||
return; | ||
} | ||
|
||
const {hasQueryCorrection, wasAutomaticallyCorrected} = | ||
this.didYouMeanState; | ||
const hasTrigger = this.queryTriggerState.wasQueryModified; | ||
|
||
if (hasQueryCorrection && wasAutomaticallyCorrected) { | ||
return ( | ||
<AutoCorrection | ||
correctedTo={this.didYouMeanState.wasCorrectedTo} | ||
originalQuery={this.didYouMeanState.originalQuery} | ||
i18n={this.bindings.i18n} | ||
/> | ||
); | ||
} | ||
if (hasQueryCorrection) { | ||
return ( | ||
<Correction | ||
correctedQuery={this.didYouMeanState.queryCorrection.correctedQuery} | ||
i18n={this.bindings.i18n} | ||
onClick={() => {}} | ||
/> | ||
); | ||
} | ||
if (hasTrigger) { | ||
return ( | ||
<TriggerCorrection | ||
i18n={this.bindings.i18n} | ||
correctedQuery={this.queryTriggerState.newQuery} | ||
originalQuery={this.queryTriggerState.originalQuery} | ||
onClick={() => this.queryTrigger.undo()} | ||
/> | ||
); | ||
} | ||
} | ||
|
||
public render() { | ||
if (!this.didYouMeanState || !this.queryTriggerState) { | ||
return; | ||
} | ||
|
||
return ( | ||
<QueryCorrectionGuard | ||
hasCorrection={ | ||
this.didYouMeanState.hasQueryCorrection || | ||
this.queryTriggerState.wasQueryModified | ||
} | ||
> | ||
{this.content} | ||
</QueryCorrectionGuard> | ||
); | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
packages/atomic/src/components/common/query-correction/auto-correction.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import {FunctionalComponent, h, Fragment} from '@stencil/core'; | ||
import {i18n} from 'i18next'; | ||
import {LocalizedString} from '../../../utils/jsx-utils'; | ||
|
||
interface AutoCorrectionProps { | ||
i18n: i18n; | ||
originalQuery: string; | ||
correctedTo: string; | ||
} | ||
export const AutoCorrection: FunctionalComponent<AutoCorrectionProps> = ({ | ||
i18n, | ||
correctedTo, | ||
originalQuery, | ||
}) => { | ||
return ( | ||
<Fragment> | ||
<p class="text-on-background mb-1" part="no-results"> | ||
<LocalizedString | ||
i18n={i18n} | ||
key={'no-results-for-did-you-mean'} | ||
params={{query: <b part="highlight">{originalQuery}</b>}} | ||
/> | ||
</p> | ||
<p class="text-on-background" part="auto-corrected"> | ||
<LocalizedString | ||
i18n={i18n} | ||
key={'query-auto-corrected-to'} | ||
params={{query: <b part="highlight">{correctedTo}</b>}} | ||
/> | ||
</p> | ||
</Fragment> | ||
); | ||
}; |
34 changes: 34 additions & 0 deletions
34
packages/atomic/src/components/common/query-correction/correction.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import {FunctionalComponent, h} from '@stencil/core'; | ||
import {i18n} from 'i18next'; | ||
import {LocalizedString} from '../../../utils/jsx-utils'; | ||
|
||
interface CorrectionProps { | ||
i18n: i18n; | ||
onClick: () => void; | ||
correctedQuery: string; | ||
} | ||
export const Correction: FunctionalComponent<CorrectionProps> = ({ | ||
i18n, | ||
onClick, | ||
correctedQuery, | ||
}) => { | ||
return ( | ||
<p class="text-on-background" part="did-you-mean"> | ||
<LocalizedString | ||
i18n={i18n} | ||
key="did-you-mean" | ||
params={{ | ||
query: ( | ||
<button | ||
class="link py-1" | ||
part="correction-btn" | ||
onClick={() => onClick()} | ||
> | ||
{correctedQuery} | ||
</button> | ||
), | ||
}} | ||
/> | ||
</p> | ||
); | ||
}; |
13 changes: 13 additions & 0 deletions
13
packages/atomic/src/components/common/query-correction/guard.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import {Fragment, FunctionalComponent, h} from '@stencil/core'; | ||
|
||
interface QueryCorrectionGuardProps { | ||
hasCorrection: boolean; | ||
} | ||
export const QueryCorrectionGuard: FunctionalComponent< | ||
QueryCorrectionGuardProps | ||
> = ({hasCorrection}, children) => { | ||
if (!hasCorrection) { | ||
return; | ||
} | ||
return <Fragment>{children}</Fragment>; | ||
}; |
51 changes: 51 additions & 0 deletions
51
packages/atomic/src/components/common/query-correction/trigger-correction.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import {FunctionalComponent, Fragment, h} from '@stencil/core'; | ||
import {i18n} from 'i18next'; | ||
import {LocalizedString} from '../../../utils/jsx-utils'; | ||
|
||
interface TriggerCorrectionProps { | ||
i18n: i18n; | ||
correctedQuery: string; | ||
originalQuery: string; | ||
onClick: () => void; | ||
} | ||
export const TriggerCorrection: FunctionalComponent<TriggerCorrectionProps> = ({ | ||
i18n, | ||
correctedQuery, | ||
originalQuery, | ||
onClick, | ||
}) => { | ||
return ( | ||
<Fragment> | ||
<p | ||
class="text-on-background leading-6 text-lg" | ||
part="showing-results-for" | ||
> | ||
<LocalizedString | ||
i18n={i18n} | ||
key={'showing-results-for'} | ||
params={{query: <b part="highlight">{correctedQuery}</b>}} | ||
/> | ||
</p> | ||
<p | ||
class="text-on-background leading-5 text-base" | ||
part="search-instead-for" | ||
> | ||
<LocalizedString | ||
i18n={i18n} | ||
key="search-instead-for" | ||
params={{ | ||
query: ( | ||
<button | ||
class="link py-1" | ||
part="undo-btn" | ||
onClick={() => onClick()} | ||
> | ||
{originalQuery} | ||
</button> | ||
), | ||
}} | ||
/> | ||
</p> | ||
</Fragment> | ||
); | ||
}; |
Oops, something went wrong.