diff --git a/src/components/Drawer.tsx b/src/components/Drawer.tsx index 1484047..ec4281d 100644 --- a/src/components/Drawer.tsx +++ b/src/components/Drawer.tsx @@ -2,8 +2,10 @@ import { useRef, useState, + useCallback, useEffect, type ReactElement, + use, } from "react"; import { @@ -207,6 +209,58 @@ export function MultiSelect({ ); } +function debounce( + func: (...param: T[]) => void, + timeout = 3000 +) { + let timer: number; + + return (...args: T[]) => { + window.clearTimeout(timer); + timer = window.setTimeout(func, timeout, ...args); + }; +} + +const TextFieldDebounced: React.FC<{ + debounceMs?: number; + onChange: (p: string) => void; + value: string; +}> = ({debounceMs = 300, onChange, value = ""}) => { + const debouncedChangeHandler = useCallback( + debounce(onChange, debounceMs), + [] + ); + + const handleChange = ({ + target, + }: React.ChangeEvent) => { + debouncedChangeHandler(target.value); + }; + + return ( + + ); +}; + +const useDebounce = (value: string, delay = 500) => { + const [debouncedValue, setDebouncedValue] = useState(""); + const timerRef = useRef(); + + useEffect(() => { + timerRef.current = setTimeout( + () => setDebouncedValue(value), + delay + ); + + return () => { + if (timerRef.current !== null) + clearTimeout(timerRef.current); + }; + }, [value, delay]); + + return debouncedValue; +}; + export function SearchBox() { const [openSearch, setOpenSearch] = useState(false); const {search, setSearch} = useStore((state) => ({ @@ -214,6 +268,12 @@ export function SearchBox() { setSearch: state.setSearch, })); + const [text, setText] = useState(search); + const debouncedSearch = useDebounce(text, 300); + useEffect(() => { + setSearch(debouncedSearch); + }, [debouncedSearch]); + return ( { - setSearch(event.target.value); + setText(event.target.value); }} /> diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 513ff10..bb59daf 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -60,14 +60,21 @@ const tabs = { }; export default function Header() { - const {open, setOpen, activeStatsTab, user, guest} = - useStore((state) => ({ - open: state.drawerOpen, - setOpen: state.toggleDrawer, - activeStatsTab: state.activeStatsTab, - user: state.user, - guest: state.guest, - })); + const { + open, + setOpen, + activeStatsTab, + user, + guest, + loading, + } = useStore((state) => ({ + open: state.drawerOpen, + setOpen: state.toggleDrawer, + activeStatsTab: state.activeStatsTab, + user: state.user, + guest: state.guest, + loading: state.loading, + })); const pathname = usePathname(); const parts = pathname.split("/"); const valueKey = parts.length > 1 ? `/${parts[1]}` : ""; @@ -161,7 +168,7 @@ export default function Header() { )}{" "} - {!user && !guest && } + {!user && !guest && !loading && } ); diff --git a/src/components/MainContainer.tsx b/src/components/MainContainer.tsx index c924128..d4df8f9 100644 --- a/src/components/MainContainer.tsx +++ b/src/components/MainContainer.tsx @@ -21,6 +21,7 @@ export default function MainContainer({ toggleUserSettings, setUser, setGuest, + setLoading, } = useStore((state) => ({ loadFromDB: state.loadFromDB, updateFilters: state.updateFilters, @@ -29,6 +30,7 @@ export default function MainContainer({ loadPhotos: state.loadPhotos, setUser: state.setUser, setGuest: state.setGuest, + setLoading: state.setLoading, })); const searchParams = useSearchParams(); @@ -63,6 +65,8 @@ export default function MainContainer({ load(activities) .then(console.log) .catch(console.error); + } else { + setLoading(false); } async function load(activities?: number[]) { diff --git a/src/contexts/Filter.ts b/src/contexts/Filter.ts index df10be5..313bed2 100644 --- a/src/contexts/Filter.ts +++ b/src/contexts/Filter.ts @@ -133,6 +133,9 @@ export const filterSlice: StateCreator< state.search && !row.name .toLowerCase() + .includes(state.search.toLowerCase()) && + !row.description + ?.toLowerCase() .includes(state.search.toLowerCase()) ) { return false;