@atlaskit/global-search
Version:
A cross-product search component (batteries included)
209 lines (182 loc) • 6.52 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import React from 'react';
import debounce from 'lodash/debounce';
import { QuickSearch } from '@atlaskit/quick-search';
import { withAnalyticsEvents, AnalyticsContext } from '@atlaskit/analytics-next';
import { fireSelectedSearchResult, fireHighlightedSearchResult, fireSelectedAdvancedSearch, fireTextEnteredEvent, fireDismissedEvent, fireAutocompleteRenderedEvent, fireAutocompleteCompletedEvent } from '../util/analytics-event-helper';
import { isAdvancedSearchResult } from './SearchResultsUtil';
import { getAutocompleteText } from '../util/autocomplete';
const ATLASKIT_QUICKSEARCH_NS = 'atlaskit.navigation.quick-search';
const QS_ANALYTICS_EV_KB_CTRLS_USED = `${ATLASKIT_QUICKSEARCH_NS}.keyboard-controls-used`;
const QS_ANALYTICS_EV_SUBMIT = `${ATLASKIT_QUICKSEARCH_NS}.submit`;
/**
* Presentational component that renders the search input and search results.
*/
export class GlobalQuickSearch extends React.Component {
constructor(...args) {
super(...args);
_defineProperty(this, "queryVersion", 0);
_defineProperty(this, "autoCompleteVersion", 0);
_defineProperty(this, "autoCompleteLastTimeStamp", 0);
_defineProperty(this, "resultSelected", false);
_defineProperty(this, "state", {
query: '',
autocompleteText: undefined
});
_defineProperty(this, "handleSearchInput", ({
target
}, isAutocompleted) => {
const query = target.value;
this.debouncedSearch(query);
if (query.length > 0) {
this.autoCompleteLastTimeStamp = +new Date();
this.debouncedAutocomplete(query);
}
if (isAutocompleted) {
const {
searchSessionId,
createAnalyticsEvent
} = this.props;
const {
query: prevQuery
} = this.state;
fireAutocompleteCompletedEvent(searchSessionId, prevQuery, query, createAnalyticsEvent);
}
this.setState({
query
});
});
_defineProperty(this, "debouncedSearch", debounce(this.doSearch, 350));
_defineProperty(this, "debouncedAutocomplete", debounce(this.doAutocomplete, 100));
_defineProperty(this, "fireSearchResultSelectedEvent", eventData => {
const {
createAnalyticsEvent,
searchSessionId,
referralContextIdentifiers,
advancedSearchId
} = this.props;
this.resultSelected = true;
const resultId = eventData.resultCount && eventData.method === 'shortcut' ? advancedSearchId : eventData.resultId;
if (isAdvancedSearchResult(resultId)) {
fireSelectedAdvancedSearch({ ...eventData,
resultId,
query: this.state.query,
queryVersion: this.queryVersion,
isLoading: this.props.isLoading
}, searchSessionId, referralContextIdentifiers, createAnalyticsEvent);
} else {
fireSelectedSearchResult({ ...eventData,
query: this.state.query,
queryVersion: this.queryVersion
}, searchSessionId, referralContextIdentifiers, createAnalyticsEvent);
}
});
_defineProperty(this, "fireSearchResultEvents", (eventName, eventData) => {
const {
createAnalyticsEvent,
searchSessionId,
referralContextIdentifiers
} = this.props;
if (eventName === QS_ANALYTICS_EV_SUBMIT) {
this.fireSearchResultSelectedEvent(eventData);
} else if (eventName === QS_ANALYTICS_EV_KB_CTRLS_USED) {
const data = eventData;
if (data.key === 'ArrowDown' || data.key === 'ArrowUp') {
fireHighlightedSearchResult(data, searchSessionId, referralContextIdentifiers, createAnalyticsEvent);
}
}
});
}
static getDerivedStateFromProps(nextProps, prevState) {
const {
autocompleteSuggestions
} = nextProps;
const {
query
} = prevState;
return { ...prevState,
autocompleteText: getAutocompleteText(query, autocompleteSuggestions)
};
}
componentDidMount() {
this.props.onMount && this.props.onMount();
}
componentDidUpdate(prevProps, prevState) {
const {
createAnalyticsEvent,
searchSessionId,
autocompleteSuggestions
} = this.props;
const {
query,
autocompleteText
} = this.state;
if (query.length > 0 && autocompleteText && autocompleteText.length > query.length && (query !== prevState.query || autocompleteText !== prevState.autocompleteText)) {
const duration = +new Date() - this.autoCompleteLastTimeStamp;
fireAutocompleteRenderedEvent(duration, searchSessionId, query, autocompleteText, this.autoCompleteVersion, autocompleteSuggestions === prevProps.autocompleteSuggestions, createAnalyticsEvent);
this.autoCompleteLastTimeStamp = +new Date();
this.autoCompleteVersion++;
}
}
doSearch(query) {
const {
onSearch,
searchSessionId,
createAnalyticsEvent,
filters
} = this.props;
onSearch(query.trim(), this.queryVersion, filters);
fireTextEnteredEvent(query, searchSessionId, this.queryVersion, createAnalyticsEvent);
this.queryVersion++;
}
doAutocomplete(query) {
const {
onAutocomplete
} = this.props;
onAutocomplete && onAutocomplete(query);
}
componentWillUnmount() {
if (this.resultSelected) {
return;
}
const {
createAnalyticsEvent,
searchSessionId
} = this.props;
fireDismissedEvent(searchSessionId, createAnalyticsEvent);
}
render() {
const {
isLoading,
placeholder,
linkComponent,
children,
onSearchSubmit,
selectedResultId,
onSelectedResultIdChanged,
inputControls
} = this.props;
const {
query,
autocompleteText
} = this.state;
return /*#__PURE__*/React.createElement(AnalyticsContext, {
data: {
searchSessionId: this.props.searchSessionId
}
}, /*#__PURE__*/React.createElement(QuickSearch, {
firePrivateAnalyticsEvent: this.fireSearchResultEvents,
isLoading: isLoading,
onSearchInput: this.handleSearchInput,
placeholder: placeholder,
value: query,
linkComponent: linkComponent,
onSearchSubmit: onSearchSubmit,
selectedResultId: selectedResultId,
onSelectedResultIdChanged: onSelectedResultIdChanged,
inputControls: inputControls,
autocompleteText: autocompleteText
}, children));
}
}
export default withAnalyticsEvents()(GlobalQuickSearch);