"use client"; import type { ChangeEvent } from "react"; import { useCallback, useEffect, useState } from "react"; import { usePathname, useRouter, useSearchParams } from "next/navigation"; import { Loader, TextInput } from "@mantine/core"; import { useDebouncedCallback } from "@mantine/hooks"; import { IconSearch } from "@tabler/icons-react"; interface SearchInputProps { defaultValue?: string; placeholder: string; ariaLabel: string; flexExpand?: boolean; } export const SearchInput = ({ placeholder, ariaLabel, defaultValue, flexExpand = false }: SearchInputProps) => { // eslint-disable-next-line @typescript-eslint/unbound-method const { replace } = useRouter(); const pathName = usePathname(); const searchParams = useSearchParams(); const [loading, setLoading] = useState(false); const [value, setValue] = useState(defaultValue ?? ""); useEffect(() => { setValue(defaultValue ?? ""); setLoading(false); }, [defaultValue]); const handleSearchDebounced = useDebouncedCallback((value: string) => { const params = new URLSearchParams(searchParams); const normalizedValue = value.trim(); if (normalizedValue.length === 0) { params.delete("search"); } else { params.set("search", normalizedValue); } if (params.has("page")) params.set("page", "1"); // Reset page to 1 const query = params.toString(); replace(query ? `${pathName}?${query}` : pathName); setLoading(false); }, 250); const handleSearch = useCallback( (event: ChangeEvent) => { setValue(event.currentTarget.value); setLoading(true); handleSearchDebounced(event.currentTarget.value); }, [setLoading, handleSearchDebounced], ); return ( } value={value} onChange={handleSearch} placeholder={placeholder} aria-label={ariaLabel} style={{ flex: flexExpand ? "1" : undefined }} /> ); }; interface LeftSectionProps { loading: boolean; } const LeftSection = ({ loading }: LeftSectionProps) => { if (loading) { return ; } return ; };