From 2e31ff6d15b95c8e0ab32fcd64978dd1066c1d16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=A1vio=20Juvenal?= Date: Fri, 7 Feb 2025 09:49:59 -0300 Subject: [PATCH] clearProfilePushToken on logout --- app/(app)/index.tsx | 4 +- app/_layout.tsx | 2 + contexts/NotificationsContext.tsx | 66 +----------------------- utils/notifications.ts | 85 +++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 65 deletions(-) create mode 100644 utils/notifications.ts diff --git a/app/(app)/index.tsx b/app/(app)/index.tsx index 33f270f..b1a51e2 100644 --- a/app/(app)/index.tsx +++ b/app/(app)/index.tsx @@ -9,6 +9,7 @@ import { ThreadList } from "@/components/ThreadList"; import { ThreadListHeader } from "@/components/ThreadListHeader"; import { useAvatars } from "@/hooks/useAvatars"; import { useThreads } from "@/hooks/useThreads"; +import { clearProfilePushToken } from "@/utils/notifications"; export default function Index() { const { medplum, profile } = useMedplumContext(); @@ -21,7 +22,8 @@ export default function Index() { const { getAvatarURL, isLoading: isAvatarsLoading } = useAvatars(avatarReferences); const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); - const handleLogout = useCallback(() => { + const handleLogout = useCallback(async () => { + await clearProfilePushToken(medplum); medplum.signOut(); router.replace("/sign-in"); }, [medplum, router]); diff --git a/app/_layout.tsx b/app/_layout.tsx index f2d1a55..9955489 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -14,6 +14,7 @@ import * as SplashScreen from "expo-splash-screen"; import { StatusBar } from "expo-status-bar"; import { useColorScheme } from "nativewind"; import { useEffect } from "react"; +import { Alert } from "react-native"; import { GestureHandlerRootView } from "react-native-gesture-handler"; import { initialWindowMetrics, @@ -36,6 +37,7 @@ const medplum = new MedplumClient({ clientId: oauth2ClientId, storage: new ExpoClientStorage(), onUnauthenticated: () => { + Alert.alert("Your session has expired", "Please sign in again."); router.replace("/sign-in"); }, }); diff --git a/contexts/NotificationsContext.tsx b/contexts/NotificationsContext.tsx index 8cb0360..dab06a8 100644 --- a/contexts/NotificationsContext.tsx +++ b/contexts/NotificationsContext.tsx @@ -1,12 +1,11 @@ -import { MedplumClient } from "@medplum/core"; import { useMedplum } from "@medplum/react-hooks"; -import Constants from "expo-constants"; -import * as Device from "expo-device"; import * as Notifications from "expo-notifications"; import { router } from "expo-router"; import { createContext, useCallback, useContext, useEffect, useRef, useState } from "react"; import { Platform } from "react-native"; +import { getPushToken, updateProfilePushToken } from "@/utils/notifications"; + Notifications.setNotificationHandler({ handleNotification: async () => ({ shouldShowAlert: true, @@ -25,67 +24,6 @@ const NotificationsContext = createContext({ setUpPushNotifications: async () => false, }); -async function getPushToken() { - let token; - - if (!Device.isDevice || Platform.OS === "web") { - return; - } - - if (Platform.OS === "android") { - await Notifications.setNotificationChannelAsync("default", { - name: "default", - importance: Notifications.AndroidImportance.MAX, - vibrationPattern: [0, 250, 250, 250], - lightColor: "#FF231F7C", - }); - } - - try { - const projectId = Constants.expoConfig?.extra?.eas?.projectId; - if (!projectId) { - throw new Error("Missing EAS project ID"); - } - - token = await Notifications.getExpoPushTokenAsync({ - projectId, - }); - return token?.data; - } catch (error) { - console.error("Error getting push token:", error); - } -} - -async function updateProfilePushToken(medplum: MedplumClient, token: string) { - try { - const profile = medplum.getProfile(); - if (!profile) return; - - // Check if token already exists and matches - const existingToken = profile.extension?.find( - (e) => e.url === "https://medplum.com/push-token", - )?.valueString; - - if (existingToken === token) { - return; // Token hasn't changed, no need to update - } - - // Update the token - const extensions = - profile.extension?.filter((e) => e.url !== "https://medplum.com/push-token") || []; - extensions.push({ - url: "https://medplum.com/push-token", - valueString: token, - }); - await medplum.updateResource({ - ...profile, - extension: extensions, - }); - } catch (error) { - console.error("Error updating push token in Medplum:", error); - } -} - function handleMessageNotificationInteraction(response: Notifications.NotificationResponse) { const data = response.notification.request.content.data; if (data.threadId) { diff --git a/utils/notifications.ts b/utils/notifications.ts new file mode 100644 index 0000000..8c7bbba --- /dev/null +++ b/utils/notifications.ts @@ -0,0 +1,85 @@ +import { MedplumClient } from "@medplum/core"; +import Constants from "expo-constants"; +import * as Device from "expo-device"; +import * as Notifications from "expo-notifications"; +import { Platform } from "react-native"; + +export async function getPushToken() { + let token; + + if (!Device.isDevice || Platform.OS === "web") { + return; + } + + if (Platform.OS === "android") { + await Notifications.setNotificationChannelAsync("default", { + name: "default", + importance: Notifications.AndroidImportance.MAX, + vibrationPattern: [0, 250, 250, 250], + lightColor: "#FF231F7C", + }); + } + + try { + const projectId = Constants.expoConfig?.extra?.eas?.projectId; + if (!projectId) { + throw new Error("Missing EAS project ID"); + } + + token = await Notifications.getExpoPushTokenAsync({ + projectId, + }); + return token?.data; + } catch (error) { + console.error("Error getting push token:", error); + } +} + +export async function updateProfilePushToken(medplum: MedplumClient, token: string) { + try { + const profile = medplum.getProfile(); + if (!profile) return; + + // Check if token already exists and matches + const existingToken = profile.extension?.find( + (e) => e.url === "https://medplum.com/push-token", + )?.valueString; + + if (existingToken === token) { + return; // Token hasn't changed, no need to update + } + + // Update the token + const extensions = + profile.extension?.filter((e) => e.url !== "https://medplum.com/push-token") || []; + extensions.push({ + url: "https://medplum.com/push-token", + valueString: token, + }); + await medplum.updateResource({ + ...profile, + extension: extensions, + }); + } catch (error) { + console.error("Error updating push token in Medplum:", error); + } +} + +export async function clearProfilePushToken(medplum: MedplumClient) { + try { + const profile = medplum.getProfile(); + if (!profile) return; + + // Filter out the push token extension + const extensions = + profile.extension?.filter((e) => e.url !== "https://medplum.com/push-token") || []; + + // Update the profile with the filtered extensions + await medplum.updateResource({ + ...profile, + extension: extensions, + }); + } catch (error) { + console.error("Error clearing push token from Medplum:", error); + } +}