import {AntDesign, Ionicons} from "@expo/vector-icons"; import React, {useCallback, useState} from "react"; import {Button, Checkbox, Text, View} from "react-native-ui-lib"; import {ScrollView, StyleSheet} from "react-native"; import {colorMap} from "@/contexts/SettingsContext"; import {TouchableOpacity} from "react-native-gesture-handler"; import {fetchGoogleCalendarEvents} from "@/calendar-integration/google-calendar-utils"; import {fetchMicrosoftCalendarEvents} from "@/calendar-integration/microsoft-calendar-utils"; import {useCreateEventFromProvider} from "@/hooks/firebase/useCreateEvent"; import {useAuthContext} from "@/contexts/AuthContext"; import {useUpdateUserData} from "@/hooks/firebase/useUpdateUserData"; import {GoogleSignin} from "@react-native-google-signin/google-signin"; import * as AuthSession from "expo-auth-session"; import debounce from "debounce"; GoogleSignin.configure({ webClientId: "406146460310-hjadmfa1gg4ptaouira5rkhu0djlo5ut.apps.googleusercontent.com", scopes: ["profile", "email"], // Note: add calendar scope }); const GoogleLogin = async () => { return await GoogleSignin.signIn(); }; const microsoftConfig = { clientId: "13c79071-1066-40a9-9f71-b8c4b138b4af", // Replace with your Microsoft client ID redirectUri: AuthSession.makeRedirectUri({path: "settings"}), // Generate redirect URI automatically for Expo scopes: [ "openid", "profile", "email", "offline_access", "Calendars.ReadWrite", // Scope for reading calendar events ], authorizationEndpoint: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize", tokenEndpoint: "https://login.microsoftonline.com/common/oauth2/v2.0/token" }; const CalendarSettingsPage = (props: { setSelectedPage: (page: number) => void; }) => { const [startDate, setStartDate] = useState(true); const {profileData} = useAuthContext(); const [selectedColor, setSelectedColor] = useState(profileData?.eventColor ?? colorMap.pink); const [previousSelectedColor, setPreviousSelectedColor] = useState(profileData?.eventColor ?? colorMap.pink); const {mutateAsync: createEventFromProvider} = useCreateEventFromProvider(); const {mutateAsync: updateUserData} = useUpdateUserData(); const fetchAndSaveGoogleEvents = () => { const timeMin = new Date(new Date().setHours(0, 0, 0, 0)); const timeMax = new Date( new Date(new Date().setHours(0, 0, 0, 0)).setDate(timeMin.getDate() + 30) ); fetchGoogleCalendarEvents( profileData?.googleToken, timeMin.toISOString().slice(0, -5) + "Z", timeMax.toISOString().slice(0, -5) + "Z", ).then((response) => { response?.forEach((item) => saveData(item)); }); }; async function saveData(item: any) { await createEventFromProvider(item); } const fetchAndSaveMicrosoftEvents = () => { const startDateTime = new Date(new Date().setHours(0, 0, 0, 0)); const endDateTime = new Date( new Date(new Date().setHours(0, 0, 0, 0)).setDate( startDateTime.getDate() + 30 ) ); fetchMicrosoftCalendarEvents( profileData?.microsoftToken, startDateTime.toISOString().slice(0, -5) + "Z", endDateTime.toISOString().slice(0, -5) + "Z" ).then((response) => { console.log(response) response?.forEach((item) => saveData(item)); }); }; const handleGoogleLogin = async () => { try { const response = await GoogleLogin(); if (response) { const googleUserData = response.data; let idToken = googleUserData?.idToken; if (idToken) { await updateUserData({newUserData: {googleToken: idToken}}); } } } catch (apiError) { console.log(apiError || "Something went wrong"); } }; 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")}`, }); console.log("Token response status:", tokenResponse.status); if (!tokenResponse.ok) { console.error("Token exchange failed:", await tokenResponse.text()); return; } const tokenData = await tokenResponse.json(); console.log("Token data received:", tokenData); if (tokenData?.id_token) { console.log("ID token received, updating user data..."); await updateUserData({newUserData: {microsoftToken: tokenData.access_token}}); 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 debouncedUpdateUserData = useCallback( debounce(async (color: string) => { try { await updateUserData({ newUserData: { eventColor: color } }); } catch (error) { console.error("Failed to update color:", error); setSelectedColor(previousSelectedColor) } }, 500), [] ); const handleChangeColor = (color: string) => { setPreviousSelectedColor(selectedColor) setSelectedColor(color); debouncedUpdateUserData(color); }; return ( props.setSelectedPage(0)}> Return to main settings Calendar settings Event Color Preference handleChangeColor(colorMap.pink)}> {selectedColor == colorMap.pink && ( )} handleChangeColor(colorMap.orange)}> {selectedColor == colorMap.orange && ( )} handleChangeColor(colorMap.green)}> {selectedColor == colorMap.green && ( )} handleChangeColor(colorMap.teal)}> {selectedColor == colorMap.teal && ( )} handleChangeColor(colorMap.purple)}> {selectedColor == colorMap.purple && ( )} Weekly Start Date setStartDate(true)} /> Sundays {" "} (default) setStartDate(false)} /> Mondays Add Calendar