mirror of
https://github.com/urosran/cally.git
synced 2025-11-26 08:24:55 +00:00
fixed settings paging, calendar style,
This commit is contained in:
@ -23,9 +23,16 @@ import NavToDosIcon from "@/assets/svgs/NavToDosIcon";
|
|||||||
import NavBrainDumpIcon from "@/assets/svgs/NavBrainDumpIcon";
|
import NavBrainDumpIcon from "@/assets/svgs/NavBrainDumpIcon";
|
||||||
import NavCalendarIcon from "@/assets/svgs/NavCalendarIcon";
|
import NavCalendarIcon from "@/assets/svgs/NavCalendarIcon";
|
||||||
import NavSettingsIcon from "@/assets/svgs/NavSettingsIcon";
|
import NavSettingsIcon from "@/assets/svgs/NavSettingsIcon";
|
||||||
|
import { useAtom } from "jotai";
|
||||||
|
import {
|
||||||
|
settingsPageIndex,
|
||||||
|
userSettingsView,
|
||||||
|
} from "@/components/pages/calendar/atoms";
|
||||||
|
|
||||||
export default function TabLayout() {
|
export default function TabLayout() {
|
||||||
const { mutateAsync: signOut } = useSignOut();
|
const { mutateAsync: signOut } = useSignOut();
|
||||||
|
const [pageIndex, setPageIndex] = useAtom(settingsPageIndex);
|
||||||
|
const [userView, setUserView] = useAtom(userSettingsView);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<Drawer
|
||||||
@ -66,14 +73,22 @@ export default function TabLayout() {
|
|||||||
title={"Calendar"}
|
title={"Calendar"}
|
||||||
color="rgb(7, 184, 199)"
|
color="rgb(7, 184, 199)"
|
||||||
bgColor={"rgb(231, 248, 250)"}
|
bgColor={"rgb(231, 248, 250)"}
|
||||||
pressFunc={() => props.navigation.navigate("calendar")}
|
pressFunc={() => {
|
||||||
|
props.navigation.navigate("calendar");
|
||||||
|
setPageIndex(0);
|
||||||
|
setUserView(true);
|
||||||
|
}}
|
||||||
icon={<NavCalendarIcon />}
|
icon={<NavCalendarIcon />}
|
||||||
/>
|
/>
|
||||||
<DrawerButton
|
<DrawerButton
|
||||||
color="#50be0c"
|
color="#50be0c"
|
||||||
title={"Groceries"}
|
title={"Groceries"}
|
||||||
bgColor={"#eef9e7"}
|
bgColor={"#eef9e7"}
|
||||||
pressFunc={() => props.navigation.navigate("grocery")}
|
pressFunc={() => {
|
||||||
|
props.navigation.navigate("grocery");
|
||||||
|
setPageIndex(0);
|
||||||
|
setUserView(true);
|
||||||
|
}}
|
||||||
icon={<NavGroceryIcon />}
|
icon={<NavGroceryIcon />}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@ -95,21 +110,33 @@ export default function TabLayout() {
|
|||||||
color="#8005eb"
|
color="#8005eb"
|
||||||
title={"To Do's"}
|
title={"To Do's"}
|
||||||
bgColor={"#f3e6fd"}
|
bgColor={"#f3e6fd"}
|
||||||
pressFunc={() => props.navigation.navigate("todos")}
|
pressFunc={() => {
|
||||||
|
props.navigation.navigate("todos");
|
||||||
|
setPageIndex(0);
|
||||||
|
setUserView(true);
|
||||||
|
}}
|
||||||
icon={<NavToDosIcon />}
|
icon={<NavToDosIcon />}
|
||||||
/>
|
/>
|
||||||
<DrawerButton
|
<DrawerButton
|
||||||
color="#e0ca03"
|
color="#e0ca03"
|
||||||
title={"Brain Dump"}
|
title={"Brain Dump"}
|
||||||
bgColor={"#fffacb"}
|
bgColor={"#fffacb"}
|
||||||
pressFunc={() => props.navigation.navigate("brain_dump")}
|
pressFunc={() => {
|
||||||
|
props.navigation.navigate("brain_dump");
|
||||||
|
setPageIndex(0);
|
||||||
|
setUserView(true);
|
||||||
|
}}
|
||||||
icon={<NavBrainDumpIcon />}
|
icon={<NavBrainDumpIcon />}
|
||||||
/>
|
/>
|
||||||
{/*<DrawerItem label="Logout" onPress={() => signOut()} />*/}
|
{/*<DrawerItem label="Logout" onPress={() => signOut()} />*/}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<Button
|
<Button
|
||||||
onPress={() => props.navigation.navigate("settings")}
|
onPress={() => {
|
||||||
|
props.navigation.navigate("settings");
|
||||||
|
setPageIndex(0);
|
||||||
|
setUserView(true);
|
||||||
|
}}
|
||||||
label={"Manage Settings"}
|
label={"Manage Settings"}
|
||||||
labelStyle={styles.label}
|
labelStyle={styles.label}
|
||||||
iconSource={() => (
|
iconSource={() => (
|
||||||
|
|||||||
@ -1,17 +1,24 @@
|
|||||||
import React, {memo} from "react";
|
import React, { memo } from "react";
|
||||||
import {Button, Picker, PickerModes, SegmentedControl, Text, View,} from "react-native-ui-lib";
|
import {
|
||||||
import {MaterialIcons} from "@expo/vector-icons";
|
Button,
|
||||||
import {modeMap, months} from "./constants";
|
Picker,
|
||||||
import {StyleSheet} from "react-native";
|
PickerModes,
|
||||||
import {useAtom} from "jotai";
|
SegmentedControl,
|
||||||
import {modeAtom, selectedDateAtom} from "@/components/pages/calendar/atoms";
|
Text,
|
||||||
import {isSameDay} from "date-fns";
|
View,
|
||||||
import {useAuthContext} from "@/contexts/AuthContext";
|
} from "react-native-ui-lib";
|
||||||
|
import { MaterialIcons } from "@expo/vector-icons";
|
||||||
|
import { modeMap, months } from "./constants";
|
||||||
|
import { StyleSheet } from "react-native";
|
||||||
|
import { useAtom } from "jotai";
|
||||||
|
import { modeAtom, selectedDateAtom } from "@/components/pages/calendar/atoms";
|
||||||
|
import { format, isSameDay } from "date-fns";
|
||||||
|
import { useAuthContext } from "@/contexts/AuthContext";
|
||||||
|
|
||||||
export const CalendarHeader = memo(() => {
|
export const CalendarHeader = memo(() => {
|
||||||
const [selectedDate, setSelectedDate] = useAtom(selectedDateAtom);
|
const [selectedDate, setSelectedDate] = useAtom(selectedDateAtom);
|
||||||
const [mode, setMode] = useAtom(modeAtom);
|
const [mode, setMode] = useAtom(modeAtom);
|
||||||
const {profileData} = useAuthContext();
|
const { profileData } = useAuthContext();
|
||||||
|
|
||||||
const handleSegmentChange = (index: number) => {
|
const handleSegmentChange = (index: number) => {
|
||||||
const selectedMode = modeMap.get(index);
|
const selectedMode = modeMap.get(index);
|
||||||
@ -49,23 +56,23 @@ export const CalendarHeader = memo(() => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<View row centerV gap-3>
|
<View row centerV gap-3>
|
||||||
<Text style={{fontFamily: "Manrope_500Medium", fontSize: 17}}>
|
<Text style={{ fontFamily: "Manrope_500Medium", fontSize: 17 }}>
|
||||||
{selectedDate.getFullYear()}
|
{selectedDate.getFullYear()}
|
||||||
</Text>
|
</Text>
|
||||||
<Picker
|
<Picker
|
||||||
value={months[selectedDate.getMonth()]}
|
value={months[selectedDate.getMonth()]}
|
||||||
placeholder={"Select Month"}
|
placeholder={"Select Month"}
|
||||||
style={{fontFamily: "Manrope_500Medium", fontSize: 17, width: 85}}
|
style={{ fontFamily: "Manrope_500Medium", fontSize: 17, width: 85 }}
|
||||||
mode={PickerModes.SINGLE}
|
mode={PickerModes.SINGLE}
|
||||||
onChange={(itemValue) => handleMonthChange(itemValue as string)}
|
onChange={(itemValue) => handleMonthChange(itemValue as string)}
|
||||||
trailingAccessory={<MaterialIcons name={"keyboard-arrow-down"}/>}
|
trailingAccessory={<MaterialIcons name={"keyboard-arrow-down"} />}
|
||||||
topBarProps={{
|
topBarProps={{
|
||||||
title: selectedDate.getFullYear().toString(),
|
title: selectedDate.getFullYear().toString(),
|
||||||
titleStyle: {fontFamily: "Manrope_500Medium", fontSize: 17},
|
titleStyle: { fontFamily: "Manrope_500Medium", fontSize: 17 },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{months.map((month) => (
|
{months.map((month) => (
|
||||||
<Picker.Item key={month} label={month} value={month}/>
|
<Picker.Item key={month} label={month} value={month} />
|
||||||
))}
|
))}
|
||||||
</Picker>
|
</Picker>
|
||||||
</View>
|
</View>
|
||||||
@ -82,16 +89,14 @@ export const CalendarHeader = memo(() => {
|
|||||||
borderWidth: 0.7,
|
borderWidth: 0.7,
|
||||||
borderColor: "#dadce0",
|
borderColor: "#dadce0",
|
||||||
height: 30,
|
height: 30,
|
||||||
paddingHorizontal: 10
|
paddingHorizontal: 10,
|
||||||
}}
|
}}
|
||||||
labelStyle={{
|
labelStyle={{
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: "black",
|
color: "black",
|
||||||
fontFamily: "Manrope_500Medium",
|
fontFamily: "Manrope_500Medium",
|
||||||
}}
|
}}
|
||||||
label={new Date().toLocaleDateString("en-US", {
|
label={format(new Date(), "dd/MM/yyyy")}
|
||||||
timeZone: profileData?.timeZone || "",
|
|
||||||
})}
|
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
setSelectedDate(new Date());
|
setSelectedDate(new Date());
|
||||||
}}
|
}}
|
||||||
@ -100,7 +105,7 @@ export const CalendarHeader = memo(() => {
|
|||||||
|
|
||||||
<View>
|
<View>
|
||||||
<SegmentedControl
|
<SegmentedControl
|
||||||
segments={[{label: "D"}, {label: "W"}, {label: "M"}]}
|
segments={[{ label: "D" }, { label: "W" }, { label: "M" }]}
|
||||||
backgroundColor="#ececec"
|
backgroundColor="#ececec"
|
||||||
inactiveColor="#919191"
|
inactiveColor="#919191"
|
||||||
activeBackgroundColor="#ea156c"
|
activeBackgroundColor="#ea156c"
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import React, {useCallback, useEffect, useMemo, useState} from "react";
|
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import {Calendar} from "react-native-big-calendar";
|
import { Calendar } from "react-native-big-calendar";
|
||||||
import {ActivityIndicator, StyleSheet, View, ViewStyle} from "react-native";
|
import { ActivityIndicator, StyleSheet, View, ViewStyle } from "react-native";
|
||||||
import {useGetEvents} from "@/hooks/firebase/useGetEvents";
|
import { useGetEvents } from "@/hooks/firebase/useGetEvents";
|
||||||
import {useAtom, useSetAtom} from "jotai";
|
import { useAtom, useSetAtom } from "jotai";
|
||||||
import {
|
import {
|
||||||
editVisibleAtom,
|
editVisibleAtom,
|
||||||
eventForEditAtom,
|
eventForEditAtom,
|
||||||
@ -10,9 +10,9 @@ import {
|
|||||||
selectedDateAtom,
|
selectedDateAtom,
|
||||||
selectedNewEventDateAtom,
|
selectedNewEventDateAtom,
|
||||||
} from "@/components/pages/calendar/atoms";
|
} from "@/components/pages/calendar/atoms";
|
||||||
import {useAuthContext} from "@/contexts/AuthContext";
|
import { useAuthContext } from "@/contexts/AuthContext";
|
||||||
import {CalendarEvent} from "@/components/pages/calendar/interfaces";
|
import { CalendarEvent } from "@/components/pages/calendar/interfaces";
|
||||||
import {Text} from "react-native-ui-lib";
|
import { Text } from "react-native-ui-lib";
|
||||||
|
|
||||||
interface EventCalendarProps {
|
interface EventCalendarProps {
|
||||||
calendarHeight: number;
|
calendarHeight: number;
|
||||||
@ -26,9 +26,9 @@ const getTotalMinutes = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const EventCalendar: React.FC<EventCalendarProps> = React.memo(
|
export const EventCalendar: React.FC<EventCalendarProps> = React.memo(
|
||||||
({calendarHeight}) => {
|
({ calendarHeight }) => {
|
||||||
const {data: events, isLoading} = useGetEvents();
|
const { data: events, isLoading } = useGetEvents();
|
||||||
const {profileData} = useAuthContext();
|
const { profileData } = useAuthContext();
|
||||||
const [selectedDate, setSelectedDate] = useAtom(selectedDateAtom);
|
const [selectedDate, setSelectedDate] = useAtom(selectedDateAtom);
|
||||||
const [mode, setMode] = useAtom(modeAtom);
|
const [mode, setMode] = useAtom(modeAtom);
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ export const EventCalendar: React.FC<EventCalendarProps> = React.memo(
|
|||||||
const [isRendering, setIsRendering] = useState(true);
|
const [isRendering, setIsRendering] = useState(true);
|
||||||
const [offsetMinutes, setOffsetMinutes] = useState(getTotalMinutes());
|
const [offsetMinutes, setOffsetMinutes] = useState(getTotalMinutes());
|
||||||
|
|
||||||
const todaysDate = new Date()
|
const todaysDate = new Date();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (events && mode) {
|
if (events && mode) {
|
||||||
@ -55,7 +55,7 @@ export const EventCalendar: React.FC<EventCalendarProps> = React.memo(
|
|||||||
(event: CalendarEvent) => {
|
(event: CalendarEvent) => {
|
||||||
if (mode === "day" || mode === "week") {
|
if (mode === "day" || mode === "week") {
|
||||||
setEditVisible(true);
|
setEditVisible(true);
|
||||||
console.log({event});
|
console.log({ event });
|
||||||
setEventForEdit(event);
|
setEventForEdit(event);
|
||||||
} else {
|
} else {
|
||||||
setMode("day");
|
setMode("day");
|
||||||
@ -85,7 +85,7 @@ export const EventCalendar: React.FC<EventCalendarProps> = React.memo(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const memoizedEventCellStyle = useCallback(
|
const memoizedEventCellStyle = useCallback(
|
||||||
(event: CalendarEvent) => ({backgroundColor: event.eventColor}),
|
(event: CalendarEvent) => ({ backgroundColor: event.eventColor }),
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ export const EventCalendar: React.FC<EventCalendarProps> = React.memo(
|
|||||||
}, [selectedDate, mode]);
|
}, [selectedDate, mode]);
|
||||||
|
|
||||||
const dateStyle = useMemo(() => {
|
const dateStyle = useMemo(() => {
|
||||||
if (mode === "week") return undefined
|
if (mode === "week") return undefined;
|
||||||
return isSameDate(todaysDate, selectedDate) && mode === "day"
|
return isSameDate(todaysDate, selectedDate) && mode === "day"
|
||||||
? styles.dayHeader
|
? styles.dayHeader
|
||||||
: styles.otherDayHeader;
|
: styles.otherDayHeader;
|
||||||
@ -161,9 +161,9 @@ export const EventCalendar: React.FC<EventCalendarProps> = React.memo(
|
|||||||
const appliedStyle = isCurrentDate ? currentDateStyle : defaultStyle;
|
const appliedStyle = isCurrentDate ? currentDateStyle : defaultStyle;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={{alignItems: "center"}}>
|
<View style={{ alignItems: "center" }}>
|
||||||
<View style={appliedStyle}>
|
<View style={appliedStyle}>
|
||||||
<Text style={{color: isCurrentDate ? "white" : "black"}}>
|
<Text style={{ color: isCurrentDate ? "white" : "black" }}>
|
||||||
{date.getDate()}
|
{date.getDate()}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
@ -183,7 +183,7 @@ export const EventCalendar: React.FC<EventCalendarProps> = React.memo(
|
|||||||
if (isLoading || isRendering) {
|
if (isLoading || isRendering) {
|
||||||
return (
|
return (
|
||||||
<View style={styles.loadingContainer}>
|
<View style={styles.loadingContainer}>
|
||||||
<ActivityIndicator size="large" color="#0000ff"/>
|
<ActivityIndicator size="large" color="#0000ff" />
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -205,8 +205,29 @@ export const EventCalendar: React.FC<EventCalendarProps> = React.memo(
|
|||||||
headerContentStyle={memoizedHeaderContentStyle}
|
headerContentStyle={memoizedHeaderContentStyle}
|
||||||
onSwipeEnd={handleSwipeEnd}
|
onSwipeEnd={handleSwipeEnd}
|
||||||
scrollOffsetMinutes={offsetMinutes}
|
scrollOffsetMinutes={offsetMinutes}
|
||||||
|
theme={{
|
||||||
|
palette: {
|
||||||
|
nowIndicator: "#fd1575",
|
||||||
|
gray: {
|
||||||
|
"100": "#e8eaed",
|
||||||
|
"200": "#e8eaed",
|
||||||
|
"500": "#b7b7b7",
|
||||||
|
"800": "#919191",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
typography: {
|
||||||
|
fontFamily: "PlusJakartaSans_500Medium",
|
||||||
|
sm: { fontFamily: "Manrope_600SemiBold", fontSize: 15 },
|
||||||
|
xl: {
|
||||||
|
fontFamily: "PlusJakartaSans_500Medium",
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
moreLabel: {},
|
||||||
|
xs:{fontSize: 10}
|
||||||
|
},
|
||||||
|
}}
|
||||||
dayHeaderStyle={dateStyle}
|
dayHeaderStyle={dateStyle}
|
||||||
dayHeaderHighlightColor={dayHeaderColor}
|
dayHeaderHighlightColor={"white"}
|
||||||
renderCustomDateForMonth={renderCustomDateForMonth}
|
renderCustomDateForMonth={renderCustomDateForMonth}
|
||||||
showAdjacentMonths
|
showAdjacentMonths
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { atom } from 'jotai';
|
import { atom } from "jotai";
|
||||||
import {CalendarEvent} from "@/components/pages/calendar/interfaces";
|
import { CalendarEvent } from "@/components/pages/calendar/interfaces";
|
||||||
|
|
||||||
export const editVisibleAtom = atom<boolean>(false);
|
export const editVisibleAtom = atom<boolean>(false);
|
||||||
export const eventForEditAtom = atom<CalendarEvent | undefined>(undefined);
|
export const eventForEditAtom = atom<CalendarEvent | undefined>(undefined);
|
||||||
@ -7,3 +7,5 @@ export const isFamilyViewAtom = atom<boolean>(false);
|
|||||||
export const modeAtom = atom<"week" | "month" | "day">("week");
|
export const modeAtom = atom<"week" | "month" | "day">("week");
|
||||||
export const selectedDateAtom = atom<Date>(new Date());
|
export const selectedDateAtom = atom<Date>(new Date());
|
||||||
export const selectedNewEventDateAtom = atom<Date | undefined>(undefined);
|
export const selectedNewEventDateAtom = atom<Date | undefined>(undefined);
|
||||||
|
export const settingsPageIndex = atom<number>(0);
|
||||||
|
export const userSettingsView = atom<boolean>(true);
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import {AntDesign, Ionicons} from "@expo/vector-icons";
|
import { AntDesign, Ionicons } from "@expo/vector-icons";
|
||||||
import React, {useCallback, useEffect, useState} from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
import {Button, Checkbox, Text, View} from "react-native-ui-lib";
|
import { Button, Checkbox, Text, View } from "react-native-ui-lib";
|
||||||
import {ActivityIndicator, ScrollView, StyleSheet} from "react-native";
|
import { ActivityIndicator, ScrollView, StyleSheet } from "react-native";
|
||||||
import {TouchableOpacity} from "react-native-gesture-handler";
|
import { TouchableOpacity } from "react-native-gesture-handler";
|
||||||
import {useAuthContext} from "@/contexts/AuthContext";
|
import { useAuthContext } from "@/contexts/AuthContext";
|
||||||
import {useUpdateUserData} from "@/hooks/firebase/useUpdateUserData";
|
import { useUpdateUserData } from "@/hooks/firebase/useUpdateUserData";
|
||||||
import debounce from "debounce";
|
import debounce from "debounce";
|
||||||
import AppleIcon from "@/assets/svgs/AppleIcon";
|
import AppleIcon from "@/assets/svgs/AppleIcon";
|
||||||
import GoogleIcon from "@/assets/svgs/GoogleIcon";
|
import GoogleIcon from "@/assets/svgs/GoogleIcon";
|
||||||
@ -12,13 +12,15 @@ import OutlookIcon from "@/assets/svgs/OutlookIcon";
|
|||||||
import * as AuthSession from "expo-auth-session";
|
import * as AuthSession from "expo-auth-session";
|
||||||
import * as Google from "expo-auth-session/providers/google";
|
import * as Google from "expo-auth-session/providers/google";
|
||||||
import * as WebBrowser from "expo-web-browser";
|
import * as WebBrowser from "expo-web-browser";
|
||||||
import {UserProfile} from "@firebase/auth";
|
import { UserProfile } from "@firebase/auth";
|
||||||
import {useFetchAndSaveGoogleEvents} from "@/hooks/useFetchAndSaveGoogleEvents";
|
import { useFetchAndSaveGoogleEvents } from "@/hooks/useFetchAndSaveGoogleEvents";
|
||||||
import {useFetchAndSaveOutlookEvents} from "@/hooks/useFetchAndSaveOutlookEvents";
|
import { useFetchAndSaveOutlookEvents } from "@/hooks/useFetchAndSaveOutlookEvents";
|
||||||
import {useFetchAndSaveAppleEvents} from "@/hooks/useFetchAndSaveAppleEvents";
|
import { useFetchAndSaveAppleEvents } from "@/hooks/useFetchAndSaveAppleEvents";
|
||||||
import * as AppleAuthentication from 'expo-apple-authentication';
|
import * as AppleAuthentication from "expo-apple-authentication";
|
||||||
import ExpoLocalization from "expo-localization/src/ExpoLocalization";
|
import ExpoLocalization from "expo-localization/src/ExpoLocalization";
|
||||||
import {colorMap} from "@/constants/colorMap";
|
import { colorMap } from "@/constants/colorMap";
|
||||||
|
import { useAtom } from "jotai";
|
||||||
|
import { settingsPageIndex } from "../calendar/atoms";
|
||||||
|
|
||||||
const googleConfig = {
|
const googleConfig = {
|
||||||
androidClientId:
|
androidClientId:
|
||||||
@ -36,24 +38,29 @@ const googleConfig = {
|
|||||||
|
|
||||||
const microsoftConfig = {
|
const microsoftConfig = {
|
||||||
clientId: "13c79071-1066-40a9-9f71-b8c4b138b4af",
|
clientId: "13c79071-1066-40a9-9f71-b8c4b138b4af",
|
||||||
redirectUri: AuthSession.makeRedirectUri({path: "settings"}),
|
redirectUri: AuthSession.makeRedirectUri({ path: "settings" }),
|
||||||
scopes: [
|
scopes: [
|
||||||
"openid",
|
"openid",
|
||||||
"profile",
|
"profile",
|
||||||
"email",
|
"email",
|
||||||
"offline_access",
|
"offline_access",
|
||||||
"Calendars.ReadWrite",
|
"Calendars.ReadWrite",
|
||||||
"User.Read"
|
"User.Read",
|
||||||
],
|
],
|
||||||
authorizationEndpoint: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
|
authorizationEndpoint:
|
||||||
|
"https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
|
||||||
tokenEndpoint: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
|
tokenEndpoint: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
|
||||||
};
|
};
|
||||||
|
|
||||||
const CalendarSettingsPage = (props: {
|
const CalendarSettingsPage = () => {
|
||||||
setSelectedPage: (page: number) => void;
|
const { profileData } = useAuthContext();
|
||||||
}) => {
|
const [pageIndex, setPageIndex] = useAtom(settingsPageIndex);
|
||||||
const {profileData} = useAuthContext();
|
const [firstDayOfWeek, setFirstDayOfWeek] = useState<string>(
|
||||||
const [firstDayOfWeek, setFirstDayOfWeek] = useState<string>(profileData?.firstDayOfWeek ?? ExpoLocalization.getCalendars()[0].firstWeekday === 1 ? "Mondays" : "Sundays");
|
profileData?.firstDayOfWeek ??
|
||||||
|
ExpoLocalization.getCalendars()[0].firstWeekday === 1
|
||||||
|
? "Mondays"
|
||||||
|
: "Sundays"
|
||||||
|
);
|
||||||
|
|
||||||
const [selectedColor, setSelectedColor] = useState<string>(
|
const [selectedColor, setSelectedColor] = useState<string>(
|
||||||
profileData?.eventColor ?? colorMap.pink
|
profileData?.eventColor ?? colorMap.pink
|
||||||
@ -62,11 +69,15 @@ const CalendarSettingsPage = (props: {
|
|||||||
profileData?.eventColor ?? colorMap.pink
|
profileData?.eventColor ?? colorMap.pink
|
||||||
);
|
);
|
||||||
|
|
||||||
const {mutateAsync: updateUserData} = useUpdateUserData();
|
const { mutateAsync: updateUserData } = useUpdateUserData();
|
||||||
const {mutateAsync: fetchAndSaveGoogleEvents, isLoading: isSyncingGoogle} = useFetchAndSaveGoogleEvents();
|
const { mutateAsync: fetchAndSaveGoogleEvents, isLoading: isSyncingGoogle } =
|
||||||
const {mutateAsync: fetchAndSaveOutlookEvents, isLoading: isSyncingOutlook} = useFetchAndSaveOutlookEvents();
|
useFetchAndSaveGoogleEvents();
|
||||||
const {mutateAsync: fetchAndSaveAppleEvents, isLoading: isSyncingApple} = useFetchAndSaveAppleEvents();
|
const {
|
||||||
|
mutateAsync: fetchAndSaveOutlookEvents,
|
||||||
|
isLoading: isSyncingOutlook,
|
||||||
|
} = useFetchAndSaveOutlookEvents();
|
||||||
|
const { mutateAsync: fetchAndSaveAppleEvents, isLoading: isSyncingApple } =
|
||||||
|
useFetchAndSaveAppleEvents();
|
||||||
|
|
||||||
WebBrowser.maybeCompleteAuthSession();
|
WebBrowser.maybeCompleteAuthSession();
|
||||||
const [_, response, promptAsync] = Google.useAuthRequest(googleConfig);
|
const [_, response, promptAsync] = Google.useAuthRequest(googleConfig);
|
||||||
@ -83,7 +94,7 @@ const CalendarSettingsPage = (props: {
|
|||||||
const userInfoResponse = await fetch(
|
const userInfoResponse = await fetch(
|
||||||
"https://www.googleapis.com/oauth2/v3/userinfo",
|
"https://www.googleapis.com/oauth2/v3/userinfo",
|
||||||
{
|
{
|
||||||
headers: {Authorization: `Bearer ${accessToken}`},
|
headers: { Authorization: `Bearer ${accessToken}` },
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -91,13 +102,18 @@ const CalendarSettingsPage = (props: {
|
|||||||
const googleMail = userInfo.email;
|
const googleMail = userInfo.email;
|
||||||
|
|
||||||
let googleAccounts = profileData?.googleAccounts;
|
let googleAccounts = profileData?.googleAccounts;
|
||||||
const updatedGoogleAccounts = googleAccounts ? {...googleAccounts, [googleMail]: accessToken} : {[googleMail]: accessToken};
|
const updatedGoogleAccounts = googleAccounts
|
||||||
|
? { ...googleAccounts, [googleMail]: accessToken }
|
||||||
|
: { [googleMail]: accessToken };
|
||||||
|
|
||||||
await updateUserData({
|
await updateUserData({
|
||||||
newUserData: {googleAccounts: updatedGoogleAccounts},
|
newUserData: { googleAccounts: updatedGoogleAccounts },
|
||||||
});
|
});
|
||||||
|
|
||||||
await fetchAndSaveGoogleEvents({token: accessToken, email: googleMail})
|
await fetchAndSaveGoogleEvents({
|
||||||
|
token: accessToken,
|
||||||
|
email: googleMail,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error during Google sign-in:", error);
|
console.error("Error during Google sign-in:", error);
|
||||||
@ -160,11 +176,14 @@ const CalendarSettingsPage = (props: {
|
|||||||
console.log("Access token received, fetching user info...");
|
console.log("Access token received, fetching user info...");
|
||||||
|
|
||||||
// Fetch user info from Microsoft Graph API to get the email
|
// Fetch user info from Microsoft Graph API to get the email
|
||||||
const userInfoResponse = await fetch("https://graph.microsoft.com/v1.0/me", {
|
const userInfoResponse = await fetch(
|
||||||
|
"https://graph.microsoft.com/v1.0/me",
|
||||||
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokenData.access_token}`,
|
Authorization: `Bearer ${tokenData.access_token}`,
|
||||||
},
|
},
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const userInfo = await userInfoResponse.json();
|
const userInfo = await userInfoResponse.json();
|
||||||
console.log("User info received:", userInfo);
|
console.log("User info received:", userInfo);
|
||||||
@ -175,14 +194,19 @@ const CalendarSettingsPage = (props: {
|
|||||||
const outlookMail = userInfo.mail || userInfo.userPrincipalName;
|
const outlookMail = userInfo.mail || userInfo.userPrincipalName;
|
||||||
|
|
||||||
let microsoftAccounts = profileData?.microsoftAccounts;
|
let microsoftAccounts = profileData?.microsoftAccounts;
|
||||||
const updatedMicrosoftAccounts = microsoftAccounts ? {...microsoftAccounts, [outlookMail]: tokenData.access_token} : {[outlookMail]: tokenData.access_token};
|
const updatedMicrosoftAccounts = microsoftAccounts
|
||||||
|
? { ...microsoftAccounts, [outlookMail]: tokenData.access_token }
|
||||||
|
: { [outlookMail]: tokenData.access_token };
|
||||||
|
|
||||||
// Update user data with Microsoft token and email
|
// Update user data with Microsoft token and email
|
||||||
await updateUserData({
|
await updateUserData({
|
||||||
newUserData: {microsoftAccounts: updatedMicrosoftAccounts},
|
newUserData: { microsoftAccounts: updatedMicrosoftAccounts },
|
||||||
});
|
});
|
||||||
|
|
||||||
await fetchAndSaveOutlookEvents(tokenData.access_token, outlookMail)
|
await fetchAndSaveOutlookEvents(
|
||||||
|
tokenData.access_token,
|
||||||
|
outlookMail
|
||||||
|
);
|
||||||
console.log("User data updated successfully.");
|
console.log("User data updated successfully.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -214,13 +238,15 @@ const CalendarSettingsPage = (props: {
|
|||||||
console.log("Apple ID token received. Fetch user info if needed...");
|
console.log("Apple ID token received. Fetch user info if needed...");
|
||||||
|
|
||||||
await updateUserData({
|
await updateUserData({
|
||||||
newUserData: {appleToken, appleMail},
|
newUserData: { appleToken, appleMail },
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("User data updated with Apple ID token.");
|
console.log("User data updated with Apple ID token.");
|
||||||
await fetchAndSaveAppleEvents({token: appleToken, email: appleMail!});
|
await fetchAndSaveAppleEvents({ token: appleToken, email: appleMail! });
|
||||||
} else {
|
} else {
|
||||||
console.warn("Apple authentication was not successful or email was hidden.");
|
console.warn(
|
||||||
|
"Apple authentication was not successful or email was hidden."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error during Apple Sign-in:", error);
|
console.error("Error during Apple Sign-in:", error);
|
||||||
@ -260,8 +286,10 @@ const CalendarSettingsPage = (props: {
|
|||||||
|
|
||||||
const handleChangeFirstDayOfWeek = (firstDayOfWeek: string) => {
|
const handleChangeFirstDayOfWeek = (firstDayOfWeek: string) => {
|
||||||
setFirstDayOfWeek(firstDayOfWeek === "Sundays" ? "Mondays" : "Sundays");
|
setFirstDayOfWeek(firstDayOfWeek === "Sundays" ? "Mondays" : "Sundays");
|
||||||
debouncedUpdateFirstDayOfWeek(firstDayOfWeek === "Sundays" ? "Mondays" : "Sundays");
|
debouncedUpdateFirstDayOfWeek(
|
||||||
}
|
firstDayOfWeek === "Sundays" ? "Mondays" : "Sundays"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const handleChangeColor = (color: string) => {
|
const handleChangeColor = (color: string) => {
|
||||||
setPreviousSelectedColor(selectedColor);
|
setPreviousSelectedColor(selectedColor);
|
||||||
@ -269,7 +297,10 @@ const CalendarSettingsPage = (props: {
|
|||||||
debouncedUpdateUserData(color);
|
debouncedUpdateUserData(color);
|
||||||
};
|
};
|
||||||
|
|
||||||
const clearToken = async (provider: "google" | "outlook" | "apple", email: string) => {
|
const clearToken = async (
|
||||||
|
provider: "google" | "outlook" | "apple",
|
||||||
|
email: string
|
||||||
|
) => {
|
||||||
const newUserData: Partial<UserProfile> = {};
|
const newUserData: Partial<UserProfile> = {};
|
||||||
if (provider === "google") {
|
if (provider === "google") {
|
||||||
let googleAccounts = profileData?.googleAccounts;
|
let googleAccounts = profileData?.googleAccounts;
|
||||||
@ -290,7 +321,7 @@ const CalendarSettingsPage = (props: {
|
|||||||
newUserData.appleAccounts = appleAccounts;
|
newUserData.appleAccounts = appleAccounts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await updateUserData({newUserData});
|
await updateUserData({ newUserData });
|
||||||
};
|
};
|
||||||
|
|
||||||
let isConnectedToGoogle = false;
|
let isConnectedToGoogle = false;
|
||||||
@ -326,23 +357,23 @@ const CalendarSettingsPage = (props: {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
<View marginH-30 marginB-30>
|
<TouchableOpacity onPress={() => setPageIndex(0)}>
|
||||||
<TouchableOpacity onPress={() => props.setSelectedPage(0)}>
|
<View row marginT-20 marginB-20 marginL-20 centerV>
|
||||||
<View row marginT-20 marginB-35 centerV>
|
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="chevron-back"
|
name="chevron-back"
|
||||||
size={14}
|
size={14}
|
||||||
color="#979797"
|
color="#979797"
|
||||||
style={{paddingBottom: 3}}
|
style={{ paddingBottom: 3 }}
|
||||||
/>
|
/>
|
||||||
<Text
|
<Text
|
||||||
style={{fontFamily: "Poppins_400Regular", fontSize: 14.71}}
|
style={{ fontFamily: "Poppins_400Regular", fontSize: 14.71 }}
|
||||||
color="#979797"
|
color="#979797"
|
||||||
>
|
>
|
||||||
Return to main settings
|
Return to main settings
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
<View marginH-30 marginB-30>
|
||||||
<Text style={styles.subTitle}>Calendar settings</Text>
|
<Text style={styles.subTitle}>Calendar settings</Text>
|
||||||
<View style={styles.card}>
|
<View style={styles.card}>
|
||||||
<Text style={styles.cardTitle} marginB-14>
|
<Text style={styles.cardTitle} marginB-14>
|
||||||
@ -352,7 +383,7 @@ const CalendarSettingsPage = (props: {
|
|||||||
<TouchableOpacity onPress={() => handleChangeColor(colorMap.pink)}>
|
<TouchableOpacity onPress={() => handleChangeColor(colorMap.pink)}>
|
||||||
<View style={styles.colorBox} backgroundColor={colorMap.pink}>
|
<View style={styles.colorBox} backgroundColor={colorMap.pink}>
|
||||||
{selectedColor == colorMap.pink && (
|
{selectedColor == colorMap.pink && (
|
||||||
<AntDesign name="check" size={30} color="white"/>
|
<AntDesign name="check" size={30} color="white" />
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
@ -361,21 +392,21 @@ const CalendarSettingsPage = (props: {
|
|||||||
>
|
>
|
||||||
<View style={styles.colorBox} backgroundColor={colorMap.orange}>
|
<View style={styles.colorBox} backgroundColor={colorMap.orange}>
|
||||||
{selectedColor == colorMap.orange && (
|
{selectedColor == colorMap.orange && (
|
||||||
<AntDesign name="check" size={30} color="white"/>
|
<AntDesign name="check" size={30} color="white" />
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<TouchableOpacity onPress={() => handleChangeColor(colorMap.green)}>
|
<TouchableOpacity onPress={() => handleChangeColor(colorMap.green)}>
|
||||||
<View style={styles.colorBox} backgroundColor={colorMap.green}>
|
<View style={styles.colorBox} backgroundColor={colorMap.green}>
|
||||||
{selectedColor == colorMap.green && (
|
{selectedColor == colorMap.green && (
|
||||||
<AntDesign name="check" size={30} color="white"/>
|
<AntDesign name="check" size={30} color="white" />
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<TouchableOpacity onPress={() => handleChangeColor(colorMap.teal)}>
|
<TouchableOpacity onPress={() => handleChangeColor(colorMap.teal)}>
|
||||||
<View style={styles.colorBox} backgroundColor={colorMap.teal}>
|
<View style={styles.colorBox} backgroundColor={colorMap.teal}>
|
||||||
{selectedColor == colorMap.teal && (
|
{selectedColor == colorMap.teal && (
|
||||||
<AntDesign name="check" size={30} color="white"/>
|
<AntDesign name="check" size={30} color="white" />
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
@ -384,7 +415,7 @@ const CalendarSettingsPage = (props: {
|
|||||||
>
|
>
|
||||||
<View style={styles.colorBox} backgroundColor={colorMap.purple}>
|
<View style={styles.colorBox} backgroundColor={colorMap.purple}>
|
||||||
{selectedColor == colorMap.purple && (
|
{selectedColor == colorMap.purple && (
|
||||||
<AntDesign name="check" size={30} color="white"/>
|
<AntDesign name="check" size={30} color="white" />
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
@ -428,136 +459,173 @@ const CalendarSettingsPage = (props: {
|
|||||||
label={"Connect Google"}
|
label={"Connect Google"}
|
||||||
labelStyle={styles.addCalLbl}
|
labelStyle={styles.addCalLbl}
|
||||||
labelProps={{
|
labelProps={{
|
||||||
numberOfLines: 2
|
numberOfLines: 2,
|
||||||
}}
|
}}
|
||||||
iconSource={() => (
|
iconSource={() => (
|
||||||
<View marginR-15>
|
<View marginR-15>
|
||||||
<GoogleIcon/>
|
<GoogleIcon />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
style={styles.addCalBtn}
|
style={styles.addCalBtn}
|
||||||
color="black"
|
color="black"
|
||||||
text70BL
|
text70BL
|
||||||
/>
|
/>
|
||||||
{profileData?.googleAccounts ? Object.keys(profileData?.googleAccounts)?.map((googleMail) => {
|
{profileData?.googleAccounts
|
||||||
|
? Object.keys(profileData?.googleAccounts)?.map((googleMail) => {
|
||||||
const googleToken = profileData?.googleAccounts?.[googleMail];
|
const googleToken = profileData?.googleAccounts?.[googleMail];
|
||||||
return googleToken && <Button
|
return (
|
||||||
|
googleToken && (
|
||||||
|
<Button
|
||||||
key={googleMail}
|
key={googleMail}
|
||||||
onPress={() => clearToken("google", googleMail)}
|
onPress={() => clearToken("google", googleMail)}
|
||||||
label={`Disconnect ${googleMail}`}
|
label={`Disconnect ${googleMail}`}
|
||||||
labelStyle={styles.addCalLbl}
|
labelStyle={styles.addCalLbl}
|
||||||
labelProps={{
|
labelProps={{
|
||||||
numberOfLines: 2
|
numberOfLines: 2,
|
||||||
}}
|
}}
|
||||||
iconSource={() => (
|
iconSource={() => (
|
||||||
<View marginR-15>
|
<View marginR-15>
|
||||||
<GoogleIcon/>
|
<GoogleIcon />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
style={styles.addCalBtn}
|
style={styles.addCalBtn}
|
||||||
color="black"
|
color="black"
|
||||||
text70BL
|
text70BL
|
||||||
/>
|
/>
|
||||||
}) : null}
|
)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
: null}
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
onPress={() => handleAppleSignIn()}
|
onPress={() => handleAppleSignIn()}
|
||||||
label={"Connect Apple"}
|
label={"Connect Apple"}
|
||||||
labelStyle={styles.addCalLbl}
|
labelStyle={styles.addCalLbl}
|
||||||
labelProps={{
|
labelProps={{
|
||||||
numberOfLines: 2
|
numberOfLines: 2,
|
||||||
}}
|
}}
|
||||||
iconSource={() => (
|
iconSource={() => (
|
||||||
<View marginR-15>
|
<View marginR-15>
|
||||||
<AppleIcon/>
|
<AppleIcon />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
style={styles.addCalBtn}
|
style={styles.addCalBtn}
|
||||||
color="black"
|
color="black"
|
||||||
text70BL
|
text70BL
|
||||||
/>
|
/>
|
||||||
{profileData?.appleAccounts ? Object.keys(profileData?.appleAccounts)?.map((appleEmail) => {
|
{profileData?.appleAccounts
|
||||||
|
? Object.keys(profileData?.appleAccounts)?.map((appleEmail) => {
|
||||||
const appleToken = profileData?.appleAccounts?.[appleEmail];
|
const appleToken = profileData?.appleAccounts?.[appleEmail];
|
||||||
return appleToken && <Button
|
return (
|
||||||
|
appleToken && (
|
||||||
|
<Button
|
||||||
key={appleEmail}
|
key={appleEmail}
|
||||||
onPress={() => clearToken("apple", appleEmail)}
|
onPress={() => clearToken("apple", appleEmail)}
|
||||||
label={`Disconnect ${appleEmail}`}
|
label={`Disconnect ${appleEmail}`}
|
||||||
labelStyle={styles.addCalLbl}
|
labelStyle={styles.addCalLbl}
|
||||||
labelProps={{
|
labelProps={{
|
||||||
numberOfLines: 2
|
numberOfLines: 2,
|
||||||
}}
|
}}
|
||||||
iconSource={() => (
|
iconSource={() => (
|
||||||
<View marginR-15>
|
<View marginR-15>
|
||||||
<AppleIcon/>
|
<AppleIcon />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
style={styles.addCalBtn}
|
style={styles.addCalBtn}
|
||||||
color="black"
|
color="black"
|
||||||
text70BL
|
text70BL
|
||||||
/>
|
/>
|
||||||
}) : null}
|
)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
: null}
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
onPress={() => handleMicrosoftSignIn()}
|
onPress={() => handleMicrosoftSignIn()}
|
||||||
label={"Connect Outlook"}
|
label={"Connect Outlook"}
|
||||||
labelStyle={styles.addCalLbl}
|
labelStyle={styles.addCalLbl}
|
||||||
labelProps={{
|
labelProps={{
|
||||||
numberOfLines: 2
|
numberOfLines: 2,
|
||||||
}}
|
}}
|
||||||
iconSource={() => (
|
iconSource={() => (
|
||||||
<View marginR-15>
|
<View marginR-15>
|
||||||
<OutlookIcon/>
|
<OutlookIcon />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
style={styles.addCalBtn}
|
style={styles.addCalBtn}
|
||||||
color="black"
|
color="black"
|
||||||
text70BL
|
text70BL
|
||||||
/>
|
/>
|
||||||
{profileData?.microsoftAccounts ? Object.keys(profileData?.microsoftAccounts)?.map((microsoftEmail) => {
|
{profileData?.microsoftAccounts
|
||||||
const microsoftToken = profileData?.microsoftAccounts?.[microsoftEmail];
|
? Object.keys(profileData?.microsoftAccounts)?.map(
|
||||||
return microsoftToken && <Button
|
(microsoftEmail) => {
|
||||||
|
const microsoftToken =
|
||||||
|
profileData?.microsoftAccounts?.[microsoftEmail];
|
||||||
|
return (
|
||||||
|
microsoftToken && (
|
||||||
|
<Button
|
||||||
key={microsoftEmail}
|
key={microsoftEmail}
|
||||||
onPress={() => clearToken("outlook", microsoftEmail)}
|
onPress={() => clearToken("outlook", microsoftEmail)}
|
||||||
label={`Disconnect ${microsoftEmail}`}
|
label={`Disconnect ${microsoftEmail}`}
|
||||||
labelStyle={styles.addCalLbl}
|
labelStyle={styles.addCalLbl}
|
||||||
labelProps={{
|
labelProps={{
|
||||||
numberOfLines: 2
|
numberOfLines: 2,
|
||||||
}}
|
}}
|
||||||
iconSource={() => (
|
iconSource={() => (
|
||||||
<View marginR-15>
|
<View marginR-15>
|
||||||
<OutlookIcon/>
|
<OutlookIcon />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
style={styles.addCalBtn}
|
style={styles.addCalBtn}
|
||||||
color="black"
|
color="black"
|
||||||
text70BL
|
text70BL
|
||||||
/>
|
/>
|
||||||
}) : null}
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
: null}
|
||||||
|
|
||||||
{(isConnectedToGoogle || isConnectedToMicrosoft || isConnectedToApple) && (
|
{(isConnectedToGoogle ||
|
||||||
|
isConnectedToMicrosoft ||
|
||||||
|
isConnectedToApple) && (
|
||||||
<>
|
<>
|
||||||
<Text style={styles.subTitle} marginT-30 marginB-20>
|
<Text style={styles.subTitle} marginT-30 marginB-20>
|
||||||
Connected Calendars
|
Connected Calendars
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<View style={styles.noPaddingCard}>
|
<View style={styles.noPaddingCard}>
|
||||||
<View style={{marginTop: 20}}>
|
<View style={{ marginTop: 20 }}>
|
||||||
{profileData?.googleAccounts && Object.keys(profileData?.googleAccounts)?.map((googleEmail) => {
|
{profileData?.googleAccounts &&
|
||||||
const googleToken = profileData?.googleAccounts?.[googleEmail];
|
Object.keys(profileData?.googleAccounts)?.map(
|
||||||
return googleToken && (
|
(googleEmail) => {
|
||||||
|
const googleToken =
|
||||||
|
profileData?.googleAccounts?.[googleEmail];
|
||||||
|
return (
|
||||||
|
googleToken && (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={() => fetchAndSaveGoogleEvents({token: googleToken, email: googleEmail})}
|
onPress={() =>
|
||||||
|
fetchAndSaveGoogleEvents({
|
||||||
|
token: googleToken,
|
||||||
|
email: googleEmail,
|
||||||
|
})
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<View row paddingR-20 center>
|
<View row paddingR-20 center>
|
||||||
<Button
|
<Button
|
||||||
disabled={isSyncingGoogle}
|
disabled={isSyncingGoogle}
|
||||||
onPress={() => fetchAndSaveGoogleEvents({token: googleToken, email: googleEmail})}
|
onPress={() =>
|
||||||
|
fetchAndSaveGoogleEvents({
|
||||||
|
token: googleToken,
|
||||||
|
email: googleEmail,
|
||||||
|
})
|
||||||
|
}
|
||||||
label={`Sync ${googleEmail}`}
|
label={`Sync ${googleEmail}`}
|
||||||
labelStyle={styles.addCalLbl}
|
labelStyle={styles.addCalLbl}
|
||||||
labelProps={{numberOfLines: 3}}
|
labelProps={{ numberOfLines: 3 }}
|
||||||
iconSource={() => (
|
iconSource={() => (
|
||||||
<View marginR-15>
|
<View marginR-15>
|
||||||
<GoogleIcon/>
|
<GoogleIcon />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
style={styles.addCalBtn}
|
style={styles.addCalBtn}
|
||||||
@ -566,36 +634,49 @@ const CalendarSettingsPage = (props: {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{isSyncingGoogle ? (
|
{isSyncingGoogle ? (
|
||||||
<ActivityIndicator/>
|
<ActivityIndicator />
|
||||||
) : (
|
) : (
|
||||||
<Ionicons name={"refresh"} size={20} color={"#000000"}/>
|
<Ionicons
|
||||||
|
name={"refresh"}
|
||||||
|
size={20}
|
||||||
|
color={"#000000"}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)
|
)
|
||||||
})}
|
);
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
|
||||||
{profileData?.appleAccounts && Object.keys(profileData?.appleAccounts)?.map((appleEmail) => {
|
{profileData?.appleAccounts &&
|
||||||
|
Object.keys(profileData?.appleAccounts)?.map((appleEmail) => {
|
||||||
const appleToken = profileData?.appleAccounts?.[appleEmail];
|
const appleToken = profileData?.appleAccounts?.[appleEmail];
|
||||||
return appleToken && (
|
return (
|
||||||
|
appleToken && (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={() => fetchAndSaveAppleEvents({
|
onPress={() =>
|
||||||
|
fetchAndSaveAppleEvents({
|
||||||
email: appleEmail,
|
email: appleEmail,
|
||||||
token: appleToken
|
token: appleToken,
|
||||||
})}>
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
<View row paddingR-20 center>
|
<View row paddingR-20 center>
|
||||||
<Button
|
<Button
|
||||||
disabled={isSyncingApple}
|
disabled={isSyncingApple}
|
||||||
onPress={() => fetchAndSaveAppleEvents({
|
onPress={() =>
|
||||||
|
fetchAndSaveAppleEvents({
|
||||||
email: appleEmail,
|
email: appleEmail,
|
||||||
token: appleToken
|
token: appleToken,
|
||||||
})}
|
})
|
||||||
|
}
|
||||||
label={`Sync ${appleEmail}`}
|
label={`Sync ${appleEmail}`}
|
||||||
labelStyle={styles.addCalLbl}
|
labelStyle={styles.addCalLbl}
|
||||||
labelProps={{numberOfLines: 3}}
|
labelProps={{ numberOfLines: 3 }}
|
||||||
iconSource={() => (
|
iconSource={() => (
|
||||||
<View marginR-15>
|
<View marginR-15>
|
||||||
<AppleIcon/>
|
<AppleIcon />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
style={styles.addCalBtn}
|
style={styles.addCalBtn}
|
||||||
@ -603,37 +684,50 @@ const CalendarSettingsPage = (props: {
|
|||||||
text70BL
|
text70BL
|
||||||
/>
|
/>
|
||||||
{isSyncingApple ? (
|
{isSyncingApple ? (
|
||||||
<ActivityIndicator/>
|
<ActivityIndicator />
|
||||||
) : (
|
) : (
|
||||||
<Ionicons name={"refresh"} size={20} color={"#000000"}/>
|
<Ionicons
|
||||||
|
name={"refresh"}
|
||||||
|
size={20}
|
||||||
|
color={"#000000"}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)
|
)
|
||||||
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
{profileData?.microsoftAccounts && Object.keys(profileData?.microsoftAccounts)?.map((microsoftEmail) => {
|
{profileData?.microsoftAccounts &&
|
||||||
const microsoftToken = profileData?.microsoftAccounts?.[microsoftEmail];
|
Object.keys(profileData?.microsoftAccounts)?.map(
|
||||||
return microsoftToken && (
|
(microsoftEmail) => {
|
||||||
|
const microsoftToken =
|
||||||
|
profileData?.microsoftAccounts?.[microsoftEmail];
|
||||||
|
return (
|
||||||
|
microsoftToken && (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={() => fetchAndSaveOutlookEvents({
|
onPress={() =>
|
||||||
|
fetchAndSaveOutlookEvents({
|
||||||
token: microsoftToken,
|
token: microsoftToken,
|
||||||
email: microsoftEmail
|
email: microsoftEmail,
|
||||||
})}
|
})
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<View row paddingR-20 center>
|
<View row paddingR-20 center>
|
||||||
<Button
|
<Button
|
||||||
disabled={isSyncingOutlook}
|
disabled={isSyncingOutlook}
|
||||||
onPress={() => fetchAndSaveOutlookEvents({
|
onPress={() =>
|
||||||
|
fetchAndSaveOutlookEvents({
|
||||||
token: microsoftToken,
|
token: microsoftToken,
|
||||||
email: microsoftEmail
|
email: microsoftEmail,
|
||||||
})}
|
})
|
||||||
|
}
|
||||||
label={`Sync ${microsoftEmail}`}
|
label={`Sync ${microsoftEmail}`}
|
||||||
labelStyle={styles.addCalLbl}
|
labelStyle={styles.addCalLbl}
|
||||||
labelProps={{numberOfLines: 3}}
|
labelProps={{ numberOfLines: 3 }}
|
||||||
iconSource={() => (
|
iconSource={() => (
|
||||||
<View marginR-15>
|
<View marginR-15>
|
||||||
<OutlookIcon/>
|
<OutlookIcon />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
style={styles.addCalBtn}
|
style={styles.addCalBtn}
|
||||||
@ -641,14 +735,20 @@ const CalendarSettingsPage = (props: {
|
|||||||
text70BL
|
text70BL
|
||||||
/>
|
/>
|
||||||
{isSyncingOutlook ? (
|
{isSyncingOutlook ? (
|
||||||
<ActivityIndicator/>
|
<ActivityIndicator />
|
||||||
) : (
|
) : (
|
||||||
<Ionicons name={"refresh"} size={20} color={"#000000"}/>
|
<Ionicons
|
||||||
|
name={"refresh"}
|
||||||
|
size={20}
|
||||||
|
color={"#000000"}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)
|
)
|
||||||
})}
|
);
|
||||||
|
}
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
@ -701,7 +801,7 @@ const styles = StyleSheet.create({
|
|||||||
width: "75%",
|
width: "75%",
|
||||||
textAlign: "left",
|
textAlign: "left",
|
||||||
lineHeight: 20,
|
lineHeight: 20,
|
||||||
overflow: "visible"
|
overflow: "visible",
|
||||||
},
|
},
|
||||||
subTitle: {
|
subTitle: {
|
||||||
fontFamily: "Manrope_600SemiBold",
|
fontFamily: "Manrope_600SemiBold",
|
||||||
|
|||||||
@ -4,16 +4,16 @@ import { Ionicons } from "@expo/vector-icons";
|
|||||||
import { ToDosContextProvider } from "@/contexts/ToDosContext";
|
import { ToDosContextProvider } from "@/contexts/ToDosContext";
|
||||||
import ToDosList from "../todos/ToDosList";
|
import ToDosList from "../todos/ToDosList";
|
||||||
import { ScrollView } from "react-native-gesture-handler";
|
import { ScrollView } from "react-native-gesture-handler";
|
||||||
|
import { settingsPageIndex } from "../calendar/atoms";
|
||||||
|
import { useAtom } from "jotai";
|
||||||
|
|
||||||
|
const ChoreRewardSettings = () => {
|
||||||
|
const [pageIndex, setPageIndex] = useAtom(settingsPageIndex);
|
||||||
|
|
||||||
const ChoreRewardSettings = (props: {
|
|
||||||
setSelectedPage: (page: number) => void;
|
|
||||||
}) => {
|
|
||||||
return (
|
return (
|
||||||
<ToDosContextProvider>
|
<ToDosContextProvider>
|
||||||
<View marginT-10 marginH-20>
|
<TouchableOpacity onPress={() => setPageIndex(0)}>
|
||||||
<ScrollView>
|
<View row marginT-20 marginB-20 marginL-20 centerV>
|
||||||
<TouchableOpacity onPress={() => props.setSelectedPage(0)}>
|
|
||||||
<View row marginT-20 marginB-35 centerV>
|
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="chevron-back"
|
name="chevron-back"
|
||||||
size={14}
|
size={14}
|
||||||
@ -28,6 +28,8 @@ const ChoreRewardSettings = (props: {
|
|||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
<View marginH-20>
|
||||||
|
<ScrollView>
|
||||||
<Text text60R marginB-20>
|
<Text text60R marginB-20>
|
||||||
Chore Reward Settings
|
Chore Reward Settings
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import {Button, Text, View} from "react-native-ui-lib";
|
import { Button, Text, View } from "react-native-ui-lib";
|
||||||
import React, {useState} from "react";
|
import React, { useState } from "react";
|
||||||
import {StyleSheet} from "react-native";
|
import { StyleSheet } from "react-native";
|
||||||
import {Octicons} from "@expo/vector-icons";
|
import { Octicons } from "@expo/vector-icons";
|
||||||
import CalendarSettingsPage from "./CalendarSettingsPage";
|
import CalendarSettingsPage from "./CalendarSettingsPage";
|
||||||
import ChoreRewardSettings from "./ChoreRewardSettings";
|
import ChoreRewardSettings from "./ChoreRewardSettings";
|
||||||
import UserSettings from "./UserSettings";
|
import UserSettings from "./UserSettings";
|
||||||
@ -9,7 +9,9 @@ import ProfileIcon from "@/assets/svgs/ProfileIcon";
|
|||||||
import CalendarIcon from "@/assets/svgs/CalendarIcon";
|
import CalendarIcon from "@/assets/svgs/CalendarIcon";
|
||||||
import PrivacyPolicyIcon from "@/assets/svgs/PrivacyPolicyIcon";
|
import PrivacyPolicyIcon from "@/assets/svgs/PrivacyPolicyIcon";
|
||||||
import ArrowRightIcon from "@/assets/svgs/ArrowRightIcon";
|
import ArrowRightIcon from "@/assets/svgs/ArrowRightIcon";
|
||||||
import {ProfileType, useAuthContext} from "@/contexts/AuthContext";
|
import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
|
||||||
|
import { settingsPageIndex } from "../calendar/atoms";
|
||||||
|
import { useAtom } from "jotai";
|
||||||
|
|
||||||
const pageIndex = {
|
const pageIndex = {
|
||||||
main: 0,
|
main: 0,
|
||||||
@ -20,13 +22,13 @@ const pageIndex = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const SettingsPage = () => {
|
const SettingsPage = () => {
|
||||||
const {profileData} = useAuthContext()
|
const { profileData } = useAuthContext();
|
||||||
const isntParent = profileData?.userType !== ProfileType.PARENT
|
const [pageIndex, setPageIndex] = useAtom(settingsPageIndex);
|
||||||
|
const isntParent = profileData?.userType !== ProfileType.PARENT;
|
||||||
|
|
||||||
const [selectedPage, setSelectedPage] = useState<number>(0);
|
|
||||||
return (
|
return (
|
||||||
<View flexG>
|
<View flexG>
|
||||||
{selectedPage == 0 && (
|
{pageIndex == 0 && (
|
||||||
<View flexG centerH marginH-30 marginT-30>
|
<View flexG centerH marginH-30 marginT-30>
|
||||||
<Button
|
<Button
|
||||||
disabled={isntParent}
|
disabled={isntParent}
|
||||||
@ -34,14 +36,19 @@ const SettingsPage = () => {
|
|||||||
style={styles.mainBtn}
|
style={styles.mainBtn}
|
||||||
children={
|
children={
|
||||||
<View row centerV width={"100%"}>
|
<View row centerV width={"100%"}>
|
||||||
<ProfileIcon style={{marginRight: 10}} color="#07b9c8"/>
|
<ProfileIcon style={{ marginRight: 10 }} color="#07b9c8" />
|
||||||
<Text style={[styles.label, isntParent && styles.disabledText]}>
|
<Text
|
||||||
|
style={[
|
||||||
|
styles.label,
|
||||||
|
isntParent ? styles.disabledText : { color: "#07b9c8" },
|
||||||
|
]}
|
||||||
|
>
|
||||||
Manage My Profile
|
Manage My Profile
|
||||||
</Text>
|
</Text>
|
||||||
<ArrowRightIcon style={{marginLeft: "auto"}}/>
|
<ArrowRightIcon style={{ marginLeft: "auto" }} />
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
onPress={() => setSelectedPage(pageIndex.user)}
|
onPress={() => setPageIndex(1)}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
disabled={isntParent}
|
disabled={isntParent}
|
||||||
@ -49,15 +56,20 @@ const SettingsPage = () => {
|
|||||||
style={styles.mainBtn}
|
style={styles.mainBtn}
|
||||||
children={
|
children={
|
||||||
<View row centerV width={"100%"}>
|
<View row centerV width={"100%"}>
|
||||||
<CalendarIcon style={{marginRight: 10}}/>
|
<CalendarIcon style={{ marginRight: 10 }} />
|
||||||
<Text style={[styles.label, isntParent && styles.disabledText]}>
|
<Text
|
||||||
|
style={[
|
||||||
|
styles.label,
|
||||||
|
isntParent ? styles.disabledText : { color: "#FD1775" },
|
||||||
|
]}
|
||||||
|
>
|
||||||
Calendar Settings
|
Calendar Settings
|
||||||
</Text>
|
</Text>
|
||||||
<ArrowRightIcon style={{marginLeft: "auto"}}/>
|
<ArrowRightIcon style={{ marginLeft: "auto" }} />
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
setSelectedPage(pageIndex.calendar);
|
setPageIndex(2);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
@ -70,40 +82,32 @@ const SettingsPage = () => {
|
|||||||
name="gear"
|
name="gear"
|
||||||
size={24}
|
size={24}
|
||||||
color="#ff9900"
|
color="#ff9900"
|
||||||
style={{marginRight: 10}}
|
style={{ marginRight: 10 }}
|
||||||
/>
|
/>
|
||||||
<Text style={[styles.label, isntParent && styles.disabledText]}>
|
<Text style={[styles.label, isntParent ? styles.disabledText : {color: "#ff9900"}]}>
|
||||||
To-Do Reward Settings
|
To-Do Reward Settings
|
||||||
</Text>
|
</Text>
|
||||||
<ArrowRightIcon style={{marginLeft: "auto"}}/>
|
<ArrowRightIcon style={{ marginLeft: "auto" }} />
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
onPress={() => setSelectedPage(pageIndex.chore)}
|
onPress={() => setPageIndex(3)}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
backgroundColor="white"
|
backgroundColor="white"
|
||||||
style={styles.mainBtn}
|
style={styles.mainBtn}
|
||||||
children={
|
children={
|
||||||
<View row centerV width={"100%"}>
|
<View row centerV width={"100%"}>
|
||||||
<PrivacyPolicyIcon style={{marginRight: 10}}/>
|
<PrivacyPolicyIcon style={{ marginRight: 10 }} />
|
||||||
<Text style={styles.label}>
|
<Text style={[styles.label]} color={"#6C645B"}>Cally Privacy Policy</Text>
|
||||||
Cally Privacy Policy
|
<ArrowRightIcon style={{ marginLeft: "auto" }} />
|
||||||
</Text>
|
|
||||||
<ArrowRightIcon style={{marginLeft: "auto"}}/>
|
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
{selectedPage == pageIndex.calendar && (
|
{pageIndex == 2 && <CalendarSettingsPage />}
|
||||||
<CalendarSettingsPage setSelectedPage={setSelectedPage}/>
|
{pageIndex == 3 && <ChoreRewardSettings />}
|
||||||
)}
|
{pageIndex == 1 && <UserSettings />}
|
||||||
{selectedPage == pageIndex.chore && (
|
|
||||||
<ChoreRewardSettings setSelectedPage={setSelectedPage}/>
|
|
||||||
)}
|
|
||||||
{selectedPage == pageIndex.user && (
|
|
||||||
<UserSettings setSelectedPage={setSelectedPage}/>
|
|
||||||
)}
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -123,6 +127,6 @@ const styles = StyleSheet.create({
|
|||||||
textAlignVertical: "center",
|
textAlignVertical: "center",
|
||||||
},
|
},
|
||||||
disabledText: {
|
disabledText: {
|
||||||
color: '#A9A9A9', // Example of a gray color for disabled text
|
color: "#A9A9A9", // Example of a gray color for disabled text
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -4,15 +4,30 @@ import { Ionicons } from "@expo/vector-icons";
|
|||||||
import { ScrollView, StyleSheet } from "react-native";
|
import { ScrollView, StyleSheet } from "react-native";
|
||||||
import MyProfile from "./user_settings_views/MyProfile";
|
import MyProfile from "./user_settings_views/MyProfile";
|
||||||
import MyGroup from "./user_settings_views/MyGroup";
|
import MyGroup from "./user_settings_views/MyGroup";
|
||||||
|
import { useAtom } from "jotai";
|
||||||
|
import { settingsPageIndex, userSettingsView } from "../calendar/atoms";
|
||||||
|
import { AuthContextProvider } from "@/contexts/AuthContext";
|
||||||
|
|
||||||
const UserSettings = (props: { setSelectedPage: (page: number) => void }) => {
|
const UserSettings = () => {
|
||||||
const [selectedView, setSelectedView] = useState<boolean>(true);
|
const [pageIndex, setPageIndex] = useAtom(settingsPageIndex);
|
||||||
|
const [userView, setUserView] = useAtom(userSettingsView);
|
||||||
return (
|
return (
|
||||||
|
<AuthContextProvider>
|
||||||
<View flexG>
|
<View flexG>
|
||||||
<ScrollView style={{ paddingBottom: 20, minHeight: "100%" }}>
|
<ScrollView style={{ paddingBottom: 20, minHeight: "100%" }}>
|
||||||
<TouchableOpacity onPress={() => props.setSelectedPage(0)}>
|
<TouchableOpacity
|
||||||
<View row marginT-20 marginB-35 centerV>
|
onPress={() => {
|
||||||
<Ionicons name="chevron-back" size={14} color="#979797" style={{paddingBottom: 3}} />
|
setPageIndex(0);
|
||||||
|
setUserView(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<View row marginT-20 marginB-20 marginL-20 centerV>
|
||||||
|
<Ionicons
|
||||||
|
name="chevron-back"
|
||||||
|
size={14}
|
||||||
|
color="#979797"
|
||||||
|
style={{ paddingBottom: 3 }}
|
||||||
|
/>
|
||||||
<Text
|
<Text
|
||||||
style={{ fontFamily: "Poppins_400Regular", fontSize: 14.71 }}
|
style={{ fontFamily: "Poppins_400Regular", fontSize: 14.71 }}
|
||||||
color="#979797"
|
color="#979797"
|
||||||
@ -21,53 +36,54 @@ const UserSettings = (props: { setSelectedPage: (page: number) => void }) => {
|
|||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<View marginH-20 flexG style={{ minHeight: "90%" }}>
|
<View marginH-26 flexG style={{ minHeight: "90%" }}>
|
||||||
<Text text60R marginB-25>
|
<Text text60R marginB-25>
|
||||||
User Management
|
User Management
|
||||||
</Text>
|
</Text>
|
||||||
<View style={styles.buttonSwitch} spread row>
|
<View style={styles.buttonSwitch} spread row>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={() => setSelectedView(true)}
|
onPress={() => setUserView(true)}
|
||||||
centerV
|
centerV
|
||||||
centerH
|
centerH
|
||||||
style={selectedView == true ? styles.btnSelected : styles.btnNot}
|
style={userView == true ? styles.btnSelected : styles.btnNot}
|
||||||
>
|
>
|
||||||
<View>
|
<View>
|
||||||
<Text
|
<Text
|
||||||
style={styles.btnTxt}
|
style={styles.btnTxt}
|
||||||
color={selectedView ? "white" : "black"}
|
color={userView ? "white" : "black"}
|
||||||
>
|
>
|
||||||
My Profile
|
My Profile
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={() => setSelectedView(false)}
|
onPress={() => setUserView(false)}
|
||||||
centerV
|
centerV
|
||||||
centerH
|
centerH
|
||||||
style={selectedView == false ? styles.btnSelected : styles.btnNot}
|
style={userView == false ? styles.btnSelected : styles.btnNot}
|
||||||
>
|
>
|
||||||
<View>
|
<View>
|
||||||
<Text
|
<Text
|
||||||
style={styles.btnTxt}
|
style={styles.btnTxt}
|
||||||
color={!selectedView ? "white" : "black"}
|
color={!userView ? "white" : "black"}
|
||||||
>
|
>
|
||||||
My Group
|
My Group
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
{selectedView && <MyProfile />}
|
{userView && <MyProfile />}
|
||||||
{!selectedView && <MyGroup />}
|
{!userView && <MyGroup />}
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
{!selectedView && (
|
{!userView && (
|
||||||
<View>
|
<View>
|
||||||
<Text>selview</Text>
|
<Text>selview</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
</AuthContextProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -14,21 +14,21 @@ import {
|
|||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
View,
|
View,
|
||||||
} from "react-native-ui-lib";
|
} from "react-native-ui-lib";
|
||||||
import React, {useEffect, useRef, useState} from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import {ScrollView, StyleSheet} from "react-native";
|
import { ImageBackground, ScrollView, StyleSheet } from "react-native";
|
||||||
import {PickerSingleValue} from "react-native-ui-lib/src/components/picker/types";
|
import { PickerSingleValue } from "react-native-ui-lib/src/components/picker/types";
|
||||||
import {useCreateSubUser} from "@/hooks/firebase/useCreateSubUser";
|
import { useCreateSubUser } from "@/hooks/firebase/useCreateSubUser";
|
||||||
import {ProfileType} from "@/contexts/AuthContext";
|
import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
|
||||||
import {useGetFamilyMembers} from "@/hooks/firebase/useGetFamilyMembers";
|
import { useGetFamilyMembers } from "@/hooks/firebase/useGetFamilyMembers";
|
||||||
import UserMenu from "@/components/pages/settings/user_settings_views/UserMenu";
|
import UserMenu from "@/components/pages/settings/user_settings_views/UserMenu";
|
||||||
import {uuidv4} from "@firebase/util";
|
import { uuidv4 } from "@firebase/util";
|
||||||
import QRIcon from "@/assets/svgs/QRIcon";
|
import QRIcon from "@/assets/svgs/QRIcon";
|
||||||
import EmailIcon from "@/assets/svgs/EmailIcon";
|
import EmailIcon from "@/assets/svgs/EmailIcon";
|
||||||
import CircledXIcon from "@/assets/svgs/CircledXIcon";
|
import CircledXIcon from "@/assets/svgs/CircledXIcon";
|
||||||
import ProfileIcon from "@/assets/svgs/ProfileIcon";
|
import ProfileIcon from "@/assets/svgs/ProfileIcon";
|
||||||
import NavToDosIcon from "@/assets/svgs/NavToDosIcon";
|
import NavToDosIcon from "@/assets/svgs/NavToDosIcon";
|
||||||
import Ionicons from "@expo/vector-icons/Ionicons";
|
import Ionicons from "@expo/vector-icons/Ionicons";
|
||||||
import {PreviousNextView} from "react-native-keyboard-manager";
|
import { PreviousNextView } from "react-native-keyboard-manager";
|
||||||
|
|
||||||
const MyGroup = () => {
|
const MyGroup = () => {
|
||||||
const [showAddUserDialog, setShowAddUserDialog] = useState(false);
|
const [showAddUserDialog, setShowAddUserDialog] = useState(false);
|
||||||
@ -43,10 +43,13 @@ const MyGroup = () => {
|
|||||||
const lNameRef = useRef<TextFieldRef>(null);
|
const lNameRef = useRef<TextFieldRef>(null);
|
||||||
const emailRef = useRef<TextFieldRef>(null);
|
const emailRef = useRef<TextFieldRef>(null);
|
||||||
|
|
||||||
const [showQRCodeDialog, setShowQRCodeDialog] = useState<string | boolean>(false);
|
const [showQRCodeDialog, setShowQRCodeDialog] = useState<string | boolean>(
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
const {mutateAsync: createSubUser, isLoading, isError} = useCreateSubUser();
|
const { mutateAsync: createSubUser, isLoading, isError } = useCreateSubUser();
|
||||||
const {data: familyMembers} = useGetFamilyMembers(true);
|
const { data: familyMembers } = useGetFamilyMembers(true);
|
||||||
|
const { user } = useAuthContext();
|
||||||
|
|
||||||
const parents =
|
const parents =
|
||||||
familyMembers?.filter((x) => x.userType === ProfileType.PARENT) ?? [];
|
familyMembers?.filter((x) => x.userType === ProfileType.PARENT) ?? [];
|
||||||
@ -101,12 +104,11 @@ const MyGroup = () => {
|
|||||||
setFirstName("");
|
setFirstName("");
|
||||||
setLastName("");
|
setLastName("");
|
||||||
setEmail("");
|
setEmail("");
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return (
|
return (
|
||||||
<View style={{flex: 1, minHeight: 500}}>
|
<View style={{ flex: 1, minHeight: 500 }}>
|
||||||
<View>
|
<View>
|
||||||
<ScrollView style={styles.card}>
|
<ScrollView style={styles.card}>
|
||||||
{!parents.length && !children.length && !caregivers.length && (
|
{!parents.length && !children.length && !caregivers.length && (
|
||||||
@ -117,7 +119,7 @@ const MyGroup = () => {
|
|||||||
|
|
||||||
{(!!parents.length || !!children.length) && (
|
{(!!parents.length || !!children.length) && (
|
||||||
<>
|
<>
|
||||||
<Text style={styles.subTit} marginV-10>
|
<Text style={styles.subTit} marginB-10>
|
||||||
Family
|
Family
|
||||||
</Text>
|
</Text>
|
||||||
{[...parents, ...children]?.map((member, index) => (
|
{[...parents, ...children]?.map((member, index) => (
|
||||||
@ -128,31 +130,37 @@ const MyGroup = () => {
|
|||||||
style={styles.familyCard}
|
style={styles.familyCard}
|
||||||
row
|
row
|
||||||
centerV
|
centerV
|
||||||
padding-10
|
paddingT-10
|
||||||
>
|
>
|
||||||
<Avatar
|
{member.pfp ? (
|
||||||
source={{uri: "https://via.placeholder.com/60"}}
|
<ImageBackground
|
||||||
size={40}
|
style={styles.pfp}
|
||||||
backgroundColor={Colors.grey60}
|
borderRadius={10.56}
|
||||||
|
source={{ uri: member.pfp || undefined }}
|
||||||
/>
|
/>
|
||||||
<View marginL-10>
|
) : (
|
||||||
<Text text70M>
|
<View style={[styles.pfp, {backgroundColor: "#ea156d"}]} />
|
||||||
|
)}
|
||||||
|
<View row marginL-10 centerV>
|
||||||
|
<Text style={styles.name}>
|
||||||
{member.firstName} {member.lastName}
|
{member.firstName} {member.lastName}
|
||||||
</Text>
|
</Text>
|
||||||
<Text text90 grey40>
|
</View>
|
||||||
|
<View flexG />
|
||||||
|
<View row centerV gap-10>
|
||||||
|
<Text style={styles.userType}>
|
||||||
{member.userType === ProfileType.PARENT
|
{member.userType === ProfileType.PARENT
|
||||||
? "Admin (You)"
|
? `Admin${
|
||||||
|
member.uid === user?.uid ? " (You)" : ""
|
||||||
|
}`
|
||||||
: "Child"}
|
: "Child"}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
|
||||||
|
|
||||||
<View flex-1/>
|
|
||||||
|
|
||||||
<UserMenu
|
<UserMenu
|
||||||
setShowQRCodeDialog={(val) => setShowQRCodeDialog(val)}
|
setShowQRCodeDialog={(val) => setShowQRCodeDialog(val)}
|
||||||
showQRCodeDialog={showQRCodeDialog === member?.uid}
|
showQRCodeDialog={showQRCodeDialog === member?.uid}
|
||||||
userId={member?.uid!}
|
userId={member?.uid!}
|
||||||
/>
|
/>
|
||||||
|
</View>
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
@ -160,7 +168,7 @@ const MyGroup = () => {
|
|||||||
|
|
||||||
{!!caregivers.length && (
|
{!!caregivers.length && (
|
||||||
<>
|
<>
|
||||||
<Text text70 marginB-10 marginT-15>
|
<Text style={styles.subTit} marginB-10 marginT-15>
|
||||||
Caregivers
|
Caregivers
|
||||||
</Text>
|
</Text>
|
||||||
{caregivers?.map((member) => (
|
{caregivers?.map((member) => (
|
||||||
@ -174,7 +182,7 @@ const MyGroup = () => {
|
|||||||
padding-10
|
padding-10
|
||||||
>
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
source={{uri: member?.pfp ?? undefined}}
|
source={{ uri: member?.pfp ?? undefined }}
|
||||||
size={40}
|
size={40}
|
||||||
backgroundColor={Colors.grey60}
|
backgroundColor={Colors.grey60}
|
||||||
/>
|
/>
|
||||||
@ -187,7 +195,7 @@ const MyGroup = () => {
|
|||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View flex-1/>
|
<View flex-1 />
|
||||||
|
|
||||||
<UserMenu
|
<UserMenu
|
||||||
setShowQRCodeDialog={(val) => setShowQRCodeDialog(val)}
|
setShowQRCodeDialog={(val) => setShowQRCodeDialog(val)}
|
||||||
@ -215,7 +223,7 @@ const MyGroup = () => {
|
|||||||
padding-10
|
padding-10
|
||||||
>
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
source={{uri: member?.pfp ?? undefined}}
|
source={{ uri: member?.pfp ?? undefined }}
|
||||||
size={40}
|
size={40}
|
||||||
backgroundColor={Colors.grey60}
|
backgroundColor={Colors.grey60}
|
||||||
/>
|
/>
|
||||||
@ -226,7 +234,7 @@ const MyGroup = () => {
|
|||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View flex-1/>
|
<View flex-1 />
|
||||||
|
|
||||||
<UserMenu
|
<UserMenu
|
||||||
setShowQRCodeDialog={(val) => setShowQRCodeDialog(val)}
|
setShowQRCodeDialog={(val) => setShowQRCodeDialog(val)}
|
||||||
@ -269,7 +277,7 @@ const MyGroup = () => {
|
|||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Button backgroundColor={"#FD1775"} style={styles.dialogBtn}>
|
<Button backgroundColor={"#FD1775"} style={styles.dialogBtn}>
|
||||||
<QRIcon/>
|
<QRIcon />
|
||||||
<Text style={styles.dialogBtnLbl} marginL-7>
|
<Text style={styles.dialogBtnLbl} marginL-7>
|
||||||
Show a QR Code
|
Show a QR Code
|
||||||
</Text>
|
</Text>
|
||||||
@ -284,7 +292,7 @@ const MyGroup = () => {
|
|||||||
}, 500);
|
}, 500);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<EmailIcon/>
|
<EmailIcon />
|
||||||
<Text style={styles.dialogBtnLbl} marginL-7>
|
<Text style={styles.dialogBtnLbl} marginL-7>
|
||||||
Enter email address
|
Enter email address
|
||||||
</Text>
|
</Text>
|
||||||
@ -309,30 +317,31 @@ const MyGroup = () => {
|
|||||||
<KeyboardAwareScrollView>
|
<KeyboardAwareScrollView>
|
||||||
<Card padding-25 style={styles.dialogCard}>
|
<Card padding-25 style={styles.dialogCard}>
|
||||||
<View row spread>
|
<View row spread>
|
||||||
<Text style={{fontFamily: "Manrope_500Medium", fontSize: 16}}>
|
<Text style={{ fontFamily: "Manrope_500Medium", fontSize: 16 }}>
|
||||||
New User Information
|
New User Information
|
||||||
</Text>
|
</Text>
|
||||||
<TouchableOpacity onPress={() => {
|
<TouchableOpacity
|
||||||
setShowNewUserInfoDialog(false)
|
onPress={() => {
|
||||||
}}>
|
setShowNewUserInfoDialog(false);
|
||||||
<CircledXIcon/>
|
}}
|
||||||
|
>
|
||||||
|
<CircledXIcon />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.divider} spread/>
|
<View style={styles.divider} spread />
|
||||||
|
|
||||||
<View row centerV gap-20 marginV-20>
|
<View row centerV gap-20 marginV-20>
|
||||||
<View
|
<View
|
||||||
height={65.54}
|
height={65.54}
|
||||||
width={65.54}
|
width={65.54}
|
||||||
children={
|
children={
|
||||||
<ProfileIcon color={"#d6d6d6"} width={37} height={37}/>
|
<ProfileIcon color={"#d6d6d6"} width={37} height={37} />
|
||||||
}
|
}
|
||||||
backgroundColor={Colors.grey60}
|
backgroundColor={Colors.grey60}
|
||||||
style={{borderRadius: 25}}
|
style={{ borderRadius: 25 }}
|
||||||
center
|
center
|
||||||
/>
|
/>
|
||||||
<TouchableOpacity onPress={() => {
|
<TouchableOpacity onPress={() => {}}>
|
||||||
}}>
|
|
||||||
<Text color="#50be0c" style={styles.jakarta13} marginL-15>
|
<Text color="#50be0c" style={styles.jakarta13} marginL-15>
|
||||||
Upload User Profile Photo
|
Upload User Profile Photo
|
||||||
</Text>
|
</Text>
|
||||||
@ -349,21 +358,30 @@ const MyGroup = () => {
|
|||||||
floatingPlaceholder
|
floatingPlaceholder
|
||||||
style={styles.inViewPicker}
|
style={styles.inViewPicker}
|
||||||
trailingAccessory={
|
trailingAccessory={
|
||||||
<View style={{
|
<View
|
||||||
|
style={{
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
marginTop: -38,
|
marginTop: -38,
|
||||||
paddingRight: 15
|
paddingRight: 15,
|
||||||
}}>
|
}}
|
||||||
<Ionicons name={"chevron-down"} style={{alignSelf: "center"}} size={20}
|
>
|
||||||
color={"#000000"}/>
|
<Ionicons
|
||||||
|
name={"chevron-down"}
|
||||||
|
style={{ alignSelf: "center" }}
|
||||||
|
size={20}
|
||||||
|
color={"#000000"}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Picker.Item label="Child" value={ProfileType.CHILD}/>
|
<Picker.Item label="Child" value={ProfileType.CHILD} />
|
||||||
<Picker.Item label="Parent" value={ProfileType.PARENT}/>
|
<Picker.Item label="Parent" value={ProfileType.PARENT} />
|
||||||
<Picker.Item label="Caregiver" value={ProfileType.CAREGIVER}/>
|
<Picker.Item
|
||||||
|
label="Caregiver"
|
||||||
|
value={ProfileType.CAREGIVER}
|
||||||
|
/>
|
||||||
<Picker.Item
|
<Picker.Item
|
||||||
label="Family Device"
|
label="Family Device"
|
||||||
value={ProfileType.FAMILY_DEVICE}
|
value={ProfileType.FAMILY_DEVICE}
|
||||||
@ -387,7 +405,7 @@ const MyGroup = () => {
|
|||||||
onChangeText={setFirstName}
|
onChangeText={setFirstName}
|
||||||
style={styles.inputField}
|
style={styles.inputField}
|
||||||
onSubmitEditing={() => {
|
onSubmitEditing={() => {
|
||||||
lNameRef.current?.focus()
|
lNameRef.current?.focus();
|
||||||
}}
|
}}
|
||||||
blurOnSubmit={false}
|
blurOnSubmit={false}
|
||||||
returnKeyType="next"
|
returnKeyType="next"
|
||||||
@ -404,11 +422,10 @@ const MyGroup = () => {
|
|||||||
onChangeText={setLastName}
|
onChangeText={setLastName}
|
||||||
style={styles.inputField}
|
style={styles.inputField}
|
||||||
onSubmitEditing={() => {
|
onSubmitEditing={() => {
|
||||||
emailRef.current?.focus()
|
emailRef.current?.focus();
|
||||||
}}
|
}}
|
||||||
blurOnSubmit={false}
|
blurOnSubmit={false}
|
||||||
returnKeyType="next"
|
returnKeyType="next"
|
||||||
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@ -443,8 +460,8 @@ const MyGroup = () => {
|
|||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
marginLeft: 7,
|
marginLeft: 7,
|
||||||
}}
|
}}
|
||||||
style={{marginTop: 20, backgroundColor: "#fd1775"}}
|
style={{ marginTop: 20, backgroundColor: "#fd1775" }}
|
||||||
iconSource={() => <NavToDosIcon width={22} color={"white"}/>}
|
iconSource={() => <NavToDosIcon width={22} color={"white"} />}
|
||||||
onPress={handleCreateSubUser}
|
onPress={handleCreateSubUser}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
@ -460,7 +477,7 @@ const styles = StyleSheet.create({
|
|||||||
height: 47,
|
height: 47,
|
||||||
width: 279,
|
width: 279,
|
||||||
},
|
},
|
||||||
dialogTitle: {fontFamily: "Manrope_600SemiBold", fontSize: 22},
|
dialogTitle: { fontFamily: "Manrope_600SemiBold", fontSize: 22 },
|
||||||
dialogBackBtn: {
|
dialogBackBtn: {
|
||||||
fontFamily: "PlusJakartaSans_500Medium",
|
fontFamily: "PlusJakartaSans_500Medium",
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
@ -470,8 +487,9 @@ const styles = StyleSheet.create({
|
|||||||
marginVertical: 15,
|
marginVertical: 15,
|
||||||
backgroundColor: "white",
|
backgroundColor: "white",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
borderRadius: 15,
|
borderRadius: 12,
|
||||||
padding: 20,
|
paddingHorizontal: 21,
|
||||||
|
paddingVertical: 20,
|
||||||
},
|
},
|
||||||
bottomButton: {
|
bottomButton: {
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
@ -546,7 +564,7 @@ const styles = StyleSheet.create({
|
|||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
color: "white",
|
color: "white",
|
||||||
},
|
},
|
||||||
divider: {height: 0.7, backgroundColor: "#e6e6e6", width: "100%"},
|
divider: { height: 0.7, backgroundColor: "#e6e6e6", width: "100%" },
|
||||||
jakarta12: {
|
jakarta12: {
|
||||||
fontFamily: "PlusJakartaSans_500Medium",
|
fontFamily: "PlusJakartaSans_500Medium",
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
@ -556,6 +574,16 @@ const styles = StyleSheet.create({
|
|||||||
fontFamily: "PlusJakartaSans_500Medium",
|
fontFamily: "PlusJakartaSans_500Medium",
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
},
|
},
|
||||||
|
pfp: { aspectRatio: 1, width: 37.03, borderRadius: 10.56 },
|
||||||
|
userType: {
|
||||||
|
fontFamily: "Manrope_500Medium",
|
||||||
|
fontSize: 12,
|
||||||
|
color: "#858585",
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
fontFamily: "Manrope_600SemiBold",
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default MyGroup;
|
export default MyGroup;
|
||||||
|
|||||||
Reference in New Issue
Block a user