import Drawer from "@mui/material/Drawer"; import * as React from "react"; import {useContext, useState} from "react"; import ListItemButton from "@mui/material/ListItemButton"; import ListItemIcon from "@mui/material/ListItemIcon"; import ChatBubbleOutlineIcon from "@mui/icons-material/ChatBubbleOutline"; import Person from "@mui/icons-material/Person"; import ListItemText from "@mui/material/ListItemText"; import Toolbar from "@mui/material/Toolbar"; import Divider from "@mui/material/Divider"; import List from "@mui/material/List"; import SettingsIcon from "@mui/icons-material/Settings"; import AddIcon from "@mui/icons-material/Add"; import SubscribeDialog from "./SubscribeDialog"; import {Alert, AlertTitle, Badge, CircularProgress, Link, ListSubheader, Tooltip} from "@mui/material"; import Button from "@mui/material/Button"; import Typography from "@mui/material/Typography"; import {openUrl, topicDisplayName, topicUrl} from "../app/utils"; import routes from "./routes"; import {ConnectionState} from "../app/Connection"; import {useLocation, useNavigate} from "react-router-dom"; import subscriptionManager from "../app/SubscriptionManager"; import {ChatBubble, Lock, NotificationsOffOutlined, Public, PublicOff, Send} from "@mui/icons-material"; import Box from "@mui/material/Box"; import notifier from "../app/Notifier"; import config from "../app/config"; import ArticleIcon from '@mui/icons-material/Article'; import {Trans, useTranslation} from "react-i18next"; import session from "../app/Session"; import accountApi from "../app/AccountApi"; import CelebrationIcon from '@mui/icons-material/Celebration'; import UpgradeDialog from "./UpgradeDialog"; import {AccountContext} from "./App"; const navWidth = 280; const Navigation = (props) => { const navigationList = ; return ( {/* Mobile drawer; only shown if menu icon clicked (mobile open) and display is small */} {navigationList} {/* Big screen drawer; persistent, shown if screen is big */} {navigationList} ); }; Navigation.width = navWidth; const NavList = (props) => { const { t } = useTranslation(); const navigate = useNavigate(); const location = useLocation(); const { account } = useContext(AccountContext); const [subscribeDialogKey, setSubscribeDialogKey] = useState(0); const [subscribeDialogOpen, setSubscribeDialogOpen] = useState(false); const handleSubscribeReset = () => { setSubscribeDialogOpen(false); setSubscribeDialogKey(prev => prev+1); } const handleSubscribeSubmit = (subscription) => { console.log(`[Navigation] New subscription: ${subscription.id}`, subscription); handleSubscribeReset(); navigate(routes.forSubscription(subscription)); handleRequestNotificationPermission(); } const handleRequestNotificationPermission = () => { notifier.maybeRequestPermission(granted => props.onNotificationGranted(granted)) }; const handleAccountClick = () => { accountApi.sync(); // Dangle! navigate(routes.account); }; const isAdmin = account?.role === "admin"; const isPaid = account?.billing?.subscription; const showUpgradeBanner = config.enable_payments && !isAdmin && !isPaid; const showSubscriptionsList = props.subscriptions?.length > 0; const showNotificationBrowserNotSupportedBox = !notifier.browserSupported(); const showNotificationContextNotSupportedBox = notifier.browserSupported() && !notifier.contextSupported(); // Only show if notifications are generally supported in the browser const showNotificationGrantBox = notifier.supported() && props.subscriptions?.length > 0 && !props.notificationsGranted; const navListPadding = (showNotificationGrantBox || showNotificationBrowserNotSupportedBox || showNotificationContextNotSupportedBox) ? '0' : ''; return ( <> {showNotificationBrowserNotSupportedBox && } {showNotificationContextNotSupportedBox && } {showNotificationGrantBox && } {!showSubscriptionsList && navigate(routes.app)} selected={location.pathname === config.app_root}> } {showSubscriptionsList && <> {t("nav_topics_title")} navigate(routes.app)} selected={location.pathname === config.app_root}> } {session.exists() && } navigate(routes.settings)} selected={location.pathname === routes.settings}> openUrl("/docs")}> props.onPublishMessageClick()}> setSubscribeDialogOpen(true)}> {showUpgradeBanner && } ); }; const UpgradeBanner = () => { const [dialogKey, setDialogKey] = useState(0); const [dialogOpen, setDialogOpen] = useState(false); const handleClick = () => { setDialogKey(k => k + 1); setDialogOpen(true); }; return ( setDialogOpen(false)} /> ); }; const SubscriptionList = (props) => { const sortedSubscriptions = props.subscriptions .filter(s => !s.internal) .sort((a, b) => { return (topicUrl(a.baseUrl, a.topic) < topicUrl(b.baseUrl, b.topic)) ? -1 : 1; }); return ( <> {sortedSubscriptions.map(subscription => )} ); } const SubscriptionItem = (props) => { const { t } = useTranslation(); const navigate = useNavigate(); const subscription = props.subscription; const iconBadge = (subscription.new <= 99) ? subscription.new : "99+"; const icon = (subscription.state === ConnectionState.Connecting) ? : ; const displayName = topicDisplayName(subscription); const ariaLabel = (subscription.state === ConnectionState.Connecting) ? `${displayName} (${t("nav_button_connecting")})` : displayName; const handleClick = async () => { navigate(routes.forSubscription(subscription)); await subscriptionManager.markNotificationsRead(subscription.id); }; return ( {icon} {subscription.reservation?.everyone && {subscription.reservation?.everyone === "read-write" && } {subscription.reservation?.everyone === "read-only" && } {subscription.reservation?.everyone === "write-only" && } {subscription.reservation?.everyone === "deny-all" && } } {subscription.mutedUntil > 0 && } ); }; const NotificationGrantAlert = (props) => { const { t } = useTranslation(); return ( <> {t("alert_grant_title")} {t("alert_grant_description")} ); }; const NotificationBrowserNotSupportedAlert = () => { const { t } = useTranslation(); return ( <> {t("alert_not_supported_title")} {t("alert_not_supported_description")} ); }; const NotificationContextNotSupportedAlert = () => { const { t } = useTranslation(); return ( <> {t("alert_not_supported_title")} }} /> ); }; export default Navigation;