import {useAuthContext} from "@/contexts/AuthContext"; import {useEffect} from "react"; import {useUpdateUserData} from "@/hooks/firebase/useUpdateUserData"; import {useFetchAndSaveGoogleEvents} from "@/hooks/useFetchAndSaveGoogleEvents"; import {useFetchAndSaveOutlookEvents} from "@/hooks/useFetchAndSaveOutlookEvents"; import {useFetchAndSaveAppleEvents} from "@/hooks/useFetchAndSaveAppleEvents"; import * as WebBrowser from "expo-web-browser"; import * as Google from "expo-auth-session/providers/google"; import * as AuthSession from "expo-auth-session"; import * as AppleAuthentication from "expo-apple-authentication"; const googleConfig = { androidClientId: "406146460310-2u67ab2nbhu23trp8auho1fq4om29fc0.apps.googleusercontent.com", iosClientId: "406146460310-2u67ab2nbhu23trp8auho1fq4om29fc0.apps.googleusercontent.com", webClientId: "406146460310-2u67ab2nbhu23trp8auho1fq4om29fc0.apps.googleusercontent.com", scopes: [ "email", "profile", "https://www.googleapis.com/auth/calendar.events.owned", ], extraParams: { access_type: "offline", }, }; const microsoftConfig = { clientId: "13c79071-1066-40a9-9f71-b8c4b138b4af", redirectUri: AuthSession.makeRedirectUri({path: "settings"}), scopes: [ "openid", "profile", "email", "offline_access", "Calendars.ReadWrite", "User.Read", ], authorizationEndpoint: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize", tokenEndpoint: "https://login.microsoftonline.com/common/oauth2/v2.0/token", }; export const useCalSync = () => { const {profileData} = useAuthContext(); const {mutateAsync: updateUserData} = useUpdateUserData(); const {mutateAsync: fetchAndSaveGoogleEvents, isLoading: isSyncingGoogle} = useFetchAndSaveGoogleEvents(); const {mutateAsync: fetchAndSaveOutlookEvents, isLoading: isSyncingOutlook} = useFetchAndSaveOutlookEvents(); const {mutateAsync: fetchAndSaveAppleEvents, isLoading: isSyncingApple} = useFetchAndSaveAppleEvents(); WebBrowser.maybeCompleteAuthSession(); const [_, response, promptAsync] = Google.useAuthRequest(googleConfig); useEffect(() => { signInWithGoogle(); }, [response]); const signInWithGoogle = async () => { try { if (response?.type === "success") { const {accessToken, refreshToken} = response?.authentication!; const userInfoResponse = await fetch( "https://www.googleapis.com/oauth2/v3/userinfo", { headers: {Authorization: `Bearer ${accessToken}`}, } ); console.log(response) const userInfo = await userInfoResponse.json(); const googleMail = userInfo.email; let googleAccounts = profileData?.googleAccounts || {}; const updatedGoogleAccounts = { ...googleAccounts, [googleMail]: {accessToken, refreshToken}, }; await updateUserData({ newUserData: {googleAccounts: updatedGoogleAccounts}, }); await fetchAndSaveGoogleEvents({ token: accessToken, refreshToken: refreshToken, email: googleMail, }); } } catch (error) { console.error("Error during Google sign-in:", error); } }; const handleMicrosoftSignIn = async () => { try { console.log("Starting Microsoft sign-in..."); const authRequest = new AuthSession.AuthRequest({ clientId: microsoftConfig.clientId, scopes: microsoftConfig.scopes, redirectUri: microsoftConfig.redirectUri, responseType: AuthSession.ResponseType.Code, usePKCE: true, // Enable PKCE }); console.log("Auth request created:", authRequest); const authResult = await authRequest.promptAsync({ authorizationEndpoint: microsoftConfig.authorizationEndpoint, }); console.log("Auth result:", authResult); if (authResult.type === "success" && authResult.params?.code) { const code = authResult.params.code; console.log("Authorization code received:", code); // Exchange authorization code for tokens const tokenResponse = await fetch(microsoftConfig.tokenEndpoint, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", }, body: `client_id=${ microsoftConfig.clientId }&redirect_uri=${encodeURIComponent( microsoftConfig.redirectUri )}&grant_type=authorization_code&code=${code}&code_verifier=${ authRequest.codeVerifier }&scope=${encodeURIComponent( "https://graph.microsoft.com/Calendars.ReadWrite offline_access User.Read" )}`, }); console.log("Token response status:", tokenResponse.status); if (!tokenResponse.ok) { const errorText = await tokenResponse.text(); console.error("Token exchange failed:", errorText); return; } const tokenData = await tokenResponse.json(); console.log("Token data received:", tokenData); if (tokenData?.access_token) { console.log("Access token received, fetching user info..."); // Fetch user info from Microsoft Graph API to get the email const userInfoResponse = await fetch( "https://graph.microsoft.com/v1.0/me", { headers: { Authorization: `Bearer ${tokenData.access_token}`, }, } ); const userInfo = await userInfoResponse.json(); console.log("User info received:", userInfo); if (userInfo.error) { console.error("Error fetching user info:", userInfo.error); } else { const outlookMail = userInfo.mail || userInfo.userPrincipalName; let microsoftAccounts = profileData?.microsoftAccounts; const updatedMicrosoftAccounts = microsoftAccounts ? {...microsoftAccounts, [outlookMail]: tokenData.access_token} : {[outlookMail]: tokenData.access_token}; await updateUserData({ newUserData: {microsoftAccounts: updatedMicrosoftAccounts}, }); await fetchAndSaveOutlookEvents( tokenData.access_token, outlookMail ); console.log("User data updated successfully."); } } } else { console.warn("Authentication was not successful:", authResult); } } catch (error) { console.error("Error during Microsoft sign-in:", error); } }; const handleAppleSignIn = async () => { try { console.log("Starting Apple Sign-in..."); const credential = await AppleAuthentication.signInAsync({ requestedScopes: [ AppleAuthentication.AppleAuthenticationScope.EMAIL, AppleAuthentication.AppleAuthenticationScope.FULL_NAME, ], }); console.log("Apple sign-in result:", credential); alert(JSON.stringify(credential)) const appleToken = credential.identityToken; const appleMail = credential.email!; if (appleToken) { console.log("Apple ID token received. Fetch user info if needed..."); let appleAcounts = profileData?.appleAccounts; const updatedAppleAccounts = appleAcounts ? {...appleAcounts, [appleMail]: appleToken} : {[appleMail]: appleToken}; await updateUserData({ newUserData: {appleAccounts: updatedAppleAccounts}, }); console.log("User data updated with Apple ID token."); await fetchAndSaveAppleEvents({token: appleToken, email: appleMail!}); } else { console.warn( "Apple authentication was not successful or email was hidden." ); } } catch (error) { console.error("Error during Apple Sign-in:", error); } }; let isConnectedToGoogle = false; if (profileData?.googleAccounts) { Object.values(profileData?.googleAccounts).forEach((item) => { if (item !== null) { isConnectedToGoogle = true; return; } }); } let isConnectedToMicrosoft = false; const microsoftAccounts = profileData?.microsoftAccounts; if (microsoftAccounts) { Object.values(profileData?.microsoftAccounts).forEach((item) => { if (item !== null) { isConnectedToMicrosoft = true; return; } }); } let isConnectedToApple = false; if (profileData?.appleAccounts) { Object.values(profileData?.appleAccounts).forEach((item) => { if (item !== null) { isConnectedToApple = true; return; } }); } return { handleAppleSignIn, handleMicrosoftSignIn, handleGoogleSignIn: signInWithGoogle, handleStartGoogleSignIn: promptAsync, fetchAndSaveOutlookEvents, fetchAndSaveAppleEvents, fetchAndSaveGoogleEvents, isConnectedToApple, isConnectedToMicrosoft, isConnectedToGoogle, isSyncingOutlook, isSyncingGoogle, isSyncingApple, isSyncing: isSyncingApple || isSyncingOutlook || isSyncingGoogle } }