mirror of
https://github.com/urosran/cally.git
synced 2025-07-15 01:35:22 +00:00
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) => 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 {
|
|
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 }}
|
|
marginR-10
|
|
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 }}
|
|
marginR-10
|
|
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 }}>
|
|
<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}
|
|
/>
|
|
{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}
|
|
/>
|
|
)}
|
|
</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;
|