import * as Device from "expo-device"; import * as Notifications from "expo-notifications"; import { useEffect, useState } from "react"; import { Platform } from "react-native"; import { version as packageVersion } from '../package.json'; type RegisterTokenParams = { apiKey?: string | null; backendUrl: string; appVersion?: string; locale?: string; topics?: string[]; }; export function usePushNotifications({ apiKey, backendUrl, appVersion = packageVersion, locale, topics }: RegisterTokenParams & { apiKey?: string | null }) { const [expoPushToken, setExpoPushToken] = useState(null); const [registered, setRegistered] = useState(false); const [registrationError, setRegistrationError] = useState(null); useEffect(() => { if (!apiKey) { console.log("No API key available, skipping registration"); return; } const registerTokenWithBackend = async (token: string) => { console.log("Attempting to register token with backend..."); const res = await fetch(`${backendUrl}/register-token`, { method: "POST", headers: { "Content-Type": "application/json", "X-API-Key": apiKey }, body: JSON.stringify({ token, platform: Platform.OS, app_ver: appVersion, locale, topics }) }); if (!res.ok) { const errorText = await res.text(); console.error("Backend registration failed:", res.status, errorText); throw new Error(`Failed to register token: ${res.status}`); } console.log("Push token registered with backend ✅"); }; (async () => { try { const token = await registerForPushNotificationsAsync(); if (token) { console.log("Got push token:", token); setExpoPushToken(token); await registerTokenWithBackend(token); setRegistered(true); setRegistrationError(null); } else { console.log("No push token received"); setRegistrationError("Could not get push token"); } } catch (err) { console.error("Registration error:", err); setRegistered(false); setRegistrationError(err instanceof Error ? err.message : "Failed to register push token"); } })(); }, [apiKey, backendUrl, appVersion, locale, topics]); const unregisterToken = async () => { if (!expoPushToken || !apiKey) { console.log("Cannot unregister: missing token or API key"); return; } try { console.log("Unregistering token from backend..."); const res = await fetch(`${backendUrl}/unregister-token`, { method: "POST", headers: { "Content-Type": "application/json", "X-API-Key": apiKey, }, body: JSON.stringify({ token: expoPushToken, platform: Platform.OS, app_ver: appVersion, locale, topics }) }); if (!res.ok) { throw new Error(`Unregister failed: ${res.status}`); } console.log("Push token unregistered from backend ✅"); setExpoPushToken(null); setRegistered(false); } catch (error) { console.error("Failed to unregister token:", error); } }; return { expoPushToken, registered, registrationError, unregisterToken }; } async function registerForPushNotificationsAsync() { if (!Device.isDevice) { console.log("Must use physical device for Push Notifications"); return null; } const { status: existingStatus } = await Notifications.getPermissionsAsync(); let finalStatus = existingStatus; if (existingStatus !== "granted") { const { status } = await Notifications.requestPermissionsAsync(); finalStatus = status; } if (finalStatus !== "granted") { console.log("Permission not granted for push notifications."); return null; } const tokenData = await Notifications.getExpoPushTokenAsync(); const token = tokenData.data; console.log("Expo Push Token:", token); // Android-specific setup if (Platform.OS === "android") { await Notifications.setNotificationChannelAsync("default", { name: "default", importance: Notifications.AndroidImportance.MAX, vibrationPattern: [0, 250, 250, 250], lightColor: "#FF231F7C" }); } return token; }