UNPKG

charity-base-search

Version:

React component for CharityBase search input

203 lines (185 loc) 6.15 kB
import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import debounce from 'lodash.debounce'; import FilterSuggest, { HelperText, Input, TextField } from 'filter-suggest'; import svgSearch from './search.svg'; var DEBOUNCE_TIME = 100; var applyDebounced = debounce(function (f, x) { return f(x); }, DEBOUNCE_TIME); var QUERY = '\n query CBS_SEARCH_FILTERS(\n $search: String!\n $filterType: [String]\n ) {\n CHC {\n getFilters(\n search: $search\n filterType: $filterType\n ) {\n id\n value\n label\n filterType\n score\n }\n }\n }\n'; var getData = function getData(apiUrl, apiKey, variables) { return fetch(apiUrl + '?query=' + QUERY + '&variables=' + JSON.stringify(variables), { headers: { Authorization: 'Apikey ' + apiKey } }).then(function (x) { return x.json(); }); }; var getSearchItem = function getSearchItem(inputValue) { return { id: 'search-' + inputValue, value: inputValue, label: inputValue, filterType: 'search' }; }; var errorMessage = function errorMessage(_ref) { var error = _ref.error, empty = _ref.empty, loading = _ref.loading, searchTerm = _ref.searchTerm; if (error) { return 'Oops something went wrong, please try again'; } if (empty && searchTerm.length > 1 && !loading) { return 'Sorry we can\'t find anything matching \'' + searchTerm + '\''; } return null; }; var CharityBaseSearch = function CharityBaseSearch(_ref2) { var apiKey = _ref2.apiKey, apiUrl = _ref2.apiUrl, className = _ref2.className, filterTypes = _ref2.filterTypes, hideAcknowledgement = _ref2.hideAcknowledgement, label = _ref2.label, mapItem = _ref2.mapItem, menuClassName = _ref2.menuClassName, onBlur = _ref2.onBlur, onFocus = _ref2.onFocus, _onSelect = _ref2.onSelect, outlined = _ref2.outlined, style = _ref2.style, textFieldClassName = _ref2.textFieldClassName; var _useState = useState(''), inputValue = _useState[0], setInputValue = _useState[1]; var _useState2 = useState(''), debouncedInputValue = _useState2[0], setDebouncedInputValue = _useState2[1]; var _useState3 = useState(null), data = _useState3[0], setData = _useState3[1]; var _useState4 = useState(null), error = _useState4[0], setError = _useState4[1]; var _useState5 = useState(false), loading = _useState5[0], setLoading = _useState5[1]; var onInputValueChange = function onInputValueChange(x) { var value = x || ''; setInputValue(value); applyDebounced(setDebouncedInputValue, value.trim()); }; useEffect(function () { var ignore = false; if (debouncedInputValue) { var variables = { search: debouncedInputValue, filterType: filterTypes }; setLoading(true); getData(apiUrl, apiKey, variables).then(function (_ref3) { var data = _ref3.data, errors = _ref3.errors; if (ignore) return; if (errors) { // setData(null) return setError(errors[0].message); // graphql error } setError(null); setData(data); }).catch(function (error) { if (ignore) return; // setData(null) setError(error && error.message || 'Unknown error'); // probably network error }).then(function () { if (ignore) return; setLoading(false); }); } else { setError(null); setData(null); } return function () { ignore = true; }; }, [apiUrl, apiKey, debouncedInputValue, JSON.stringify(filterTypes)]); var syncItems = [getSearchItem(inputValue)].reduce(function (agg, x) { return filterTypes && filterTypes.indexOf(x.filterType) === -1 ? agg : [].concat(agg, [x]); }, []); var filterItems = data && data.CHC ? [].concat(syncItems, data.CHC.getFilters) : []; return React.createElement( 'div', { className: className, style: style }, hideAcknowledgement ? null : React.createElement( 'a', { className: 'cbs-acknowledgement', href: 'https://charitybase.uk', target: '_blank', rel: 'noopener noreferrer' }, 'Powered by CharityBase' ), React.createElement(FilterSuggest, { errorMessage: errorMessage({ error: error, loading: loading, empty: filterItems.length === 0, searchTerm: debouncedInputValue }), inputValue: inputValue, items: filterItems.map(mapItem), label: label, leadingIcon: React.createElement('img', { width: 24, height: 24, src: svgSearch }), loading: loading, menuClassName: menuClassName, onBlur: onBlur, onFocus: onFocus, onInputValueChange: onInputValueChange, onSelect: function onSelect(item) { onInputValueChange(''); _onSelect(item); }, outlined: outlined, textFieldClassName: textFieldClassName }) ); }; CharityBaseSearch.propTypes = process.env.NODE_ENV !== "production" ? { apiKey: PropTypes.string.isRequired, apiUrl: PropTypes.string, className: PropTypes.string, filterTypes: PropTypes.array, hideAcknowledgement: PropTypes.bool, label: PropTypes.string, mapItem: PropTypes.func, menuClassName: PropTypes.string, onBlur: PropTypes.func, onFocus: PropTypes.func, onSelect: PropTypes.func.isRequired, outlined: PropTypes.bool, style: PropTypes.object, textFieldClassName: PropTypes.string } : {}; CharityBaseSearch.defaultProps = { apiUrl: 'https://charitybase.uk/api/graphql', label: 'Search charities', mapItem: function mapItem(_ref4) { var id = _ref4.id, filterType = _ref4.filterType, value = _ref4.value, label = _ref4.label; return { // __typename ? id: id, filterType: filterType, value: value, label: label, icon: null, primary: label, secondary: 'Filter by ' + filterType }; } }; export default CharityBaseSearch; export { HelperText, Input, TextField };