import clsx from "clsx"; import { Calendar, ChevronRight, Heart, LogIn, Menu, MessageSquare, Settings, Tv, User, Users, X, } from "lucide-react"; import * as React from "react"; import { Dialog, Modal, ModalOverlay } from "react-aria-components"; import { useTranslation } from "react-i18next"; import { Link } from "react-router"; import { useUser } from "~/features/auth/core/user"; import { useChatContext } from "~/features/chat/useChatContext"; import { FriendMenu } from "~/features/friends/components/FriendMenu"; import { SENDOUQ_ACTIVITY_LABEL } from "~/features/friends/friends-constants"; import { useLayoutSize } from "~/hooks/useMainContentWidth"; import type { RootLoaderData } from "~/root"; import { EVENTS_PAGE, FRIENDS_PAGE, navIconUrl, SETTINGS_PAGE, SUPPORT_PAGE, userPage, } from "~/utils/urls"; import { Avatar } from "./Avatar"; import { EventsList } from "./EventsList"; import { LinkButton } from "./elements/Button"; import { Image } from "./Image"; import { ChatSidebar } from "./layout/ChatSidebar"; import { LogInButtonContainer } from "./layout/LogInButtonContainer"; import { NotificationContent, useNotifications, } from "./layout/NotificationPopover"; import { navItems } from "./layout/nav-items"; import styles from "./MobileNav.module.css"; import { NotificationDot } from "./NotificationDot"; import { StreamListItems } from "./StreamListItems"; type SidebarData = RootLoaderData["sidebar"] | undefined; type PanelType = "closed" | "menu" | "friends" | "tourneys" | "chat" | "you"; export function MobileNav({ sidebarData }: { sidebarData: SidebarData }) { const [activePanel, setActivePanel] = React.useState("closed"); const previousPanelRef = React.useRef("closed"); const user = useUser(); const { unseenIds } = useNotifications(); const chatContext = useChatContext(); const layoutSize = useLayoutSize(); const hasUnseenNotifications = unseenIds.length > 0; const hasFriendInSendouQ = sidebarData?.friends.some((f) => f.subtitle === SENDOUQ_ACTIVITY_LABEL) ?? false; const skipAnimation = previousPanelRef.current !== "closed"; const closePanel = () => { previousPanelRef.current = activePanel; setActivePanel("closed"); }; const handleTabPress = (panel: PanelType) => { if (activePanel === panel) { if (panel === "chat") { chatContext?.setChatOpen(false); } previousPanelRef.current = activePanel; setActivePanel("closed"); return; } if (activePanel === "chat") { chatContext?.setChatOpen(false); } if (panel === "chat") { chatContext?.setChatOpen(true); } previousPanelRef.current = activePanel; setActivePanel(panel); }; const closeChatPanel = () => { chatContext?.setChatOpen(false); closePanel(); }; return (
{activePanel === "menu" ? ( ) : null} {activePanel === "friends" ? ( ) : null} {activePanel === "tourneys" ? ( ) : null} {activePanel === "you" ? ( ) : null} {chatContext?.chatOpen && layoutSize === "mobile" ? ( ) : null}
); } function MobileTabBar({ activePanel, onTabPress, isLoggedIn, hasUnseenNotifications, hasFriendInSendouQ, }: { activePanel: PanelType; onTabPress: (panel: PanelType) => void; isLoggedIn: boolean; hasUnseenNotifications: boolean; hasFriendInSendouQ: boolean; }) { const { t } = useTranslation(["front", "common"]); const chatContext = useChatContext(); return ( ); } function MobileTab({ icon, label, isActive, onPress, showNotificationDot, unreadCount, }: { icon: React.ReactNode; label: string; isActive: boolean; onPress: () => void; showNotificationDot?: boolean; unreadCount?: number; }) { return ( ); } function MobilePanel({ title, icon, onClose, children, onTabPress, isLoggedIn, skipAnimation, }: { title: string; icon: React.ReactNode; onClose: () => void; children: React.ReactNode; onTabPress: (panel: PanelType) => void; isLoggedIn: boolean; skipAnimation: boolean; }) { return (
{icon}

{title}

{children}
); } function MenuOverlay({ streams, savedTournamentIds, onClose, onTabPress, isLoggedIn, skipAnimation, }: { streams: NonNullable["streams"]; savedTournamentIds?: number[]; onClose: () => void; onTabPress: (panel: PanelType) => void; isLoggedIn: boolean; skipAnimation: boolean; }) { const { t } = useTranslation(["front", "common"]); const user = useUser(); return (

{t("front:mobileNav.menu")}

{!user?.roles.includes("MINOR_SUPPORT") ? ( } variant="outlined" > {t("common:pages.support")} ) : null}

{t("front:sideNav.streams")}

{streams.length === 0 ? (
{t("front:sideNav.noStreams")}
) : null}
); } function FriendsPanel({ friends, onClose, onTabPress, isLoggedIn, skipAnimation, }: { friends: NonNullable["friends"]; onClose: () => void; onTabPress: (panel: PanelType) => void; isLoggedIn: boolean; skipAnimation: boolean; }) { const { t } = useTranslation(["front", "common"]); const user = useUser(); return ( } onClose={onClose} onTabPress={onTabPress} isLoggedIn={isLoggedIn} skipAnimation={skipAnimation} > {friends.length > 0 ? ( friends.map((friend) => ( )) ) : (
{user ? t("front:sideNav.friends.noFriends") : t("front:sideNav.friends.notLoggedIn")}
)} {t("common:actions.viewAll")}
); } function TourneysPanel({ events, onClose, onTabPress, isLoggedIn, skipAnimation, }: { events: NonNullable["events"]; onClose: () => void; onTabPress: (panel: PanelType) => void; isLoggedIn: boolean; skipAnimation: boolean; }) { const { t } = useTranslation(["front", "common"]); return ( } onClose={onClose} onTabPress={onTabPress} isLoggedIn={isLoggedIn} skipAnimation={skipAnimation} > {t("common:actions.viewAll")} ); } function YouPanel({ onClose, onTabPress, isLoggedIn, skipAnimation, }: { onClose: () => void; onTabPress: (panel: PanelType) => void; isLoggedIn: boolean; skipAnimation: boolean; }) { const { t } = useTranslation(["front", "common"]); const user = useUser(); const { notifications, unseenIds } = useNotifications(); if (!user) { return null; } return ( } onClose={onClose} onTabPress={onTabPress} isLoggedIn={isLoggedIn} skipAnimation={skipAnimation} >
{user.username}
{notifications ? ( ) : null}
); } function ChatPanel({ onClose, onTabPress, isLoggedIn, skipAnimation, }: { onClose: () => void; onTabPress: (panel: PanelType) => void; isLoggedIn: boolean; skipAnimation: boolean; }) { return ( ); } const LOGGED_IN_TABS: PanelType[] = [ "menu", "friends", "tourneys", "chat", "you", ]; const LOGGED_OUT_TABS: PanelType[] = ["menu"]; function GhostTabBar({ onTabPress, isLoggedIn, }: { onTabPress: (panel: PanelType) => void; isLoggedIn: boolean; }) { const tabs = isLoggedIn ? LOGGED_IN_TABS : LOGGED_OUT_TABS; return ( ); }