From 11cb35d0acd816b1335468d1c504938b7b946dcf Mon Sep 17 00:00:00 2001 From: Corey Sotiropoulos Date: Mon, 13 May 2024 04:14:20 -0400 Subject: [PATCH] Improve shadows in search box and fix url param parsing SearchServers component useEffect wasn't getting an updated location.search value, so give it the same treatment as Header and keep state of initial load. --- client/src/components/Header/Header.tsx | 7 +- .../src/components/Header/SearchServers.tsx | 82 ++++++++++--------- client/src/pages/Home.tsx | 61 +++++++------- 3 files changed, 82 insertions(+), 68 deletions(-) diff --git a/client/src/components/Header/Header.tsx b/client/src/components/Header/Header.tsx index 199ebdf..2f0e00d 100644 --- a/client/src/components/Header/Header.tsx +++ b/client/src/components/Header/Header.tsx @@ -38,7 +38,7 @@ export default function Header({ const { progress, setProgress, showAlert } = useLoadingContext(); const [showSearchServer, setShowSearchServer] = useState(false); const [filtersApplied, setFiltersApplied] = useState(false); - const [initialFetch, setInitialFetch] = useState(false); + const [initialFetch, setInitialFetch] = useState(true); const toggleShowSearchServer = () => { setShowSearchServer((prev) => !prev); }; @@ -69,9 +69,10 @@ export default function Header({ }, [showAlert, setServers, setProgress]); useEffect(() => { - if (!initialFetch) { + // TODO: Check if there's a better way to do this than "initialFetch" state, see also SearchServers + if (initialFetch) { fetchServerData(); - setInitialFetch(true); + setInitialFetch(false); } setFiltersApplied( JSON.stringify(searchState) !== JSON.stringify(SearchStateDefaults) diff --git a/client/src/components/Header/SearchServers.tsx b/client/src/components/Header/SearchServers.tsx index 1be7eee..8eb2684 100644 --- a/client/src/components/Header/SearchServers.tsx +++ b/client/src/components/Header/SearchServers.tsx @@ -22,6 +22,32 @@ type SearchServersProps = { setSearchState: React.Dispatch>; }; +function parseSearchParams(searchParams: string): SearchState { + const params = new URLSearchParams(searchParams); + const parsedState = { ...SearchStateDefaults }; + + const keys = Object.keys(SearchStateDefaults) as Array; + + keys.forEach((key) => { + if (params.has(key)) { + const value = params.get(key) as string; + const decodedValue = decodeURIComponent(value); + + if (key === 'maxLevel') { + const maxLevelArray = decodedValue.split(' ').map(Number); + parsedState[key] = + maxLevelArray.length === 1 ? [1, maxLevelArray[0]] : maxLevelArray; + } else if (key === 'expansionsEnabled') { + parsedState[key] = decodedValue.split(' ') as string[]; + } else { + parsedState[key] = decodedValue; + } + } + }); + + return parsedState as SearchState; +} + export default function SearchServers({ showSearchServer, searchState, @@ -31,48 +57,33 @@ export default function SearchServers({ const location = useLocation(); const [initialPath] = useState(location.pathname); const [contentHeight, setContentHeight] = useState(0); - - function parseSearchParams(searchParams: string): SearchState { - const params = new URLSearchParams(searchParams); - const parsedState = SearchStateDefaults; - - const keys = Object.keys(SearchStateDefaults) as Array; - - keys.forEach((key) => { - if (params.has(key)) { - const value = params.get(key) as string; - const decodedValue = decodeURIComponent(value); - - if (key === 'maxLevel') { - const maxLevelArray = decodedValue.split(',').map(Number); - parsedState[key] = - maxLevelArray.length === 1 ? [1, maxLevelArray[0]] : maxLevelArray; - } else if (key === 'expansionsEnabled') { - parsedState[key] = decodedValue.split(',') as string[]; - } else { - parsedState[key] = decodedValue; - } - } - }); - - return parsedState as SearchState; - } + const [initialLoad, setInitialLoad] = useState(true); useEffect(() => { // Populate search state with URL params only if loading the home page // Home page manages updating URL params - if (initialPath === '/') { - const params = parseSearchParams(location.search); - if (params !== SearchStateDefaults) { - setSearchState(params); + // TODO: Check if there's a better way to do this than "initialLoad" state, see also Header + if (initialLoad) { + if (initialPath === '/') { + const params = parseSearchParams(location.search); + if (JSON.stringify(params) !== JSON.stringify(SearchStateDefaults)) { + setSearchState(params); + } } + setInitialLoad(false); } if (showSearchServer && containerRef.current) { setContentHeight(containerRef.current.scrollHeight); } else { setContentHeight(0); } - }, [showSearchServer, location.search, setSearchState, initialPath]); + }, [ + showSearchServer, + location.search, + setSearchState, + initialPath, + initialLoad, + ]); const handleChange = ( name: string, @@ -141,11 +152,11 @@ export default function SearchServers({ theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, .06)' : 'rgba(0, 0, 0, .06)', - boxShadow: 'inset 0em 3em 5em -5em black,inset 0em -3em 5em -6em black', + boxShadow: 'inset 0em 3em 5em -6em black,inset 0em -3em 5em -7em black', }} > - - + + {/* Name */} { - if (location.pathname === '/') { - window.history.replaceState({}, '', '/'); - } setSearchState(SearchStateDefaults); }} > diff --git a/client/src/pages/Home.tsx b/client/src/pages/Home.tsx index c440461..f229edd 100644 --- a/client/src/pages/Home.tsx +++ b/client/src/pages/Home.tsx @@ -6,37 +6,42 @@ import SettingsChipCloud from '../components/Server/SettingsChipCloud'; import { SearchState, SearchStateDefaults } from '../data/SearchState'; import { ServerData } from '../data/ServerData'; -export default function Home({ - servers, - searchState, -}: { +function serializeSearchState(search: SearchState): string { + const params = new URLSearchParams(); + + Object.entries(search).forEach(([key, value]) => { + if ( + value !== null && + value !== undefined && + !(key === 'name' && value === SearchStateDefaults.name) && + !( + key === 'maxLevel' && + JSON.stringify(value) === JSON.stringify(SearchStateDefaults.maxLevel) + ) + ) { + if (Array.isArray(value)) { + if (key === 'maxLevel') { + if (value[0] === value[1]) { + params.append(key, JSON.stringify(value[0])); + return; + } + } + params.append(key, value.join(' ')); + } else { + params.append(key, value); + } + } + }); + + return params.toString(); +} + +type HomeProps = { servers: ServerData[]; searchState: SearchState; -}) { - function serializeSearchState(search: SearchState): string { - const params = new URLSearchParams(); - - Object.entries(search).forEach(([key, value]) => { - if ( - value !== null && - value !== undefined && - !(key === 'name' && value === '') && - !( - key === 'maxLevel' && - JSON.stringify(value) === JSON.stringify(SearchStateDefaults.maxLevel) - ) - ) { - if (Array.isArray(value)) { - params.append(key, value.join(',')); - } else { - params.append(key, value); - } - } - }); - - return params.toString(); - } +}; +export default function Home({ servers, searchState }: HomeProps) { useEffect(() => { // Update URL params whenever search state changes const searchParams = serializeSearchState(searchState);