Skip to content

Commit

Permalink
[C-2825] Fix push notification registration (#3672)
Browse files Browse the repository at this point in the history
Co-authored-by: Dylan Jeffers <dylan@audius.co>
  • Loading branch information
michellebrier and dylanjeffers authored Jul 7, 2023
1 parent 475e14e commit 79da3ee
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,18 @@ const actions = [
}
]

const useStyles = makeStyles(({ palette }) => ({
const useStyles = makeStyles(({ palette, spacing }) => ({
drawer: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-evenly',
alignItems: 'center',
padding: 16,
paddingTop: 64,
paddingBottom: 32
paddingHorizontal: spacing(4),
paddingTop: spacing(12),
paddingBottom: spacing(8)
},

cta: {
marginTop: 16,
marginTop: spacing(4),
fontSize: 28
},

Expand All @@ -88,24 +87,21 @@ const useStyles = makeStyles(({ palette }) => ({
},

top: {
marginBottom: 32,
display: 'flex',
marginBottom: spacing(8),
flexDirection: 'column',
alignItems: 'center'
},

actions: {
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
marginBottom: 32
marginBottom: spacing(8)
},

action: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
marginBottom: 12
marginBottom: spacing(3)
},

actionText: {
Expand All @@ -114,7 +110,7 @@ const useStyles = makeStyles(({ palette }) => ({
},

actionIcon: {
marginRight: 16
marginRight: spacing(4)
}
}))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { useCallback } from 'react'
import { getHasCompletedAccount } from 'common/store/pages/signon/selectors'
import { checkNotifications, RESULTS } from 'react-native-permissions'
import { useDispatch, useSelector } from 'react-redux'
import type { Dispatch } from 'redux'

import useSessionCount from 'app/hooks/useSessionCount'
import { setVisibility } from 'app/store/drawers/slice'
Expand All @@ -23,21 +22,9 @@ const NotificationReminderInternal = () => {
const dispatch = useDispatch()

// Sets up reminders to turn on push notifications
const reminder = useCallback(() => {
remindUserToTurnOnNotifications(dispatch)
}, [dispatch])

useSessionCount(reminder, REMINDER_FREQUENCY, FIRST_REMINDER_SESSION)

// No UI component
return null
}

// Sends a notification to the WebApp to turn on push notifications if we're in the DENIED
// state. Is called from the `NotificationsReminder` component as well as `handleMessage`
export const remindUserToTurnOnNotifications = (dispatch: Dispatch) => {
checkNotifications()
.then(({ status }) => {
const remindUserToTurnOnNotifications = useCallback(async () => {
try {
const { status } = await checkNotifications()
switch (status) {
case RESULTS.UNAVAILABLE:
// Notifications are not available (on this device / in this context).
Expand All @@ -63,9 +50,18 @@ export const remindUserToTurnOnNotifications = (dispatch: Dispatch) => {
setVisibility({ drawer: 'EnablePushNotifications', visible: true })
)
}
})
.catch((error) => {
} catch (error) {
// Not sure what happened, but swallow the error. Not worth blocking on.
console.error(error)
})
}
}, [dispatch])

useSessionCount(
remindUserToTurnOnNotifications,
REMINDER_FREQUENCY,
FIRST_REMINDER_SESSION
)

// No UI component
return null
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { useDispatch } from 'react-redux'
import { useEffectOnce } from 'react-use'

import { Screen, ScreenContent } from 'app/components/core'
import { remindUserToTurnOnNotifications } from 'app/components/notification-reminder/NotificationReminder'
import { useFeatureFlag } from 'app/hooks/useRemoteConfig'

import { Divider } from './Divider'
Expand Down Expand Up @@ -35,7 +34,6 @@ export const NotificationSettingsScreen = () => {
useEffectOnce(() => {
dispatch(getPushNotificationSettings())
dispatch(getNotificationSettings())
remindUserToTurnOnNotifications(dispatch)
})

return (
Expand Down
3 changes: 0 additions & 3 deletions packages/mobile/src/screens/signon/SignOn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import ValidationIconX from 'app/assets/images/iconValidationX.svg'
import signupCTA from 'app/assets/images/signUpCTA.png'
import Button from 'app/components/button'
import LoadingSpinner from 'app/components/loading-spinner'
import { remindUserToTurnOnNotifications } from 'app/components/notification-reminder/NotificationReminder'
import useAppState from 'app/hooks/useAppState'
import { useToast } from 'app/hooks/useToast'
import { screen, track, make } from 'app/services/analytics'
Expand Down Expand Up @@ -386,8 +385,6 @@ const SignOn = ({ navigation }: SignOnProps) => {
setPassword('')
}, 1000)

remindUserToTurnOnNotifications(dispatch)

return () => {
clearTimeout(timeout)
}
Expand Down
95 changes: 63 additions & 32 deletions packages/mobile/src/store/settings/sagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,33 @@ import {
PushNotificationSetting,
settingsPageActions as actions,
getContext,
waitForValue
waitForValue,
waitForAccount,
settingsPageActions
} from '@audius/common'
import { waitForRead } from 'audius-client/src/utils/sagaHelpers'
import commonSettingsSagas from 'common/store/pages/settings/sagas'
import { mapValues } from 'lodash'
import { select, call, put, takeEvery } from 'typed-redux-saga'
import { RESULTS, checkNotifications } from 'react-native-permissions'
import { select, call, put, takeEvery, take } from 'typed-redux-saga'

import PushNotifications from 'app/notifications'

const { getPushNotificationSettings } = settingsPageSelectors
const { getAccountUser } = accountSelectors
import { setVisibility } from '../drawers/slice'

const { getPushNotificationSettings, SET_PUSH_NOTIFICATION_SETTINGS } =
settingsPageActions
const { getPushNotificationSettings: selectPushNotificationSettings } =
settingsPageSelectors
const { getAccountUser, getHasAccount } = accountSelectors

function* getIsMobilePushEnabled() {
yield* put(getPushNotificationSettings())
yield* take(SET_PUSH_NOTIFICATION_SETTINGS)
const { [PushNotificationSetting.MobilePush]: isMobilePushEnabled } =
yield* select(selectPushNotificationSettings)
return isMobilePushEnabled
}

export function* deregisterPushNotifications() {
const audiusBackendInstance = yield* getContext('audiusBackendInstance')
Expand All @@ -26,21 +42,36 @@ export function* deregisterPushNotifications() {
yield* call(audiusBackendInstance.deregisterDeviceToken, token)
}

/*
* Runs once at startup and re-registers the device-token in case it changes
*/
function* reregisterDeviceToken() {
function* registerDeviceToken() {
let { token, os } = yield* call([PushNotifications, 'getToken'])

if (!token) {
yield* call([PushNotifications, 'requestPermission'])
;({ token, os } = yield* call([PushNotifications, 'getToken']))
}

const audiusBackend = yield* getContext('audiusBackendInstance')
const hasPermission = yield* call([PushNotifications, 'hasPermission'])
if (hasPermission) {
const { token, os } = yield* call([PushNotifications, 'getToken'])
yield* call(audiusBackend.registerDeviceToken, token, os)
yield* call(audiusBackend.registerDeviceToken, token, os)
}

function* reregisterDeviceTokenOnStartup() {
yield* call(waitForAccount)
const isSignedIn = yield* select(getHasAccount)
if (!isSignedIn) return

const { status } = yield* call(checkNotifications)
const isMobilePushEnabled = yield* call(getIsMobilePushEnabled)

if (
(status === RESULTS.GRANTED || status === RESULTS.LIMITED) &&
isMobilePushEnabled
) {
yield* call(registerDeviceToken)
}
}

function* enablePushNotifications() {
yield* call([PushNotifications, 'requestPermission'])
const { token, os } = yield* call([PushNotifications, 'getToken'])
yield* call(registerDeviceToken)

const audiusBackendInstance = yield* getContext('audiusBackendInstance')

Expand All @@ -52,8 +83,6 @@ function* enablePushNotifications() {
// have one right away when this function is called)
yield* call(waitForValue, getAccountUser)
yield* call(audiusBackendInstance.updatePushNotificationSettings, newSettings)

yield* call(audiusBackendInstance.registerDeviceToken, token, os)
}

function* disablePushNotifications() {
Expand Down Expand Up @@ -128,7 +157,7 @@ function* watchUpdatePushNotificationSettings() {
} else {
if (isOn === undefined) {
const pushNotificationSettings = yield* select(
getPushNotificationSettings
selectPushNotificationSettings
)
isOn = !pushNotificationSettings[action.notificationType]
}
Expand All @@ -149,27 +178,29 @@ function* watchUpdatePushNotificationSettings() {
}

function* watchRequestPushNotificationPermissions() {
yield* takeEvery(
actions.REQUEST_PUSH_NOTIFICATION_PERMISSIONS,
function* (_action: actions.RequestPushNotificationPermissions) {
const hasPermissions = yield* call([PushNotifications, 'hasPermission'])
if (!hasPermissions) {
// Request permission to send push notifications and enable all if accepted
yield* put(
actions.togglePushNotificationSetting(
PushNotificationSetting.MobilePush,
true
)
)
}
yield* takeEvery(actions.REQUEST_PUSH_NOTIFICATION_PERMISSIONS, function* () {
const { status } = yield* call(checkNotifications)
const isMobilePushEnabled = yield* call(getIsMobilePushEnabled)

if (
(status === RESULTS.GRANTED || status === RESULTS.LIMITED) &&
isMobilePushEnabled
) {
yield* call(registerDeviceToken)
} else if (status === RESULTS.BLOCKED || status === RESULTS.UNAVAILABLE) {
// do nothing
} else {
yield* put(
setVisibility({ drawer: 'EnablePushNotifications', visible: true })
)
}
)
})
}

export default function sagas() {
return [
...commonSettingsSagas(),
reregisterDeviceToken,
reregisterDeviceTokenOnStartup,
watchGetPushNotificationSettings,
watchUpdatePushNotificationSettings,
watchRequestPushNotificationPermissions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
} from 'common/store/pages/signon/selectors'
import { takeEvery, put, select } from 'typed-redux-saga'

import { remindUserToTurnOnNotifications } from 'app/components/notification-reminder/NotificationReminder'
import { EventNames } from 'app/types/analytics'

export function* watchSignUpSucceeded() {
Expand All @@ -33,6 +32,4 @@ function* handleSignUpSucceeded() {
handle: handleField.value
})
)

remindUserToTurnOnNotifications(put)
}
14 changes: 2 additions & 12 deletions packages/web/src/common/store/pages/signon/sagas.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
Genre,
MAX_HANDLE_LENGTH,
Name,
PushNotificationSetting,
accountActions,
accountSelectors,
cacheUsersSelectors,
Expand Down Expand Up @@ -53,8 +52,7 @@ import { getRouteOnCompletion, getSignOn } from './selectors'
import { FollowArtistsCategory, Pages } from './types'
import { checkHandle } from './verifiedChecker'

const { requestPushNotificationPermissions, togglePushNotificationSetting } =
settingsPageActions
const { requestPushNotificationPermissions } = settingsPageActions
const { getFeePayer } = solanaSelectors
const { saveCollection } = collectionsSocialActions
const { getUsers } = cacheUsersSelectors
Expand Down Expand Up @@ -439,13 +437,7 @@ function* signUp() {

const isNativeMobile = yield getContext('isNativeMobile')
if (isNativeMobile) {
// Request permission to send push notifications and enable all if accepted
yield put(
togglePushNotificationSetting(
PushNotificationSetting.MobilePush,
true
)
)
yield put(requestPushNotificationPermissions())
} else {
// Set the has request browser permission to true as the signon provider will open it
setHasRequestedBrowserPermission()
Expand Down Expand Up @@ -545,8 +537,6 @@ function* signIn(action) {
yield put(signOnActions.resetSignOn())
const isNativeMobile = yield getContext('isNativeMobile')
if (isNativeMobile) {
// If permissions not already enabled, request permission to send push notifications
// and enable all if accepted
yield put(requestPushNotificationPermissions())
} else {
setHasRequestedBrowserPermission()
Expand Down

0 comments on commit 79da3ee

Please sign in to comment.