mirror of
https://github.com/urosran/cally.git
synced 2025-11-26 16:34:54 +00:00
852 lines
28 KiB
TypeScript
852 lines
28 KiB
TypeScript
import { AntDesign, Ionicons } from "@expo/vector-icons";
|
|
import React, { useCallback, useEffect, useState } from "react";
|
|
import { Button, Checkbox, Text, View } from "react-native-ui-lib";
|
|
import { ActivityIndicator, Alert, ScrollView, StyleSheet } from "react-native";
|
|
import { TouchableOpacity } from "react-native-gesture-handler";
|
|
import { useAuthContext } from "@/contexts/AuthContext";
|
|
import { useUpdateUserData } from "@/hooks/firebase/useUpdateUserData";
|
|
import debounce from "debounce";
|
|
import AppleIcon from "@/assets/svgs/AppleIcon";
|
|
import GoogleIcon from "@/assets/svgs/GoogleIcon";
|
|
import OutlookIcon from "@/assets/svgs/OutlookIcon";
|
|
import * as AuthSession from "expo-auth-session";
|
|
import * as Google from "expo-auth-session/providers/google";
|
|
import * as WebBrowser from "expo-web-browser";
|
|
import { UserProfile } from "@firebase/auth";
|
|
import { useFetchAndSaveGoogleEvents } from "@/hooks/useFetchAndSaveGoogleEvents";
|
|
import { useFetchAndSaveOutlookEvents } from "@/hooks/useFetchAndSaveOutlookEvents";
|
|
import { useFetchAndSaveAppleEvents } from "@/hooks/useFetchAndSaveAppleEvents";
|
|
import * as AppleAuthentication from "expo-apple-authentication";
|
|
import ExpoLocalization from "expo-localization/src/ExpoLocalization";
|
|
import { colorMap } from "@/constants/colorMap";
|
|
import { useAtom } from "jotai";
|
|
import { settingsPageIndex } from "../calendar/atoms";
|
|
import CalendarSettingsDialog from "./calendar_components/CalendarSettingsDialog";
|
|
|
|
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",
|
|
],
|
|
};
|
|
|
|
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",
|
|
};
|
|
|
|
const CalendarSettingsPage = () => {
|
|
const { profileData } = useAuthContext();
|
|
const [pageIndex, setPageIndex] = useAtom(settingsPageIndex);
|
|
const [firstDayOfWeek, setFirstDayOfWeek] = useState<string>(
|
|
profileData?.firstDayOfWeek ??
|
|
ExpoLocalization.getCalendars()[0].firstWeekday === 1
|
|
? "Mondays"
|
|
: "Sundays"
|
|
);
|
|
const [isModalVisible, setModalVisible] = useState<boolean>(false);
|
|
const [selectedService, setSelectedService] = useState<
|
|
"google" | "outlook" | "apple"
|
|
>("google");
|
|
const [selectedEmail, setSelectedEmail] = useState<string>("");
|
|
|
|
const showConfirmationDialog = (
|
|
serviceName: "google" | "outlook" | "apple",
|
|
email: string
|
|
) => {
|
|
setSelectedService(serviceName);
|
|
setSelectedEmail(email);
|
|
setModalVisible(true);
|
|
};
|
|
|
|
const handleConfirm = () => {
|
|
clearToken(selectedService, selectedEmail);
|
|
setModalVisible(false);
|
|
};
|
|
|
|
const handleCancel = () => {
|
|
setModalVisible(false);
|
|
};
|
|
|
|
const [selectedColor, setSelectedColor] = useState<string>(
|
|
profileData?.eventColor ?? colorMap.pink
|
|
);
|
|
const [previousSelectedColor, setPreviousSelectedColor] = useState<string>(
|
|
profileData?.eventColor ?? colorMap.pink
|
|
);
|
|
|
|
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 = response.authentication?.accessToken;
|
|
|
|
const userInfoResponse = await fetch(
|
|
"https://www.googleapis.com/oauth2/v3/userinfo",
|
|
{
|
|
headers: { Authorization: `Bearer ${accessToken}` },
|
|
}
|
|
);
|
|
|
|
const userInfo = await userInfoResponse.json();
|
|
const googleMail = userInfo.email;
|
|
|
|
let googleAccounts = profileData?.googleAccounts;
|
|
const updatedGoogleAccounts = googleAccounts
|
|
? { ...googleAccounts, [googleMail]: accessToken }
|
|
: { [googleMail]: accessToken };
|
|
|
|
await updateUserData({
|
|
newUserData: { googleAccounts: updatedGoogleAccounts },
|
|
});
|
|
|
|
await fetchAndSaveGoogleEvents({
|
|
token: accessToken,
|
|
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 };
|
|
|
|
// Update user data with Microsoft token and email
|
|
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);
|
|
|
|
const appleToken = credential.identityToken;
|
|
const appleMail = credential.email;
|
|
|
|
if (appleToken) {
|
|
console.log("Apple ID token received. Fetch user info if needed...");
|
|
|
|
await updateUserData({
|
|
newUserData: { appleToken, appleMail },
|
|
});
|
|
|
|
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);
|
|
}
|
|
};
|
|
|
|
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 debouncedUpdateFirstDayOfWeek = useCallback(
|
|
debounce(async (firstDayOfWeek: string) => {
|
|
try {
|
|
await updateUserData({
|
|
newUserData: {
|
|
firstDayOfWeek,
|
|
},
|
|
});
|
|
} catch (error) {
|
|
console.error("Failed to update first day of week:", error);
|
|
}
|
|
}, 500),
|
|
[]
|
|
);
|
|
|
|
const handleChangeFirstDayOfWeek = (firstDayOfWeek: string) => {
|
|
setFirstDayOfWeek(firstDayOfWeek === "Sundays" ? "Mondays" : "Sundays");
|
|
debouncedUpdateFirstDayOfWeek(
|
|
firstDayOfWeek === "Sundays" ? "Mondays" : "Sundays"
|
|
);
|
|
};
|
|
|
|
const handleChangeColor = (color: string) => {
|
|
setPreviousSelectedColor(selectedColor);
|
|
setSelectedColor(color);
|
|
debouncedUpdateUserData(color);
|
|
};
|
|
|
|
const clearToken = async (
|
|
provider: "google" | "outlook" | "apple",
|
|
email: string
|
|
) => {
|
|
const newUserData: Partial<UserProfile> = {};
|
|
if (provider === "google") {
|
|
let googleAccounts = profileData?.googleAccounts;
|
|
if (googleAccounts) {
|
|
googleAccounts[email] = null;
|
|
newUserData.googleAccounts = googleAccounts;
|
|
}
|
|
} else if (provider === "outlook") {
|
|
let microsoftAccounts = profileData?.microsoftAccounts;
|
|
if (microsoftAccounts) {
|
|
microsoftAccounts[email] = null;
|
|
newUserData.microsoftAccounts = microsoftAccounts;
|
|
}
|
|
} else if (provider === "apple") {
|
|
let appleAccounts = profileData?.appleAccounts;
|
|
if (appleAccounts) {
|
|
appleAccounts[email] = null;
|
|
newUserData.appleAccounts = appleAccounts;
|
|
}
|
|
}
|
|
await updateUserData({ newUserData });
|
|
};
|
|
|
|
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 (
|
|
<ScrollView>
|
|
<TouchableOpacity onPress={() => setPageIndex(0)}>
|
|
<View row marginT-20 marginB-20 marginL-20 centerV>
|
|
<Ionicons
|
|
name="chevron-back"
|
|
size={14}
|
|
color="#979797"
|
|
style={{ paddingBottom: 3 }}
|
|
/>
|
|
<Text
|
|
style={{ fontFamily: "Poppins_400Regular", fontSize: 14.71 }}
|
|
color="#979797"
|
|
>
|
|
Return to main settings
|
|
</Text>
|
|
</View>
|
|
</TouchableOpacity>
|
|
<View marginH-30 marginB-30>
|
|
<Text style={styles.subTitle}>Calendar settings</Text>
|
|
<View style={styles.card}>
|
|
<Text style={styles.cardTitle} marginB-14>
|
|
Event Color Preference
|
|
</Text>
|
|
<View row spread>
|
|
<TouchableOpacity onPress={() => handleChangeColor(colorMap.pink)}>
|
|
<View style={styles.colorBox} backgroundColor={colorMap.pink}>
|
|
{selectedColor == colorMap.pink && (
|
|
<AntDesign name="check" size={30} color="white" />
|
|
)}
|
|
</View>
|
|
</TouchableOpacity>
|
|
<TouchableOpacity
|
|
onPress={() => handleChangeColor(colorMap.orange)}
|
|
>
|
|
<View style={styles.colorBox} backgroundColor={colorMap.orange}>
|
|
{selectedColor == colorMap.orange && (
|
|
<AntDesign name="check" size={30} color="white" />
|
|
)}
|
|
</View>
|
|
</TouchableOpacity>
|
|
<TouchableOpacity onPress={() => handleChangeColor(colorMap.green)}>
|
|
<View style={styles.colorBox} backgroundColor={colorMap.green}>
|
|
{selectedColor == colorMap.green && (
|
|
<AntDesign name="check" size={30} color="white" />
|
|
)}
|
|
</View>
|
|
</TouchableOpacity>
|
|
<TouchableOpacity onPress={() => handleChangeColor(colorMap.teal)}>
|
|
<View style={styles.colorBox} backgroundColor={colorMap.teal}>
|
|
{selectedColor == colorMap.teal && (
|
|
<AntDesign name="check" size={30} color="white" />
|
|
)}
|
|
</View>
|
|
</TouchableOpacity>
|
|
<TouchableOpacity
|
|
onPress={() => handleChangeColor(colorMap.purple)}
|
|
>
|
|
<View style={styles.colorBox} backgroundColor={colorMap.purple}>
|
|
{selectedColor == colorMap.purple && (
|
|
<AntDesign name="check" size={30} color="white" />
|
|
)}
|
|
</View>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</View>
|
|
<View style={styles.card}>
|
|
<Text style={styles.cardTitle}>Weekly Start Date</Text>
|
|
<View row marginV-5 marginT-20>
|
|
<Checkbox
|
|
value={firstDayOfWeek === "Sundays"}
|
|
style={styles.checkbox}
|
|
color="#ea156d"
|
|
onValueChange={() => handleChangeFirstDayOfWeek("Sundays")}
|
|
/>
|
|
<View row marginL-8>
|
|
<Text text70>Sundays</Text>
|
|
<Text text70 color="gray">
|
|
{" "}
|
|
(default)
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
<View row marginV-5>
|
|
<Checkbox
|
|
value={firstDayOfWeek === "Mondays"}
|
|
style={styles.checkbox}
|
|
color="#ea156d"
|
|
onValueChange={() => handleChangeFirstDayOfWeek("Mondays")}
|
|
/>
|
|
<Text text70 marginL-8>
|
|
Mondays
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
<Text style={styles.subTitle} marginT-30 marginB-25>
|
|
Add Calendar
|
|
</Text>
|
|
|
|
<Button
|
|
onPress={() => promptAsync()}
|
|
label={"Connect Google"}
|
|
labelStyle={styles.addCalLbl}
|
|
labelProps={{
|
|
numberOfLines: 2,
|
|
}}
|
|
iconSource={() => (
|
|
<View marginR-15>
|
|
<GoogleIcon />
|
|
</View>
|
|
)}
|
|
style={styles.addCalBtn}
|
|
color="black"
|
|
text70BL
|
|
/>
|
|
{profileData?.googleAccounts
|
|
? Object.keys(profileData?.googleAccounts)?.map((googleMail) => {
|
|
const googleToken = profileData?.googleAccounts?.[googleMail];
|
|
return (
|
|
googleToken && (
|
|
<Button
|
|
key={googleMail}
|
|
onPress={() => {
|
|
showConfirmationDialog("google", googleMail);
|
|
}}
|
|
label={`Disconnect ${googleMail}`}
|
|
labelStyle={styles.addCalLbl}
|
|
labelProps={{
|
|
numberOfLines: 2,
|
|
}}
|
|
iconSource={() => (
|
|
<View marginR-15>
|
|
<GoogleIcon />
|
|
</View>
|
|
)}
|
|
style={styles.addCalBtn}
|
|
color="black"
|
|
text70BL
|
|
/>
|
|
)
|
|
);
|
|
})
|
|
: null}
|
|
|
|
<Button
|
|
onPress={() => handleAppleSignIn()}
|
|
label={"Connect Apple"}
|
|
labelStyle={styles.addCalLbl}
|
|
labelProps={{
|
|
numberOfLines: 2,
|
|
}}
|
|
iconSource={() => (
|
|
<View marginR-15>
|
|
<AppleIcon />
|
|
</View>
|
|
)}
|
|
style={styles.addCalBtn}
|
|
color="black"
|
|
text70BL
|
|
/>
|
|
{profileData?.appleAccounts
|
|
? Object.keys(profileData?.appleAccounts)?.map((appleEmail) => {
|
|
const appleToken = profileData?.appleAccounts?.[appleEmail];
|
|
return (
|
|
appleToken && (
|
|
<Button
|
|
key={appleEmail}
|
|
onPress={() => showConfirmationDialog("apple", appleEmail)}
|
|
label={`Disconnect ${appleEmail}`}
|
|
labelStyle={styles.addCalLbl}
|
|
labelProps={{
|
|
numberOfLines: 2,
|
|
}}
|
|
iconSource={() => (
|
|
<View marginR-15>
|
|
<AppleIcon />
|
|
</View>
|
|
)}
|
|
style={styles.addCalBtn}
|
|
color="black"
|
|
text70BL
|
|
/>
|
|
)
|
|
);
|
|
})
|
|
: null}
|
|
|
|
<Button
|
|
onPress={() => handleMicrosoftSignIn()}
|
|
label={"Connect Outlook"}
|
|
labelStyle={styles.addCalLbl}
|
|
labelProps={{
|
|
numberOfLines: 2,
|
|
}}
|
|
iconSource={() => (
|
|
<View marginR-15>
|
|
<OutlookIcon />
|
|
</View>
|
|
)}
|
|
style={styles.addCalBtn}
|
|
color="black"
|
|
text70BL
|
|
/>
|
|
{profileData?.microsoftAccounts
|
|
? Object.keys(profileData?.microsoftAccounts)?.map(
|
|
(microsoftEmail) => {
|
|
const microsoftToken =
|
|
profileData?.microsoftAccounts?.[microsoftEmail];
|
|
return (
|
|
microsoftToken && (
|
|
<Button
|
|
key={microsoftEmail}
|
|
onPress={() => {
|
|
showConfirmationDialog("outlook", microsoftEmail);
|
|
}}
|
|
label={`Disconnect ${microsoftEmail}`}
|
|
labelStyle={styles.addCalLbl}
|
|
labelProps={{
|
|
numberOfLines: 2,
|
|
}}
|
|
iconSource={() => (
|
|
<View marginR-15>
|
|
<OutlookIcon />
|
|
</View>
|
|
)}
|
|
style={styles.addCalBtn}
|
|
color="black"
|
|
text70BL
|
|
/>
|
|
)
|
|
);
|
|
}
|
|
)
|
|
: null}
|
|
|
|
{(isConnectedToGoogle ||
|
|
isConnectedToMicrosoft ||
|
|
isConnectedToApple) && (
|
|
<>
|
|
<Text style={styles.subTitle} marginT-30 marginB-20>
|
|
Connected Calendars
|
|
</Text>
|
|
|
|
<View style={styles.noPaddingCard}>
|
|
<View style={{ marginTop: 20 }}>
|
|
{profileData?.googleAccounts &&
|
|
Object.keys(profileData?.googleAccounts)?.map(
|
|
(googleEmail) => {
|
|
const googleToken =
|
|
profileData?.googleAccounts?.[googleEmail];
|
|
return (
|
|
googleToken && (
|
|
<TouchableOpacity
|
|
onPress={() =>
|
|
fetchAndSaveGoogleEvents({
|
|
token: googleToken,
|
|
email: googleEmail,
|
|
})
|
|
}
|
|
>
|
|
<View row paddingR-20 center>
|
|
<Button
|
|
disabled={isSyncingGoogle}
|
|
onPress={() =>
|
|
fetchAndSaveGoogleEvents({
|
|
token: googleToken,
|
|
email: googleEmail,
|
|
})
|
|
}
|
|
label={`Sync ${googleEmail}`}
|
|
labelStyle={styles.addCalLbl}
|
|
labelProps={{ numberOfLines: 3 }}
|
|
iconSource={() => (
|
|
<View marginR-15>
|
|
<GoogleIcon />
|
|
</View>
|
|
)}
|
|
style={styles.addCalBtn}
|
|
color="black"
|
|
text70BL
|
|
/>
|
|
|
|
{isSyncingGoogle ? (
|
|
<ActivityIndicator />
|
|
) : (
|
|
<Ionicons
|
|
name={"refresh"}
|
|
size={20}
|
|
color={"#000000"}
|
|
/>
|
|
)}
|
|
</View>
|
|
</TouchableOpacity>
|
|
)
|
|
);
|
|
}
|
|
)}
|
|
|
|
{profileData?.appleAccounts &&
|
|
Object.keys(profileData?.appleAccounts)?.map((appleEmail) => {
|
|
const appleToken = profileData?.appleAccounts?.[appleEmail];
|
|
return (
|
|
appleToken && (
|
|
<TouchableOpacity
|
|
onPress={() =>
|
|
fetchAndSaveAppleEvents({
|
|
email: appleEmail,
|
|
token: appleToken,
|
|
})
|
|
}
|
|
>
|
|
<View row paddingR-20 center>
|
|
<Button
|
|
disabled={isSyncingApple}
|
|
onPress={() =>
|
|
fetchAndSaveAppleEvents({
|
|
email: appleEmail,
|
|
token: appleToken,
|
|
})
|
|
}
|
|
label={`Sync ${appleEmail}`}
|
|
labelStyle={styles.addCalLbl}
|
|
labelProps={{ numberOfLines: 3 }}
|
|
iconSource={() => (
|
|
<View marginR-15>
|
|
<AppleIcon />
|
|
</View>
|
|
)}
|
|
style={styles.addCalBtn}
|
|
color="black"
|
|
text70BL
|
|
/>
|
|
{isSyncingApple ? (
|
|
<ActivityIndicator />
|
|
) : (
|
|
<Ionicons
|
|
name={"refresh"}
|
|
size={20}
|
|
color={"#000000"}
|
|
/>
|
|
)}
|
|
</View>
|
|
</TouchableOpacity>
|
|
)
|
|
);
|
|
})}
|
|
|
|
{profileData?.microsoftAccounts &&
|
|
Object.keys(profileData?.microsoftAccounts)?.map(
|
|
(microsoftEmail) => {
|
|
const microsoftToken =
|
|
profileData?.microsoftAccounts?.[microsoftEmail];
|
|
return (
|
|
microsoftToken && (
|
|
<TouchableOpacity
|
|
onPress={() =>
|
|
fetchAndSaveOutlookEvents({
|
|
token: microsoftToken,
|
|
email: microsoftEmail,
|
|
})
|
|
}
|
|
>
|
|
<View row paddingR-20 center>
|
|
<Button
|
|
disabled={isSyncingOutlook}
|
|
onPress={() =>
|
|
fetchAndSaveOutlookEvents({
|
|
token: microsoftToken,
|
|
email: microsoftEmail,
|
|
})
|
|
}
|
|
label={`Sync ${microsoftEmail}`}
|
|
labelStyle={styles.addCalLbl}
|
|
labelProps={{ numberOfLines: 3 }}
|
|
iconSource={() => (
|
|
<View marginR-15>
|
|
<OutlookIcon />
|
|
</View>
|
|
)}
|
|
style={styles.addCalBtn}
|
|
color="black"
|
|
text70BL
|
|
/>
|
|
{isSyncingOutlook ? (
|
|
<ActivityIndicator />
|
|
) : (
|
|
<Ionicons
|
|
name={"refresh"}
|
|
size={20}
|
|
color={"#000000"}
|
|
/>
|
|
)}
|
|
</View>
|
|
</TouchableOpacity>
|
|
)
|
|
);
|
|
}
|
|
)}
|
|
</View>
|
|
</View>
|
|
</>
|
|
)}
|
|
</View>
|
|
<CalendarSettingsDialog
|
|
visible={isModalVisible}
|
|
serviceName={selectedService}
|
|
email={selectedEmail}
|
|
onDismiss={handleCancel}
|
|
onConfirm={handleConfirm}
|
|
/>
|
|
</ScrollView>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
addCalBtn: {
|
|
backgroundColor: "#ffffff",
|
|
marginBottom: 15,
|
|
justifyContent: "flex-start",
|
|
paddingLeft: 25,
|
|
},
|
|
backBtn: {
|
|
backgroundColor: "red",
|
|
marginLeft: -2,
|
|
justifyContent: "flex-start",
|
|
},
|
|
card: {
|
|
backgroundColor: "white",
|
|
width: "100%",
|
|
padding: 20,
|
|
paddingBottom: 30,
|
|
marginTop: 20,
|
|
borderRadius: 12,
|
|
},
|
|
noPaddingCard: {
|
|
backgroundColor: "white",
|
|
width: "100%",
|
|
marginTop: 20,
|
|
borderRadius: 12,
|
|
},
|
|
colorBox: {
|
|
aspectRatio: 1,
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
width: 51,
|
|
borderRadius: 12,
|
|
},
|
|
checkbox: {
|
|
borderRadius: 50,
|
|
},
|
|
addCalLbl: {
|
|
fontSize: 16,
|
|
fontFamily: "PlusJakartaSan_500Medium",
|
|
flexWrap: "wrap",
|
|
width: "75%",
|
|
textAlign: "left",
|
|
lineHeight: 20,
|
|
overflow: "visible",
|
|
},
|
|
subTitle: {
|
|
fontFamily: "Manrope_600SemiBold",
|
|
fontSize: 18,
|
|
},
|
|
cardTitle: {
|
|
fontFamily: "Manrope_500Medium",
|
|
fontSize: 15,
|
|
},
|
|
});
|
|
|
|
export default CalendarSettingsPage;
|