Преглед изворни кода

Move more stuff out of App.js

Philipp Heckel пре 4 година
родитељ
комит
09b128f27a

+ 120 - 4
web/src/components/ActionBar.js

@@ -4,11 +4,20 @@ import Toolbar from "@mui/material/Toolbar";
 import IconButton from "@mui/material/IconButton";
 import MenuIcon from "@mui/icons-material/Menu";
 import Typography from "@mui/material/Typography";
-import SubscribeSettings from "./SubscribeSettings";
 import * as React from "react";
+import {useEffect, useRef, useState} from "react";
 import Box from "@mui/material/Box";
-import {topicShortUrl} from "../app/utils";
-import {useLocation} from "react-router-dom";
+import {subscriptionRoute, topicShortUrl} from "../app/utils";
+import {useLocation, useNavigate} from "react-router-dom";
+import ClickAwayListener from '@mui/material/ClickAwayListener';
+import Grow from '@mui/material/Grow';
+import Paper from '@mui/material/Paper';
+import Popper from '@mui/material/Popper';
+import MenuItem from '@mui/material/MenuItem';
+import MenuList from '@mui/material/MenuList';
+import MoreVertIcon from "@mui/icons-material/MoreVert";
+import api from "../app/Api";
+import subscriptionManager from "../app/SubscriptionManager";
 
 const ActionBar = (props) => {
     const location = useLocation();
@@ -41,7 +50,7 @@ const ActionBar = (props) => {
                 <Typography variant="h6" noWrap component="div" sx={{ flexGrow: 1 }}>
                     {title}
                 </Typography>
-                {props.selectedSubscription && <SubscribeSettings
+                {props.selectedSubscription && <SettingsIcon
                     subscription={props.selectedSubscription}
                     onUnsubscribe={props.onUnsubscribe}
                 />}
@@ -50,4 +59,111 @@ const ActionBar = (props) => {
     );
 };
 
+// Originally from https://mui.com/components/menus/#MenuListComposition.js
+const SettingsIcon = (props) => {
+    const navigate = useNavigate();
+    const [open, setOpen] = useState(false);
+    const anchorRef = useRef(null);
+
+    const handleToggle = () => {
+        setOpen((prevOpen) => !prevOpen);
+    };
+
+    const handleClose = (event) => {
+        if (anchorRef.current && anchorRef.current.contains(event.target)) {
+            return;
+        }
+        setOpen(false);
+    };
+
+    const handleClearAll = async (event) => {
+        handleClose(event);
+        console.log(`[ActionBar] Deleting all notifications from ${props.subscription.id}`);
+        await subscriptionManager.deleteNotifications(props.subscription.id);
+    };
+
+    const handleUnsubscribe = async (event) => {
+        console.log(`[ActionBar] Unsubscribing from ${props.subscription.id}`);
+        handleClose(event);
+        await subscriptionManager.remove(props.subscription.id);
+        const newSelected = await subscriptionManager.first(); // May be undefined
+        if (newSelected) {
+            navigate(subscriptionRoute(newSelected));
+        }
+    };
+
+    const handleSendTestMessage = () => {
+        const baseUrl = props.subscription.baseUrl;
+        const topic = props.subscription.topic;
+        api.publish(baseUrl, topic,
+            `This is a test notification sent by the ntfy Web UI at ${new Date().toString()}.`); // FIXME result ignored
+        setOpen(false);
+    }
+
+    const handleListKeyDown = (event) => {
+        if (event.key === 'Tab') {
+            event.preventDefault();
+            setOpen(false);
+        } else if (event.key === 'Escape') {
+            setOpen(false);
+        }
+    }
+
+    // return focus to the button when we transitioned from !open -> open
+    const prevOpen = useRef(open);
+    useEffect(() => {
+        if (prevOpen.current === true && open === false) {
+            anchorRef.current.focus();
+        }
+        prevOpen.current = open;
+    }, [open]);
+
+    return (
+        <>
+            <IconButton
+                color="inherit"
+                size="large"
+                edge="end"
+                ref={anchorRef}
+                id="composition-button"
+                onClick={handleToggle}
+            >
+                <MoreVertIcon/>
+            </IconButton>
+            <Popper
+                open={open}
+                anchorEl={anchorRef.current}
+                role={undefined}
+                placement="bottom-start"
+                transition
+                disablePortal
+            >
+                {({TransitionProps, placement}) => (
+                    <Grow
+                        {...TransitionProps}
+                        style={{
+                            transformOrigin:
+                                placement === 'bottom-start' ? 'left top' : 'left bottom',
+                        }}
+                    >
+                        <Paper>
+                            <ClickAwayListener onClickAway={handleClose}>
+                                <MenuList
+                                    autoFocusItem={open}
+                                    id="composition-menu"
+                                    onKeyDown={handleListKeyDown}
+                                >
+                                    <MenuItem onClick={handleSendTestMessage}>Send test notification</MenuItem>
+                                    <MenuItem onClick={handleClearAll}>Clear all notifications</MenuItem>
+                                    <MenuItem onClick={handleUnsubscribe}>Unsubscribe</MenuItem>
+                                </MenuList>
+                            </ClickAwayListener>
+                        </Paper>
+                    </Grow>
+                )}
+            </Popper>
+        </>
+    );
+};
+
 export default ActionBar;

+ 8 - 16
web/src/components/App.js

@@ -47,31 +47,21 @@ const Root = () => {
     const subscriptions = useLiveQuery(() => subscriptionManager.all());
     const selectedSubscription = findSelected(location, subscriptions);
 
-    const handleSubscriptionClick = async (subscriptionId) => {
-        const subscription = await subscriptionManager.get(subscriptionId);
-        navigate(subscriptionRoute(subscription));
-    }
     const handleSubscribeSubmit = async (subscription) => {
         console.log(`[App] New subscription: ${subscription.id}`, subscription);
         navigate(subscriptionRoute(subscription));
         handleRequestPermission();
     };
-    const handleUnsubscribe = async (subscriptionId) => {
-        console.log(`[App] Unsubscribing from ${subscriptionId}`);
-        const newSelected = await subscriptionManager.first(); // May be undefined
-        if (newSelected) {
-            navigate(subscriptionRoute(newSelected));
-        }
-    };
+
     const handleRequestPermission = () => {
         notificationManager.maybeRequestPermission(granted => setNotificationsGranted(granted));
     };
-    // Define hooks: Note that the order of the hooks is important. The "loading" hooks
-    // must be before the "saving" hooks.
+
     useEffect(() => {
         poller.startWorker();
         pruner.startWorker();
     }, [/* initial render */]);
+
     useEffect(() => {
         const handleNotification = async (subscriptionId, notification) => {
             try {
@@ -93,14 +83,17 @@ const Root = () => {
 // This is for the use of 'navigate' // FIXME
 //eslint-disable-next-line
     }, [/* initial render */]);
-    useEffect(() => { connectionManager.refresh(subscriptions, users) }, [subscriptions, users]); // Dangle!
+
+    useEffect(() => {
+        connectionManager.refresh(subscriptions, users);
+    }, [subscriptions, users]); // Dangle!
+
     return (
         <Box sx={{display: 'flex'}}>
             <CssBaseline/>
             <ActionBar
                 subscriptions={subscriptions}
                 selectedSubscription={selectedSubscription}
-                onUnsubscribe={handleUnsubscribe}
                 onMobileDrawerToggle={() => setMobileDrawerOpen(!mobileDrawerOpen)}
             />
             <Box component="nav" sx={{width: {sm: Navigation.width}, flexShrink: {sm: 0}}}>
@@ -110,7 +103,6 @@ const Root = () => {
                     mobileDrawerOpen={mobileDrawerOpen}
                     notificationsGranted={notificationsGranted}
                     onMobileDrawerToggle={() => setMobileDrawerOpen(!mobileDrawerOpen)}
-                    onSubscriptionClick={handleSubscriptionClick}
                     onSubscribeSubmit={handleSubscribeSubmit}
                     onRequestPermissionClick={handleRequestPermission}
                 />

+ 4 - 0
web/src/components/Navigation.js

@@ -58,16 +58,20 @@ const NavList = (props) => {
     const location = useLocation();
     const [subscribeDialogKey, setSubscribeDialogKey] = useState(0);
     const [subscribeDialogOpen, setSubscribeDialogOpen] = useState(false);
+
     const handleSubscribeReset = () => {
         setSubscribeDialogOpen(false);
         setSubscribeDialogKey(prev => prev+1);
     }
+
     const handleSubscribeSubmit = (subscription) => {
         handleSubscribeReset();
         props.onSubscribeSubmit(subscription);
     }
+
     const showSubscriptionsList = props.subscriptions?.length > 0;
     const showGrantPermissionsBox = props.subscriptions?.length > 0 && !props.notificationsGranted;
+
     return (
         <>
             <Toolbar sx={{ display: { xs: 'none', sm: 'block' } }}/>

+ 0 - 116
web/src/components/SubscribeSettings.js

@@ -1,116 +0,0 @@
-import * as React from 'react';
-import {useEffect, useRef, useState} from 'react';
-import ClickAwayListener from '@mui/material/ClickAwayListener';
-import Grow from '@mui/material/Grow';
-import Paper from '@mui/material/Paper';
-import Popper from '@mui/material/Popper';
-import MenuItem from '@mui/material/MenuItem';
-import MenuList from '@mui/material/MenuList';
-import IconButton from "@mui/material/IconButton";
-import MoreVertIcon from "@mui/icons-material/MoreVert";
-import api from "../app/Api";
-import subscriptionManager from "../app/SubscriptionManager";
-
-// Originally from https://mui.com/components/menus/#MenuListComposition.js
-const SubscribeSettings = (props) => {
-    const [open, setOpen] = useState(false);
-    const anchorRef = useRef(null);
-
-    const handleToggle = () => {
-        setOpen((prevOpen) => !prevOpen);
-    };
-
-    const handleClose = (event) => {
-        if (anchorRef.current && anchorRef.current.contains(event.target)) {
-            return;
-        }
-        setOpen(false);
-    };
-
-    const handleClearAll = async (event) => {
-        handleClose(event);
-        console.log(`[IconSubscribeSettings] Deleting all notifications from ${props.subscription.id}`);
-        await subscriptionManager.deleteNotifications(props.subscription.id);
-    };
-
-    const handleUnsubscribe = async (event) => {
-        handleClose(event);
-        await subscriptionManager.remove(props.subscription.id);
-        props.onUnsubscribe(props.subscription.id);
-    };
-
-    const handleSendTestMessage = () => {
-        const baseUrl = props.subscription.baseUrl;
-        const topic = props.subscription.topic;
-        api.publish(baseUrl, topic,
-            `This is a test notification sent by the ntfy Web UI at ${new Date().toString()}.`); // FIXME result ignored
-        setOpen(false);
-    }
-
-    const handleListKeyDown = (event) => {
-        if (event.key === 'Tab') {
-            event.preventDefault();
-            setOpen(false);
-        } else if (event.key === 'Escape') {
-            setOpen(false);
-        }
-    }
-
-    // return focus to the button when we transitioned from !open -> open
-    const prevOpen = useRef(open);
-    useEffect(() => {
-        if (prevOpen.current === true && open === false) {
-            anchorRef.current.focus();
-        }
-        prevOpen.current = open;
-    }, [open]);
-
-    return (
-        <>
-            <IconButton
-                color="inherit"
-                size="large"
-                edge="end"
-                ref={anchorRef}
-                id="composition-button"
-                onClick={handleToggle}
-            >
-                <MoreVertIcon/>
-            </IconButton>
-            <Popper
-                open={open}
-                anchorEl={anchorRef.current}
-                role={undefined}
-                placement="bottom-start"
-                transition
-                disablePortal
-            >
-                {({TransitionProps, placement}) => (
-                    <Grow
-                        {...TransitionProps}
-                        style={{
-                            transformOrigin:
-                                placement === 'bottom-start' ? 'left top' : 'left bottom',
-                        }}
-                    >
-                        <Paper>
-                            <ClickAwayListener onClickAway={handleClose}>
-                                <MenuList
-                                    autoFocusItem={open}
-                                    id="composition-menu"
-                                    onKeyDown={handleListKeyDown}
-                                >
-                                    <MenuItem onClick={handleSendTestMessage}>Send test notification</MenuItem>
-                                    <MenuItem onClick={handleClearAll}>Clear all notifications</MenuItem>
-                                    <MenuItem onClick={handleUnsubscribe}>Unsubscribe</MenuItem>
-                                </MenuList>
-                            </ClickAwayListener>
-                        </Paper>
-                    </Grow>
-                )}
-            </Popper>
-        </>
-    );
-}
-
-export default SubscribeSettings;