Close profileDropdown if clicked outside, removed console.debugs

This commit is contained in:
Martin Berg Alstad 2023-07-23 12:26:58 +02:00
parent 05154798a6
commit 1bee3d60b3
5 changed files with 37 additions and 26 deletions

View File

@ -1,4 +1,4 @@
import React, {FC} from "react";
import React, {FC, useEffect} from "react";
import {Link, useNavigate} from "react-router-dom";
import {useAtom, useAtomValue} from "jotai";
import {thisPlayerAtom} from "../utils/state";
@ -20,7 +20,6 @@ const NavMenu: FC = () => {
player === undefined ?
<NavItem className={"mx-2"} to={"/login"}>Login</NavItem>
:
/*TODO show user instead, when clicking a dropdown menu opens where the user can log out or other actions*/
<ProfileDropdown className={"mx-2"}/>
}
</ul>
@ -35,11 +34,11 @@ const NavItem: FC<LinkProps> = ({to, children, className}) => (
<li>
<Link className={`hover:underline ${className}`} to={to}>{children}</Link>
</li>
)
);
const ProfileDropdown: FC<ComponentProps> = ({className}) => {
const [player, setPlayer] = useAtom(thisPlayerAtom);
const [isOpened, toggle] = useToggle(false);
const [isOpened, toggleOpen] = useToggle();
const navigate = useNavigate();
async function logout(): Promise<void> {
@ -47,18 +46,35 @@ const ProfileDropdown: FC<ComponentProps> = ({className}) => {
navigate("/login");
}
useEffect(() => {
if (isOpened) {
function closeIfOutsideButton(e: MouseEvent): void {
if (isOpened && e.target instanceof HTMLElement) {
if (e.target.closest("#profile-dropdown") === null) {
toggleOpen(false);
}
}
}
document.addEventListener("click", closeIfOutsideButton);
return () => document.removeEventListener("click", closeIfOutsideButton);
}
}, [isOpened]);
return (
<>
<li
className={`inline-flex justify-center items-center cursor-pointer hover:bg-gray-100 h-full px-2 ${className}`}
onClick={() => toggle()}>
<li id={"profile-dropdown"}
className={`inline-flex-center cursor-pointer hover:bg-gray-100 h-full px-2 ${className}`}
onClick={() => toggleOpen()}>
<UserCircleIcon className={"w-7"}/>
<span>{player?.username}</span>
</li>
{
isOpened &&
<div className={"absolute right-2 border rounded-b -bottom-7 px-5"}>
<button onClick={logout} className={"hover:underline"}>Logout</button>
<div className={"absolute right-2 border rounded-b -bottom-9 px-5"}>
<button onClick={logout} className={"hover:underline py-1"}>Logout</button>
</div>
}
</>

View File

@ -1,5 +1,10 @@
import {useState} from "react";
/**
* A hook that returns a boolean value and a function to toggle it. The function can optionally be passed a boolean
* @param defaultValue The default value of the boolean, defaults to false.
* @returns A tuple containing the boolean value and a function to toggle it.
*/
export default function useToggle(defaultValue = false): [boolean, (value?: boolean) => void] {
const [value, setValue] = useState(defaultValue);
const toggleValue = (newValue?: boolean) => newValue ? setValue(newValue) : setValue(!value);

View File

@ -11,6 +11,10 @@
@apply flex justify-center items-center;
}
.inline-flex-center {
@apply inline-flex justify-center items-center;
}
.wh-full {
@apply w-full h-full;
}

View File

@ -1,4 +1,4 @@
import React, {FC, useEffect} from "react";
import React, {FC} from "react";
import {GameComponent} from "../components/gameComponent";
import {useAtomValue} from "jotai";
import {selectedMapAtom, thisPlayerAtom} from "../utils/state";
@ -7,12 +7,6 @@ const Game: FC = () => {
const player = useAtomValue(thisPlayerAtom);
const map = useAtomValue(selectedMapAtom);
useEffect(() => {
if (!player) {
window.location.href = "/";
}
}, []);
if (player && map) {
return <GameComponent player={player} map={map}/>;
} else {

View File

@ -1,4 +1,4 @@
import React, {FC, Suspense, useEffect} from "react";
import React, {FC, Suspense} from "react";
import {atom, useAtomValue} from "jotai";
import {Button} from "../components/button";
import {selectedMapAtom, thisPlayerAtom} from "../utils/state";
@ -11,7 +11,7 @@ const fetchAtom = atom(async () => {
return await response.json() as Game[];
});
const LobbyPage: FC = () => { // TODO check if player is defined in storage, if not redirect to login
const LobbyPage: FC = () => {
const thisPlayer = useAtomValue(thisPlayerAtom);
const navigate = useNavigate();
@ -25,7 +25,6 @@ const LobbyPage: FC = () => { // TODO check if player is defined in storage, if
if (response.ok) {
const data = await response.json();
console.debug("Game created: ", data);
navigate("/game/" + data.id)
} else {
const data = await response.text();
@ -35,10 +34,6 @@ const LobbyPage: FC = () => { // TODO check if player is defined in storage, if
}
useEffect(() => {
console.debug(thisPlayer)
})
return (
<>
<Button onClick={createGame}>New game</Button>
@ -60,12 +55,9 @@ const GameTable: FC<ComponentProps> = ({className}) => {
async function joinGame(gameId: string): Promise<void> {
if (thisPlayer === undefined) throw new Error("Player is undefined");
console.debug("Joining game " + gameId);
const result = await postData("/game/join/" + gameId, {body: thisPlayer});
if (result.ok) {
console.debug("Joined game " + gameId, await result.text());
navigate("/game/" + gameId);
} else {
console.error("Failed to join game " + gameId, await result.text());