import {createContext, FC, ReactNode, useContext, useEffect, useState} from "react"; import * as SplashScreen from "expo-splash-screen"; import auth, {FirebaseAuthTypes} from "@react-native-firebase/auth"; import {useRouter} from "expo-router"; import firestore from "@react-native-firebase/firestore"; import {UserProfile} from "@/hooks/firebase/types/profileTypes"; import * as Notifications from 'expo-notifications'; import * as Device from 'expo-device'; import Constants from 'expo-constants'; import {Platform} from 'react-native'; import {useQueryClient} from "@tanstack/react-query"; export enum ProfileType { "PARENT" = "parent", "CHILD" = "child", "CAREGIVER" = "caregiver", FAMILY_DEVICE = "FAMILY_DEVICE" } interface IAuthContext { user: FirebaseAuthTypes.User | null, profileType?: ProfileType, profileData?: UserProfile, setProfileData: (profileData: UserProfile) => void, setRedirectOverride: (val: boolean) => void, refreshProfileData: () => Promise } Notifications.setNotificationHandler({ handleNotification: async () => ({ shouldShowAlert: true, shouldPlaySound: true, shouldSetBadge: true, }), }); Notifications.addNotificationReceivedListener(notification => { console.log('Notification received:', notification); }); async function registerForPushNotificationsAsync() { if (Platform.OS === 'android') { await Notifications.setNotificationChannelAsync('default', { name: 'default', importance: Notifications.AndroidImportance.MAX, vibrationPattern: [0, 250, 250, 250], lightColor: '#FF231F7C', }); } if (Device.isDevice) { const {status: existingStatus} = await Notifications.getPermissionsAsync(); let finalStatus = existingStatus; if (existingStatus !== 'granted') { const {status} = await Notifications.requestPermissionsAsync(); finalStatus = status; } if (finalStatus !== 'granted') { // alert('Failed to get push token for push notification!'); return; } const projectId = Constants?.expoConfig?.extra?.eas?.projectId ?? Constants?.easConfig?.projectId; if (!projectId) { alert('Project ID not found'); return; } try { const token = (await Notifications.getExpoPushTokenAsync({projectId})).data; console.log('Push Token:', token); return token; } catch (error) { // alert(`Error getting push token: ${error}`); throw error; } } else { // alert('Must use a physical device for push notifications'); } } const AuthContext = createContext(undefined!) export const AuthContextProvider: FC<{ children: ReactNode }> = ({children}) => { const [user, setUser] = useState(null); const [initializing, setInitializing] = useState(true); const [profileType, setProfileType] = useState(undefined); const [profileData, setProfileData] = useState(undefined); const [redirectOverride, setRedirectOverride] = useState(false); const {replace} = useRouter(); const ready = !initializing; const queryClient = useQueryClient(); const onAuthStateChangedHandler = async (authUser: FirebaseAuthTypes.User | null) => { if (!redirectOverride) { setUser(authUser); if (authUser) { await refreshProfileData(authUser); const pushToken = await registerForPushNotificationsAsync(); if (pushToken) { await savePushTokenToFirestore(authUser.uid, pushToken); } } if (initializing) setInitializing(false); } }; const refreshProfileData = async (user?: FirebaseAuthTypes.User) => { const authUser = user ?? auth().currentUser if (authUser) { try { const documentSnapshot = await firestore() .collection("Profiles") .doc(authUser.uid) .get(); if (documentSnapshot.exists) { setProfileType(documentSnapshot.data()?.userType); setProfileData(documentSnapshot.data() as UserProfile); } } catch (error) { setProfileType(undefined); setProfileData(undefined); } } }; const savePushTokenToFirestore = async (uid: string, token: string) => { try { await firestore().collection("Profiles").doc(uid).update({ pushToken: token, }); } catch (error) { console.error('Error saving push token to Firestore:', error); } }; useEffect(() => { const subscriber = auth().onAuthStateChanged(onAuthStateChangedHandler); return subscriber; }, []); useEffect(() => { if (!initializing) { if(auth().currentUser) { setTimeout(() => SplashScreen.hideAsync(), 1000); } else { SplashScreen.hideAsync(); } } }, [initializing]); useEffect(() => { if (ready && user && !redirectOverride) { replace({pathname: "/(auth)/calendar"}); } else if (ready && !user && !redirectOverride) { replace({pathname: "/(unauth)"}); } }, [user, ready, redirectOverride]); useEffect(() => { const handleNotification = async (notification: Notifications.Notification) => { queryClient.invalidateQueries({queryKey: ["notifications"]}); }; const sub = Notifications.addNotificationReceivedListener(handleNotification); return () => sub.remove(); }, []); if (!ready) { return null; } return ( {children} ); }; export const useAuthContext = () => useContext(AuthContext)!;