fix(catalog search): use query parameter so users can share searches and link to them

This commit is contained in:
Tom (plebeius.eth)
2025-06-04 16:36:40 +02:00
parent 53e04823df
commit 6075b2ebf7
2 changed files with 45 additions and 11 deletions
@@ -1,11 +1,11 @@
.button { .button {
text-transform: capitalize; text-transform: capitalize;
color: var(--button-desktop-text-color); color: var(--button-desktop-text-color, revert);
text-decoration: var(--button-text-decoration); text-decoration: var(--button-text-decoration, revert);
} }
.button:hover { .button:hover {
color: var(--button-desktop-text-color-hover); color: var(--button-desktop-text-color-hover, revert);
cursor: pointer; cursor: pointer;
} }
@@ -22,23 +22,23 @@
margin: 0px 5px; margin: 0px 5px;
padding: 1px; padding: 1px;
outline: none; outline: none;
border: 1px solid #AAA; border: var(--post-form-field-input-border, revert);
font-size: 11px; font-size: 11px;
} }
.searchContainer input:focus { .searchContainer input:focus {
border: var(--post-form-field-input-focus-border); border: var(--post-form-field-input-focus-border, revert);
} }
.closeSearch { .closeSearch {
cursor: pointer; cursor: pointer;
border: none; border: none;
white-space: nowrap; white-space: nowrap;
color: var(--button-desktop-text-color); color: var(--button-desktop-text-color, revert);
} }
.closeSearch:hover { .closeSearch:hover {
color: var(--button-desktop-text-color-hover); color: var(--button-desktop-text-color-hover, revert);
} }
@media (max-width: 640px) { @media (max-width: 640px) {
@@ -1,5 +1,6 @@
import { useEffect, useState, useCallback } from 'react'; import { useEffect, useState, useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useLocation, useNavigate } from 'react-router-dom';
import styles from './catalog-search.module.css'; import styles from './catalog-search.module.css';
import useIsMobile from '../../hooks/use-is-mobile'; import useIsMobile from '../../hooks/use-is-mobile';
import useCatalogFiltersStore from '../../stores/use-catalog-filters-store'; import useCatalogFiltersStore from '../../stores/use-catalog-filters-store';
@@ -7,21 +8,52 @@ import _ from 'lodash';
const CatalogSearch = () => { const CatalogSearch = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const location = useLocation();
const navigate = useNavigate();
const [openSearch, setOpenSearch] = useState(false); const [openSearch, setOpenSearch] = useState(false);
const [inputValue, setInputValue] = useState(''); const [inputValue, setInputValue] = useState('');
const { setSearchFilter, clearSearchFilter } = useCatalogFiltersStore(); const { setSearchFilter, clearSearchFilter } = useCatalogFiltersStore();
// Create a debounced version of setSearchFilter // Extract query parameter from URL
useEffect(() => {
const urlParams = new URLSearchParams(location.search);
const queryParam = urlParams.get('q');
if (queryParam) {
setInputValue(queryParam);
setSearchFilter(queryParam);
setOpenSearch(true);
}
}, [location.search, setSearchFilter]);
// Update URL when search changes
const updateURL = useCallback(
(searchText: string) => {
const urlParams = new URLSearchParams(location.search);
if (searchText.trim()) {
urlParams.set('q', searchText);
} else {
urlParams.delete('q');
}
const newSearch = urlParams.toString();
const newPath = location.pathname + (newSearch ? `?${newSearch}` : '');
navigate(newPath, { replace: true });
},
[location.pathname, location.search, navigate],
);
// Create a debounced version of setSearchFilter and URL update
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
const debouncedSetSearchFilter = useCallback( const debouncedSetSearchFilter = useCallback(
_.debounce((text: string) => { _.debounce((text: string) => {
if (text.trim()) { if (text.trim()) {
setSearchFilter(text); setSearchFilter(text);
updateURL(text);
} else { } else {
clearSearchFilter(); clearSearchFilter();
updateURL('');
} }
}, 300), }, 300),
[setSearchFilter, clearSearchFilter], [setSearchFilter, clearSearchFilter, updateURL],
); );
const handleToggleSearch = useCallback(() => { const handleToggleSearch = useCallback(() => {
@@ -30,14 +62,16 @@ const CatalogSearch = () => {
if (openSearch) { if (openSearch) {
setInputValue(''); setInputValue('');
clearSearchFilter(); clearSearchFilter();
updateURL('');
} }
}, [openSearch, clearSearchFilter]); }, [openSearch, clearSearchFilter, updateURL]);
const handleCloseSearch = useCallback(() => { const handleCloseSearch = useCallback(() => {
setOpenSearch(false); setOpenSearch(false);
setInputValue(''); setInputValue('');
clearSearchFilter(); clearSearchFilter();
}, [clearSearchFilter]); updateURL('');
}, [clearSearchFilter, updateURL]);
useEffect(() => { useEffect(() => {
if (openSearch) { if (openSearch) {