-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Push Notifications #47
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't register a firebase session from secure keys on any user facing app. For a non-authenticated push notification flow, you have to set up an open endpoint that accepts the token, and have throttling mechanisms for preventing missuse
App.js
Outdated
const googleFontsLoaded = useFonts({ | ||
Roboto_400Regular, | ||
Roboto_500Medium, | ||
Roboto_700Bold, | ||
Roboto_900Black, | ||
}); | ||
|
||
useEffect(() => { | ||
registerForPushNotificationsAsync(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't happen on app mount, as this will trigger the push notification dialog immediately in app
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm.. i'll use a callback so it only renders initially
finalStatus = status; | ||
} | ||
if (finalStatus !== 'granted') { | ||
Alert.alert('Failed to get push token for push notification!'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please localize all strings. Also, this will trigger every app mount, so this is only accounting for the happy path right now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, useTranslations()
is a hook and this isn't a functional component, it's just a function that doesn't need to return anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how can i bypass?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can access the i18n instance directly instead (config/i18n
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks l like this is still based on app mount logic -- we should make all notification logic based on notification UX states (threading through the on boarding permissions, so we only prompt the dialogue after users have accepted the first time, in our UI)
import * as Permissions from 'expo-permissions'; | ||
import Constants from 'expo-constants'; | ||
|
||
export const sendTokenToBackend = (_token) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
export const sendTokenToBackend = (_token) => { | |
const sendTokenToBackend = (_token) => { |
token: _token, | ||
}), | ||
}) | ||
.then((response) => response.json()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These console logs should be removed / we should gracefully handle the failure case
// send post request to store token in backend | ||
sendTokenToBackend(token); | ||
} else { | ||
Alert.alert('Must use physical device for Push Notifications'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this the fallback? is there a specific case for this? Can this be guaranteed to be case exhaustive?
useEffect(() => { | ||
if (!isInitialRender) { | ||
setIsInitialRender(true); | ||
RegisterForPushNotificationsAsync(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This probably shouldn't occur on app mount. This will force the push notification permission on first app launch, where we want this to occur after an explanation in onboarding.
Also:
- if you're trying to make an effect happen once on mount, just remove the dependency chain (
[]
empty array for it) - if you want an effect to happen once, but conditionally, use a
memo
, so that this state logic doesn't affect renders set
properties fromuseState
hook do not need to be included in dependency chains as the references are guaranteed to not mutate
finalStatus = status; | ||
} | ||
if (finalStatus !== 'granted') { | ||
Alert.alert('Failed to get push token for push notification!'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can access the i18n instance directly instead (config/i18n
).
// eslint-disable-next-line no-unused-vars | ||
export const handleNotification = (_notification) => { | ||
Vibration.vibrate(); | ||
}; | ||
|
||
export const notificationSubscription = Notifications.addListener( | ||
handleNotification | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// eslint-disable-next-line no-unused-vars | |
export const handleNotification = (_notification) => { | |
Vibration.vibrate(); | |
}; | |
export const notificationSubscription = Notifications.addListener( | |
handleNotification | |
); | |
export const initNotificationSubscription = () => Notifications.addListener(Vibration.vibrate); |
And initialize this at the same place as other initialization steps (like sentry, iin app.js), rather than having this occur implicitly by the file being loaded
Summary:
Added push notification using expo v.37. sdk push notifications. App is now connected to firebase to store the tokens.
Tokens are stored using timestamps for anonymity, and are not stored in the store for added security measures.
Backend flask app would send push notification to expo's frontend when admin clicks 'approve' 🍰
User Flow:
User clicks 'approve' in flask app.
Notification shows up in mobile:
🌵 Message me for firebase secrets! 🐑