diff --git a/src/components/SelectLichessStudy.tsx b/src/components/SelectLichessStudy.tsx index 2e9de88..2fa2d14 100644 --- a/src/components/SelectLichessStudy.tsx +++ b/src/components/SelectLichessStudy.tsx @@ -1,4 +1,5 @@ -import { useEffect, useRef, useState } from "react"; +import { useRef, useState } from "react"; +import { useClickOutside } from "#/hooks/useClickOutside.ts"; import { type IUserStudyChapter, useLichess } from "#/hooks/useLichess.ts"; interface IProps { @@ -30,24 +31,7 @@ const SelectLichessStudy = ({ setSelectedStudyId }: IProps) => { setSearch(""); }; - useEffect(() => { - const handleClickOutside = (event: MouseEvent) => { - if ( - isOpen && - dropdownRef.current && - !dropdownRef.current.contains(event.target as Node) - ) { - setIsOpen(false); - setSearch(""); - } - }; - - document.addEventListener("mousedown", handleClickOutside); - - return () => { - document.removeEventListener("mousedown", handleClickOutside); - }; - }, [isOpen]); + useClickOutside({ isOpen, setIsOpen, setSearch, ref: dropdownRef }); return (
@@ -74,6 +58,7 @@ const SelectLichessStudy = ({ setSelectedStudyId }: IProps) => { strokeLinecap="round" strokeLinejoin="round" > + search diff --git a/src/components/SelectStudyChapter.tsx b/src/components/SelectStudyChapter.tsx index 22c3eeb..74e6814 100644 --- a/src/components/SelectStudyChapter.tsx +++ b/src/components/SelectStudyChapter.tsx @@ -1,4 +1,5 @@ -import { type Dispatch, useEffect, useRef, useState } from "react"; +import { type Dispatch, useRef, useState } from "react"; +import { useClickOutside } from "#/hooks/useClickOutside.ts"; import { type IUserStudyChapter, useLichess } from "#/hooks/useLichess.ts"; import type { GameAction } from "#/reducers/gameReducer.ts"; @@ -19,24 +20,7 @@ const SelectStudyChapter = ({ selectedStudyId, gameDispatch }: IProps) => { chapter.name.toLowerCase().includes(search.toLowerCase()), ); - useEffect(() => { - const handleClickOutside = (event: MouseEvent) => { - if ( - isOpen && - dropdownRef.current && - !dropdownRef.current.contains(event.target as Node) - ) { - setIsOpen(false); - setSearch(""); - } - }; - - document.addEventListener("mousedown", handleClickOutside); - - return () => { - document.removeEventListener("mousedown", handleClickOutside); - }; - }, [isOpen]); + useClickOutside({ isOpen, setIsOpen, setSearch, ref: dropdownRef }); const onClickHandler = async () => { const studies = await getLichessStudyChapters({ studyId: selectedStudyId }); @@ -79,7 +63,7 @@ const SelectStudyChapter = ({ selectedStudyId, gameDispatch }: IProps) => { strokeLinecap="round" strokeLinejoin="round" > - link + search diff --git a/src/hooks/useClickOutside.ts b/src/hooks/useClickOutside.ts index e69de29..78587e0 100644 --- a/src/hooks/useClickOutside.ts +++ b/src/hooks/useClickOutside.ts @@ -0,0 +1,34 @@ +import { type RefObject, useEffect } from "react"; + +interface IProps { + isOpen: boolean; + setIsOpen: (isOpen: boolean) => void; + ref: RefObject; + setSearch: (search: string) => void; +} + +export const useClickOutside = ({ + isOpen, + setIsOpen, + setSearch, + ref, +}: IProps) => { + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + isOpen && + ref.current && + !ref.current.contains(event.target as Node) + ) { + setIsOpen(false); + setSearch(""); + } + }; + + document.addEventListener("mousedown", handleClickOutside); + + return () => { + document.removeEventListener("mousedown", handleClickOutside); + }; + }, [isOpen, setIsOpen, setSearch, ref]); +};