Skip to content
This repository has been archived by the owner on Dec 30, 2022. It is now read-only.

feat(voice): add additionalQueryParameters #2366

Merged
merged 7 commits into from
Nov 20, 2019
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@
},
{
"path": "packages/react-instantsearch-dom/dist/umd/ReactInstantSearchDOM.min.js",
"maxSize": "35.50 kB"
"maxSize": "35.75 kB"
},
{
"path": "packages/react-instantsearch-dom-maps/dist/umd/ReactInstantSearchDOMMaps.min.js",
Expand Down
156 changes: 156 additions & 0 deletions packages/react-instantsearch-core/src/connectors/connectVoiceSearch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import PropTypes from 'prop-types';
import createConnector from '../core/createConnector';
import {
cleanUpValue,
refineValue,
getCurrentRefinementValue,
getIndexId,
} from '../core/indexUtils';

function getId() {
return 'query';
}

function getAdditionalId() {
Haroenv marked this conversation as resolved.
Show resolved Hide resolved
return 'additionalVoiceParameters';
}

function getCurrentRefinementQuery(props, searchState, context) {
const id = getId();
const currentRefinement = getCurrentRefinementValue(
props,
searchState,
context,
id,
''
);

if (currentRefinement) {
return currentRefinement;
}
return '';
}

function getCurrentRefinementAdditional(props, searchState, context) {
const id = getAdditionalId();
const currentRefinement = getCurrentRefinementValue(
props,
searchState,
context,
id,
''
);

if (currentRefinement) {
return currentRefinement;
}
return {};
Haroenv marked this conversation as resolved.
Show resolved Hide resolved
}

function refine(props, searchState, nextRefinement, context) {
const id = getId();
const voiceParams = getAdditionalId();

const nextValue = {
[id]: nextRefinement,
[voiceParams]:
typeof props.additionalQueryParameters === 'function'
? {
queryLanguages: props.language
Haroenv marked this conversation as resolved.
Show resolved Hide resolved
? [props.language.split('-')[0]]
: undefined,
ignorePlurals: true,
removeStopWords: true,
optionalWords: nextRefinement,
...props.additionalQueryParameters({ query: nextRefinement }),
}
: {},
};
const resetPage = true;
return refineValue(searchState, nextValue, context, resetPage);
}

function cleanUp(props, searchState, context) {
const interimState = cleanUpValue(searchState, context, getId());
return cleanUpValue(interimState, context, getAdditionalId());
}

export default createConnector({
displayName: 'AlgoliaVoiceSearch',

propTypes: {
defaultRefinement: PropTypes.string,
},

getProvidedProps(props, searchState, searchResults) {
return {
currentRefinement: getCurrentRefinementQuery(props, searchState, {
ais: props.contextValue,
multiIndexContext: props.indexContextValue,
}),
isSearchStalled: searchResults.isSearchStalled,
};
},

refine(props, searchState, nextRefinement) {
return refine(props, searchState, nextRefinement, {
ais: props.contextValue,
multiIndexContext: props.indexContextValue,
});
},

cleanUp(props, searchState) {
return cleanUp(props, searchState, {
ais: props.contextValue,
multiIndexContext: props.indexContextValue,
});
},

getSearchParameters(searchParameters, props, searchState) {
const query = getCurrentRefinementQuery(props, searchState, {
ais: props.contextValue,
multiIndexContext: props.indexContextValue,
});
const additionalParams = getCurrentRefinementAdditional(
props,
searchState,
{
ais: props.contextValue,
multiIndexContext: props.indexContextValue,
}
);

return searchParameters
.setQuery(query)
.setQueryParameters(additionalParams);
},

getMetadata(props, searchState) {
const id = getId(props);
Haroenv marked this conversation as resolved.
Show resolved Hide resolved
const currentRefinement = getCurrentRefinementQuery(props, searchState, {
ais: props.contextValue,
multiIndexContext: props.indexContextValue,
});
return {
id,
index: getIndexId({
ais: props.contextValue,
multiIndexContext: props.indexContextValue,
}),
items:
currentRefinement === null
? []
: [
{
label: `${id}: ${currentRefinement}`,
value: nextState =>
refine(props, nextState, '', {
ais: props.contextValue,
multiIndexContext: props.indexContextValue,
}),
currentRefinement,
},
],
};
},
});
1 change: 1 addition & 0 deletions packages/react-instantsearch-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export {
default as connectToggleRefinement,
} from './connectors/connectToggleRefinement';
export { default as connectHitInsights } from './connectors/connectHitInsights';
export { default as connectVoiceSearch } from './connectors/connectVoiceSearch';

// Types
export * from './types';
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ export type InnerComponentProps = {

type VoiceSearchProps = {
searchAsYouSpeak: boolean;
language?: string;
additionalQueryParameters?: (params: { query: string }) => {} | void;

refine: (query: string) => void;
translate: Translate;
buttonTextComponent: React.FC<InnerComponentProps>;
Expand Down Expand Up @@ -84,9 +87,10 @@ class VoiceSearch extends Component<VoiceSearchProps, VoiceListeningState> {
private voiceSearchHelper?: VoiceSearchHelper;

public componentDidMount() {
const { searchAsYouSpeak, refine } = this.props;
const { searchAsYouSpeak = false, language, refine } = this.props;
this.voiceSearchHelper = createVoiceSearchHelper({
searchAsYouSpeak,
language,
onQueryChange: query => refine(query),
onStateChange: () => {
this.setState(this.voiceSearchHelper!.getState());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

export type VoiceSearchHelperParams = {
searchAsYouSpeak: boolean;
language?: string;
onQueryChange: (query: string) => void;
onStateChange: () => void;
};
Expand Down Expand Up @@ -33,6 +34,7 @@ export type ToggleListening = () => void;

export default function createVoiceSearchHelper({
searchAsYouSpeak,
language,
onQueryChange,
onStateChange,
}: VoiceSearchHelperParams): VoiceSearchHelper {
Expand Down Expand Up @@ -107,6 +109,9 @@ export default function createVoiceSearchHelper({
}
resetState('askingPermission');
recognition.interimResults = true;
if (language) {
recognition.lang = language;
}
recognition.addEventListener('start', onStart);
recognition.addEventListener('error', onError);
recognition.addEventListener('result', onResult);
Expand Down
4 changes: 2 additions & 2 deletions packages/react-instantsearch-dom/src/widgets/VoiceSearch.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { connectSearchBox } from 'react-instantsearch-core';
import { connectVoiceSearch } from 'react-instantsearch-core';
import VoiceSearch from '../components/VoiceSearch';

export default connectSearchBox(VoiceSearch);
export default connectVoiceSearch(VoiceSearch);
33 changes: 32 additions & 1 deletion stories/VoiceSearch.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,35 @@ stories
</div>
</WrapWithHits>
);
});
})
.add('with additional paramaters', () => (
<WrapWithHits
searchBox={false}
hasPlayground={true}
linkedStoryGroup="VoiceSearch"
>
<VoiceSearch additionalQueryParameters={() => {}} />
<SearchBox />
</WrapWithHits>
))
.add('with additional paramaters & language', () => (
<WrapWithHits
searchBox={false}
hasPlayground={true}
linkedStoryGroup="VoiceSearch"
>
<VoiceSearch language="fr-FR" additionalQueryParameters={() => {}} />
</WrapWithHits>
))
.add('with additional paramaters & user set & language', () => (
<WrapWithHits
searchBox={false}
hasPlayground={true}
linkedStoryGroup="VoiceSearch"
>
<VoiceSearch
language="fr-FR"
additionalQueryParameters={() => ({ analyticsTags: ['voice'] })}
/>
</WrapWithHits>
));