2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017-2018 Amdocs
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
21 import React, {Component} from 'react';
22 import { PropTypes } from 'prop-types';
23 import {Button} from 'react-bootstrap';
24 import AutoSuggest from 'react-autosuggest';
25 import Highlighter from 'react-highlight-words';
26 import debounce from 'lodash.debounce';
27 import {ButtonGroup} from 'react-bootstrap';
28 import {Link} from 'react-router-dom';
30 import {changeUrlAddress} from 'utils/Routes.js';
37 SEARCH_PLACEHOLDER_TEXT
38 } from './AutoCompleteSearchBarConstants.js';
40 export default class AutoCompleteSearchBar extends Component {
42 value: PropTypes.string,
43 suggestions: PropTypes.array,
44 cachedSuggestions: PropTypes.array,
45 suggestionName: PropTypes.string
48 componentWillMount() {
49 this.debouncedLoadSuggestions =
50 debounce(this.props.onSuggestionsFetchRequested, SEARCH_DEBOUNCE_TIME);
53 onSuggestionsFetchRequested = ({value}) => {
54 this.debouncedLoadSuggestions({value});
57 isValidSearch(value) {
58 return (value && value !== NO_MATCHES_FOUND);
61 isValidSuggestionObject(suggestionObj) {
62 return (suggestionObj &&
63 Object.keys(suggestionObj).length > 0 &&
64 this.isValidSearch(suggestionObj.text));
67 getSelectedSuggestionObj(value, cachedSuggestions) {
68 let matchesSuggestion = {};
70 if (this.isValidSearch(value)) {
71 for (let suggestionIndex in cachedSuggestions) {
72 if (cachedSuggestions[suggestionIndex].text === value) {
73 matchesSuggestion = cachedSuggestions[suggestionIndex];
79 return matchesSuggestion;
83 cachedSuggestion, invalidSearchCallback, dispatchAnalytics, value) {
84 if (this.isValidSuggestionObject(cachedSuggestion)) {
85 changeUrlAddress(cachedSuggestion, this.props.history);
86 //Call analytics if defined
87 if (dispatchAnalytics) {
91 invalidSearchCallback(value);
98 suggestionName, cachedSuggestions,
99 onInputChange, onInvalidSearch,
100 onClearSuggestionsTextFieldRequested,
101 onSuggestionsClearRequested,
105 placeholder: SEARCH_PLACEHOLDER_TEXT,
107 onChange: onInputChange
110 let clearButtonClass = (value.length > 0)
111 ? 'auto-complete-clear-button'
112 : 'auto-complete-clear-button hidden';
114 <div className='auto-complete-search'>
116 suggestions={suggestions}
117 getSuggestionValue={suggestion => suggestion[suggestionName]}
118 onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
119 onSuggestionsClearRequested={onSuggestionsClearRequested}
120 onSuggestionSelected={(event, {suggestion}) => {
121 this.newSearchSelected(suggestion, onInvalidSearch, dispatchAnalytics, value);
122 this.props.onClearSuggestionsTextFieldRequested();
124 renderSuggestion={this.renderSuggestion}
125 inputProps={inputProps}
126 focusFirstSuggestion={false}
127 renderSuggestionsContainer={this.renderSuggestionsContainer}/>
128 <ButtonGroup className='auto-complete-search-button-group'>
129 <Button type='submit' className={clearButtonClass}
130 onClick={onClearSuggestionsTextFieldRequested}>
131 <i className={ICON_CLASS_CLEAR} aria-hidden='true'/>
134 <Button type='submit' className='auto-complete-search-button' onClick={() => {
135 this.newSearchSelected(this.getSelectedSuggestionObj(value, cachedSuggestions),
136 onInvalidSearch, dispatchAnalytics, value);
137 this.props.onSuggestionsClearRequested();
139 <i className={ICON_CLASS_SEARCH} aria-hidden='true'/>
146 renderSuggestion(suggestion, {query}) {
147 let toHighLightArray = query.split(' ');
148 let suggestionTextArray = suggestion.text.split(' ');
151 if (suggestion.text !== NO_MATCHES_FOUND) {
152 // render the suggestion as a clickable link
154 <div className='suggestionFlexContainer'>
155 <span key={'sugSpan1'}
156 className='suggestionColumnTwo'>
157 <Link style={{textDecoration: 'none'}}
158 to={'/' + suggestion.route + '/' + suggestion.hashId}
160 {suggestionTextArray.map(
163 <span key={arrayIndex + 'sugSpan3'}>
164 <Highlighter key={arrayIndex + 'high'}
165 highlightClassName='highlight'
166 searchWords={toHighLightArray}
167 textToHighlight={suggestionTextArray[arrayIndex]}
169 { ++arrayIndex ? ' ' : ' '}
177 // render the suggestion as plain text
179 <div className='suggestionFlexContainer'>
180 <span key={'sugSpan1'}
181 className='suggestionColumnTwo'>
182 {suggestionTextArray.map(
185 <span key={arrayIndex + 'sugSpan3'}>
186 <Highlighter key={arrayIndex + 'high'}
187 highlightClassName='highlight'
188 searchWords={toHighLightArray}
189 textToHighlight={suggestionTextArray[arrayIndex]}
191 { ++arrayIndex ? ' ' : ' '}
201 renderSuggestionsContainer({children, ...rest}) {
202 if (children !== null && children.props.items.length < 5) {
203 rest.className = 'react-autosuggest__suggestions-containerCopy';
206 <div {...rest.containerProps} {...rest}>