Skip to content

Commit

Permalink
Merge pull request #334 from BinaryStudioAcademy/fix/OV-326-close-men…
Browse files Browse the repository at this point in the history
…u-body-click-outside-open-modal

OV-326:  Close Menu Body when click outside, but also when click out…
  • Loading branch information
nikita-remeslov authored Sep 20, 2024
2 parents b9b29ee + ffc4a25 commit c8b79fb
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 9 deletions.
9 changes: 7 additions & 2 deletions frontend/src/bundles/chat/pages/chat-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@ import {
type Properties = {
isChatOpen: boolean;
onModalChatClose: () => void;
modalReference: React.RefObject<HTMLDivElement>;
};

const ChatModal: React.FC<Properties> = ({ isChatOpen, onModalChatClose }) => {
const ChatModal: React.FC<Properties> = ({
isChatOpen,
onModalChatClose,
modalReference,
}) => {
const dispatch = useAppDispatch();
const { messages } = useAppSelector(({ chat }) => ({
messages: chat.messages,
Expand All @@ -42,7 +47,7 @@ const ChatModal: React.FC<Properties> = ({ isChatOpen, onModalChatClose }) => {
size="5xl"
>
<ModalOverlay />
<ModalContent borderRadius="xl">
<ModalContent borderRadius="xl" ref={modalReference}>
<ModalCloseButton color="white" />
<Chat
messages={messages}
Expand Down
14 changes: 12 additions & 2 deletions frontend/src/bundles/common/components/modal/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,21 @@ import { type ModalProps } from '~/bundles/common/types/types.js';

import styles from './styles.module.css';

const Modal: React.FC<ModalProps> = ({ children, ...properties }) => {
type Properties = {
modalReference?: React.RefObject<HTMLElement>;
} & ModalProps;
const Modal: React.FC<Properties> = ({
children,
modalReference,
...properties
}) => {
return (
<LibraryModal {...properties} isCentered>
<ModalOverlay />
<ModalContent className={styles['modal-content']}>
<ModalContent
className={styles['modal-content']}
ref={modalReference}
>
<ModalCloseButton margin="20px" zIndex={10} />
<ModalBody padding={0}>{children}</ModalBody>
</ModalContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ type Properties = {
title: string | React.ReactNode;
onClose: () => void;
onChatOpen?: () => void;
menuBodyReference: React.RefObject<HTMLDivElement>;
};

const MenuBody: React.FC<React.PropsWithChildren<Properties>> = ({
title,
children,
onClose,
onChatOpen,
menuBodyReference,
}) => {
const menuReference = useRef<HTMLDivElement | null>(null);

Expand All @@ -48,7 +50,7 @@ const MenuBody: React.FC<React.PropsWithChildren<Properties>> = ({

return (
<Box
ref={menuReference}
ref={menuBodyReference}
bg="background.900"
className={styles['menu-body']}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,21 @@ type Properties = {
isOpen: boolean;
onClose: () => void;
scriptId: string | null;
modalReference: React.RefObject<HTMLDivElement>;
};
const VoicesModal: React.FC<Properties> = ({ isOpen, onClose, scriptId }) => {
const VoicesModal: React.FC<Properties> = ({
isOpen,
onClose,
scriptId,
modalReference,
}) => {
return (
<Modal isOpen={isOpen} onClose={onClose} scrollBehavior="inside">
<Modal
isOpen={isOpen}
onClose={onClose}
modalReference={modalReference}
scrollBehavior="inside"
>
{scriptId && (
<VoicesModalContent
scriptId={scriptId}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ import { actions as studioActions } from '~/bundles/studio/store/studio.js';

import { Script, VoicesModal } from './components/components.js';

const ScriptContent: React.FC = () => {
type Properties = {
modalReference: React.RefObject<HTMLDivElement>;
};
const ScriptContent: React.FC<Properties> = ({ modalReference }) => {
const dispatch = useAppDispatch();
const { dataStatus, scripts, voices } = useAppSelector(
({ studio }) => studio,
Expand Down Expand Up @@ -86,6 +89,7 @@ const ScriptContent: React.FC = () => {
isOpen={Boolean(changeVoiceScriptId)}
onClose={handleCloseVoicesModal}
scriptId={changeVoiceScriptId}
modalReference={modalReference}
/>
</>
);
Expand Down
32 changes: 31 additions & 1 deletion frontend/src/bundles/studio/components/video-menu/video-menu.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { ChatModal } from '~/bundles/chat/pages/chat-modal.js';
import { Icon } from '~/bundles/common/components/components.js';
import { DOMEvent } from '~/bundles/common/enums/enums.js';
import {
useAppDispatch,
useAppSelector,
useCallback,
useEffect,
useRef,
useState,
} from '~/bundles/common/hooks/hooks.js';
import { IconName } from '~/bundles/common/icons/icons.js';
Expand All @@ -29,6 +31,8 @@ const VideoMenu: React.FC = () => {

const dispatch = useAppDispatch();
const [isChatOpen, setIsChatOpen] = useState(false);
const modalReference = useRef<HTMLDivElement | null>(null);
const menuBodyReference = useRef<HTMLDivElement | null>(null);

const setActiveItem = useCallback(
(item: ValueOf<typeof MenuItems> | null): void => {
Expand Down Expand Up @@ -74,7 +78,7 @@ const VideoMenu: React.FC = () => {
script: {
label: 'Script',
icon: <Icon as={IconName.SCRIPT} />,
getContent: () => <ScriptContent />,
getContent: () => <ScriptContent modalReference={modalReference} />,
},
// text: {
// label: 'Text',
Expand All @@ -90,6 +94,30 @@ const VideoMenu: React.FC = () => {

const activeMenuItem = activeItem && menuItems[activeItem];

useEffect(() => {
const handleClickOutside = (event: MouseEvent): void => {
const isInsideMenuBody = menuBodyReference.current?.contains(
event.target as Node,
);
const isInsideModal = modalReference.current?.contains(
event.target as Node,
);

if (!isInsideMenuBody && !isInsideModal) {
handleMenuClose();
}
};

document.addEventListener(DOMEvent.MOUSE_DOWN, handleClickOutside);

return () => {
document.removeEventListener(
DOMEvent.MOUSE_DOWN,
handleClickOutside,
);
};
}, [handleMenuClose, menuBodyReference, modalReference]);

return (
<>
<Menu
Expand All @@ -102,13 +130,15 @@ const VideoMenu: React.FC = () => {
title={activeMenuItem.label}
onClose={handleMenuClose}
onChatOpen={handleChatOpen}
menuBodyReference={menuBodyReference}
>
{activeMenuItem.getContent()}
</MenuBody>
)}
<ChatModal
isChatOpen={isChatOpen}
onModalChatClose={handleChatClose}
modalReference={modalReference}
/>
</>
);
Expand Down

0 comments on commit c8b79fb

Please sign in to comment.