summaryrefslogtreecommitdiffstats
path: root/src/generic-components/autoCompleteSearchBar
diff options
context:
space:
mode:
Diffstat (limited to 'src/generic-components/autoCompleteSearchBar')
-rw-r--r--src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBar.jsx211
-rw-r--r--src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBarConstants.js42
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';