diff --git a/packages/frontend/src/components/application/NavbarContainer/NavbarContainer.tsx b/packages/frontend/src/components/application/NavbarContainer/NavbarContainer.tsx index 41849ca..19bce8f 100644 --- a/packages/frontend/src/components/application/NavbarContainer/NavbarContainer.tsx +++ b/packages/frontend/src/components/application/NavbarContainer/NavbarContainer.tsx @@ -21,7 +21,7 @@ import { API_URL } from "../../../repository/constants"; const NavbarContainer: React.FC = () => { const { open, setOpen, repertoires, updateRepertoires } = useNavbarContext(); const { showConfirmDialog, showTextDialog } = useDialogContext(); - const { showMenu } = useMenuContext(); + const { toggleMenu } = useMenuContext(); const navigate = useNavigate(); const { pathname } = useLocation(); useEffect(() => { @@ -81,7 +81,7 @@ const NavbarContainer: React.FC = () => { name: repertoire.name, url: `/repertoire/${repertoire._id}`, onActionClick: (event) => - showMenu(event.currentTarget, [ + toggleMenu(event.currentTarget, [ { name: "Move to Up", action: () => handleOrderUp(repertoire), diff --git a/packages/frontend/src/components/design/ActionsMenu/ActionsMenu.tsx b/packages/frontend/src/components/design/ActionsMenu/ActionsMenu.tsx index 9f78cb6..5663a1e 100644 --- a/packages/frontend/src/components/design/ActionsMenu/ActionsMenu.tsx +++ b/packages/frontend/src/components/design/ActionsMenu/ActionsMenu.tsx @@ -2,15 +2,15 @@ import React, { useState, useEffect, useRef, useLayoutEffect } from "react"; interface ActionsMenuProps { anchorEl: HTMLElement | null; - setAnchorEl: React.Dispatch>; + closeMenu: () => void; items: {name: string, action: () => void}[]; } -export const ActionsMenu: React.FC = ({anchorEl, setAnchorEl, items}) => { +export const ActionsMenu: React.FC = ({anchorEl, closeMenu, items}) => { const open = Boolean(anchorEl); const handleClose = () => { - setAnchorEl(null); + closeMenu(); }; const handleClick = (event: React.MouseEvent, action: () => void) => { @@ -58,7 +58,12 @@ export const ActionsMenu: React.FC = ({anchorEl, setAnchorEl, useEffect(() => { const handleClickOutside = (event: MouseEvent) => { - if (menuRef.current && !menuRef.current.contains(event.target as Node)) { + if ( + menuRef.current && + !menuRef.current.contains(event.target as Node) && + anchorEl && + !anchorEl.contains(event.target as Node) + ) { handleClose(); } }; diff --git a/packages/frontend/src/components/design/dialogs/ConfirmDialog.tsx b/packages/frontend/src/components/design/dialogs/ConfirmDialog.tsx index 3a0dbf3..b845394 100644 --- a/packages/frontend/src/components/design/dialogs/ConfirmDialog.tsx +++ b/packages/frontend/src/components/design/dialogs/ConfirmDialog.tsx @@ -12,10 +12,10 @@ interface TextDialogProps { export const ConfirmDialog: React.FC = ({open, onConfirm, onClose, title, contentText: contextText}) => { return ( - onClose(true)} className="fixed z-10 inset-0 overflow-y-auto"> + onClose(true)} className="fixed z-50 inset-0 overflow-y-auto">
- + {title} {contextText} diff --git a/packages/frontend/src/components/design/dialogs/NumberDialog.tsx b/packages/frontend/src/components/design/dialogs/NumberDialog.tsx index 88c8d45..6974975 100644 --- a/packages/frontend/src/components/design/dialogs/NumberDialog.tsx +++ b/packages/frontend/src/components/design/dialogs/NumberDialog.tsx @@ -32,10 +32,10 @@ export const NumberDialog: React.FC = ({ open, min, max, init const isValidNumber = (num: number) => num >= min && num <= max; return ( - onClose(true)} className="fixed z-10 inset-0 overflow-y-auto"> {/* changed */} + onClose(true)} className="fixed z-50 inset-0 overflow-y-auto"> {/* changed */}
- + {/* changed */} {title} {contentText} diff --git a/packages/frontend/src/components/design/dialogs/RepertoireDialog.tsx b/packages/frontend/src/components/design/dialogs/RepertoireDialog.tsx index f89cbd9..c60cb3f 100644 --- a/packages/frontend/src/components/design/dialogs/RepertoireDialog.tsx +++ b/packages/frontend/src/components/design/dialogs/RepertoireDialog.tsx @@ -29,10 +29,10 @@ const RepertoireDialog: React.FC = ({ open, title, conten }; return ( - onClose(true)} className="fixed z-10 inset-0 overflow-y-auto"> {/* changed */} + onClose(true)} className="fixed z-50 inset-0 overflow-y-auto"> {/* changed */}
- + {/* changed */} {title} {contentText} diff --git a/packages/frontend/src/components/design/dialogs/SelectNextMoveDialog.tsx b/packages/frontend/src/components/design/dialogs/SelectNextMoveDialog.tsx index a10caf1..6ffc5ec 100644 --- a/packages/frontend/src/components/design/dialogs/SelectNextMoveDialog.tsx +++ b/packages/frontend/src/components/design/dialogs/SelectNextMoveDialog.tsx @@ -27,9 +27,9 @@ const SelectNextMoveDialog: React.FC = ({ }; return ( - onClose(true)} className="fixed z-10 inset-0 overflow-y-auto"> {/* changed */} + onClose(true)} className="fixed z-50 inset-0 overflow-y-auto"> {/* changed */}
- + {/* changed */} {title}
{contentText} diff --git a/packages/frontend/src/components/design/dialogs/SelectTrainVariantsDialog.tsx b/packages/frontend/src/components/design/dialogs/SelectTrainVariantsDialog.tsx index 15b4889..0e0245c 100644 --- a/packages/frontend/src/components/design/dialogs/SelectTrainVariantsDialog.tsx +++ b/packages/frontend/src/components/design/dialogs/SelectTrainVariantsDialog.tsx @@ -176,11 +176,11 @@ const SelectTrainVariantsDialog: React.FC = ({ handleClose(true)} // changed - className="fixed z-10 inset-0 overflow-y-auto" + className="fixed z-50 inset-0 overflow-y-auto" >
- + {title} diff --git a/packages/frontend/src/components/design/dialogs/SelectVariantsDialog.tsx b/packages/frontend/src/components/design/dialogs/SelectVariantsDialog.tsx index e86644e..3c82666 100644 --- a/packages/frontend/src/components/design/dialogs/SelectVariantsDialog.tsx +++ b/packages/frontend/src/components/design/dialogs/SelectVariantsDialog.tsx @@ -152,11 +152,11 @@ const SelectVariantsDialog: React.FC = ({ handleClose(true)} - className="fixed z-10 inset-0 overflow-y-auto" + className="fixed z-50 inset-0 overflow-y-auto" >
- + {title} @@ -172,7 +172,6 @@ const SelectVariantsDialog: React.FC = ({ /> {multiple && (
- = ({
{multiple && ( - - handleSelectAllGroup(groupName)} className="ml-2 text-textLight" /> + handleSelectAllGroup(groupName)} + className="ml-2 text-textLight" + /> )}

{groupName} diff --git a/packages/frontend/src/contexts/AppContext.tsx b/packages/frontend/src/contexts/AppContext.tsx index def8fab..1a82031 100644 --- a/packages/frontend/src/contexts/AppContext.tsx +++ b/packages/frontend/src/contexts/AppContext.tsx @@ -13,11 +13,11 @@ export const AppContext: React.FC<{ children: React.ReactNode }> = ({ - - - {children} - - + + + {children} + + diff --git a/packages/frontend/src/contexts/DialogContext.tsx b/packages/frontend/src/contexts/DialogContext.tsx index 69cb26d..aa33cd8 100644 --- a/packages/frontend/src/contexts/DialogContext.tsx +++ b/packages/frontend/src/contexts/DialogContext.tsx @@ -313,54 +313,66 @@ export const DialogContextProvider = ({ }} > {children} - - - - - - + {openTextDialog && ( + + )} + {openConfirmDialog && ( + + )} + {openTrainVariantsDialog && ( + + )} + {openSelectNextMoveDialog && ( + + )} + {openRepertoireDialog && ( + + )} + {openSelectVariantsDialog && ( + + )} {numberDialogProps && ( void}[]) => void; + closeMenu: () => void; + toggleMenu: (anchorEl: HTMLElement | null, items: {name: string, action: () => void}[]) => void; } export const MenuContext = React.createContext(null); @@ -21,21 +24,81 @@ interface MenuContextProviderProps { children: React.ReactNode; } +interface MenuState { + anchorEl: HTMLElement | null; + open: boolean; + items: { name: string; action: () => void }[]; +} + +type MenuAction = + | { type: 'SHOW_MENU'; payload: { anchorEl: HTMLElement | null; items: { name: string; action: () => void }[] } } + | { type: 'CLOSE_MENU' }; + +const initialState: MenuState = { + anchorEl: null, + open: false, + items: [], +}; + +const reducer = (state: MenuState, action: MenuAction): MenuState => { + switch (action.type) { + case 'SHOW_MENU': + return { + anchorEl: action.payload.anchorEl, + open: true, + items: action.payload.items, + }; + case 'CLOSE_MENU': + return { + ...state, + open: false, + anchorEl: null, + items: [], + }; + default: + return state; + } +}; + export const MenuContextProvider: React.FC = ({ children, }) => { - const [anchorEl, setAnchorEl] = React.useState(null); - const [items, setItems] = React.useState<{name: string, action: () => void}[]>([]); + const [state, dispatch] = React.useReducer(reducer, initialState); + + const showMenu = useCallback((anchorEl: HTMLElement | null, items: { name: string; action: () => void }[]) => { + dispatch({ type: 'SHOW_MENU', payload: { anchorEl, items } }); + }, []); + + + const closeMenu = useCallback(() => { + dispatch({ type: 'CLOSE_MENU' }); + }, []); - const showMenu = (anchorEl: HTMLElement | null, items: {name: string, action: () => void}[]) => { - setAnchorEl(anchorEl); - setItems(items); - }; + const toggleMenu = useCallback((anchorEl: HTMLElement | null, items: { name: string; action: () => void }[]) => { + if (state.open) { + dispatch({ type: 'CLOSE_MENU' }); + } else { + dispatch({ type: 'SHOW_MENU', payload: { anchorEl, items } }); + } + }, [state.open]); return ( - + {children} - + {state.open && ( + + )} ); }; diff --git a/packages/frontend/src/pages/repertoires/EditRepertoirePage/EditRepertoireViewContainer.tsx b/packages/frontend/src/pages/repertoires/EditRepertoirePage/EditRepertoireViewContainer.tsx index f2b7189..2cf9e18 100644 --- a/packages/frontend/src/pages/repertoires/EditRepertoirePage/EditRepertoireViewContainer.tsx +++ b/packages/frontend/src/pages/repertoires/EditRepertoirePage/EditRepertoireViewContainer.tsx @@ -21,12 +21,12 @@ const EditRepertoireViewContainer: React.FC = () => { const navigate = useNavigate(); const [panelSelected, setPanelSelected] = useState("variants"); const { repertoireId, repertoireName, saveRepertory, getPgn, chess } = useRepertoireContext(); - const { showMenu } = useMenuContext(); - const { addIcon: addIconHeader, removeIcon: removeIconHeader, changeIconCallback } = useHeaderContext(); + const { toggleMenu } = useMenuContext(); + const { addIcon: addIconHeader, removeIcon: removeIconHeader } = useHeaderContext(); const { addIcon: addIconFooter, removeIcon: removeIconFooter, setIsVisible } = useFooterContext(); - const showMenuHeader = (event: React.MouseEvent) => { - showMenu(event.currentTarget || null, [ + const toggleMenuHeader = (event: React.MouseEvent) => { + toggleMenu(event.currentTarget || null, [ { name: "Download PGN", action: () => { @@ -46,8 +46,7 @@ const EditRepertoireViewContainer: React.FC = () => { }, }, ]); - }; - + } useEffect(() => { addIconHeader({ @@ -65,7 +64,7 @@ const EditRepertoireViewContainer: React.FC = () => { addIconHeader({ key: "moreOptions", icon: , - onClick: showMenuHeader, + onClick: toggleMenuHeader, }); return () => { @@ -73,17 +72,7 @@ const EditRepertoireViewContainer: React.FC = () => { removeIconHeader("saveRepertoire"); removeIconHeader("moreOptions"); }; - }, []); - - useEffect(() => { - changeIconCallback("saveRepertoire", saveRepertory); - }, [saveRepertory]); - - useEffect(() => { - changeIconCallback("moreOptions", (event: React.MouseEvent) => { - showMenuHeader(event); - }); - }, [getPgn]); + }, [navigate, repertoireId, saveRepertory, getPgn, toggleMenu]); useEffect(() => { setIsVisible(true);