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 {
text-transform: capitalize;
color: var(--button-desktop-text-color);
text-decoration: var(--button-text-decoration);
color: var(--button-desktop-text-color, revert);
text-decoration: var(--button-text-decoration, revert);
}
.button:hover {
color: var(--button-desktop-text-color-hover);
color: var(--button-desktop-text-color-hover, revert);
cursor: pointer;
}
@@ -22,23 +22,23 @@
margin: 0px 5px;
padding: 1px;
outline: none;
border: 1px solid #AAA;
border: var(--post-form-field-input-border, revert);
font-size: 11px;
}
.searchContainer input:focus {
border: var(--post-form-field-input-focus-border);
border: var(--post-form-field-input-focus-border, revert);
}
.closeSearch {
cursor: pointer;
border: none;
white-space: nowrap;
color: var(--button-desktop-text-color);
color: var(--button-desktop-text-color, revert);
}
.closeSearch:hover {
color: var(--button-desktop-text-color-hover);
color: var(--button-desktop-text-color-hover, revert);
}
@media (max-width: 640px) {
@@ -1,5 +1,6 @@
import { useEffect, useState, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation, useNavigate } from 'react-router-dom';
import styles from './catalog-search.module.css';
import useIsMobile from '../../hooks/use-is-mobile';
import useCatalogFiltersStore from '../../stores/use-catalog-filters-store';
@@ -7,21 +8,52 @@ import _ from 'lodash';
const CatalogSearch = () => {
const { t } = useTranslation();
const location = useLocation();
const navigate = useNavigate();
const [openSearch, setOpenSearch] = useState(false);
const [inputValue, setInputValue] = useState('');
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
const debouncedSetSearchFilter = useCallback(
_.debounce((text: string) => {
if (text.trim()) {
setSearchFilter(text);
updateURL(text);
} else {
clearSearchFilter();
updateURL('');
}
}, 300),
[setSearchFilter, clearSearchFilter],
[setSearchFilter, clearSearchFilter, updateURL],
);
const handleToggleSearch = useCallback(() => {
@@ -30,14 +62,16 @@ const CatalogSearch = () => {
if (openSearch) {
setInputValue('');
clearSearchFilter();
updateURL('');
}
}, [openSearch, clearSearchFilter]);
}, [openSearch, clearSearchFilter, updateURL]);
const handleCloseSearch = useCallback(() => {
setOpenSearch(false);
setInputValue('');
clearSearchFilter();
}, [clearSearchFilter]);
updateURL('');
}, [clearSearchFilter, updateURL]);
useEffect(() => {
if (openSearch) {