From dd13534a397f84bc073e6d57bfde2391f3f3d458 Mon Sep 17 00:00:00 2001 From: Roland Date: Sat, 25 May 2024 10:48:08 -0600 Subject: [PATCH] Modifying Dashboard search clear button to clear all search params. --- app/src/DashboardPage.js | 17 +++++++++++++---- app/src/Tags.js | 5 +++-- app/src/components/Common.js | 9 ++++++--- app/src/components/DatesSelector.js | 11 +++++++++++ app/src/components/Search.js | 6 +++++- app/src/contexts/contexts.js | 1 + app/src/hooks/customHooks.js | 5 ++++- 7 files changed, 43 insertions(+), 11 deletions(-) diff --git a/app/src/DashboardPage.js b/app/src/DashboardPage.js index 3c6ff534..d0a25616 100644 --- a/app/src/DashboardPage.js +++ b/app/src/DashboardPage.js @@ -1,6 +1,6 @@ import {LoadStatistic, PageContainer, SearchResultsInput, useTitle} from "./components/Common"; import React, {useContext, useState} from "react"; -import {Media, SettingsContext, StatusContext} from "./contexts/contexts"; +import {Media, QueryContext, SettingsContext, StatusContext} from "./contexts/contexts"; import {DownloadMenu} from "./components/Download"; import { Button, @@ -24,7 +24,7 @@ import {TagsDashboard} from "./Tags"; import {Upload} from "./components/Upload"; import {SearchView, useSearch, useSearchSuggestions} from "./components/Search"; import {KiwixRestartMessage, OutdatedZimsMessage} from "./components/Zim"; -import {useWROLMode} from "./hooks/customHooks"; +import {useSearchDate, useSearchFilter, useWROLMode} from "./hooks/customHooks"; import {FileSearchFilterButton} from "./components/Files"; import {DateSelectorButton} from "./components/DatesSelector"; @@ -161,7 +161,7 @@ export function DashboardPage() { const navigate = useNavigate(); // The search the user submitted. - const {searchStr, setSearchStr, activeTags} = useSearch(); + const {searchStr, setSearchStr, activeTags, isEmpty} = useSearch(); // The search that the user is typing. const [localSearchStr, setLocalSearchStr] = React.useState(searchStr); const { @@ -211,6 +211,14 @@ export function DashboardPage() { // User has submitted and wants full search. body = ; } + const {setFilter} = useSearchFilter(); + + const clearAllSearch = () => { + clearDate(); + setFilter(null); + setSearchStr(null); + navigate('/'); + } const getSearchResultsInput = (props) => { return navigate('/')} + onClear={clearAllSearch} + clearDisabled={isEmpty} style={{marginBottom: '2em'}} results={suggestionsResults} handleResultSelect={handleResultSelect} diff --git a/app/src/Tags.js b/app/src/Tags.js index 9259bfc1..cdee1491 100644 --- a/app/src/Tags.js +++ b/app/src/Tags.js @@ -16,7 +16,7 @@ import { import _ from "lodash"; import {HexColorPicker} from "react-colorful"; import {useRecurringTimeout} from "./hooks/customHooks"; -import {Media, ThemeContext} from "./contexts/contexts"; +import {Media, QueryContext, ThemeContext} from "./contexts/contexts"; import {Link, useNavigate} from "react-router-dom"; import {TagPlaceholder} from "./components/Placeholder"; import {SortableTable} from "./components/SortableTable"; @@ -38,6 +38,7 @@ const DEFAULT_TAG_COLOR = '#000000'; export function useTags() { const [tags, setTags] = React.useState(null); const [tagNames, setTagNames] = React.useState(null); + const {getLocationStr} = React.useContext(QueryContext); const fetchTags = async () => { try { @@ -104,7 +105,7 @@ export function useTags() { } const TagLabelLink = ({name, props}) => { - const to = `/search?tag=${encodeURIComponent(name)}`; + const to = getLocationStr({tag: name}, '/search'); const style = {marginLeft: '0.3em', marginRight: '0.3em'}; try { // We prefer to use Link to avoid reloading the page, check if React Router is available, so we can use it. diff --git a/app/src/components/Common.js b/app/src/components/Common.js index 15779498..320fb1e0 100644 --- a/app/src/components/Common.js +++ b/app/src/components/Common.js @@ -400,7 +400,7 @@ export function scrollToTopOfElement(element, smooth = true) { }); } -const useClearableInput = (searchStr, onChange, onClear, onSubmit, size = 'small', placeholder = 'Search...', icon = 'search') => { +const useClearableInput = (searchStr, onChange, onClear, onSubmit, size = 'small', placeholder = 'Search...', icon = 'search', clearDisabled = null) => { const [value, setValue] = useState(searchStr || ''); const [submitted, setSubmitted] = useState(false); @@ -459,7 +459,9 @@ const useClearableInput = (searchStr, onChange, onClear, onSubmit, size = 'small size={size} onClick={handleClearSearch} type='button' - disabled={!!!value} + // If `clearDisabled` is provided, use it to disable the clear button. Fallback to disabling if there is no + // search value. + disabled={clearDisabled !== null ? clearDisabled : !!!value} className='search-clear' />; @@ -508,6 +510,7 @@ export function SearchResultsInput({ action, actionIcon, clearable = false, + clearDisabled = null, autoFocus = false, results = undefined, handleResultSelect = null, @@ -521,7 +524,7 @@ export function SearchResultsInput({ clearButton, localOnSubmit, handleChange, - } = useClearableInput(searchStr, onChange, onClear, onSubmit, size, placeholder); + } = useClearableInput(searchStr, onChange, onClear, onSubmit, size, placeholder, icon, clearDisabled); // Show a "Loading" message rather than "No results" while results are pending. const loadingResults = {'loading': {name: 'Loading', results: [{title: 'Results are pending...'}]}}; diff --git a/app/src/components/DatesSelector.js b/app/src/components/DatesSelector.js index 0e7992be..aa13d135 100644 --- a/app/src/components/DatesSelector.js +++ b/app/src/components/DatesSelector.js @@ -170,6 +170,17 @@ export function DateSelectorButton({ } }, [JSON.stringify(dateRange), JSON.stringify(monthsSelected)]); + React.useEffect(() => { + if (!defaultMonthsSelected || (defaultMonthsSelected && defaultMonthsSelected.length === 0)) { + setMonthsSelected([]); + } + console.log(defaultDateRange); + if (!defaultDateRange || (defaultDateRange && defaultDateRange.length === 2 + && defaultDateRange[0] == null && defaultDateRange[1] === null)) { + setDateRange(emptyDateRange); + } + }, [JSON.stringify(defaultMonthsSelected), JSON.stringify(defaultDateRange)]); + const handleOpen = (e) => { if (e) e.preventDefault(); setOpen(true); diff --git a/app/src/components/Search.js b/app/src/components/Search.js index f53ce886..d63346eb 100644 --- a/app/src/components/Search.js +++ b/app/src/components/Search.js @@ -38,7 +38,7 @@ const SUGGESTED_APPS = [ export const useSearch = (defaultLimit = 48, totalPages = 0, emptySearch = false, model) => { const navigate = useNavigate(); - const {dateRange, setDateRange, months, setDates} = useSearchDate(); + const {dateRange, setDateRange, months, setDates, isEmpty: datesIsEmpty} = useSearchDate(); const {searchParams, updateQuery, getLocationStr} = React.useContext(QueryContext); // `searchStr` means actually fetch the files/zims. const searchStr = searchParams.get('q'); @@ -50,6 +50,9 @@ export const useSearch = (defaultLimit = 48, totalPages = 0, emptySearch = false // archive/video/ebook/etc. const model_ = searchParams.get('model') || model; + const anySearch = (!datesIsEmpty) || searchStr || (activeTags && activeTags.length > 0) || filter || model; + const isEmpty = !anySearch; + const setSearchStr = (value) => { const searchQuery = {q: value, o: 0}; if (filter) { @@ -90,6 +93,7 @@ export const useSearch = (defaultLimit = 48, totalPages = 0, emptySearch = false clearSearch, setTags, months, dateRange, setDateRange, setDates, + anySearch, isEmpty, } } diff --git a/app/src/contexts/contexts.js b/app/src/contexts/contexts.js index 75ddc6b5..70ca26b1 100644 --- a/app/src/contexts/contexts.js +++ b/app/src/contexts/contexts.js @@ -13,6 +13,7 @@ export const SettingsContext = React.createContext({ fetchSettings: null, }); +// `useQuery` export const QueryContext = React.createContext({ searchParams: null, setSearchParams: null, diff --git a/app/src/hooks/customHooks.js b/app/src/hooks/customHooks.js index 4fc3f7cb..5a4880d3 100644 --- a/app/src/hooks/customHooks.js +++ b/app/src/hooks/customHooks.js @@ -987,7 +987,10 @@ export const useSearchDate = () => { updateQuery({fromDate: newFromDate, toDate: newToDate, month: newMonths, 'o': 0}); } - return {dateRange: [fromDate, toDate], setDates, months, clearDate} + const anySearch = (months && months.length > 0) || (fromDate !== null || toDate !== null); + const isEmpty = !anySearch; + + return {dateRange: [fromDate, toDate], setDates, months, clearDate, isEmpty} } export const useUploadFile = () => {