Skip to content

fix: register device push token with backend on permission grant#1669

Open
ManAnRuck wants to merge 6 commits intomainfrom
reenable-push
Open

fix: register device push token with backend on permission grant#1669
ManAnRuck wants to merge 6 commits intomainfrom
reenable-push

Conversation

@ManAnRuck
Copy link
Copy Markdown
Member

Add useAddTokenMutation to NotificationsProvider and register the native device push token whenever notification permission is granted. Triggers on every app state change so tokens are re-registered after permission is granted while the app is backgrounded.

Add useAddTokenMutation to NotificationsProvider and register the native
device push token whenever notification permission is granted. Triggers
on every app state change so tokens are re-registered after permission is
granted while the app is backgrounded.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@ManAnRuck ManAnRuck self-assigned this Mar 1, 2026
Copilot AI review requested due to automatic review settings March 1, 2026 07:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Registers the native device push token with the backend from within the existing notifications permission state provider, so the backend can associate the device for push delivery once permission is granted.

Changes:

  • Add useAddTokenMutation to NotificationsProvider.
  • On appState changes, if notification permission is granted, fetch the native device push token and send it to the backend with the platform OS.

Comment on lines +73 to +79
Notifications.getPermissionsAsync().then(({ status }) => {
if (status === "granted") {
Notifications.getDevicePushTokenAsync()
.then(({ data: token }) => {
addToken({ variables: { token, os: Platform.OS } });
})
.catch(() => undefined);
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addToken(...) returns a Promise; if the mutation fails (e.g., auth/network error) this can create an unhandled rejection because the returned Promise is not awaited/handled. Handle the Promise (e.g., await in an async IIFE or .catch(...)) and consider handling errors from getPermissionsAsync() as well to avoid unhandled rejections in this effect.

Copilot uses AI. Check for mistakes.
Comment on lines +71 to +82
// Register device token with backend whenever permission is granted
useEffect(() => {
Notifications.getPermissionsAsync().then(({ status }) => {
if (status === "granted") {
Notifications.getDevicePushTokenAsync()
.then(({ data: token }) => {
addToken({ variables: { token, os: Platform.OS } });
})
.catch(() => undefined);
}
});
}, [appState, addToken]);
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This effect runs on every appState change, including transitions to inactive/background. Consider gating the registration logic to only run when the app is active (or on foreground) to avoid doing network/token work while backgrounded, which can be unreliable and is more expensive than needed for the stated goal.

Copilot uses AI. Check for mistakes.
Comment on lines +71 to +75
// Register device token with backend whenever permission is granted
useEffect(() => {
Notifications.getPermissionsAsync().then(({ status }) => {
if (status === "granted") {
Notifications.getDevicePushTokenAsync()
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notifications.getPermissionsAsync() is now called in two separate useEffects that both depend on appState (this one and the alreadyDenied effect below). Consider consolidating into a single permission check per app-state change (and then branching into both behaviors) to reduce duplicated work and keep the permission/token flow easier to follow.

Copilot uses AI. Check for mistakes.
ManAnRuck and others added 5 commits March 1, 2026 12:35
Updated the push token retrieval logic in the DevScreen component to use promise chaining instead of an async IIFE. This improves readability and maintains the same functionality for obtaining Expo and device push tokens.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ted hooks

- Create usePermissionStatus hook: gates getPermissionsAsync to active state only,
  eliminates duplicate permission checks
- Create useDeviceTokenRegistration hook: caches last token in useRef, handles
  addToken errors with .catch(), only fires when permission is granted
- Refactor NotificationsProvider to use new hooks, removing 3 effects and
  consolidating permission logic
- Remove dead alreadyDenied state (not exposed in context interface)
- Add unit tests for both hooks (14 test cases)

Fixes: unhandled promise on addToken, duplicate getPermissionsAsync calls,
unnecessary background/inactive state network calls, no token caching

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- PUSH_NOTIFICATIONS.md: Main feature doc (1140 lines, 12 Mermaid diagrams)
  Covers architecture, permissions, token registration, categories,
  deep-link routing, settings, UI components, file structure, config, testing
- PUSH_NOTIFICATION_ROUTING.md: Deep-dive routing doc (993 lines, 13 Mermaid diagrams)
  Covers type system, native push taps, URL scheme handling, routing logic,
  navigation strategies, E2E testing, web URL deep links

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants