mirror of
https://github.com/urosran/cally.git
synced 2025-07-15 17:47:08 +00:00

- INtroduced new method to save the event data from the google and microsoft providers only if there isn't already an event with the same id
322 lines
10 KiB
TypeScript
322 lines
10 KiB
TypeScript
import { AntDesign, Ionicons } from "@expo/vector-icons";
|
|
import React, { useState } from "react";
|
|
import { Button, Checkbox, Text, View } from "react-native-ui-lib";
|
|
import { 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 { authorize } from "react-native-app-auth";
|
|
|
|
GoogleSignin.configure({
|
|
webClientId:
|
|
"406146460310-hjadmfa1gg4ptaouira5rkhu0djlo5ut.apps.googleusercontent.com",
|
|
scopes: ["profile", "email"], // Note: add calendar scope
|
|
});
|
|
|
|
const GoogleLogin = async () => {
|
|
return await GoogleSignin.signIn();
|
|
};
|
|
|
|
const microsoftConfig = {
|
|
issuer: "https://login.microsoftonline.com/common",
|
|
clientId: "<your-client-id>", // Replace with your microsoft client id
|
|
redirectUrl: "<your-redirect-uri>", // replace with your redirect uri added in microsoft portal
|
|
scopes: ["openid", "profile", "email"], // Add calendar scope
|
|
serviceConfiguration: {
|
|
authorizationEndpoint:
|
|
"https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
|
|
tokenEndpoint: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
|
|
revocationEndpoint:
|
|
"https://login.microsoftonline.com/common/oauth2/v2.0/logout",
|
|
},
|
|
useNonce: true,
|
|
usePKCE: true, //For iOS, we have added the useNonce and usePKCE parameters, which are recommended for security reasons.
|
|
additionalParameters: {
|
|
prompt: "consent",
|
|
},
|
|
};
|
|
|
|
const CalendarSettingsPage = (props: {
|
|
setSelectedPage: (page: number) => void;
|
|
}) => {
|
|
const [selectedColor, setSelectedColor] = useState<string>(colorMap.pink);
|
|
const [startDate, setStartDate] = useState<boolean>(true);
|
|
const { profileData } = useAuthContext();
|
|
|
|
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) {
|
|
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) => {
|
|
response?.forEach((item) => createEvent(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 {
|
|
const { idToken } = await authorize(microsoftConfig);
|
|
if (idToken) {
|
|
await updateUserData({ newUserData: { microsoftToken: idToken } });
|
|
}
|
|
} catch (error) {
|
|
console.log(error);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<View marginH-30>
|
|
<TouchableOpacity onPress={() => props.setSelectedPage(0)}>
|
|
<View row marginT-20 marginB-35 centerV>
|
|
<Ionicons name="chevron-back" size={22} color="#979797" />
|
|
<Text text70 color="#979797">
|
|
Return to main settings
|
|
</Text>
|
|
</View>
|
|
</TouchableOpacity>
|
|
<Text text60R>Calendar settings</Text>
|
|
<View style={styles.card}>
|
|
<Text text70 marginB-14>
|
|
Event Color Preference
|
|
</Text>
|
|
<View row spread>
|
|
<TouchableOpacity onPress={() => setSelectedColor(colorMap.pink)}>
|
|
<View style={styles.colorBox} backgroundColor={colorMap.pink}>
|
|
{selectedColor == colorMap.pink && (
|
|
<AntDesign name="check" size={30} color="white" />
|
|
)}
|
|
</View>
|
|
</TouchableOpacity>
|
|
<TouchableOpacity onPress={() => setSelectedColor(colorMap.orange)}>
|
|
<View style={styles.colorBox} backgroundColor={colorMap.orange}>
|
|
{selectedColor == colorMap.orange && (
|
|
<AntDesign name="check" size={30} color="white" />
|
|
)}
|
|
</View>
|
|
</TouchableOpacity>
|
|
<TouchableOpacity onPress={() => setSelectedColor(colorMap.green)}>
|
|
<View style={styles.colorBox} backgroundColor={colorMap.green}>
|
|
{selectedColor == colorMap.green && (
|
|
<AntDesign name="check" size={30} color="white" />
|
|
)}
|
|
</View>
|
|
</TouchableOpacity>
|
|
<TouchableOpacity onPress={() => setSelectedColor(colorMap.teal)}>
|
|
<View style={styles.colorBox} backgroundColor={colorMap.teal}>
|
|
{selectedColor == colorMap.teal && (
|
|
<AntDesign name="check" size={30} color="white" />
|
|
)}
|
|
</View>
|
|
</TouchableOpacity>
|
|
<TouchableOpacity onPress={() => setSelectedColor(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 text70>Weekly Start Date</Text>
|
|
<View row marginV-5 marginT-20>
|
|
<Checkbox
|
|
value={startDate}
|
|
style={styles.checkbox}
|
|
color="#ea156d"
|
|
onValueChange={() => setStartDate(true)}
|
|
/>
|
|
<View row marginL-8>
|
|
<Text text70>Sundays</Text>
|
|
<Text text70 color="gray">
|
|
{" "}
|
|
(default)
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
<View row marginV-5>
|
|
<Checkbox
|
|
value={!startDate}
|
|
style={styles.checkbox}
|
|
color="#ea156d"
|
|
onValueChange={() => setStartDate(false)}
|
|
/>
|
|
<Text text70 marginL-8>
|
|
Mondays
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
<View style={styles.card}>
|
|
<Text text70>Add Calendar</Text>
|
|
<View style={{ marginTop: 20 }}>
|
|
<Button
|
|
label={"Connect Google"}
|
|
iconSource={() => (
|
|
<View
|
|
backgroundColor="#ededed"
|
|
width={40}
|
|
height={40}
|
|
style={{ borderRadius: 50 }}
|
|
centerV
|
|
centerH
|
|
>
|
|
<Ionicons name="logo-google" size={22} color="#979797" />
|
|
</View>
|
|
)}
|
|
backgroundColor="white"
|
|
color="#464039"
|
|
borderRadius={15}
|
|
onPress={handleGoogleLogin}
|
|
/>
|
|
<Button
|
|
label={"Connect Microsoft"}
|
|
iconSource={() => (
|
|
<View
|
|
backgroundColor="#ededed"
|
|
width={40}
|
|
height={40}
|
|
style={{ borderRadius: 50 }}
|
|
centerV
|
|
centerH
|
|
>
|
|
<Ionicons name="logo-microsoft" size={22} color="#979797" />
|
|
</View>
|
|
)}
|
|
backgroundColor="white"
|
|
color="#464039"
|
|
borderRadius={15}
|
|
onPress={handleMicrosoftSignIn}
|
|
/>
|
|
</View>
|
|
</View>
|
|
<View style={styles.card}>
|
|
<Text text70>Calendars</Text>
|
|
<View style={{ marginTop: 20 }}>
|
|
{profileData?.googleToken !== undefined && (
|
|
<Button
|
|
label={"Sync Google"}
|
|
iconSource={() => (
|
|
<View
|
|
backgroundColor="#ededed"
|
|
width={40}
|
|
height={40}
|
|
style={{ borderRadius: 50 }}
|
|
marginR-10
|
|
centerV
|
|
centerH
|
|
>
|
|
<Ionicons name="logo-google" size={22} color="#979797" />
|
|
</View>
|
|
)}
|
|
backgroundColor="white"
|
|
color="#464039"
|
|
borderRadius={15}
|
|
onPress={fetchAndSaveGoogleEvents}
|
|
/>
|
|
)}
|
|
{profileData?.microsoftToken !== undefined && (
|
|
<Button
|
|
label={"Sync Outlook"}
|
|
iconSource={() => (
|
|
<View
|
|
backgroundColor="#ededed"
|
|
width={40}
|
|
height={40}
|
|
style={{ borderRadius: 50 }}
|
|
marginR-10
|
|
centerV
|
|
centerH
|
|
>
|
|
<Ionicons name="logo-microsoft" size={22} color="#979797" />
|
|
</View>
|
|
)}
|
|
backgroundColor="white"
|
|
color="#464039"
|
|
borderRadius={15}
|
|
onPress={fetchAndSaveMicrosoftEvents}
|
|
/>
|
|
)}
|
|
</View>
|
|
</View>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
backBtn: {
|
|
backgroundColor: "red",
|
|
marginLeft: -2,
|
|
justifyContent: "flex-start",
|
|
},
|
|
card: {
|
|
backgroundColor: "white",
|
|
width: "100%",
|
|
padding: 20,
|
|
paddingBottom: 30,
|
|
marginTop: 20,
|
|
borderRadius: 20,
|
|
},
|
|
colorBox: {
|
|
aspectRatio: 1,
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
width: 50,
|
|
borderRadius: 12,
|
|
},
|
|
checkbox: {
|
|
borderRadius: 50,
|
|
},
|
|
});
|
|
|
|
export default CalendarSettingsPage;
|