@kiwicom/smart-faq
Version:
173 lines (145 loc) • 4.58 kB
JavaScript
// @flow
import * as React from 'react';
import { Search } from '@kiwicom/orbit-components/lib/icons';
import { withRouter } from 'react-router-dom';
import type { ContextRouter } from 'react-router-dom';
import IntlContext from '@kiwicom/nitro/lib/services/intl/context';
import type { Context as Intl } from '@kiwicom/nitro/lib/services/intl/context';
import InputField from '@kiwicom/orbit-components/lib/InputField';
import ButtonLink from '@kiwicom/orbit-components/lib/ButtonLink';
import CloseCircle from '@kiwicom/orbit-components/lib/icons/CloseCircle';
import LogContext from '@kiwicom/nitro/lib/services/log/context';
import { SearchState } from '../../SmartFAQ/context/SearchState';
import PageVariant from '../../SmartFAQ/context/PageVariant';
import type { SearchStateType } from '../../SmartFAQ/context/SearchState';
import { debounce } from '../../SmartFAQ/helpers/functionUtils';
import { events } from '../../const/events';
import type { log } from '../../const/events';
type ContainerProps = {|
...ContextRouter,
autofocus?: boolean,
|};
type Props = {|
...ContainerProps,
searchContext: SearchStateType,
intl: Intl,
isFullPage: boolean,
log: log,
|};
type State = {|
value: string,
|};
class SearchBar extends React.Component<Props, State> {
input = React.createRef();
constructor(props: Props) {
super(props);
this.state = {
value: props.searchContext.searchText,
};
}
componentDidMount() {
const { autofocus } = this.props;
const input = this.input.current;
if (input && autofocus) {
input.focus();
}
}
componentDidUpdate(prevProps) {
if (
prevProps.searchContext.searchText !== this.props.searchContext.searchText
) {
// I know what I'm doing - keep local state synced with context
// eslint-disable-next-line react/no-did-update-set-state
this.setState({ value: this.props.searchContext.searchText });
}
}
getResetButton = () => {
const { searchText } = this.props.searchContext;
const isSearching = searchText.length > 0;
if (!isSearching) {
// show reset icon only when some text was entered
return null;
}
return (
<ButtonLink
transparent
type="secondary"
icon={<CloseCircle />}
onClick={this.handleSearchCancel}
dataTest="SearchBarInput-ResetButton"
/>
);
};
updateSearchText = searchedText => {
const { searchContext, log } = this.props;
const {
changeSearchText,
resetQueriesCount,
incrementQueriesCount,
} = searchContext;
changeSearchText(searchedText);
incrementQueriesCount();
if (searchedText.length >= 2) {
log(events.FAQ_SEARCH, { searchedText: searchedText.toLowerCase() });
}
if (searchedText.length) {
incrementQueriesCount();
} else {
resetQueriesCount();
}
};
// this is regular method and can't be before "updateSearchText"!
// eslint-disable-next-line react/sort-comp
debouncedUpdateSearchText = debounce(this.updateSearchText, 350);
handleSearchCancel = () => {
this.setState({ value: '' });
this.updateSearchText('');
};
handleSearchChange = (e: SyntheticInputEvent<HTMLInputElement>) => {
const searchedText = e.target.value;
if (
searchedText.length &&
this.props.match.url.includes('article') &&
!this.props.isFullPage
) {
this.props.history.push('/faq');
}
this.setState({ value: searchedText });
this.debouncedUpdateSearchText(searchedText);
};
render() {
const { intl, isFullPage } = this.props;
const { value } = this.state;
const placeholder = isFullPage
? __('smartfaq.full_page.search.placeholder')
: __('smartfaq.search_input.placeholder');
return (
<InputField
type="text"
ref={this.input}
value={value}
onChange={this.handleSearchChange}
placeholder={intl.translate(placeholder)}
prefix={<Search />}
suffix={this.getResetButton()}
dataTest="SearchBarInput"
/>
);
}
}
const WrappedSearchBar = (props: ContainerProps) => {
const searchContext = React.useContext(SearchState);
const intl = React.useContext(IntlContext);
const { log } = React.useContext(LogContext);
const { variant } = React.useContext(PageVariant);
return (
<SearchBar
{...props}
log={log}
searchContext={searchContext}
intl={intl}
isFullPage={variant === 'fullPage'}
/>
);
};
export default withRouter(WrappedSearchBar);