import * as React from 'react'; import {useEffect, useState} from 'react'; import Box from '@mui/material/Box'; import {ThemeProvider} from '@mui/material/styles'; import CssBaseline from '@mui/material/CssBaseline'; import Toolbar from '@mui/material/Toolbar'; import Notifications from "./Notifications"; import theme from "./theme"; import Navigation from "./Navigation"; import ActionBar from "./ActionBar"; import notifier from "../app/Notifier"; import Preferences from "./Preferences"; import {useLiveQuery} from "dexie-react-hooks"; import subscriptionManager from "../app/SubscriptionManager"; import userManager from "../app/UserManager"; import {BrowserRouter, Outlet, Route, Routes, useOutletContext, useParams} from "react-router-dom"; import {expandUrl, topicUrl} from "../app/utils"; import ErrorBoundary from "./ErrorBoundary"; import routes from "./routes"; import {useAutoSubscribe, useBackgroundProcesses, useConnectionListeners} from "./hooks"; import {Backdrop} from "@mui/material"; import Paper from "@mui/material/Paper"; import IconButton from "@mui/material/IconButton"; import {MoreVert} from "@mui/icons-material"; import TextField from "@mui/material/TextField"; import SendIcon from "@mui/icons-material/Send"; import api from "../app/Api"; import SendDialog from "./SendDialog"; import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'; // TODO add drag and drop // TODO races when two tabs are open // TODO investigate service workers const App = () => { return ( }> }/> }/> }/> }/> ); } const AllSubscriptions = () => { const { subscriptions } = useOutletContext(); return ; }; const SingleSubscription = () => { const { subscriptions, selected } = useOutletContext(); useAutoSubscribe(subscriptions, selected); return ; }; const Layout = () => { const params = useParams(); const [mobileDrawerOpen, setMobileDrawerOpen] = useState(false); const [notificationsGranted, setNotificationsGranted] = useState(notifier.granted()); const users = useLiveQuery(() => userManager.all()); const subscriptions = useLiveQuery(() => subscriptionManager.all()); const newNotificationsCount = subscriptions?.reduce((prev, cur) => prev + cur.new, 0) || 0; const [selected] = (subscriptions || []).filter(s => { return (params.baseUrl && expandUrl(params.baseUrl).includes(s.baseUrl) && params.topic === s.topic) || (window.location.origin === s.baseUrl && params.topic === s.topic) }); useConnectionListeners(subscriptions, users); useBackgroundProcesses(); useEffect(() => updateTitle(newNotificationsCount), [newNotificationsCount]); return ( setMobileDrawerOpen(!mobileDrawerOpen)} /> setMobileDrawerOpen(!mobileDrawerOpen)} onNotificationGranted={setNotificationsGranted} />
); } const Main = (props) => { return ( theme.palette.mode === 'light' ? theme.palette.grey[100] : theme.palette.grey[900] }} > {props.children} ); }; const Messaging = (props) => { const [message, setMessage] = useState(""); const [dialogKey, setDialogKey] = useState(0); const [showDialog, setShowDialog] = useState(false); const [showDropZone, setShowDropZone] = useState(false); const subscription = props.selected; const selectedTopicUrl = (subscription) ? topicUrl(subscription.baseUrl, subscription.topic) : ""; useEffect(() => { window.addEventListener('dragenter', () => { setShowDialog(true); setShowDropZone(true); }); }, []); const handleSendDialogClose = () => { setShowDialog(false); setShowDropZone(false); setDialogKey(prev => prev+1); }; const allowSubmit = () => true; const allowDrag = (e) => { if (allowSubmit()) { e.dataTransfer.dropEffect = 'copy'; e.preventDefault(); } }; return ( <> {subscription && setShowDialog(true)} />} setShowDropZone(false)} topicUrl={selectedTopicUrl} message={message} /> ); } const MessageBar = (props) => { const subscription = props.subscription; const handleSendClick = () => { api.publish(subscription.baseUrl, subscription.topic, props.message); // FIXME props.onMessageChange(""); }; return ( theme.palette.mode === 'light' ? theme.palette.grey[100] : theme.palette.grey[900] }} > props.onMessageChange(ev.target.value)} onKeyPress={(ev) => { if (ev.key === 'Enter') { ev.preventDefault(); handleSendClick(); } }} /> ); }; const updateTitle = (newNotificationsCount) => { document.title = (newNotificationsCount > 0) ? `(${newNotificationsCount}) ntfy` : "ntfy"; } export default App;