diff --git a/components/brain/BrainMobile.tsx b/components/brain/BrainMobile.tsx index 51a567c5ea..8954924142 100644 --- a/components/brain/BrainMobile.tsx +++ b/components/brain/BrainMobile.tsx @@ -162,47 +162,50 @@ const BrainMobile: React.FC = ({ children }) => { // Handle tab visibility and reset on wave changes useEffect(() => { + const globalViews = new Set([ + BrainView.DEFAULT, + BrainView.WAVES, + BrainView.MESSAGES, + BrainView.NOTIFICATIONS, + ]); + + const routeToView: Record = { + "/waves": BrainView.WAVES, + "/messages": BrainView.MESSAGES, + "/notifications": BrainView.NOTIFICATIONS, + }; + if (!hasWave) { - if ( - activeView !== BrainView.DEFAULT && - activeView !== BrainView.WAVES && - activeView !== BrainView.MESSAGES && - activeView !== BrainView.NOTIFICATIONS - ) - setActiveView(BrainView.DEFAULT); + const isWaveSpecificView = !globalViews.has(activeView); + if (isWaveSpecificView) { + setActiveView(routeToView[pathname ?? ""] ?? BrainView.DEFAULT); + } return; } if (!wave) return; - const isInLeaderboardAndVotingHasEnded = - activeView === BrainView.LEADERBOARD && isCompleted; - const isInWinnersAndFirstDecisionHasntPassed = - activeView === BrainView.WINNERS && !firstDecisionDone; - const isInMyVotesAndIsNotMemeWave = - activeView === BrainView.MY_VOTES && !isMemesWave; - const isInFAQAndIsNotMemeWave = - activeView === BrainView.FAQ && !isMemesWave; + const shouldResetToDefault = + (activeView === BrainView.LEADERBOARD && isCompleted) || + (activeView === BrainView.WINNERS && !firstDecisionDone) || + (activeView === BrainView.MY_VOTES && !isMemesWave) || + (activeView === BrainView.FAQ && !isMemesWave); - if ( - isInLeaderboardAndVotingHasEnded || - isInWinnersAndFirstDecisionHasntPassed || - isInMyVotesAndIsNotMemeWave || - isInFAQAndIsNotMemeWave - ) { + if (shouldResetToDefault) { setActiveView(BrainView.DEFAULT); + return; } - if (hasWave && waveId) { - if ( - activeView === BrainView.NOTIFICATIONS || - activeView === BrainView.MESSAGES || - activeView === BrainView.WAVES - ) { - setActiveView(BrainView.DEFAULT); - } + const nonWaveViews = new Set([ + BrainView.NOTIFICATIONS, + BrainView.MESSAGES, + BrainView.WAVES, + ]); + + if (waveId && nonWaveViews.has(activeView)) { + setActiveView(BrainView.DEFAULT); } - }, [hasWave, wave, isCompleted, firstDecisionDone, activeView, isMemesWave, waveId]); + }, [hasWave, wave, isCompleted, firstDecisionDone, activeView, isMemesWave, waveId, pathname]); const closeCreateOverlay = useCallback(() => { const params = new URLSearchParams(searchParams?.toString() || ""); diff --git a/components/voting/VotingModal.tsx b/components/voting/VotingModal.tsx index b53a155654..3bca48cc4c 100644 --- a/components/voting/VotingModal.tsx +++ b/components/voting/VotingModal.tsx @@ -1,5 +1,8 @@ +"use client"; + import { ExtendedDrop } from "@/helpers/waves/drop.helpers"; -import React from "react"; +import React, { useEffect, useId, useRef } from "react"; +import { createPortal } from "react-dom"; import SecondaryButton from "../utils/button/SecondaryButton"; import { SingleWaveDropVote } from "../waves/drop/SingleWaveDropVote"; import ModalLayout from "../waves/memes/submission/layout/ModalLayout"; @@ -15,13 +18,45 @@ const VotingModal: React.FC = ({ isOpen, onClose, }) => { + const titleId = useId(); + const modalRef = useRef(null); + const previousActiveElement = useRef(null); + + useEffect(() => { + if (!isOpen) return; + + previousActiveElement.current = document.activeElement as HTMLElement; + modalRef.current?.focus(); + + const originalOverflow = document.body.style.overflow; + document.body.style.overflow = "hidden"; + + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape") { + onClose(); + } + }; + document.addEventListener("keydown", handleKeyDown); + + return () => { + document.body.style.overflow = originalOverflow; + document.removeEventListener("keydown", handleKeyDown); + previousActiveElement.current?.focus(); + }; + }, [isOpen, onClose]); + if (!isOpen) { return null; } - return ( + const modalContent = (
e.stopPropagation()} >
= ({ >
e.stopPropagation()} > - +
@@ -46,6 +81,8 @@ const VotingModal: React.FC = ({
); + + return createPortal(modalContent, document.body); }; export default VotingModal; diff --git a/components/waves/memes/submission/layout/ModalLayout.tsx b/components/waves/memes/submission/layout/ModalLayout.tsx index cdb7aded16..d477649790 100644 --- a/components/waves/memes/submission/layout/ModalLayout.tsx +++ b/components/waves/memes/submission/layout/ModalLayout.tsx @@ -7,6 +7,7 @@ interface ModalLayoutProps { readonly title: string; readonly onCancel: () => void; readonly children: React.ReactNode; + readonly titleId?: string; } /** @@ -16,6 +17,7 @@ const ModalLayout: React.FC = ({ title, onCancel, children, + titleId, }) => { return (
@@ -44,6 +46,7 @@ const ModalLayout: React.FC = ({ {/* Header Section with bottom border */}
{title}