mirror of
https://github.com/urosran/cally.git
synced 2025-07-10 15:17:17 +00:00
195 lines
6.2 KiB
TypeScript
195 lines
6.2 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,
|
|
setRedirectOverride: (val: boolean) => 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 [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) {
|
|
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) => {
|
|
// const eventId = notification?.request?.content?.data?.eventId;
|
|
//
|
|
// // if (eventId) {
|
|
// queryClient.invalidateQueries(['events']);
|
|
// // }
|
|
// };
|
|
//
|
|
// const sub = Notifications.addNotificationReceivedListener(handleNotification);
|
|
//
|
|
// return () => sub.remove();
|
|
// }, []);
|
|
|
|
if (!ready) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<AuthContext.Provider
|
|
value={{user, profileType, profileData, setProfileData, refreshProfileData, setRedirectOverride}}>
|
|
{children}
|
|
</AuthContext.Provider>
|
|
);
|
|
};
|
|
|
|
|
|
export const useAuthContext = () => useContext(AuthContext)!;
|