Feature/improve restoring grid snapshots (#713)
* Update local storage functions * Update local storage hooks * Add session storage * Improve storing virtuoso grid snapshot * Use "useSyncExternalStore" for browser storage access * Get rid of location replacements in "AppbarSearch" Use session storage instead to prevent reloading the page all the time due to changing the location * Get rid of location replacements in "SourceMangas" Use session storage instead to prevent reloading the page all the time due to changing the location
This commit is contained in:
@@ -11,35 +11,44 @@ import SearchIcon from '@mui/icons-material/Search';
|
||||
import { IconButton, Tooltip } from '@mui/material';
|
||||
import { useQueryParam, StringParam } from 'use-query-params';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { SearchTextField } from '@/components/atoms/SearchTextField.tsx';
|
||||
import { useSessionStorage } from '@/util/useStorage.tsx';
|
||||
|
||||
interface IProps {
|
||||
autoOpen?: boolean;
|
||||
isClosable?: boolean;
|
||||
}
|
||||
|
||||
const defaultProps = {
|
||||
autoOpen: false,
|
||||
};
|
||||
|
||||
export const AppbarSearch: React.FunctionComponent<IProps> = (props) => {
|
||||
const { autoOpen } = props;
|
||||
const { isClosable = true } = props;
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { pathname, search: locationSearch, state: fullLocationState } = useLocation<{ wasSearchOpen?: boolean }>();
|
||||
const { wasSearchOpen, ...locationState } = fullLocationState ?? {};
|
||||
|
||||
const navigate = useNavigate();
|
||||
const [prevLocationKey, setPrevLocationKey] = useState<string>();
|
||||
const location = useLocation();
|
||||
|
||||
const [query, setQuery] = useQueryParam('query', StringParam);
|
||||
const [searchOpen, setSearchOpen] = useState(!!query);
|
||||
const [isSearchOpen, setIsSearchOpen] = useState(!isClosable || !!query);
|
||||
const inputRef = React.useRef<HTMLInputElement>();
|
||||
|
||||
const [searchString, setSearchString] = useState(query ?? '');
|
||||
|
||||
const [locationQuery, setLocationQuery] = useSessionStorage<string | null>(`appbarsearch-location-${location.key}`);
|
||||
if (prevLocationKey !== location.key) {
|
||||
setPrevLocationKey(location.key);
|
||||
setLocationQuery(query);
|
||||
setSearchString(locationQuery ?? '');
|
||||
setIsSearchOpen(!isClosable || !!locationQuery);
|
||||
}
|
||||
|
||||
const isOpen = isSearchOpen || !!locationQuery;
|
||||
|
||||
const updateSearchOpenState = (open: boolean) => {
|
||||
setSearchOpen(open);
|
||||
if (!isClosable) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSearchOpen(open);
|
||||
|
||||
// try to focus input component since in case of navigating to the previous/next page in the browser history
|
||||
// the "openSearch" state might not change and thus, won't trigger a focus
|
||||
@@ -54,6 +63,7 @@ export const AppbarSearch: React.FunctionComponent<IProps> = (props) => {
|
||||
}
|
||||
|
||||
setQuery(newQuery);
|
||||
updateSearchOpenState(false);
|
||||
}
|
||||
|
||||
const cancelSearch = () => {
|
||||
@@ -72,46 +82,6 @@ export const AppbarSearch: React.FunctionComponent<IProps> = (props) => {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if ((autoOpen && wasSearchOpen === undefined) || (wasSearchOpen && query)) {
|
||||
updateSearchOpenState(true);
|
||||
return;
|
||||
}
|
||||
|
||||
updateSearchOpenState(false);
|
||||
}, [autoOpen, pathname]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!searchOpen || !inputRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
inputRef.current.focus();
|
||||
}, [searchOpen, inputRef.current]);
|
||||
|
||||
useEffect(() => {
|
||||
if (wasSearchOpen === searchOpen) {
|
||||
return;
|
||||
}
|
||||
|
||||
navigate(
|
||||
{ pathname, search: locationSearch },
|
||||
{ replace: true, state: { ...locationState, wasSearchOpen: searchOpen } },
|
||||
);
|
||||
}, [searchOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
if (query === undefined && searchString !== undefined) {
|
||||
setSearchString('');
|
||||
return;
|
||||
}
|
||||
|
||||
if (query && searchString !== query) {
|
||||
setSearchString(query);
|
||||
updateSearchOpenState(true);
|
||||
}
|
||||
}, [query]);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('keydown', handleKeyboardEvent);
|
||||
|
||||
@@ -120,9 +90,10 @@ export const AppbarSearch: React.FunctionComponent<IProps> = (props) => {
|
||||
};
|
||||
}, [handleKeyboardEvent]);
|
||||
|
||||
if (searchOpen) {
|
||||
if (isOpen) {
|
||||
return (
|
||||
<SearchTextField
|
||||
autoFocus
|
||||
variant="standard"
|
||||
value={searchString}
|
||||
onCancel={cancelSearch}
|
||||
@@ -146,5 +117,3 @@ export const AppbarSearch: React.FunctionComponent<IProps> = (props) => {
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
AppbarSearch.defaultProps = defaultProps;
|
||||
|
||||
Reference in New Issue
Block a user