diff options
Diffstat (limited to 'src/generic-components/autoCompleteSearchBar')
-rw-r--r-- | src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBar.jsx | 211 | ||||
-rw-r--r-- | src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBarConstants.js | 42 |
2 files changed, 253 insertions, 0 deletions
diff --git a/src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBar.jsx b/src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBar.jsx new file mode 100644 index 0000000..4dddcbe --- /dev/null +++ b/src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBar.jsx @@ -0,0 +1,211 @@ +/* + * ============LICENSE_START=================================================== + * SPARKY (AAI UI service) + * ============================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * All rights reserved. + * ============================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END===================================================== + * + * ECOMP and OpenECOMP are trademarks + * and service marks of AT&T Intellectual Property. + */ + +import React, {Component} from 'react'; +import {Button} from 'react-bootstrap'; +import AutoSuggest from 'react-autosuggest'; +import Highlighter from 'react-highlight-words'; +import debounce from 'lodash.debounce'; +import {ButtonGroup} from 'react-bootstrap'; +import {Link} from 'react-router-dom'; + +import {changeUrlAddress} from 'utils/Routes.js'; + +import { + ICON_CLASS_SEARCH, + ICON_CLASS_CLEAR, + SEARCH_DEBOUNCE_TIME, + NO_MATCHES_FOUND, + SEARCH_PLACEHOLDER_TEXT +} from './AutoCompleteSearchBarConstants.js'; + +export default class AutoCompleteSearchBar extends Component { + static propTypes = { + value: React.PropTypes.string, + suggestions: React.PropTypes.array, + cachedSuggestions: React.PropTypes.array, + suggestionName: React.PropTypes.string + }; + + componentWillMount() { + this.debouncedLoadSuggestions = + debounce(this.props.onSuggestionsFetchRequested, SEARCH_DEBOUNCE_TIME); + } + + onSuggestionsFetchRequested = ({value}) => { + this.debouncedLoadSuggestions({value}); + }; + + isValidSearch(value) { + return (value && value !== NO_MATCHES_FOUND); + } + + isValidSuggestionObject(suggestionObj) { + return (suggestionObj && + Object.keys(suggestionObj).length > 0 && + this.isValidSearch(suggestionObj.text)); + } + + getSelectedSuggestionObj(value, cachedSuggestions) { + let matchesSuggestion = {}; + + if (this.isValidSearch(value)) { + for (let suggestionIndex in cachedSuggestions) { + if (cachedSuggestions[suggestionIndex].text === value) { + matchesSuggestion = cachedSuggestions[suggestionIndex]; + break; + } + } + } + + return matchesSuggestion; + } + + newSearchSelected( + cachedSuggestion, invalidSearchCallback, dispatchAnalytics, value) { + if (this.isValidSuggestionObject(cachedSuggestion)) { + changeUrlAddress(cachedSuggestion, this.props.history); + //Call analytics if defined + if (dispatchAnalytics) { + dispatchAnalytics(); + } + } else { + invalidSearchCallback(value); + } + } + + render() { + const { + value, suggestions, + suggestionName, cachedSuggestions, + onInputChange, onInvalidSearch, + onClearSuggestionsTextFieldRequested, + onSuggestionsClearRequested, + dispatchAnalytics + } = this.props; + const inputProps = { + placeholder: SEARCH_PLACEHOLDER_TEXT, + value, + onChange: onInputChange + }; + + let clearButtonClass = (value.length > 0) + ? 'auto-complete-clear-button' + : 'auto-complete-clear-button hidden'; + return ( + <div className='auto-complete-search'> + <AutoSuggest + suggestions={suggestions} + getSuggestionValue={suggestion => suggestion[suggestionName]} + onSuggestionsFetchRequested={this.onSuggestionsFetchRequested} + onSuggestionsClearRequested={onSuggestionsClearRequested} + onSuggestionSelected={(event, {suggestion}) => { + this.newSearchSelected(suggestion, onInvalidSearch, dispatchAnalytics, value); + }} + renderSuggestion={this.renderSuggestion} + inputProps={inputProps} + focusFirstSuggestion={false} + renderSuggestionsContainer={this.renderSuggestionsContainer}/> + <ButtonGroup className='auto-complete-search-button-group'> + <Button type='submit' className={clearButtonClass} + onClick={onClearSuggestionsTextFieldRequested}> + <i className={ICON_CLASS_CLEAR} aria-hidden='true'/> + </Button> + + <Button type='submit' className='auto-complete-search-button' onClick={() => { + this.newSearchSelected(this.getSelectedSuggestionObj(value, cachedSuggestions), + onInvalidSearch, dispatchAnalytics, value); + }}> + <i className={ICON_CLASS_SEARCH} aria-hidden='true'/> + </Button> + </ButtonGroup> + </div> + ); + } + + renderSuggestion(suggestion, {query}) { + let toHighLightArray = query.split(' '); + let suggestionTextArray = suggestion.text.split(' '); + let arrayIndex = 0; + + if (suggestion.text !== NO_MATCHES_FOUND) { + // render the suggestion as a clickable link + return ( + <div className='suggestionFlexContainer'> + <span key={'sugSpan1'} + className='suggestionColumnTwo'> + <Link style={{textDecoration: 'none'}} + to={'/' + suggestion.route + '/' + suggestion.hashId} + replace={true}> + {suggestionTextArray.map( + function () { + return ( + <span key={arrayIndex + 'sugSpan3'}> + <Highlighter key={arrayIndex + 'high'} + highlightClassName='highlight' + searchWords={toHighLightArray} + textToHighlight={suggestionTextArray[arrayIndex]}/> + { ++arrayIndex ? ' ' : ' '} + </span>); + + })} </Link> + </span> + </div> + ); + } else { + // render the suggestion as plain text + return ( + <div className='suggestionFlexContainer'> + <span key={'sugSpan1'} + className='suggestionColumnTwo'> + {suggestionTextArray.map( + function () { + return ( + <span key={arrayIndex + 'sugSpan3'}> + <Highlighter key={arrayIndex + 'high'} + highlightClassName='highlight' + searchWords={toHighLightArray} + textToHighlight={suggestionTextArray[arrayIndex]}/> + { ++arrayIndex ? ' ' : ' '} + </span>); + + })} + </span> + </div> + ); + } + } + + renderSuggestionsContainer({children, ...rest}) { + if (children !== null && children.props.items.length < 5) { + rest.className = 'react-autosuggest__suggestions-containerCopy'; + } + return ( + <div {...rest}> + {children} + </div> + ); + } +} diff --git a/src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBarConstants.js b/src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBarConstants.js new file mode 100644 index 0000000..d5afd46 --- /dev/null +++ b/src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBarConstants.js @@ -0,0 +1,42 @@ +/* + * ============LICENSE_START=================================================== + * SPARKY (AAI UI service) + * ============================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * All rights reserved. + * ============================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END===================================================== + * + * ECOMP and OpenECOMP are trademarks + * and service marks of AT&T Intellectual Property. + */ + +import keyMirror from 'utils/KeyMirror.js'; + +export const autoCompleteSearchBarActionTypes = keyMirror({ + SUGGESTION_FOUND: null, + SUGGESTION_CHANGED: null, + SUGGESTION_NOT_FOUND: null, + CLEAR_SUGGESTIONS_TEXT_FIELD: null, + CLEAR_SUGGESTIONS: null +}); + +export const NO_MATCHES_FOUND = 'No Matches Found'; +export const SEARCH_PLACEHOLDER_TEXT = 'Search Network'; +export const ERROR_INVALID_SEARCH_TERMS = 'Invalid search terms'; +export const SEARCH_DEBOUNCE_TIME = 300; + +export const ICON_CLASS_SEARCH = 'fa fa-search fa-lg'; +export const ICON_CLASS_CLEAR = 'fa fa-times fa-lg'; |