Skip to content

Conversation

@cywlol
Copy link
Collaborator

@cywlol cywlol commented Feb 2, 2025

No description provided.

@cywlol cywlol linked an issue Feb 2, 2025 that may be closed by this pull request
@cywlol cywlol changed the title added search bar 19 feature create search-bar.tsx component Feb 2, 2025
@cywlol cywlol requested a review from ahmadgaz February 2, 2025 19:56
@cywlol cywlol changed the title 19 feature create search-bar.tsx component 21 feature create search-bar.tsx component Feb 2, 2025
Copy link
Collaborator

@ahmadgaz ahmadgaz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check comment


interface Props extends React.InputHTMLAttributes<HTMLInputElement> {
className?: string;
onSearch?: (query: string) => void;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't pass an onsearch function. The parent has to be a client component in order to be able to pass in event handlers.

Querys can be handled from the search bar by just modifying some url params. Inspect this component and try to mimic how it works:

'use client';

import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import React from 'react';
import { useDebouncedCallback } from 'use-debounce';

import { Spinner, TextInput } from '@/components/atoms';
import { cn } from '@/utils/cn';
import { MagnifyingGlassIcon } from '@heroicons/react/16/solid';

interface Props extends React.HTMLProps<HTMLSpanElement> {
  name?: string;
  param?: string;
  scrollTarget?: string;
  shouldResetPageOnChange?: boolean;
}

export const SearchBar: React.FC<Props> = ({
  name = 'query',
  param = 'query',
  scrollTarget,
  shouldResetPageOnChange = true,
  className,
  ...props
}) => {
  const searchParams = useSearchParams();
  const pathname = usePathname();
  const { replace } = useRouter();
  const debouncedReplace = useDebouncedCallback(replace, 500);

  const params = new URLSearchParams(searchParams);
  const currentParam = params.get(param);
  const [pendingParam, setPendingParam] = React.useState(currentParam);

  function handleSearch(term: string) {
    shouldResetPageOnChange && params.set('page', '1');
    if (term) {
      params.set(param, term);
    } else {
      params.delete(param);
    }
    setPendingParam(params.get(param));
    debouncedReplace(`${pathname}?${params.toString()}#${scrollTarget || ''}`);
  }

  React.useEffect(() => {
    setPendingParam(currentParam);
  }, [currentParam]);

  return (
    <span className={cn('relative', className)} {...props}>
      <TextInput
        name={name}
        type="search"
        placeholder="Search"
        onChange={(e) => handleSearch(e.target.value)}
        defaultValue={currentParam ?? ''}
        className="w-full pl-xxl"
      />
      {currentParam !== pendingParam && currentParam !== null ? (
        <Spinner className="absolute left-3 top-0 flex h-full items-center" />
      ) : (
        <MagnifyingGlassIcon
          width={20}
          height={20}
          className="absolute left-3 top-0 flex h-full items-center"
        />
      )}
    </span>
  );
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Create search-bar.tsx component

3 participants