(CreatePushSubscription)
- const createPushSubscription = async () => {
- try {
- setLoading(true)
- const swr = await navigator.serviceWorker.ready
- const subscription = await swr.pushManager.getSubscription()
- if (subscription) {
- const res = await createPushSubscriptionMutation({
- variables: {
- sub: JSON.stringify(subscription)
- }
- })
- if (res.data) {
- const _id = res.data.createPushSubscription.id
- setId(_id.toString())
- localStorage.setItem(DEVICE_ID, _id.toString())
- }
- }
- } catch (err) {
- setError(err)
- } finally {
- setLoading(false)
- }
- }
-
- const resetSubscription = async (err: Error) => {
- if (confirm(`An error occured:\n${err.message}\n\nReset subscription?`)) {
- setId(null)
- localStorage.removeItem(DEVICE_ID)
- }
- }
-
- let title = id ? 'Disable notifications' : 'Enable notifications'
- let icon = id ? 'notifications_off' : 'notifications'
- let onClick = id ? deletePushSubscription : createPushSubscription
- if (error) {
- title = error.message
- icon = 'notification_important'
- onClick = () => resetSubscription(error)
- }
-
- return
-}
diff --git a/ui/src/settings/preferences/NotificationBox.tsx b/ui/src/settings/preferences/NotificationBox.tsx
new file mode 100644
index 000000000..ed7b029a9
--- /dev/null
+++ b/ui/src/settings/preferences/NotificationBox.tsx
@@ -0,0 +1,151 @@
+import React, { ReactNode, useEffect, useState } from 'react'
+import { useApolloClient, useMutation } from 'react-apollo-hooks'
+import Switch from 'react-switch'
+
+import Box from '../../components/Box'
+import Button from '../../components/Button'
+import Loader from '../../components/Loader'
+import ErrorPanel from '../../error/ErrorPanel'
+import { isNotificationGranted, isNotificationSupported, subscribePush, unSubscribePush } from '../../helpers'
+import { CreatePushSubscriptionResponse, DeletePushSubscriptionResponse, GetDeviceResponse } from '../components/models'
+import { CreatePushSubscription, DeletePushSubscription, GetDevice } from '../components/queries'
+
+const DEVICE_ID = 'device_id'
+
+interface NotificationSupportProps {
+ children: ReactNode
+}
+
+const NotificationSupport = ({ children }: NotificationSupportProps) => {
+ const supported = isNotificationSupported()
+ const [allowed, setAllowed] = useState(isNotificationGranted())
+
+ const requestPermission = () => Notification.requestPermission(permission => setAllowed(permission === 'granted'))
+
+ if (!supported) {
+ return Sorry, but this browser does not support desktop notification.
+ } else if (!allowed) {
+ return (
+ <>
+ Notifications are not yet allowed on your Browser.
+
+ >
+ )
+ } else {
+ return <>{children}>
+ }
+}
+
+interface NotificationErrorProps {
+ reset: () => void
+ err: Error
+}
+
+const NotificationError = ({ reset, err }: NotificationErrorProps) => (
+ reset subscription}
+ >
+ {err.message}
+
+)
+
+const NotificationSwitch = () => {
+ const [activated, setActivated] = useState(false)
+ const [pushID, setPushID] = useState(localStorage.getItem(DEVICE_ID))
+ const [loading, setLoading] = useState(false)
+ const [error, setError] = useState(null)
+ const client = useApolloClient()
+ const deletePushSubscriptionMutation = useMutation(DeletePushSubscription)
+ const createPushSubscriptionMutation = useMutation(CreatePushSubscription)
+
+ const resetSubscription = async () => {
+ localStorage.removeItem(DEVICE_ID)
+ setPushID(null)
+ setActivated(false)
+ try {
+ const swr = await navigator.serviceWorker.ready
+ await unSubscribePush(swr)
+ } catch (err) {
+ console.error(err)
+ }
+ }
+
+ const getPushSubscriptionStatus = async (pushId: string) => {
+ setLoading(true)
+ try {
+ const { errors } = await client.query({
+ query: GetDevice,
+ variables: { id: pushId }
+ })
+ if (errors) {
+ throw new Error(errors[0].message)
+ } else {
+ setActivated(true)
+ }
+ } catch (err) {
+ setError(err)
+ } finally {
+ setLoading(false)
+ }
+ }
+
+ const subscribe = async () => {
+ try {
+ setLoading(true)
+ const swr = await navigator.serviceWorker.ready
+ const subscription = await subscribePush(swr)
+ if (subscription) {
+ const res = await createPushSubscriptionMutation({
+ variables: {
+ sub: JSON.stringify(subscription)
+ }
+ })
+ if (res.data) {
+ const _id = res.data.createPushSubscription.id
+ setPushID(_id.toString())
+ localStorage.setItem(DEVICE_ID, _id.toString())
+ }
+ }
+ } catch (err) {
+ setError(err)
+ } finally {
+ setLoading(false)
+ }
+ }
+
+ const unsubscribe = async () => {
+ try {
+ setLoading(true)
+ await deletePushSubscriptionMutation({ variables: { id: pushID } })
+ resetSubscription()
+ } catch (err) {
+ setError(err)
+ } finally {
+ setLoading(false)
+ }
+ }
+
+ useEffect(() => {
+ if (pushID) {
+ getPushSubscriptionStatus(pushID)
+ }
+ }, [pushID])
+
+ return (
+ <>
+ {error != null && }
+
+ {loading && }
+ >
+ )
+}
+
+export default () => (
+
+ Receive notifications on your device when new articles are available.
+
+
+
+
+)
diff --git a/ui/src/settings/preferences/PreferencesTab.tsx b/ui/src/settings/preferences/PreferencesTab.tsx
index 466630a79..c2d392cd5 100644
--- a/ui/src/settings/preferences/PreferencesTab.tsx
+++ b/ui/src/settings/preferences/PreferencesTab.tsx
@@ -3,6 +3,7 @@ import React from 'react'
import Panel from '../../components/Panel'
import { usePageTitle } from '../../hooks'
import InstallationBox from './InstallationBox'
+import NotificationBox from './NotificationBox'
import classes from './PreferencesTab.module.css'
export default () => {
@@ -15,6 +16,7 @@ export default () => {
Preferences on this device.
+
)