Files
cally/contexts/AuthContext.tsx
2024-10-19 17:20:34 +02:00

186 lines
5.7 KiB
TypeScript

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 "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,
refreshProfileData: () => Promise<void>
}
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<IAuthContext>(undefined!)
export const AuthContextProvider: FC<{ children: ReactNode }> = ({children}) => {
const [user, setUser] = useState<FirebaseAuthTypes.User | null>(null);
const [initializing, setInitializing] = useState(true);
const [profileType, setProfileType] = useState<ProfileType | undefined>(undefined);
const [profileData, setProfileData] = useState<UserProfile | undefined>(undefined);
const {replace} = useRouter();
const ready = !initializing;
const queryClient = useQueryClient();
const onAuthStateChangedHandler = async (authUser: FirebaseAuthTypes.User | null) => {
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) {
SplashScreen.hideAsync();
}
}, [initializing]);
useEffect(() => {
if (ready && user) {
replace({pathname: "/(auth)/calendar"});
} else if (ready && !user) {
replace({pathname: "/(unauth)"});
}
}, [user, ready]);
useEffect(() => {
const sub = Notifications.addNotificationReceivedListener(notification => {
const eventId = notification?.request?.content?.data?.eventId;
if (eventId) {
queryClient.invalidateQueries(['events']);
}
});
return () => sub.remove()
}, []);
if (!ready) {
return null;
}
return (
<AuthContext.Provider value={{user, profileType, profileData, setProfileData, refreshProfileData}}>
{children}
</AuthContext.Provider>
);
};
export const useAuthContext = () => useContext(AuthContext)!;