From 124d03f8c164f324cd86dba2127fd6d782d1e2ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Fri, 30 Oct 2026 15:35:41 +0100 Subject: [PATCH] Search and or and not --- client/homebrew/pages/vaultPage/vaultPage.jsx | 222 ++++++++++++------ .../homebrew/pages/vaultPage/vaultPage.less | 41 ++-- server/vault.api.js | 42 +++- 3 files changed, 207 insertions(+), 98 deletions(-) diff --git a/client/homebrew/pages/vaultPage/vaultPage.jsx b/client/homebrew/pages/vaultPage/vaultPage.jsx index 328348893..bfb20bd77 100644 --- a/client/homebrew/pages/vaultPage/vaultPage.jsx +++ b/client/homebrew/pages/vaultPage/vaultPage.jsx @@ -45,7 +45,12 @@ const VaultPage = (props)=>{ const v3Ref = useRef(null); const legacyRef = useRef(null); const submitButtonRef = useRef(null); - const [tagsList, setTagList] = useState(props.query.tags.split(',') || []); + + const parseTags = (value)=>value?.split(',').filter(Boolean) || []; + + const [tagsListAnd, setTagListAnd] = useState(parseTags(props.query.tagsAnd)); + const [tagsListOr, setTagListOr] = useState(parseTags(props.query.tagsOr)); + const [tagsListNot, setTagListNot] = useState(parseTags(props.query.tagsNot)); useEffect(()=>{ disableSubmitIfFormInvalid(); @@ -65,54 +70,88 @@ const VaultPage = (props)=>{ setSearching(false); }; - const updateUrl = (titleValue, authorValue, countValue, v3Value, legacyValue, tagsValue, page, sort, dir)=>{ + + const buildQueryParams = (entries)=>{ + const params = new URLSearchParams(); + + entries.forEach(([key, value])=>{ + if(value === undefined || value === null || value === '') return; + if(Array.isArray(value) && value.length === 0) return; + + params.set(key, Array.isArray(value) ? value.join(',') : value); + }); + + return params.toString(); + }; + + + const updateUrl = (params)=>{ const url = new URL(window.location.href); - const urlParams = new URLSearchParams(url.search); - urlParams.set('title', titleValue); - urlParams.set('author', authorValue); - urlParams.set('count', countValue); - urlParams.set('v3', v3Value); - urlParams.set('legacy', legacyValue); - urlParams.set('tags', tagsValue); - urlParams.set('page', page); - urlParams.set('sort', sort); - urlParams.set('dir', dir); + url.search = params; - - console.log(urlParams.toString()); - url.search = urlParams.toString(); window.history.replaceState(null, '', url.toString()); }; - const performSearch = async (title, author, count, v3, legacy, tags, page, sort, dir)=>{ - updateUrl(title, author, count, v3, legacy, tags, page, sort, dir); - const response = await request - .get(`/api/vault?title=${title}&author=${author}&v3=${v3}&legacy=${legacy}&tags=${tags}&count=${count}&page=${page}&sort=${sort}&dir=${dir}`) - .catch((error)=>{ - console.log('error at loadPage: ', error); - setError(error); - updateStateWithBrews([], 1); - }); + const performSearch = async (formContents, page, sort, dir)=>{ + const { title, author, count, v3, legacy, tagsAnd, tagsOr, tagsNot } = formContents; - if(response?.ok) + + const params = buildQueryParams([ + ['title', title], + ['author', author], + ['v3', v3], + ['legacy', legacy], + ['tagsAnd', tagsAnd], + ['tagsOr', tagsOr], + ['tagsNot', tagsNot], + ['count', count], + ['page', page], + ['sort', sort], + ['dir', dir] + ]); + + updateUrl(params); + + const response = await request.get(`/api/vault?${params}`) + .catch((error)=>{ + console.log('error at loadPage: ', error); + setError(error); + updateStateWithBrews([], 1); + }); + + if(response?.ok) { updateStateWithBrews(response.body.brews, page); + } }; - const loadTotal = async (title, author, v3, legacy, tags)=>{ + const loadTotal = async (formContents)=>{ + const { title, author, count, v3, legacy, tagsAnd, tagsOr, tagsNot } = formContents; + setTotalBrews(null); - const response = await request.get(`/api/vault/total?title=${title}&author=${author}&v3=${v3}&legacy=${legacy}&tags=${tags}`) - .catch((error)=>{ - console.log('error at loadTotal: '); - console.error(error); - setError(error); - updateStateWithBrews([], 1); - }); + const params = buildQueryParams([ + ['title', title], + ['author', author], + ['v3', v3], + ['legacy', legacy], + ['tagsAnd', tagsAnd], + ['tagsOr', tagsOr], + ['tagsNot', tagsNot] + ]); - if(response.ok) + const response = await request.get(`/api/vault/total?${params}`) + .catch((error)=>{ + console.log('error at loadTotal: '); + console.error(error); + setError(error); + updateStateWithBrews([], 1); + }); + + if(response?.ok) { setTotalBrews(response.body.totalBrews); + } }; const loadPage = async (page, updateTotal, sort, dir)=>{ @@ -126,7 +165,14 @@ const VaultPage = (props)=>{ const count = countRef.current.value || 20; const v3 = v3Ref.current.checked != false; const legacy = legacyRef.current.checked != false; - const tags = tagsList; + const tagsAnd = tagsListAnd; + const tagsOr = tagsListOr; + const tagsNot = tagsListNot; + + const formContents = { + title, author, count, v3, legacy, tagsAnd, tagsOr, tagsNot + }; + const sortOption = sort || 'title'; const dirOption = dir || 'asc'; const pageProp = page || 1; @@ -134,10 +180,10 @@ const VaultPage = (props)=>{ setSort(sortOption); setdir(dirOption); - performSearch(title, author, count, v3, legacy, tags, pageProp, sortOption, dirOption); + performSearch(formContents, pageProp, sortOption, dirOption); if(updateTotal) - loadTotal(title, author, v3, legacy, tags); + loadTotal(formContents); }; const renderNavItems = ()=>( @@ -161,8 +207,9 @@ const VaultPage = (props)=>{ const isTitleValid = titleRef.current.validity.valid && titleRef.current.value; const isAuthorValid = authorRef.current.validity.valid && authorRef.current.value; const isCheckboxChecked = legacyRef.current.checked || v3Ref.current.checked; + const isTagsValid = tagsListAnd.length >= 1 || tagsListOr.length >= 1; - const isFormValid = (isTitleValid || isAuthorValid) && isCheckboxChecked; + const isFormValid = (isTitleValid || isAuthorValid || isTagsValid) && isCheckboxChecked; return isFormValid; }; @@ -173,7 +220,7 @@ const VaultPage = (props)=>{ const renderForm = ()=>(
-

Brew Lookup

+

Brew Lookup

- +

Tag Search

+
+ + + + + +
-

Tips and tricks

+

Tips and tricks

  • Only published brews are searchable via this tool @@ -332,8 +410,8 @@ const VaultPage = (props)=>{
    View: