From 42e2742881e640a4f4cd0355a0f461bb558ddb15 Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Wed, 4 Oct 2023 14:42:21 -0400 Subject: [PATCH] feat: add deeplinked search --- src/components/form/SearchInput.js | 23 ++++++++++++-- src/components/hooks/useQueryParamState.js | 37 ++++++++++++++++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 src/components/hooks/useQueryParamState.js diff --git a/src/components/form/SearchInput.js b/src/components/form/SearchInput.js index 7f094ec5..3e4f8874 100644 --- a/src/components/form/SearchInput.js +++ b/src/components/form/SearchInput.js @@ -1,8 +1,9 @@ import _ from 'lodash'; -import React from 'react'; +import React, { useRef, useEffect } from 'react'; import { useIntl } from 'react-intl'; import { useSelector } from 'react-redux'; import styled, { withTheme } from 'styled-components'; +import { useQueryParamState } from '../hooks/useQueryParamState'; import { MagnifyGlassIcon, MagnifyGlassIconWhite } from '../icons'; @@ -89,7 +90,10 @@ const ButtonSearchText = styled('p')` align-items: center; font-size: 1rem; width: 3.125rem; - color: ${props => (props.usePrimaryButton ? props.theme.colors.default.onButton : props.theme.colors.default.onSurface)}; + color: ${props => + props.usePrimaryButton + ? props.theme.colors.default.onButton + : props.theme.colors.default.onSurface}; box-sizing: border-box; `; @@ -104,11 +108,23 @@ const SearchInput = withTheme( disabled = false, }) => { const intl = useIntl(); + const ref = useRef(); const appStore = useSelector(state => state.app); + const [searchQuery] = useQueryParamState('search'); + + useEffect(() => { + onChange({ + target: { + value: searchQuery, + }, + }); + ref.current.value = searchQuery; + }, [searchQuery]); return ( + disabled={disabled} + > {(buttonText && ( {buttonText} diff --git a/src/components/hooks/useQueryParamState.js b/src/components/hooks/useQueryParamState.js new file mode 100644 index 00000000..131b9448 --- /dev/null +++ b/src/components/hooks/useQueryParamState.js @@ -0,0 +1,37 @@ +import _ from 'lodash'; +import { useState, useCallback, useMemo } from 'react'; +import { useLocation } from 'react-router-dom'; + +const useQueryParamState = (name, defaultValue) => { + const [param, setParam] = useState(); + const location = useLocation(); + + const setQueryStringParameter = useCallback( + value => { + const [base, hashFragment] = window.location.hash.split('?'); + let params = new URLSearchParams(hashFragment); + + if (_.isNil(value) || value === '') { + params.delete(name); + } else { + params.set(name, value); + } + + const newHash = params.toString() ? `${base}?${params}` : base; + + window.location.hash = decodeURIComponent(newHash); + setParam(value); + }, + [name], + ); + + const value = useMemo(() => { + const [, hashFragment] = window.location.hash.split('?'); + const params = new URLSearchParams(hashFragment); + return params.get(name) || defaultValue || ''; + }, [location, param, name]); + + return [value, setQueryStringParameter]; +}; + +export { useQueryParamState };