Refactor Dropdown component: integrate useOutsideClick for improved click handling, manage dropdown state with useRef and useState, and enhance button functionality for better user experience.

This commit is contained in:
Norbert Maciaszek 2025-08-15 15:00:42 +02:00
parent 5a50387685
commit 52d032d518
3 changed files with 29 additions and 17 deletions

View File

@ -1,5 +1,6 @@
"use client"; "use client";
import { FC, useEffect, useState } from "react"; import { useOutsideClick } from "@/hooks/useOutsideClick";
import { FC, useEffect, useRef, useState } from "react";
import { FaFilter } from "react-icons/fa"; import { FaFilter } from "react-icons/fa";
type Props = { type Props = {
@ -12,19 +13,31 @@ type Props = {
}; };
export const Dropdown: FC<Props> = ({ items, defaultValue, callback }) => { export const Dropdown: FC<Props> = ({ items, defaultValue, callback }) => {
const ref = useRef<HTMLDivElement>(null);
const [isOpen, setIsOpen] = useState(false);
const [value, setValue] = useState<string>(defaultValue); const [value, setValue] = useState<string>(defaultValue);
useOutsideClick(ref, () => setIsOpen(false));
useEffect(() => { useEffect(() => {
callback?.(value); callback?.(value);
}, [value]); }, [value]);
return ( return (
<div className="relative inline-block"> <div ref={ref} className="relative inline-block">
<button className="focus:[&+div]:opacity-100 relative z-10 block p-2 shadow-sm cursor-pointer bg-white text-primary rounded-md"> <button
onClick={() => setIsOpen(!isOpen)}
className="relative z-10 block p-2 shadow-sm cursor-pointer bg-white text-primary rounded-md"
>
<FaFilter /> <FaFilter />
</button> </button>
<div className="absolute left-0 z-20 w-48 py-2 mt-2 origin-top-right bg-white rounded-md shadow-xl dark:bg-gray-800 opacity-0"> <div
className="absolute left-0 z-20 w-48 py-2 mt-2 origin-top-right bg-white rounded-md shadow-xl dark:bg-gray-800"
style={{
opacity: isOpen ? 1 : 0,
}}
>
{items.map((item) => ( {items.map((item) => (
<p <p
key={item.value} key={item.value}

View File

@ -58,7 +58,7 @@ export const MovieCard: FC<Props> = ({ layout = "default", ...movie }) => {
<article className="flex flex-col w-full shadow-lg rounded-t-lg overflow-hidden bg-black/50 shadow-white/5"> <article className="flex flex-col w-full shadow-lg rounded-t-lg overflow-hidden bg-black/50 shadow-white/5">
<figure className="relative "> <figure className="relative ">
<img <img
className="w-full object-cover xl:h-[420px]" className="w-full object-cover h-[285px] xl:h-[420px]"
src={`http://image.tmdb.org/t/p/w342${poster_path}`} src={`http://image.tmdb.org/t/p/w342${poster_path}`}
/> />
<span className="absolute inset-0 bg-black/30 backdrop-blur-md opacity-0 hover-any:opacity-100 transition-opacity duration-300 flex items-center justify-center cursor-pointer"> <span className="absolute inset-0 bg-black/30 backdrop-blur-md opacity-0 hover-any:opacity-100 transition-opacity duration-300 flex items-center justify-center cursor-pointer">

View File

@ -6,6 +6,7 @@ import { SearchResult } from "@/lib/tmdb/types";
import { FC } from "react"; import { FC } from "react";
import { useEffect } from "react"; import { useEffect } from "react";
import { Pagination } from "@/components/atoms/Pagination"; import { Pagination } from "@/components/atoms/Pagination";
import { MovieList } from "../MovieList";
type Props = { type Props = {
query: string; query: string;
@ -44,18 +45,16 @@ export const SearchList: FC<Props> = ({ query }) => {
<p className="text-sm text-gray-500"> <p className="text-sm text-gray-500">
{total_results} movies found for your search {total_results} movies found for your search
</p> </p>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-6 mt-8">
{results?.map((result) => ( <MovieList
<MovieCard overrideMovies={results?.map((m) => ({
key={result.id} ...m,
layout="zeus" favorite: false,
{...result} seen: false,
genre_ids={result.genre_ids.join(",")} genre_ids: JSON.stringify(m.genre_ids),
seen={false} }))}
favorite={false} fluid
/> />
))}
</div>
<Pagination <Pagination
totalPages={total_pages} totalPages={total_pages}
currentPage={page} currentPage={page}