Files
cally/components/pages/settings/CalendarSettingsPage.tsx

474 lines
24 KiB
TypeScript

import {Ionicons} from "@expo/vector-icons";
import React, {useCallback, useState} from "react";
import {Button, Checkbox, Text, View} from "react-native-ui-lib";
import {ActivityIndicator, 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 ExpoLocalization from "expo-localization/src/ExpoLocalization";
import {useSetAtom} from "jotai";
import {settingsPageIndex} from "../calendar/atoms";
import CalendarSettingsDialog from "./calendar_components/CalendarSettingsDialog";
import {useClearTokens} from "@/hooks/firebase/useClearTokens";
import {useCalSync} from "@/hooks/useCalSync";
import Feather from "@expo/vector-icons/Feather";
const CalendarSettingsPage = () => {
const {profileData} = useAuthContext();
const setPageIndex = useSetAtom(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 = async () => {
await clearToken({email: selectedEmail, provider: selectedService});
setModalVisible(false);
};
const handleCancel = () => {
setModalVisible(false);
};
const {mutateAsync: updateUserData} = useUpdateUserData();
const {mutateAsync: clearToken} = useClearTokens();
const {
isSyncingGoogle,
isSyncingOutlook,
isConnectedToGoogle,
isConnectedToMicrosoft,
isConnectedToApple,
handleAppleSignIn,
isSyncingApple,
handleMicrosoftSignIn,
fetchAndSaveOutlookEvents,
fetchAndSaveGoogleEvents,
handleStartGoogleSignIn,
fetchAndSaveAppleEvents
} = useCalSync()
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);
debouncedUpdateFirstDayOfWeek(firstDayOfWeek);
};
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}>Weekly Start Date</Text>
<View row marginV-5 marginT-20>
<Checkbox
value={firstDayOfWeek === "Sundays"}
style={[styles.checkbox, {borderRadius: 100}]}
borderRadius={100}
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, {borderRadius: 50}]}
color="#ea156d"
borderRadius={50}
onValueChange={() => handleChangeFirstDayOfWeek("Mondays")}
/>
<Text text70 marginL-8>
Mondays
</Text>
</View>
</View>
<Text style={styles.subTitle} marginT-30 marginB-25>
Add Calendars
</Text>
<Button
onPress={() => handleStartGoogleSignIn()}
label={profileData?.googleAccounts ? "Connect another Google account" : "Connect Google account"}
labelStyle={styles.addCalLbl}
labelProps={{
numberOfLines: 2,
}}
iconSource={() => (
<View marginR-15>
<GoogleIcon/>
</View>
)}
style={styles.addCalBtn}
color="black"
text70BL
/>
{!profileData?.appleAccounts && (
<Button
onPress={() => handleAppleSignIn()}
label={"Connect Apple"}
labelStyle={styles.addCalLbl}
labelProps={{
numberOfLines: 2,
}}
iconSource={() => (
<View marginR-15>
<AppleIcon/>
</View>
)}
style={styles.addCalBtn}
color="black"
text70BL
/>
)}
<Button
onPress={() => handleMicrosoftSignIn()}
label={profileData?.microsoftAccounts ? "Connect another Outlook account" : "Connect Outlook"}
labelStyle={styles.addCalLbl}
labelProps={{
numberOfLines: 2,
}}
iconSource={() => (
<View marginR-15>
<OutlookIcon/>
</View>
)}
style={styles.addCalBtn}
color="black"
text70BL
/>
{(isConnectedToGoogle ||
isConnectedToMicrosoft ||
isConnectedToApple) && (
<>
<Text style={styles.subTitle} marginT-30 marginB-20>
Connected Calendars
</Text>
<View style={[styles.noPaddingCard, {marginBottom: 100}]}>
<View style={{marginTop: 20}}>
{profileData?.googleAccounts &&
Object.keys(profileData?.googleAccounts)?.map(
(googleEmail) => {
const googleToken =
profileData?.googleAccounts?.[googleEmail]?.accessToken;
return (
googleToken && (
<View row paddingR-5 center>
<View
style={{
backgroundColor: "#ffffff",
marginBottom: 15,
paddingLeft: 15,
}}
color="black"
text70BL
row
centerV
width="100%"
spread
>
{isSyncingGoogle ? (
<View marginR-5>
<ActivityIndicator/>
</View>
) : (
<View marginR-5>
<Button
style={{backgroundColor: "#ffffff"}}
color="black"
onPress={() =>
fetchAndSaveGoogleEvents({
token: googleToken,
email: googleEmail,
})
}
iconSource={() => <Ionicons
name={"refresh"}
size={20}
color={"#000000"}
/>}
/>
</View>
)}
<View marginR-5>
<GoogleIcon/>
</View>
<Text style={styles.addCalLbl}>
{googleEmail}
</Text>
<Button
style={{backgroundColor: "#ffffff", marginRight: 5}}
color="black"
onPress={
() => showConfirmationDialog("google", googleEmail)
}
iconSource={() => <Feather name="x" size={24} />}
/>
</View>
</View>
)
);
}
)}
{profileData?.appleAccounts &&
Object.keys(profileData?.appleAccounts)?.map((appleEmail) => {
console.log(profileData?.appleAccounts)
const appleToken = profileData?.appleAccounts?.[appleEmail];
return (
appleToken && (
<View row paddingR-5 center>
<View
style={{
backgroundColor: "#ffffff",
marginBottom: 15,
paddingLeft: 15,
}}
color="black"
text70BL
row
centerV
width="100%"
spread
>
<View marginR-5>
<AppleIcon/>
</View>
<Text style={styles.addCalLbl}>
{appleEmail}
</Text>
{isSyncingApple ? (
<View marginR-5>
<ActivityIndicator/>
</View>
) : (
<View marginR-5>
<Button
style={{backgroundColor: "#ffffff"}}
color="black"
onPress={() =>
fetchAndSaveAppleEvents({
email: appleEmail,
token: appleToken,
})
}
iconSource={() => <Ionicons
name={"refresh"}
size={20}
color={"#000000"}
/>}
/>
</View>
)}
<Button
style={{backgroundColor: "#ffffff", marginRight: 5}}
color="black"
onPress={() => showConfirmationDialog("apple", appleEmail)}
iconSource={() => <Feather name="x" size={24} />}
/>
</View>
</View>
)
);
})}
{profileData?.microsoftAccounts &&
Object.keys(profileData?.microsoftAccounts)?.map(
(microsoftEmail) => {
const microsoftToken =
profileData?.microsoftAccounts?.[microsoftEmail];
return (
microsoftToken && (
<View row paddingR-5 center>
<View
style={{
backgroundColor: "#ffffff",
marginBottom: 15,
paddingLeft: 15,
}}
color="black"
text70BL
row
centerV
width="100%"
spread
>
{isSyncingOutlook ? (
<View marginR-5>
<ActivityIndicator/>
</View>
) : (
<View marginR-5>
<Button
style={{backgroundColor: "#ffffff"}}
color="black"
onPress={() =>
fetchAndSaveOutlookEvents({
token: microsoftToken,
email: microsoftEmail,
})
}
iconSource={() => <Ionicons
name={"refresh"}
size={20}
color={"#000000"}
/>}
/>
</View>
)}
<View marginR-5>
<OutlookIcon/>
</View>
<Text style={styles.addCalLbl}>
{microsoftEmail}
</Text>
<Button
style={{backgroundColor: "#ffffff", marginRight: 5}}
color="black"
onPress={
() => showConfirmationDialog("outlook", microsoftEmail)
}
iconSource={() => <Feather name="x" size={24} />}
/>
</View>
</View>
)
);
}
)}
</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: 100,
},
addCalLbl: {
fontSize: 16,
fontFamily: "PlusJakartaSan_500Medium",
flexWrap: "wrap",
width: "70%",
textAlign: "left",
lineHeight: 20,
overflow: "hidden",
},
subTitle: {
fontFamily: "Manrope_600SemiBold",
fontSize: 18,
},
cardTitle: {
fontFamily: "Manrope_500Medium",
fontSize: 15,
},
});
export default CalendarSettingsPage;