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:
parent
5a50387685
commit
52d032d518
|
|
@ -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}
|
||||||
|
|
|
||||||
|
|
@ -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">
|
||||||
|
|
|
||||||
|
|
@ -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}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue