From 9ce35459015a16ff7786d9ac6926a2415de3a71a Mon Sep 17 00:00:00 2001 From: nimbleghost <132819643+nimbleghost@users.noreply.github.com> Date: Wed, 28 Jun 2023 20:26:54 +0200 Subject: [PATCH] Fix refreshing things when permission is granted We refreshed some things but not everything, this makes it more responsive if you have the settings page open when granting permissions, for example. --- web/src/components/App.jsx | 4 --- web/src/components/Navigation.jsx | 15 +++------ web/src/components/Preferences.jsx | 5 +-- web/src/components/hooks.js | 53 +++++++++++++++++------------- 4 files changed, 39 insertions(+), 38 deletions(-) diff --git a/web/src/components/App.jsx b/web/src/components/App.jsx index 6c4761f1..e174ccc4 100644 --- a/web/src/components/App.jsx +++ b/web/src/components/App.jsx @@ -8,7 +8,6 @@ import { AllSubscriptions, SingleSubscription } from "./Notifications"; import themeOptions, { darkPalette, lightPalette } from "./theme"; import Navigation from "./Navigation"; import ActionBar from "./ActionBar"; -import notifier from "../app/Notifier"; import Preferences from "./Preferences"; import subscriptionManager from "../app/SubscriptionManager"; import userManager from "../app/UserManager"; @@ -91,7 +90,6 @@ const Layout = () => { const params = useParams(); const { account, setAccount } = useContext(AccountContext); const [mobileDrawerOpen, setMobileDrawerOpen] = useState(false); - const [notificationsGranted, setNotificationsGranted] = useState(notifier.granted()); const [sendDialogOpenMode, setSendDialogOpenMode] = useState(""); const users = useLiveQuery(() => userManager.all()); const subscriptions = useLiveQuery(() => subscriptionManager.all()); @@ -115,10 +113,8 @@ const Layout = () => { setMobileDrawerOpen(!mobileDrawerOpen)} - onNotificationGranted={setNotificationsGranted} onPublishMessageClick={() => setSendDialogOpenMode(PublishDialog.OPEN_MODE_DEFAULT)} />
diff --git a/web/src/components/Navigation.jsx b/web/src/components/Navigation.jsx index fe1cf8be..ad671d99 100644 --- a/web/src/components/Navigation.jsx +++ b/web/src/components/Navigation.jsx @@ -43,6 +43,7 @@ import UpgradeDialog from "./UpgradeDialog"; import { AccountContext } from "./App"; import { PermissionDenyAll, PermissionRead, PermissionReadWrite, PermissionWrite } from "./ReserveIcons"; import { SubscriptionPopup } from "./SubscriptionPopup"; +import { useNotificationPermissionListener } from "./hooks"; const navWidth = 280; @@ -109,17 +110,12 @@ const NavList = (props) => { const isPaid = account?.billing?.subscription; const showUpgradeBanner = config.enable_payments && !isAdmin && !isPaid; const showSubscriptionsList = props.subscriptions?.length > 0; - const [showNotificationPermissionRequired, setShowNotificationPermissionRequired] = useState(notifier.notRequested()); - const [showNotificationPermissionDenied, setShowNotificationPermissionDenied] = useState(notifier.denied()); + const showNotificationPermissionRequired = useNotificationPermissionListener(() => notifier.notRequested()); + const showNotificationPermissionDenied = useNotificationPermissionListener(() => notifier.denied()); const showNotificationIOSInstallRequired = notifier.iosSupportedButInstallRequired(); const showNotificationBrowserNotSupportedBox = !showNotificationIOSInstallRequired && !notifier.browserSupported(); const showNotificationContextNotSupportedBox = notifier.browserSupported() && !notifier.contextSupported(); // Only show if notifications are generally supported in the browser - const refreshPermissions = () => { - setShowNotificationPermissionRequired(notifier.notRequested()); - setShowNotificationPermissionDenied(notifier.denied()); - }; - const alertVisible = showNotificationPermissionRequired || showNotificationPermissionDenied || @@ -131,7 +127,7 @@ const NavList = (props) => { <> - {showNotificationPermissionRequired && } + {showNotificationPermissionRequired && } {showNotificationPermissionDenied && } {showNotificationBrowserNotSupportedBox && } {showNotificationContextNotSupportedBox && } @@ -354,11 +350,10 @@ const SubscriptionItem = (props) => { ); }; -const NotificationPermissionRequired = ({ refreshPermissions }) => { +const NotificationPermissionRequired = () => { const { t } = useTranslation(); const requestPermission = async () => { await notifier.maybeRequestPermission(); - refreshPermissions(); }; return ( diff --git a/web/src/components/Preferences.jsx b/web/src/components/Preferences.jsx index add9b8c0..a24ccd96 100644 --- a/web/src/components/Preferences.jsx +++ b/web/src/components/Preferences.jsx @@ -49,7 +49,7 @@ import { ReserveAddDialog, ReserveDeleteDialog, ReserveEditDialog } from "./Rese import { UnauthorizedError } from "../app/errors"; import { subscribeTopic } from "./SubscribeDialog"; import notifier from "../app/Notifier"; -import { useIsLaunchedPWA } from "./hooks"; +import { useIsLaunchedPWA, useNotificationPermissionListener } from "./hooks"; const maybeUpdateAccountSettings = async (payload) => { if (!session.exists()) { @@ -79,6 +79,7 @@ const Preferences = () => ( const Notifications = () => { const { t } = useTranslation(); const isLaunchedPWA = useIsLaunchedPWA(); + const pushPossible = useNotificationPermissionListener(() => notifier.pushPossible()); return ( @@ -89,7 +90,7 @@ const Notifications = () => { - {!isLaunchedPWA && notifier.pushPossible() && } + {!isLaunchedPWA && pushPossible && } ); diff --git a/web/src/components/hooks.js b/web/src/components/hooks.js index 5ff375d2..6d5f3d51 100644 --- a/web/src/components/hooks.js +++ b/web/src/components/hooks.js @@ -136,8 +136,31 @@ export const useAutoSubscribe = (subscriptions, selected) => { }; const webPushBroadcastChannel = new BroadcastChannel("web-push-broadcast"); -const matchMedia = window.matchMedia("(display-mode: standalone)"); -const isIOSStandalone = window.navigator.standalone === true; + +/** + * Hook to return a value that's refreshed when the notification permission changes + */ +export const useNotificationPermissionListener = (query) => { + const [result, setResult] = useState(query()); + + useEffect(() => { + const handler = () => { + setResult(query()); + }; + + if ("permissions" in navigator) { + navigator.permissions.query({ name: "notifications" }).then((permission) => { + permission.addEventListener("change", handler); + + return () => { + permission.removeEventListener("change", handler); + }; + }); + } + }, []); + + return result; +}; /** * Updates the Web Push subscriptions when the list of topics changes, @@ -146,10 +169,11 @@ const isIOSStandalone = window.navigator.standalone === true; */ const useWebPushListener = (topics) => { const [lastTopics, setLastTopics] = useState(); + const pushPossible = useNotificationPermissionListener(() => notifier.pushPossible()); useEffect(() => { const topicsChanged = JSON.stringify(topics) !== JSON.stringify(lastTopics); - if (!notifier.pushPossible() || !topicsChanged) { + if (!pushPossible || !topicsChanged) { return; } @@ -183,25 +207,7 @@ const useWebPushListener = (topics) => { * automatically. */ export const useWebPushTopics = () => { - const [pushPossible, setPushPossible] = useState(notifier.pushPossible()); - - useEffect(() => { - const handler = () => { - const newPushPossible = notifier.pushPossible(); - console.log(`[useWebPushTopics] Notification Permission changed`, { pushPossible: newPushPossible }); - setPushPossible(newPushPossible); - }; - - if ("permissions" in navigator) { - navigator.permissions.query({ name: "notifications" }).then((permission) => { - permission.addEventListener("change", handler); - - return () => { - permission.removeEventListener("change", handler); - }; - }); - } - }); + const pushPossible = useNotificationPermissionListener(() => notifier.pushPossible()); const topics = useLiveQuery( async () => subscriptionManager.webPushTopics(pushPossible), @@ -214,6 +220,9 @@ export const useWebPushTopics = () => { return topics; }; +const matchMedia = window.matchMedia("(display-mode: standalone)"); +const isIOSStandalone = window.navigator.standalone === true; + /* * Watches the "display-mode" to detect if the app is running as a standalone app (PWA). */