react-use#useDebounce JavaScript Examples

The following examples show how to use react-use#useDebounce. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: useCalculation.js    From Turnip-Calculator with MIT License 6 votes vote down vote up
useCalculation = ({ filters, immediate = false }) => {
  const [state, setState] = useState(null);
  const [quantileRange] = useContext(QuantileContext);

  useDebounce(
    () => {
      if (filters) {
        calculate({ filters, quantileRange })
          .then(setState)
          .catch(() => setState(null));
      } else {
        setState(null);
      }
    },
    immediate ? 0 : 500,
    [filters, quantileRange]
  );

  const { minMaxPattern, minWeekValue, patterns, quantiles } = state || {};

  return useMemo(
    () => ({ minMaxPattern, minWeekValue, patterns, quantiles, filters }),
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [state]
  );
}
Example #2
Source File: resources.js    From covid19Nepal-react with MIT License 4 votes vote down vote up
function Resources(props) {
  const [data, setData] = useState([]);
  const [partData, setPartData] = useState([]);
  const [ogData, setOgData] = useState([]);
  const [fetched, setFetched] = useState(false);
  const [city, setCity] = useState('all');
  const [category, setCategory] = useState('all');
  const [nepalstate, setNepalState] = useState('all');
  const [resourcedict, setResourceDict] = useState({});
  const [showTable, setShowTable] = useState(false);
  const [isDesktop, setIsDesktop] = useState(false);
  const [hasScrolled, setHasScrolled] = useState(false);
  const [anchorEl, setAnchorEl] = React.useState(null);
  const [searchValue, setSearchValue] = useState('');

  useEffect(() => {
    if (fetched === false) {
      getResources();
    }
  }, [fetched, data, resourcedict]);

  const checkForResizeEvent = useCallback((event) => {
    if (window.innerWidth > 639) setIsDesktop(true);
    else setIsDesktop(false);
  }, []);

  useEffect(() => {
    if (window.innerWidth > 639) setIsDesktop(true);
    else setIsDesktop(false);
    window.addEventListener('resize', checkForResizeEvent);
    return () => {
      window.removeEventListener('resize', checkForResizeEvent);
    };
  }, [isDesktop, checkForResizeEvent]);

  const checkScrollEvent = useCallback((event) => {
    window.pageYOffset > 100 ? setHasScrolled(true) : setHasScrolled(false);
  }, []);

  useEffect(() => {
    window.pageYOffset > 100 ? setHasScrolled(true) : setHasScrolled(false);
    window.addEventListener('scroll', checkScrollEvent);
    return () => {
      window.removeEventListener('scroll', checkScrollEvent);
    };
  }, [hasScrolled, checkScrollEvent]);

  const getResources = async () => {
    try {
      const [response] = await Promise.all([
        axios.get('https://api.nepalcovid19.org/resources/resources.json'),
      ]);
      // setData(response.data.resources);
      const hashmap = {};
      response.data.resources.forEach((x) => {
        if (typeof hashmap[x['state']] === 'undefined')
          hashmap[x['state']] = {};
        if (typeof hashmap[x['state']][x['city']] === 'undefined')
          hashmap[x['state']][x['city']] = {};
        if (
          typeof hashmap[x['state']][x['city']][x['category']] === 'undefined'
        )
          hashmap[x['state']][x['city']][x['category']] = [];
        if (Array.isArray(hashmap[x['state']][x['city']][x['category']]))
          hashmap[x['state']][x['city']][x['category']].push(x);
      });

      setResourceDict(hashmap);

      setFetched(true);
    } catch (err) {}
  };

  const handleDisclaimerClick = (event) => {
    setAnchorEl(event.currentTarget);
  };

  const handleDisclaimerClose = () => {
    setAnchorEl(null);
  };

  const isDisclaimerOpen = Boolean(anchorEl);
  const id = isDisclaimerOpen ? 'simple-popover' : undefined;

  function animateScroll() {
    document.body.scrollTo({top: 0, behavior: 'smooth'}); // For Safari
    document.documentElement.scrollTo({top: 0, behavior: 'smooth'}); // For Chrome, Firefox, IE and Opera
  }

  const memocols = React.useMemo(
    () => [
      {
        Header: 'City',
        accessor: 'city',
      },
      {
        Header: 'Category',
        accessor: 'category',
      },
      {
        Header: 'Organisation',
        accessor: 'nameoftheorganisation',
      },
      {
        Header: 'Description',
        accessor: 'descriptionandorserviceprovided',
      },
      {
        Header: 'Phone',
        accessor: 'phonenumber',
      },
      {
        Header: 'Source',
        accessor: 'contact',
        isVisible: false,
      },
    ],
    []
  );
  // const memodata = React.useMemo(() => data, [data])

  const getCityOptions = function () {
    if (nepalstate) {
      if (nepalstate === 'all') return [];
      else {
        return Object.keys(resourcedict[nepalstate])
          .sort()
          .map((x, i) => (
            <option
              key={i}
              value={x}
              style={{
                fontFamily: 'archia',
                fontSize: '11px !important',
                fontWeight: 600,
                textTransform: 'uppercase',
              }}
            >
              {x}
            </option>
          ));
      }
    } else return [];
    // return getCityList().map((x) => <option value={x}>{x}</option>)
  };
  const getnepalstateOptions = function () {
    // let defaultOption = ['Please select']
    return Object.keys(resourcedict)
      .sort()
      .map((x, i) => (
        <option
          key={i}
          value={x}
          style={{
            fontFamily: 'archia',
            fontSize: '11px !important',
            fontWeight: 600,
            textTransform: 'uppercase',
          }}
        >
          {x}
        </option>
      ));
  };
  const getCategoryOptions = function () {
    if (nepalstate && city) {
      if (nepalstate === 'all') {
        const array = [];
        Object.values(resourcedict).forEach((state) => {
          Object.values(state).forEach((citydata) => {
            Object.keys(citydata).forEach((x) => {
              if (array.indexOf(x) === -1) array.push(x);
            });
          });
        });
        return array.sort().map((x, i) => (
          <option
            key={i}
            value={x}
            style={{
              fontFamily: 'archia',
              fontSize: '11px !important',
              fontWeight: 600,
              textTransform: 'uppercase',
            }}
          >
            {x}
          </option>
        ));
      } else {
        if (city === 'all') {
          const array = [];
          Object.values(resourcedict[nepalstate]).forEach((citydata) => {
            Object.keys(citydata).forEach((x) => {
              if (array.indexOf(x) === -1) array.push(x);
            });
          });
          return array.sort().map((x, i) => (
            <option
              key={i}
              value={x}
              style={{
                fontFamily: 'archia',
                fontSize: '11px !important',
                fontWeight: 600,
                textTransform: 'uppercase',
              }}
            >
              {x}
            </option>
          ));
        } else {
          return Object.keys(resourcedict[nepalstate][city])
            .sort()
            .map((x, i) => (
              <option
                key={i}
                value={x}
                style={{
                  fontFamily: 'archia',
                  fontSize: '11px !important',
                  fontWeight: 600,
                  textTransform: 'uppercase',
                }}
              >
                {x}
              </option>
            ));
        }
      }
    } else return [];
  };

  const filterTable = function () {
    let a = [];
    if (category === 'all') {
      if (city === 'all') {
        if (nepalstate === 'all') {
          Object.values(resourcedict).forEach((state) => {
            Object.values(state).forEach((citydata) => {
              Object.values(citydata).forEach((category) => {
                category.forEach((x) => a.push(x));
              });
            });
          });
        } else {
          Object.values(resourcedict[nepalstate]).forEach((citydata) => {
            Object.values(citydata).forEach((category) => {
              category.forEach((x) => a.push(x));
            });
          });
        }
      } else {
        Object.values(resourcedict[nepalstate][city]).forEach((x) => {
          x.forEach((y) => a.push(y));
        });
      }
    } else {
      if (nepalstate === 'all' && city === 'all') {
        Object.values(resourcedict).forEach((state) => {
          Object.values(state).forEach((citydata) => {
            Object.values(citydata).forEach((categorydata) => {
              categorydata.forEach((x) => {
                if (x.category === category) a.push(x);
              });
            });
          });
        });
      } else if (nepalstate !== 'all' && city === 'all') {
        Object.values(resourcedict[nepalstate]).forEach((citydata) => {
          if (category in citydata) {
            citydata[category].forEach((x) => {
              a.push(x);
            });
          }
        });
      } else {
        a = resourcedict[nepalstate][city][category];
      }
    }
    try {
      if ('PAN Nepal' in resourcedict) {
        resourcedict['PAN Nepal']['Multiple']['CoVID-19 Testing Lab'].forEach(
          (element) => {
            a.push(element);
          }
        );
      }
    } catch (err) {}
    setData(a);
    setOgData(a);
    setPartData(a.slice(0, 30));
    setShowTable(true);
    try {
      document.getElementById('input-field-searchbar').value = '';
    } catch {}
    setSearchValue('');
  };

  const changeNepalState = function (changedstateevent) {
    setNepalState(changedstateevent.target.value);
    // setCity(
    //   Object.keys(resourcedict[changedstateevent.target.value]).sort()[0]
    // );
    if (changedstateevent.target.value === '') {
      setCity('');
      document.getElementById('cityselect1').selectedIndex = 0;
      setCategory('');
      document.getElementById('categoryselect').selectedIndex = 0;
    } else {
      setCity('all');
      document.getElementById('cityselect1').selectedIndex = 1;
      setCategory('all');
      document.getElementById('categoryselect').selectedIndex = 1;
    }
  };
  const changeCity = function (changedcityevent) {
    setCity(changedcityevent.target.value);
    setCategory('all');
    document.getElementById('categoryselect').selectedIndex = 1;
  };
  const changeCategory = function (changedcategoryevent) {
    setCategory(changedcategoryevent.target.value);
  };
  const appendData = function () {
    const tempArr = partData.concat(
      data.slice(partData.length, partData.length + 30)
    );
    setPartData(tempArr);
  };

  const openSharingLink = function (message) {
    const shareUri = `https://www.addtoany.com/share#url=${encodeURI(
      'https://www.nepalcovid19.org/essentials'
    )}&title=${encodeURI(message)}`;

    const h = 500;
    const w = 500;
    const left = window.screen.width / 2 - w / 2;
    const top = window.screen.height / 2 - h / 2;
    return window.open(
      shareUri,

      document.title,
      'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width=' +
        w +
        ', height=' +
        h +
        ', top=' +
        top +
        ', left=' +
        left
    );
  };

  const openSharingTray = function () {
    const message =
      'Discover nearest coronavirus support and essential service providers such as testing lab centres, accommodation shelters and vegetable vendors at ';
    if (navigator.share !== undefined) {
      navigator
        .share({
          title: document.title,
          text: message,
          url: 'https://www.nepalcovid19.org/essentials',
        })
        .then()
        .catch((error) => {});
    } else {
      openSharingLink(message);
    }
  };

  useDebounce(
    () => {
      const newData = getSuggestions(searchValue, ogData);
      setData(newData);
      setPartData(newData.slice(0, 30));
    },
    300,
    [searchValue, ogData]
  );

  return (
    <div className="Resources" id="top-elem">
      <Helmet>
        <title>Essentials - nepalcovid19.org</title>
        <meta name="title" content="Essentials - nepalcovid19.org" />
      </Helmet>

      <div className="filtersection">
        <div className="filtertitle">
          <h3>Service Before Self</h3>
        </div>
        {!isDesktop && (
          <FiltersMobile
            handleDisclaimerClick={handleDisclaimerClick}
            popoverid={id}
            isDisclaimerOpen={isDisclaimerOpen}
            anchorEl={anchorEl}
            handleDisclaimerClose={handleDisclaimerClose}
            nepalstate={nepalstate}
            changeNepalState={changeNepalState}
            stateoptions={getnepalstateOptions()}
            city={city}
            changeCity={changeCity}
            cityoptions={getCityOptions()}
            category={category}
            changeCategory={changeCategory}
            servicesoptions={getCategoryOptions()}
            filterTable={filterTable}
            openSharingTray={openSharingTray}
          />
        )}
        {isDesktop && (
          <FiltersDesktop
            handleDisclaimerClick={handleDisclaimerClick}
            popoverid={id}
            isDisclaimerOpen={isDisclaimerOpen}
            anchorEl={anchorEl}
            handleDisclaimerClose={handleDisclaimerClose}
            nepalstate={nepalstate}
            changeNepalState={changeNepalState}
            stateoptions={getnepalstateOptions()}
            city={city}
            changeCity={changeCity}
            cityoptions={getCityOptions()}
            category={category}
            changeCategory={changeCategory}
            servicesoptions={getCategoryOptions()}
            filterTable={filterTable}
            openSharingTray={openSharingTray}
          />
        )}
      </div>
      {showTable && (
        <React.Fragment>
          <div className="searchbar">
            <TextField
              id="input-field-searchbar"
              label="Search keyword"
              fullWidth={true}
              InputLabelProps={{
                shrink: true,
              }}
              style={{
                width: '100%',
              }}
              variant="outlined"
              InputProps={{
                startAdornment: (
                  <InputAdornment position="start">
                    <Icon.Search size="0.9em" />
                  </InputAdornment>
                ),
              }}
              onChange={(event) => {
                setInterval(setSearchValue(event.target.value));
              }}
            />
          </div>
          <ResourceTable
            columns={memocols}
            data={partData}
            totalCount={data.length}
            isDesktop={isDesktop}
            onScrollUpdate={appendData}
            searchValue={searchValue}
          />
          <div>
            <Fade in={hasScrolled}>
              <Fab
                color="inherit"
                aria-label="gototop"
                id="gototopbtn"
                onClick={animateScroll}
                size="small"
                style={{
                  position: 'fixed',
                  bottom: '1rem',
                  right: '1rem',
                  zIndex: '1000',
                }}
              >
                <Icon.Navigation2 strokeWidth="2.5" color="#4c75f2" />
              </Fab>
            </Fade>
          </div>
        </React.Fragment>
      )}
    </div>
  );
}
Example #3
Source File: search.js    From covid19Nepal-react with MIT License 4 votes vote down vote up
function Search({districtZones}) {
  const [searchValue, setSearchValue] = useState('');
  const [expand, setExpand] = useState(false);
  const [results, setResults] = useState([]);
  const searchInput = useRef(null);
  const {t} = useTranslation();

  const handleSearch = useCallback((searchInput) => {
    const results = [];

    const sync = (datums) => {
      datums.map((result, index) => {
        const stateObj = {
          name: result.name,
          type: 'state',
          route: result.code,
        };
        results.push(stateObj);
        return null;
      });
    };

    const districtSync = (datums) => {
      datums.slice(0, 3).map((result, index) => {
        const districtObj = {
          name: result.district,
          type: 'district',
          route: STATE_CODES_REVERSE[result.state],
        };
        results.push(districtObj);
        return null;
      });
    };

    const essentialsSync = (datums) => {
      datums.slice(0, 5).map((result, index) => {
        const essentialsObj = {
          name: result.nameoftheorganisation,
          type: 'essentials',
          category: result.category,
          website: result.contact,
          description: result.descriptionandorserviceprovided,
          city: result.city,
          state: result.state,
          contact: result.phonenumber,
        };
        results.push(essentialsObj);
        return null;
      });
      setResults([...results]);
    };

    engine.search(searchInput, sync);
    districtEngine.search(searchInput, districtSync);
    essentialsEngine.search(searchInput, essentialsSync);
  }, []);

  useDebounce(
    () => {
      if (searchValue) {
        handleSearch(searchValue);
      } else {
        setResults([]);
      }
    },
    100,
    [searchValue]
  );

  function setNativeValue(element, value) {
    const valueSetter = Object.getOwnPropertyDescriptor(element, 'value').set;
    const prototype = Object.getPrototypeOf(element);
    const prototypeValueSetter = Object.getOwnPropertyDescriptor(
      prototype,
      'value'
    ).set;

    if (valueSetter && valueSetter !== prototypeValueSetter) {
      prototypeValueSetter.call(element, value);
    } else {
      valueSetter.call(element, value);
    }
  }

  function fillPlaceholder(target, index, cursorPosition, callback) {
    if (focused) {
      target.textContent = '';
      return true;
    }
    const text = suggestions[index];
    const placeholder = target.textContent;
    target.classList.remove('disappear');
    target.textContent = placeholder + text[cursorPosition];
    if (cursorPosition < text.length - 1) {
      setTimeout(function () {
        fillPlaceholder(target, index, cursorPosition + 1, callback);
      }, 200);
      return true;
    }
    callback();
  }

  function clearPlaceholder(target, callback) {
    const placeholder = target.textContent;
    target.classList.add('disappear');
    if (placeholder.length > 0) {
      setTimeout(function () {
        target.textContent = '';
        clearPlaceholder(target, callback);
      }, 1000);
      return true;
    }
    callback();
  }

  function loopThroughSuggestions(target, index) {
    if (focused) {
      target.textContent = '';
      return true;
    }
    fillPlaceholder(target, index, 0, function () {
      setTimeout(function () {
        clearPlaceholder(target, function () {
          loopThroughSuggestions(target, (index + 1) % suggestions.length);
        });
      }, 2000);
    });
  }

  const targetInput = document.getElementById('search-placeholder');
  if (targetInput) loopThroughSuggestions(targetInput, 0);

  return (
    <div className="Search">
      <label>{t('Search your district, resources, etc')}</label>
      <div className="line"></div>

      <input
        type="text"
        value={searchValue}
        ref={searchInput}
        onFocus={(event) => {
          focused = true;
          setExpand(true);
        }}
        onBlur={() => {
          setExpand(false);
        }}
        onChange={(event) => {
          setSearchValue(event.target.value);
        }}
      />
      <span id="search-placeholder" className="search-placeholder"></span>

      <div className={`search-button`}>
        <Icon.Search />
      </div>

      {searchValue.length > 0 && (
        <div
          className={`close-button`}
          onClick={() => {
            setSearchValue('');
            setResults([]);
          }}
        >
          <Icon.X />
        </div>
      )}

      {results.length > 0 && (
        <div className="results">
          {results.map((result, index) => {
            if (result.type === 'state' || result.type === 'district') {
              return (
                <Link key={index} to={`state/${result.route}`}>
                  <div className="result">
                    <div className="result-left">
                      <div className="result-name">
                        {`${result.name}`}
                        {result.type === 'district' &&
                          `, ${STATE_CODES[result.route]}`}
                      </div>
                      <div
                        className={classnames('result-zone', {
                          [`is-${districtZones[STATE_CODES[result.route]][
                            result.name
                          ]?.zone.toLowerCase()}`]: true,
                        })}
                      ></div>
                    </div>
                    <div className="result-type">
                      <span>{[result.route]}</span>
                      <Icon.ArrowRightCircle size={14} />
                    </div>
                  </div>
                </Link>
              );
            } else {
              return (
                <a
                  key={index}
                  href={result.website}
                  target="_noblank"
                  className="essential-result"
                >
                  <div className="result-top">
                    <div className="result-top-left">
                      <div className="result-name">{result.name}</div>
                      <div className="result-location">
                        {result.city}, {result.state}
                      </div>
                    </div>
                    <div className="result-category">
                      <div>
                        {result.category.match('Testing')
                          ? 'Covid19-Testing Labs'
                          : result.category}
                      </div>
                      <Icon.ExternalLink />
                    </div>
                  </div>
                  <div className="result-description">{result.description}</div>
                  <div className="result-contact">
                    <Icon.Phone />
                    <div>{result.contact}</div>
                  </div>
                </a>
              );
            }
          })}
        </div>
      )}

      {expand && (
        <div className="expanded">
          <div className="expanded-left">
            <h3>{t('Essentials')}</h3>
            <div className="suggestions">
              <div className="suggestion">
                <div>-</div>
                <h4
                  onMouseDown={(event) => {
                    event.preventDefault();
                    setNativeValue(searchInput.current, 'Covid19-Testing Labs');
                    searchInput.current.dispatchEvent(
                      new Event('input', {bubbles: true})
                    );
                  }}
                >
                  {t('Covid19-Testing Labs')}
                </h4>
              </div>
              <div className="suggestion">
                <div>-</div>
                <h4
                  onMouseDown={(event) => {
                    event.preventDefault();
                    setNativeValue(searchInput.current, 'Quarantine Center');
                    searchInput.current.dispatchEvent(
                      new Event('input', {bubbles: true})
                    );
                  }}
                >
                  {t('Quarantine Center')}
                </h4>
              </div>
              <div className="suggestion">
                <div>-</div>
                <h4
                  onMouseDown={(event) => {
                    event.preventDefault();
                    setNativeValue(searchInput.current, 'Health Facility');
                    searchInput.current.dispatchEvent(
                      new Event('input', {bubbles: true})
                    );
                  }}
                >
                  {t('Health Facility')}
                </h4>
              </div>
              <div className="suggestion">
                <div>-</div>
                <h4
                  onMouseDown={(event) => {
                    event.preventDefault();
                    setNativeValue(searchInput.current, 'Medical College');
                    searchInput.current.dispatchEvent(
                      new Event('input', {bubbles: true})
                    );
                  }}
                >
                  {t('Medical College')}
                </h4>
              </div>
              <div className="suggestion">
                <div>-</div>
                <h4
                  onMouseDown={(event) => {
                    event.preventDefault();
                    setNativeValue(
                      searchInput.current,
                      ' District Level Hospital'
                    );
                    searchInput.current.dispatchEvent(
                      new Event('input', {bubbles: true})
                    );
                  }}
                >
                  {t(' District Level Hospital')}
                </h4>
              </div>
            </div>
          </div>
          <div className="expanded-right">
            <h3>{t('Locations')}</h3>
            <div className="suggestions">
              <div className="suggestion">
                <div>-</div>
                <h4
                  onMouseDown={(event) => {
                    event.preventDefault();
                    setNativeValue(searchInput.current, 'Kathmandu');
                    searchInput.current.dispatchEvent(
                      new Event('input', {bubbles: true})
                    );
                  }}
                >
                  {t('Kathmandu')}
                </h4>
              </div>
              <div className="suggestion">
                <div>-</div>
                <h4
                  onMouseDown={(event) => {
                    event.preventDefault();
                    setNativeValue(searchInput.current, 'Rautahat');
                    searchInput.current.dispatchEvent(
                      new Event('input', {bubbles: true})
                    );
                  }}
                >
                  {t('Rautahat')}
                </h4>
              </div>
              <div className="suggestion">
                <div>-</div>
                <h4
                  onMouseDown={(event) => {
                    event.preventDefault();
                    setNativeValue(searchInput.current, 'Chitwan');
                    searchInput.current.dispatchEvent(
                      new Event('input', {bubbles: true})
                    );
                  }}
                >
                  {t('Chitwan')}
                </h4>
              </div>
              <div className="suggestion">
                <div>-</div>
                <h4
                  onMouseDown={(event) => {
                    event.preventDefault();
                    setNativeValue(searchInput.current, 'Baglung');
                    searchInput.current.dispatchEvent(
                      new Event('input', {bubbles: true})
                    );
                  }}
                >
                  {t('Baglung')}
                </h4>
              </div>
              <div className="suggestion">
                <div>-</div>
                <h4
                  onMouseDown={(event) => {
                    event.preventDefault();
                    setNativeValue(searchInput.current, 'Udayapur');
                    searchInput.current.dispatchEvent(
                      new Event('input', {bubbles: true})
                    );
                  }}
                >
                  {t('Udayapur')}
                </h4>
              </div>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
Example #4
Source File: Search.js    From covid19india-react with MIT License 4 votes vote down vote up
function Search() {
  const [searchValue, setSearchValue] = useState('');
  const [expand, setExpand] = useState(false);
  const [results, setResults] = useState([]);
  const searchInput = useRef(null);
  const {t} = useTranslation();

  const [engine, setEngine] = useState(null);
  const [districtEngine, setDistrictEngine] = useState(null);

  useUpdateEffect(() => {
    import('corejs-typeahead').then((Bloodhound) => {
      setEngine(
        // eslint-disable-next-line
        new Bloodhound.default({
          initialize: true,
          local: STATE_CODES_ARRAY.filter(
            ({code}) => code !== UNASSIGNED_STATE_CODE
          ),
          queryTokenizer: Bloodhound.default.tokenizers.whitespace,
          datumTokenizer: Bloodhound.default.tokenizers.obj.whitespace('name'),
        })
      );

      setDistrictEngine(
        // eslint-disable-next-line
        new Bloodhound.default({
          initialize: true,
          limit: 5,
          queryTokenizer: Bloodhound.default.tokenizers.whitespace,
          datumTokenizer:
            Bloodhound.default.tokenizers.obj.whitespace('district'),
          indexRemote: true,
          remote: {
            url: `${API_DOMAIN}/state_district_wise.json`,
            transform: function (response) {
              const districts = [];
              Object.keys(response)
                .filter((stateName) => stateName !== 'State Unassigned')
                .map((stateName) => {
                  const districtData = response[stateName].districtData;
                  Object.keys(districtData)
                    .filter(
                      (districtName) => districtName !== UNKNOWN_DISTRICT_KEY
                    )
                    .map((districtName) => {
                      return districts.push({
                        district: districtName,
                        state: stateName,
                      });
                    });
                  return null;
                });
              return districts;
            },
          },
        })
      );
    });
  }, [expand]);

  const handleSearch = useCallback(
    (searchInput) => {
      if (!engine) return null;
      const results = [];

      const sync = (datums) => {
        datums.map((result, index) => {
          const stateObj = {
            name: result.name,
            type: 'state',
            route: result.code,
          };
          results.push(stateObj);
          return null;
        });
      };

      const districtSync = (datums) => {
        datums.slice(0, 3).map((result, index) => {
          const districtObj = {
            name: result.district,
            type: 'district',
            route: STATE_CODES[result.state],
          };
          results.push(districtObj);
          return null;
        });

        setResults([...results]);
      };

      engine.search(searchInput, sync);
      districtEngine.search(searchInput, districtSync);
    },
    [districtEngine, engine]
  );

  useDebounce(
    () => {
      if (searchValue) {
        handleSearch(searchValue);
      } else {
        setResults(
          produce(results, (draftResults) => {
            draftResults.splice(0);
          })
        );
      }
    },
    100,
    [searchValue]
  );

  function setNativeValue(element, value) {
    const valueSetter = Object.getOwnPropertyDescriptor(element, 'value').set;
    const prototype = Object.getPrototypeOf(element);
    const prototypeValueSetter = Object.getOwnPropertyDescriptor(
      prototype,
      'value'
    ).set;

    if (valueSetter && valueSetter !== prototypeValueSetter) {
      prototypeValueSetter.call(element, value);
    } else {
      valueSetter.call(element, value);
    }
  }

  const fillPlaceholder = useCallback(
    (target, index, cursorPosition, callback) => {
      if (expand) {
        target.textContent = '';
        return true;
      }
      const text = t(suggestions[index]);
      const placeholder = target.textContent;
      target.classList.remove('disappear');
      target.textContent = placeholder + text[cursorPosition];
      if (cursorPosition < text.length - 1) {
        setTimeout(function () {
          fillPlaceholder(target, index, cursorPosition + 1, callback);
        }, 200);
        return true;
      }
      callback();
    },
    [expand, t]
  );

  const clearPlaceholder = useCallback((target, callback) => {
    const placeholder = target.textContent;
    target.classList.add('disappear');
    if (placeholder.length > 0) {
      setTimeout(function () {
        target.textContent = '';
        clearPlaceholder(target, callback);
      }, 1000);
      return true;
    }
    callback();
  }, []);

  const loopThroughSuggestions = useCallback(
    (target, index) => {
      if (expand) {
        target.textContent = '';
        return true;
      }

      fillPlaceholder(target, index, 0, function () {
        setTimeout(function () {
          clearPlaceholder(target, function () {
            loopThroughSuggestions(target, (index + 1) % suggestions.length);
          });
        }, 2000);
      });
    },
    [clearPlaceholder, expand, fillPlaceholder]
  );

  useEffect(() => {
    if (!expand) {
      const targetInput =
        document.getElementsByClassName('search-placeholder')[0];

      if (targetInput) {
        loopThroughSuggestions(targetInput, 0);
      }
    }
  }, [expand, loopThroughSuggestions]);

  const trail = useMemo(() => {
    const styles = [];

    [0, 0, 0].map((element, index) => {
      styles.push({
        animationDelay: `${index * 250}ms`,
      });
      return null;
    });
    return styles;
  }, []);

  const handleClose = useCallback(() => {
    setSearchValue('');
    setResults([]);
  }, []);

  const handleChange = useCallback((event) => {
    setSearchValue(event.target.value);
  }, []);

  useKeyPressEvent('/', () => {
    searchInput.current.focus();
  });

  useKeyPressEvent('Escape', () => {
    handleClose();
    searchInput.current.blur();
  });

  return (
    <div className="Search">
      <label className="fadeInUp" style={trail[0]}>
        {t('Search your district or state')}
      </label>
      <div className="line fadeInUp" style={trail[1]}></div>

      <div className="search-input-wrapper fadeInUp" style={trail[2]}>
        <input
          type="text"
          value={searchValue}
          ref={searchInput}
          onFocus={setExpand.bind(this, true)}
          onBlur={setExpand.bind(this, false)}
          onChange={handleChange}
        />

        {!expand && searchValue === '' && (
          <span className="search-placeholder"></span>
        )}

        <div className={`search-button`}>
          <Icon.Search />
        </div>

        {searchValue.length > 0 && (
          <div className={`close-button`} onClick={handleClose}>
            <Icon.X />
          </div>
        )}
      </div>

      {results.length > 0 && (
        <div className="results">
          {results.map((result, index) => (
            <Link key={index} to={`state/${result.route}`}>
              <div className="result">
                <div className="result-left">
                  <div className="result-name">
                    {`${result.name}`}
                    {result.type === 'district' &&
                      `, ${STATE_NAMES[result.route]}`}
                  </div>
                </div>
                <div className="result-type">
                  <span>{[result.route]}</span>
                  <Icon.ArrowRightCircle size={14} />
                </div>
              </div>
            </Link>
          ))}
        </div>
      )}

      {expand && (
        <>
          <div className="expanded">
            <div className="expanded-left">
              <h3>{t('District')}</h3>
              <div className="suggestions">
                {districtSuggestions.map((suggestion, index) => (
                  <div className="suggestion" key={index}>
                    <div>-</div>
                    <h4
                      onMouseDown={(event) => {
                        event.preventDefault();
                        setNativeValue(searchInput.current, suggestion);
                        searchInput.current.dispatchEvent(
                          new Event('input', {bubbles: true})
                        );
                      }}
                    >
                      {t(suggestion)}
                    </h4>
                  </div>
                ))}
              </div>
            </div>

            <div className="expanded-right">
              <h3>{t('State/UT')}</h3>
              <div className="suggestions">
                {stateSuggestions.map((suggestion, index) => (
                  <div className="suggestion" key={index}>
                    <div>-</div>
                    <h4
                      onMouseDown={(event) => {
                        event.preventDefault();
                        setNativeValue(searchInput.current, suggestion);
                        searchInput.current.dispatchEvent(
                          new Event('input', {bubbles: true})
                        );
                      }}
                    >
                      {t(suggestion)}
                    </h4>
                  </div>
                ))}
              </div>
            </div>
          </div>
        </>
      )}
    </div>
  );
}
Example #5
Source File: index.jsx    From erp-crm with MIT License 4 votes vote down vote up
export default function AutoCompleteAsync({
  entity,
  displayLabels,
  searchFields,
  outputValue = '_id',
  value, /// this is for update
  onChange, /// this is for update
}) {
  const [selectOptions, setOptions] = useState([]);
  const [currentValue, setCurrentValue] = useState(undefined);

  const isUpdating = useRef(true);
  const isSearching = useRef(false);

  const [searching, setSearching] = useState(false);

  const [valToSearch, setValToSearch] = useState('');
  const [debouncedValue, setDebouncedValue] = useState('');

  const [, cancel] = useDebounce(
    () => {
      //  setState("Typing stopped");
      setDebouncedValue(valToSearch);
    },
    500,
    [valToSearch]
  );

  const asyncSearch = (options) => {
    return request.search({ entity, options });
  };

  let { onFetch, result, isSuccess, isLoading } = useOnFetch();

  const labels = (optionField) => {
    return displayLabels.map((x) => optionField[x]).join(' ');
  };

  useEffect(() => {
    if (debouncedValue != '') {
      const options = {
        q: debouncedValue,
        fields: searchFields,
      };
      onFetch(() => asyncSearch(options));
    }

    return () => {
      cancel();
    };
  }, [debouncedValue]);

  const onSearch = (searchText) => {
    if (searchText && searchText != '') {
      isSearching.current = true;
      setSearching(true);
      setOptions([]);
      setCurrentValue(undefined);
      setValToSearch(searchText);
    }
  };

  useEffect(() => {
    if (isSearching.current) {
      if (isSuccess) {
        setOptions(result);
      } else {
        setSearching(false);
        setCurrentValue(undefined);
        setOptions([]);
      }
    }
  }, [isSuccess, result]);
  useEffect(() => {
    // this for update Form , it's for setField
    if (value && isUpdating.current) {
      if (!isSearching.current) {
        setOptions([value]);
      }
      setCurrentValue(value[outputValue] || value); // set nested value or value
      onChange(value[outputValue] || value);
      isUpdating.current = false;
    }
  }, [value]);

  return (
    <Select
      loading={isLoading}
      showSearch
      allowClear
      placeholder={'Search Here'}
      defaultActiveFirstOption={false}
      showArrow={false}
      filterOption={false}
      notFoundContent={searching ? '... Searching' : 'Not Found'}
      value={currentValue}
      onSearch={onSearch}
      onChange={(newValue) => {
        if (onChange) {
          onChange(newValue[outputValue] || newValue);
        }
      }}
    >
      {selectOptions.map((optionField) => (
        <Select.Option
          key={optionField[outputValue] || optionField}
          value={optionField[outputValue] || optionField}
        >
          {labels(optionField)}
        </Select.Option>
      ))}
    </Select>
  );
}
Example #6
Source File: index.jsx    From erp-crm with MIT License 4 votes vote down vote up
function SearchItemComponent({ config, onRerender }) {
  let { entity, searchConfig } = config;

  const { displayLabels, searchFields, outputValue = '_id' } = searchConfig;

  const dispatch = useDispatch();
  const { crudContextAction } = useCrudContext();
  const { panel, collapsedBox, readBox } = crudContextAction;
  const { result, isLoading, isSuccess } = useSelector(selectSearchedItems);

  const [selectOptions, setOptions] = useState([]);
  const [currentValue, setCurrentValue] = useState(undefined);

  const isSearching = useRef(false);

  const [searching, setSearching] = useState(false);

  const [valToSearch, setValToSearch] = useState('');
  const [debouncedValue, setDebouncedValue] = useState('');

  const [, cancel] = useDebounce(
    () => {
      setDebouncedValue(valToSearch);
    },
    500,
    [valToSearch]
  );

  const labels = (optionField) => {
    return displayLabels.map((x) => optionField[x]).join(' ');
  };

  useEffect(() => {
    if (debouncedValue != '') {
      const options = {
        q: debouncedValue,
        fields: searchFields,
      };
      dispatch(crud.search({ entity, options }));
    }
    return () => {
      cancel();
    };
  }, [debouncedValue]);

  const onSearch = (searchText) => {
    if (searchText && searchText != '') {
      isSearching.current = true;
      setSearching(true);
      setOptions([]);
      setCurrentValue(undefined);
      setValToSearch(searchText);
    }
  };

  const onSelect = (data) => {
    const currentItem = result.find((item) => {
      return item[outputValue] === data;
    });

    dispatch(crud.currentItem({ data: currentItem }));

    panel.open();
    collapsedBox.open();
    readBox.open();
    onRerender();
  };
  useEffect(() => {
    if (isSearching.current) {
      if (isSuccess) {
        setOptions(result);
      } else {
        setSearching(false);
        setCurrentValue(undefined);
        setOptions([]);
      }
    }
  }, [isSuccess, result]);

  return (
    <Select
      loading={isLoading}
      showSearch
      allowClear
      placeholder={<SearchOutlined style={{ float: 'right', padding: '8px 0' }} />}
      defaultActiveFirstOption={false}
      showArrow={false}
      filterOption={false}
      notFoundContent={searching ? '... Searching' : <Empty />}
      value={currentValue}
      onSearch={onSearch}
      style={{ width: '100%' }}
      onSelect={onSelect}
    >
      {selectOptions.map((optionField) => (
        <Select.Option key={optionField[outputValue]} value={optionField[outputValue]}>
          {labels(optionField)}
        </Select.Option>
      ))}
    </Select>
  );
}