mirror of
https://github.com/urosran/cally.git
synced 2025-11-26 08:24:55 +00:00
Merge branch 'refs/heads/dev'
This commit is contained in:
@ -1,9 +1,19 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {Drawer} from "expo-router/drawer";
|
import { Drawer } from "expo-router/drawer";
|
||||||
import {useSignOut} from "@/hooks/firebase/useSignOut";
|
import { useSignOut } from "@/hooks/firebase/useSignOut";
|
||||||
import {DrawerContentScrollView, DrawerNavigationOptions, DrawerNavigationProp} from "@react-navigation/drawer";
|
import {
|
||||||
import {Button, ButtonSize, Text, TouchableOpacity, View,} from "react-native-ui-lib";
|
DrawerContentScrollView,
|
||||||
import {ImageBackground, StyleSheet} from "react-native";
|
DrawerNavigationOptions,
|
||||||
|
DrawerNavigationProp,
|
||||||
|
} from "@react-navigation/drawer";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
ButtonSize,
|
||||||
|
Text,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
} from "react-native-ui-lib";
|
||||||
|
import { ImageBackground, StyleSheet } from "react-native";
|
||||||
import DrawerButton from "@/components/shared/DrawerButton";
|
import DrawerButton from "@/components/shared/DrawerButton";
|
||||||
import NavGroceryIcon from "@/assets/svgs/NavGroceryIcon";
|
import NavGroceryIcon from "@/assets/svgs/NavGroceryIcon";
|
||||||
import NavToDosIcon from "@/assets/svgs/NavToDosIcon";
|
import NavToDosIcon from "@/assets/svgs/NavToDosIcon";
|
||||||
@ -11,165 +21,191 @@ 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 ViewSwitch from "@/components/pages/(tablet_pages)/ViewSwitch";
|
import ViewSwitch from "@/components/pages/(tablet_pages)/ViewSwitch";
|
||||||
import {useSetAtom} from "jotai";
|
import { useSetAtom } from "jotai";
|
||||||
import {
|
import {
|
||||||
isFamilyViewAtom,
|
isFamilyViewAtom,
|
||||||
settingsPageIndex,
|
settingsPageIndex,
|
||||||
toDosPageIndex,
|
toDosPageIndex,
|
||||||
userSettingsView,
|
userSettingsView,
|
||||||
} from "@/components/pages/calendar/atoms";
|
} from "@/components/pages/calendar/atoms";
|
||||||
import Ionicons from "@expo/vector-icons/Ionicons";
|
import Ionicons from "@expo/vector-icons/Ionicons";
|
||||||
import * as Device from "expo-device";
|
import * as Device from "expo-device";
|
||||||
import {DeviceType} from "expo-device";
|
import { DeviceType } from "expo-device";
|
||||||
import FeedbackNavIcon from "@/assets/svgs/FeedbackNavIcon";
|
import FeedbackNavIcon from "@/assets/svgs/FeedbackNavIcon";
|
||||||
import DrawerIcon from "@/assets/svgs/DrawerIcon";
|
import DrawerIcon from "@/assets/svgs/DrawerIcon";
|
||||||
import {RouteProp} from "@react-navigation/core";
|
import { RouteProp } from "@react-navigation/core";
|
||||||
|
import RefreshButton from "@/components/shared/RefreshButton";
|
||||||
|
import { useCalSync } from "@/hooks/useCalSync";
|
||||||
|
|
||||||
type DrawerParamList = {
|
type DrawerParamList = {
|
||||||
index: undefined;
|
index: undefined;
|
||||||
calendar: undefined;
|
calendar: undefined;
|
||||||
todos: undefined;
|
todos: undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
type NavigationProp = DrawerNavigationProp<DrawerParamList>;
|
type NavigationProp = DrawerNavigationProp<DrawerParamList>;
|
||||||
|
|
||||||
interface ViewSwitchProps {
|
interface ViewSwitchProps {
|
||||||
navigation: NavigationProp;
|
navigation: NavigationProp;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HeaderRightProps {
|
interface HeaderRightProps {
|
||||||
routeName: keyof DrawerParamList;
|
routeName: keyof DrawerParamList;
|
||||||
navigation: NavigationProp;
|
navigation: NavigationProp;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MemoizedViewSwitch = React.memo<ViewSwitchProps>(({navigation}) => (
|
const MemoizedViewSwitch = React.memo<ViewSwitchProps>(({ navigation }) => (
|
||||||
<View marginR-16>
|
<ViewSwitch navigation={navigation} />
|
||||||
<ViewSwitch navigation={navigation}/>
|
|
||||||
</View>
|
|
||||||
));
|
));
|
||||||
|
|
||||||
const HeaderRight = React.memo<HeaderRightProps>(({routeName, navigation}) => {
|
const HeaderRight = React.memo<HeaderRightProps>(
|
||||||
|
({ routeName, navigation }) => {
|
||||||
const showViewSwitch = ["calendar", "todos", "index"].includes(routeName);
|
const showViewSwitch = ["calendar", "todos", "index"].includes(routeName);
|
||||||
|
|
||||||
if (Device.deviceType !== DeviceType.TABLET || !showViewSwitch) {
|
if (Device.deviceType !== DeviceType.TABLET || !showViewSwitch) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <MemoizedViewSwitch navigation={navigation}/>;
|
return <MemoizedViewSwitch navigation={navigation} />;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
export default function TabLayout() {
|
export default function TabLayout() {
|
||||||
const {mutateAsync: signOut} = useSignOut();
|
const { mutateAsync: signOut } = useSignOut();
|
||||||
const setIsFamilyView = useSetAtom(isFamilyViewAtom);
|
const setIsFamilyView = useSetAtom(isFamilyViewAtom);
|
||||||
const setPageIndex = useSetAtom(settingsPageIndex);
|
const setPageIndex = useSetAtom(settingsPageIndex);
|
||||||
const setUserView = useSetAtom(userSettingsView);
|
const setUserView = useSetAtom(userSettingsView);
|
||||||
const setToDosIndex = useSetAtom(toDosPageIndex);
|
const setToDosIndex = useSetAtom(toDosPageIndex);
|
||||||
|
const { resyncAllCalendars, isSyncing } = useCalSync();
|
||||||
|
|
||||||
const screenOptions = ({
|
const onRefresh = React.useCallback(async () => {
|
||||||
navigation,
|
try {
|
||||||
route,
|
await resyncAllCalendars();
|
||||||
}: {
|
} catch (error) {
|
||||||
navigation: DrawerNavigationProp<DrawerParamList>;
|
console.error("Refresh failed:", error);
|
||||||
route: RouteProp<DrawerParamList>;
|
}
|
||||||
}): DrawerNavigationOptions => ({
|
}, [resyncAllCalendars]);
|
||||||
headerShown: true,
|
|
||||||
headerTitleAlign: Device.deviceType === DeviceType.TABLET ? "left" : "center",
|
const screenOptions = ({
|
||||||
headerTitleStyle: {
|
navigation,
|
||||||
fontFamily: "Manrope_600SemiBold",
|
route,
|
||||||
fontSize: Device.deviceType === DeviceType.TABLET ? 22 : 17,
|
}: {
|
||||||
},
|
navigation: DrawerNavigationProp<DrawerParamList>;
|
||||||
headerLeft: () => (
|
route: RouteProp<DrawerParamList>;
|
||||||
<TouchableOpacity
|
}): DrawerNavigationOptions => ({
|
||||||
onPress={navigation.toggleDrawer}
|
headerShown: true,
|
||||||
style={{marginLeft: 16}}
|
headerTitleAlign:
|
||||||
|
Device.deviceType === DeviceType.TABLET ? "left" : "center",
|
||||||
|
headerTitleStyle: {
|
||||||
|
fontFamily: "Manrope_600SemiBold",
|
||||||
|
fontSize: Device.deviceType === DeviceType.TABLET ? 22 : 17,
|
||||||
|
},
|
||||||
|
headerLeft: () => (
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={navigation.toggleDrawer}
|
||||||
|
style={{ marginLeft: 16 }}
|
||||||
|
>
|
||||||
|
<DrawerIcon />
|
||||||
|
</TouchableOpacity>
|
||||||
|
),
|
||||||
|
headerRight: () => {
|
||||||
|
const showViewSwitch = ["calendar", "todos", "index"].includes(
|
||||||
|
route.name
|
||||||
|
);
|
||||||
|
const isCalendarPage = ["calendar", "index"].includes(route.name);
|
||||||
|
|
||||||
|
if (Device.deviceType !== DeviceType.TABLET || !showViewSwitch) {
|
||||||
|
return isCalendarPage ? (
|
||||||
|
<View marginR-16>
|
||||||
|
<RefreshButton onRefresh={onRefresh} isSyncing={isSyncing} />
|
||||||
|
</View>
|
||||||
|
) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View marginR-16 row centerV>
|
||||||
|
{isCalendarPage && (
|
||||||
|
<View marginR-16><RefreshButton onRefresh={onRefresh} isSyncing={isSyncing} /></View>
|
||||||
|
)}
|
||||||
|
<MemoizedViewSwitch navigation={navigation} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
drawerStyle: {
|
||||||
|
width: Device.deviceType === DeviceType.TABLET ? "30%" : "90%",
|
||||||
|
backgroundColor: "#f9f8f7",
|
||||||
|
height: "100%",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Drawer
|
||||||
|
initialRouteName={"index"}
|
||||||
|
detachInactiveScreens
|
||||||
|
screenOptions={screenOptions}
|
||||||
|
drawerContent={(props) => {
|
||||||
|
return (
|
||||||
|
<DrawerContentScrollView {...props} style={{}}>
|
||||||
|
<View centerV marginH-30 marginT-20 marginB-20 row>
|
||||||
|
<ImageBackground
|
||||||
|
source={require("../../assets/images/splash.png")}
|
||||||
|
style={{
|
||||||
|
backgroundColor: "transparent",
|
||||||
|
height: 51.43,
|
||||||
|
aspectRatio: 1,
|
||||||
|
marginRight: 8,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Text style={styles.title}>Welcome to Cally</Text>
|
||||||
|
</View>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flexDirection: "row",
|
||||||
|
paddingHorizontal: 30,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<DrawerIcon/>
|
<View style={{ flex: 1, paddingRight: 5 }}>
|
||||||
</TouchableOpacity>
|
<DrawerButton
|
||||||
),
|
title={"Calendar"}
|
||||||
headerRight: () => {
|
color="rgb(7, 184, 199)"
|
||||||
const showViewSwitch = ["calendar", "todos", "index"].includes(route.name);
|
bgColor={"rgb(231, 248, 250)"}
|
||||||
|
pressFunc={() => {
|
||||||
if (Device.deviceType !== DeviceType.TABLET || !showViewSwitch) {
|
props.navigation.navigate("calendar");
|
||||||
return null;
|
setPageIndex(0);
|
||||||
}
|
setToDosIndex(0);
|
||||||
|
setUserView(true);
|
||||||
return <MemoizedViewSwitch navigation={navigation}/>;
|
setIsFamilyView(false);
|
||||||
},
|
}}
|
||||||
drawerStyle: {
|
icon={<NavCalendarIcon />}
|
||||||
width: Device.deviceType === DeviceType.TABLET ? "30%" : "90%",
|
/>
|
||||||
backgroundColor: "#f9f8f7",
|
<DrawerButton
|
||||||
height: "100%",
|
color="#50be0c"
|
||||||
},
|
title={"Groceries"}
|
||||||
})
|
bgColor={"#eef9e7"}
|
||||||
|
pressFunc={() => {
|
||||||
return (
|
props.navigation.navigate("grocery");
|
||||||
<Drawer
|
setPageIndex(0);
|
||||||
initialRouteName={"index"}
|
setToDosIndex(0);
|
||||||
detachInactiveScreens
|
setUserView(true);
|
||||||
screenOptions={screenOptions}
|
setIsFamilyView(false);
|
||||||
drawerContent={(props) => {
|
}}
|
||||||
return (
|
icon={<NavGroceryIcon />}
|
||||||
<DrawerContentScrollView {...props} style={{}}>
|
/>
|
||||||
<View centerV marginH-30 marginT-20 marginB-20 row>
|
<DrawerButton
|
||||||
<ImageBackground
|
color="#ea156d"
|
||||||
source={require("../../assets/images/splash.png")}
|
title={"Feedback"}
|
||||||
style={{
|
bgColor={"#fdedf4"}
|
||||||
backgroundColor: "transparent",
|
pressFunc={() => {
|
||||||
height: 51.43,
|
props.navigation.navigate("feedback");
|
||||||
aspectRatio: 1,
|
setPageIndex(0);
|
||||||
marginRight: 8,
|
setToDosIndex(0);
|
||||||
}}
|
setUserView(true);
|
||||||
/>
|
setIsFamilyView(false);
|
||||||
<Text style={styles.title}>Welcome to Cally</Text>
|
}}
|
||||||
</View>
|
icon={<FeedbackNavIcon />}
|
||||||
<View
|
/>
|
||||||
style={{
|
</View>
|
||||||
flexDirection: "row",
|
<View style={{ flex: 1, paddingRight: 0 }}>
|
||||||
paddingHorizontal: 30,
|
{/*<DrawerButton
|
||||||
}}
|
|
||||||
>
|
|
||||||
<View style={{flex: 1, paddingRight: 5}}>
|
|
||||||
<DrawerButton
|
|
||||||
title={"Calendar"}
|
|
||||||
color="rgb(7, 184, 199)"
|
|
||||||
bgColor={"rgb(231, 248, 250)"}
|
|
||||||
pressFunc={() => {
|
|
||||||
props.navigation.navigate("calendar");
|
|
||||||
setPageIndex(0);
|
|
||||||
setToDosIndex(0);
|
|
||||||
setUserView(true);
|
|
||||||
setIsFamilyView(false);
|
|
||||||
}}
|
|
||||||
icon={<NavCalendarIcon/>}
|
|
||||||
/>
|
|
||||||
<DrawerButton
|
|
||||||
color="#50be0c"
|
|
||||||
title={"Groceries"}
|
|
||||||
bgColor={"#eef9e7"}
|
|
||||||
pressFunc={() => {
|
|
||||||
props.navigation.navigate("grocery");
|
|
||||||
setPageIndex(0);
|
|
||||||
setToDosIndex(0);
|
|
||||||
setUserView(true);
|
|
||||||
setIsFamilyView(false);
|
|
||||||
}}
|
|
||||||
icon={<NavGroceryIcon/>}
|
|
||||||
/>
|
|
||||||
<DrawerButton
|
|
||||||
color="#ea156d"
|
|
||||||
title={"Feedback"}
|
|
||||||
bgColor={"#fdedf4"}
|
|
||||||
pressFunc={() => {
|
|
||||||
props.navigation.navigate("feedback");
|
|
||||||
setPageIndex(0);
|
|
||||||
setToDosIndex(0);
|
|
||||||
setUserView(true);
|
|
||||||
setIsFamilyView(false);
|
|
||||||
}}
|
|
||||||
icon={<FeedbackNavIcon/>}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
<View style={{flex: 1, paddingRight: 0}}>
|
|
||||||
{/*<DrawerButton
|
|
||||||
color="#fd1775"
|
color="#fd1775"
|
||||||
title={"My Reminders"}
|
title={"My Reminders"}
|
||||||
bgColor={"#ffe8f2"}
|
bgColor={"#ffe8f2"}
|
||||||
@ -182,184 +218,184 @@ export default function TabLayout() {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>*/}
|
/>*/}
|
||||||
<DrawerButton
|
<DrawerButton
|
||||||
color="#8005eb"
|
color="#8005eb"
|
||||||
title={"To Do's"}
|
title={"To Do's"}
|
||||||
bgColor={"#f3e6fd"}
|
bgColor={"#f3e6fd"}
|
||||||
pressFunc={() => {
|
pressFunc={() => {
|
||||||
props.navigation.navigate("todos");
|
props.navigation.navigate("todos");
|
||||||
setPageIndex(0);
|
setPageIndex(0);
|
||||||
setToDosIndex(0);
|
setToDosIndex(0);
|
||||||
setUserView(true);
|
setUserView(true);
|
||||||
setIsFamilyView(false);
|
setIsFamilyView(false);
|
||||||
}}
|
}}
|
||||||
icon={<NavToDosIcon/>}
|
icon={<NavToDosIcon />}
|
||||||
/>
|
/>
|
||||||
<DrawerButton
|
<DrawerButton
|
||||||
color="#e0ca03"
|
color="#e0ca03"
|
||||||
title={"Brain Dump"}
|
title={"Brain Dump"}
|
||||||
bgColor={"#fffacb"}
|
bgColor={"#fffacb"}
|
||||||
pressFunc={() => {
|
pressFunc={() => {
|
||||||
props.navigation.navigate("brain_dump");
|
props.navigation.navigate("brain_dump");
|
||||||
setPageIndex(0);
|
setPageIndex(0);
|
||||||
setToDosIndex(0);
|
setToDosIndex(0);
|
||||||
setUserView(true);
|
setUserView(true);
|
||||||
setIsFamilyView(false);
|
setIsFamilyView(false);
|
||||||
}}
|
}}
|
||||||
icon={<NavBrainDumpIcon/>}
|
icon={<NavBrainDumpIcon />}
|
||||||
/>
|
/>
|
||||||
<DrawerButton
|
<DrawerButton
|
||||||
color="#e0ca03"
|
color="#e0ca03"
|
||||||
title={"Notifications"}
|
title={"Notifications"}
|
||||||
bgColor={"#ffdda1"}
|
bgColor={"#ffdda1"}
|
||||||
pressFunc={() => {
|
pressFunc={() => {
|
||||||
props.navigation.navigate("notifications");
|
props.navigation.navigate("notifications");
|
||||||
setPageIndex(0);
|
setPageIndex(0);
|
||||||
setToDosIndex(0);
|
setToDosIndex(0);
|
||||||
setUserView(true);
|
setUserView(true);
|
||||||
setIsFamilyView(false);
|
setIsFamilyView(false);
|
||||||
}}
|
}}
|
||||||
icon={
|
icon={
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="notifications-outline"
|
name="notifications-outline"
|
||||||
size={24}
|
size={24}
|
||||||
color={"#ffa200"}
|
color={"#ffa200"}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<Button
|
<Button
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
props.navigation.navigate("settings");
|
props.navigation.navigate("settings");
|
||||||
setPageIndex(0);
|
setPageIndex(0);
|
||||||
setToDosIndex(0);
|
setToDosIndex(0);
|
||||||
setUserView(true);
|
setUserView(true);
|
||||||
setIsFamilyView(false);
|
setIsFamilyView(false);
|
||||||
}}
|
}}
|
||||||
label={"Manage Settings"}
|
label={"Manage Settings"}
|
||||||
labelStyle={styles.label}
|
labelStyle={styles.label}
|
||||||
iconSource={() => (
|
iconSource={() => (
|
||||||
<View
|
<View
|
||||||
backgroundColor="#ededed"
|
backgroundColor="#ededed"
|
||||||
width={60}
|
width={60}
|
||||||
height={60}
|
height={60}
|
||||||
style={{borderRadius: 50}}
|
style={{ borderRadius: 50 }}
|
||||||
marginR-10
|
marginR-10
|
||||||
centerV
|
centerV
|
||||||
centerH
|
centerH
|
||||||
>
|
>
|
||||||
<NavSettingsIcon/>
|
<NavSettingsIcon />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
backgroundColor="white"
|
backgroundColor="white"
|
||||||
color="#464039"
|
color="#464039"
|
||||||
paddingV-30
|
paddingV-30
|
||||||
marginH-30
|
marginH-30
|
||||||
borderRadius={18.55}
|
borderRadius={18.55}
|
||||||
style={{elevation: 0}}
|
style={{ elevation: 0 }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
size={ButtonSize.large}
|
size={ButtonSize.large}
|
||||||
marginH-10
|
marginH-10
|
||||||
marginT-12
|
marginT-12
|
||||||
paddingV-15
|
paddingV-15
|
||||||
style={{
|
style={{
|
||||||
marginTop: 50,
|
marginTop: 50,
|
||||||
backgroundColor: "transparent",
|
backgroundColor: "transparent",
|
||||||
borderWidth: 1.3,
|
borderWidth: 1.3,
|
||||||
borderColor: "#fd1775",
|
borderColor: "#fd1775",
|
||||||
}}
|
}}
|
||||||
label="Sign out of Cally"
|
label="Sign out of Cally"
|
||||||
color="#fd1775"
|
color="#fd1775"
|
||||||
labelStyle={styles.signOut}
|
labelStyle={styles.signOut}
|
||||||
onPress={() => signOut()}
|
onPress={() => signOut()}
|
||||||
/>
|
|
||||||
</DrawerContentScrollView>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Drawer.Screen
|
|
||||||
name="index"
|
|
||||||
options={{
|
|
||||||
drawerLabel: "Calendar",
|
|
||||||
title:
|
|
||||||
Device.deviceType === DeviceType.TABLET
|
|
||||||
? "Family Calendar"
|
|
||||||
: "Calendar",
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<Drawer.Screen
|
</DrawerContentScrollView>
|
||||||
name="calendar"
|
);
|
||||||
options={{
|
}}
|
||||||
drawerLabel: "Calendar",
|
>
|
||||||
title:
|
<Drawer.Screen
|
||||||
Device.deviceType === DeviceType.TABLET
|
name="index"
|
||||||
? "Family Calendar"
|
options={{
|
||||||
: "Calendar",
|
drawerLabel: "Calendar",
|
||||||
drawerItemStyle: {display: "none"},
|
title:
|
||||||
}}
|
Device.deviceType === DeviceType.TABLET
|
||||||
/>
|
? "Family Calendar"
|
||||||
<Drawer.Screen
|
: "Calendar",
|
||||||
name="brain_dump"
|
}}
|
||||||
options={{
|
/>
|
||||||
drawerLabel: "Brain Dump",
|
<Drawer.Screen
|
||||||
title: "Brain Dump",
|
name="calendar"
|
||||||
}}
|
options={{
|
||||||
/>
|
drawerLabel: "Calendar",
|
||||||
<Drawer.Screen
|
title:
|
||||||
name="settings"
|
Device.deviceType === DeviceType.TABLET
|
||||||
options={{
|
? "Family Calendar"
|
||||||
drawerLabel: "Settings",
|
: "Calendar",
|
||||||
title: "Settings",
|
drawerItemStyle: { display: "none" },
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Drawer.Screen
|
<Drawer.Screen
|
||||||
name="grocery"
|
name="brain_dump"
|
||||||
options={{
|
options={{
|
||||||
drawerLabel: "Grocery",
|
drawerLabel: "Brain Dump",
|
||||||
title: "Grocery",
|
title: "Brain Dump",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Drawer.Screen
|
<Drawer.Screen
|
||||||
name="reminders"
|
name="settings"
|
||||||
options={{
|
options={{
|
||||||
drawerLabel: "Reminders",
|
drawerLabel: "Settings",
|
||||||
title: "Reminders",
|
title: "Settings",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Drawer.Screen
|
<Drawer.Screen
|
||||||
name="todos"
|
name="grocery"
|
||||||
options={{
|
options={{
|
||||||
drawerLabel: "To-Do",
|
drawerLabel: "Grocery",
|
||||||
title:
|
title: "Grocery",
|
||||||
Device.deviceType === DeviceType.TABLET
|
}}
|
||||||
? "Family To Do's"
|
/>
|
||||||
: "To Do's",
|
<Drawer.Screen
|
||||||
}}
|
name="reminders"
|
||||||
/>
|
options={{
|
||||||
<Drawer.Screen
|
drawerLabel: "Reminders",
|
||||||
name="notifications"
|
title: "Reminders",
|
||||||
options={{
|
}}
|
||||||
drawerLabel: "Notifications",
|
/>
|
||||||
title: "Notifications",
|
<Drawer.Screen
|
||||||
}}
|
name="todos"
|
||||||
/>
|
options={{
|
||||||
<Drawer.Screen
|
drawerLabel: "To-Do",
|
||||||
name="feedback"
|
title:
|
||||||
options={{drawerLabel: "Feedback", title: "Feedback"}}
|
Device.deviceType === DeviceType.TABLET
|
||||||
/>
|
? "Family To Do's"
|
||||||
</Drawer>
|
: "To Do's",
|
||||||
);
|
}}
|
||||||
|
/>
|
||||||
|
<Drawer.Screen
|
||||||
|
name="notifications"
|
||||||
|
options={{
|
||||||
|
drawerLabel: "Notifications",
|
||||||
|
title: "Notifications",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Drawer.Screen
|
||||||
|
name="feedback"
|
||||||
|
options={{ drawerLabel: "Feedback", title: "Feedback" }}
|
||||||
|
/>
|
||||||
|
</Drawer>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
signOut: {fontFamily: "Poppins_500Medium", fontSize: 15},
|
signOut: { fontFamily: "Poppins_500Medium", fontSize: 15 },
|
||||||
label: {fontFamily: "Poppins_400Medium", fontSize: 15},
|
label: { fontFamily: "Poppins_400Medium", fontSize: 15 },
|
||||||
title: {
|
title: {
|
||||||
fontSize: 26.13,
|
fontSize: 26.13,
|
||||||
fontFamily: "Manrope_600SemiBold",
|
fontFamily: "Manrope_600SemiBold",
|
||||||
color: "#262627",
|
color: "#262627",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -61,7 +61,6 @@ export default function Screen() {
|
|||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
paddingRight: 200,
|
paddingRight: 200,
|
||||||
}}
|
}}
|
||||||
refreshControl={refreshControl}
|
|
||||||
bounces={true}
|
bounces={true}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
pointerEvents={isSyncing ? "auto" : "none"}
|
pointerEvents={isSyncing ? "auto" : "none"}
|
||||||
@ -74,7 +73,6 @@ export default function Screen() {
|
|||||||
<ScrollView
|
<ScrollView
|
||||||
style={{flex: 1, height: "100%"}}
|
style={{flex: 1, height: "100%"}}
|
||||||
contentContainerStyle={{flex: 1, height: "100%"}}
|
contentContainerStyle={{flex: 1, height: "100%"}}
|
||||||
refreshControl={refreshControl}
|
|
||||||
bounces={true}
|
bounces={true}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
>
|
>
|
||||||
|
|||||||
20
assets/svgs/CheckmarkIcon.tsx
Normal file
20
assets/svgs/CheckmarkIcon.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import Svg, { SvgProps, Path } from "react-native-svg"
|
||||||
|
const CheckmarkIcon = (props: SvgProps) => (
|
||||||
|
<Svg
|
||||||
|
width={13}
|
||||||
|
height={10}
|
||||||
|
viewBox="0 0 13 10"
|
||||||
|
fill={props.color || "white"}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<Path
|
||||||
|
stroke="#fff"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={1.95}
|
||||||
|
d="m1.48 5.489 3.2 3.178 7.2-7.15"
|
||||||
|
/>
|
||||||
|
</Svg>
|
||||||
|
)
|
||||||
|
export default CheckmarkIcon
|
||||||
@ -15,7 +15,12 @@ import { UserProfile } from "@/hooks/firebase/types/profileTypes";
|
|||||||
import { ScrollView } from "react-native-gesture-handler";
|
import { ScrollView } from "react-native-gesture-handler";
|
||||||
|
|
||||||
const groupToDosByDate = (toDos: IToDo[]) => {
|
const groupToDosByDate = (toDos: IToDo[]) => {
|
||||||
let sortedTodos = toDos.sort((a, b) => a.date - b.date);
|
let sortedTodos = toDos.sort((a, b) => {
|
||||||
|
const dateA = a.date === null ? new Date() : a.date;
|
||||||
|
const dateB = b.date === null ? new Date() : b.date;
|
||||||
|
return dateA - dateB;
|
||||||
|
});
|
||||||
|
|
||||||
return sortedTodos.reduce(
|
return sortedTodos.reduce(
|
||||||
(groups, toDo) => {
|
(groups, toDo) => {
|
||||||
let dateKey;
|
let dateKey;
|
||||||
@ -34,9 +39,7 @@ const groupToDosByDate = (toDos: IToDo[]) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (toDo.date === null) {
|
if (toDo.date === null || isToday(toDo.date)) {
|
||||||
dateKey = "No Date";
|
|
||||||
} else if (isToday(toDo.date)) {
|
|
||||||
dateKey = "Today";
|
dateKey = "Today";
|
||||||
} else if (isTomorrow(toDo.date)) {
|
} else if (isTomorrow(toDo.date)) {
|
||||||
dateKey = "Tomorrow";
|
dateKey = "Tomorrow";
|
||||||
@ -228,42 +231,47 @@ const SingleUserChoreList = ({ user }: { user: UserProfile }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
marginB-402
|
|
||||||
marginT-10
|
marginT-10
|
||||||
paddingH-10
|
|
||||||
backgroundColor="#f9f8f7"
|
backgroundColor="#f9f8f7"
|
||||||
style={{ minHeight: 800, borderRadius: 9.11 }}
|
style={{
|
||||||
|
minHeight: 600,
|
||||||
|
maxHeight: 600,
|
||||||
|
borderRadius: 9.11,
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
width={355}
|
width={355}
|
||||||
>
|
>
|
||||||
<ScrollView>
|
<ScrollView showsVerticalScrollIndicator={false}>
|
||||||
{noDateToDos.length > 0 && (
|
<View paddingH-10 paddingB-90>
|
||||||
<View key="No Date">
|
{noDateToDos.length > 0 && (
|
||||||
<View row spread paddingH-19 marginB-12>
|
<View key="No Date">
|
||||||
<Text
|
<View row spread paddingH-19 marginB-12>
|
||||||
text70
|
<Text
|
||||||
style={{
|
text70
|
||||||
fontWeight: "bold",
|
style={{
|
||||||
}}
|
fontWeight: "bold",
|
||||||
>
|
}}
|
||||||
Unscheduled
|
>
|
||||||
</Text>
|
Unscheduled
|
||||||
<AntDesign
|
</Text>
|
||||||
name={expandNoDate ? "caretdown" : "caretright"}
|
<AntDesign
|
||||||
size={24}
|
name={expandNoDate ? "caretdown" : "caretright"}
|
||||||
color="#fd1575"
|
size={24}
|
||||||
onPress={() => {
|
color="#fd1575"
|
||||||
setExpandNoDate(!expandNoDate);
|
onPress={() => {
|
||||||
}}
|
setExpandNoDate(!expandNoDate);
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
{expandNoDate &&
|
||||||
|
noDateToDos
|
||||||
|
.sort((a, b) => Number(a.done) - Number(b.done))
|
||||||
|
.map((item) => <ToDoItem key={item.id} item={item} />)}
|
||||||
</View>
|
</View>
|
||||||
{expandNoDate &&
|
)}
|
||||||
noDateToDos
|
|
||||||
.sort((a, b) => Number(a.done) - Number(b.done))
|
|
||||||
.map((item) => <ToDoItem key={item.id} item={item} />)}
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{datedToDos.map(renderTodoGroup)}
|
{datedToDos.map(renderTodoGroup)}
|
||||||
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { ImageBackground, StyleSheet } from "react-native";
|
|||||||
import { colorMap } from "@/constants/colorMap";
|
import { colorMap } from "@/constants/colorMap";
|
||||||
import { ScrollView } from "react-native-gesture-handler";
|
import { ScrollView } from "react-native-gesture-handler";
|
||||||
import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
|
import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
|
||||||
|
import AddChore from "../../todos/AddChore";
|
||||||
|
|
||||||
const TabletChoresPage = () => {
|
const TabletChoresPage = () => {
|
||||||
const {data: users} = useGetFamilyMembers();
|
const {data: users} = useGetFamilyMembers();
|
||||||
@ -98,6 +99,9 @@ const TabletChoresPage = () => {
|
|||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
<View style={styles.addBtn}>
|
||||||
|
<AddChore />
|
||||||
|
</View>
|
||||||
</TabletContainer>
|
</TabletContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -113,6 +117,11 @@ const styles = StyleSheet.create({
|
|||||||
fontSize: 22.43,
|
fontSize: 22.43,
|
||||||
color: "#2c2c2c",
|
color: "#2c2c2c",
|
||||||
},
|
},
|
||||||
|
addBtn: {
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 50,
|
||||||
|
right: 220
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export default TabletChoresPage;
|
export default TabletChoresPage;
|
||||||
|
|||||||
@ -5,9 +5,9 @@ import { InnerCalendar } from "@/components/pages/calendar/InnerCalendar";
|
|||||||
export default function CalendarPage() {
|
export default function CalendarPage() {
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={{ flex: 1, height: "100%", padding: 10 }}
|
style={{ flex: 1, height: "100%", padding: 0 }}
|
||||||
paddingH-22
|
paddingH-0
|
||||||
paddingT-22
|
paddingT-0
|
||||||
>
|
>
|
||||||
{/*<HeaderTemplate
|
{/*<HeaderTemplate
|
||||||
message={"Let's get your week started !"}
|
message={"Let's get your week started !"}
|
||||||
|
|||||||
@ -25,9 +25,10 @@ export const InnerCalendar = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<View
|
<View
|
||||||
style={{flex: 1, backgroundColor: "#fff", borderRadius: 30, marginBottom: 10, overflow: "hidden"}}
|
style={{flex: 1, backgroundColor: "#fff", borderRadius: 0, marginBottom: 0, overflow: "hidden"}}
|
||||||
ref={calendarContainerRef}
|
ref={calendarContainerRef}
|
||||||
onLayout={onLayout}
|
onLayout={onLayout}
|
||||||
|
paddingB-15
|
||||||
>
|
>
|
||||||
<CalendarHeader/>
|
<CalendarHeader/>
|
||||||
{calendarHeight > 0 && (
|
{calendarHeight > 0 && (
|
||||||
|
|||||||
@ -40,6 +40,7 @@ import DeleteEventDialog from "./DeleteEventDialog";
|
|||||||
import { useDeleteEvent } from "@/hooks/firebase/useDeleteEvent";
|
import { useDeleteEvent } from "@/hooks/firebase/useDeleteEvent";
|
||||||
import AddPersonIcon from "@/assets/svgs/AddPersonIcon";
|
import AddPersonIcon from "@/assets/svgs/AddPersonIcon";
|
||||||
import { addHours, startOfHour, startOfMinute } from "date-fns";
|
import { addHours, startOfHour, startOfMinute } from "date-fns";
|
||||||
|
import { useAuthContext } from "@/contexts/AuthContext";
|
||||||
|
|
||||||
const daysOfWeek = [
|
const daysOfWeek = [
|
||||||
{ label: "Monday", value: "monday" },
|
{ label: "Monday", value: "monday" },
|
||||||
@ -53,6 +54,7 @@ const daysOfWeek = [
|
|||||||
|
|
||||||
export const ManuallyAddEventModal = () => {
|
export const ManuallyAddEventModal = () => {
|
||||||
const insets = useSafeAreaInsets();
|
const insets = useSafeAreaInsets();
|
||||||
|
const { user } = useAuthContext();
|
||||||
|
|
||||||
const [selectedNewEventDate, setSelectedNewEndDate] = useAtom(
|
const [selectedNewEventDate, setSelectedNewEndDate] = useAtom(
|
||||||
selectedNewEventDateAtom
|
selectedNewEventDateAtom
|
||||||
@ -115,7 +117,7 @@ export const ManuallyAddEventModal = () => {
|
|||||||
editEvent?.end ?? initialDate ?? new Date()
|
editEvent?.end ?? initialDate ?? new Date()
|
||||||
);
|
);
|
||||||
const [selectedAttendees, setSelectedAttendees] = useState<string[]>(
|
const [selectedAttendees, setSelectedAttendees] = useState<string[]>(
|
||||||
editEvent?.attendees ?? []
|
editEvent?.attendees ?? [user?.uid]
|
||||||
);
|
);
|
||||||
const [repeatInterval, setRepeatInterval] = useState<PickerMultiValue>([]);
|
const [repeatInterval, setRepeatInterval] = useState<PickerMultiValue>([]);
|
||||||
|
|
||||||
@ -162,7 +164,7 @@ export const ManuallyAddEventModal = () => {
|
|||||||
|
|
||||||
setStartDate(initialDate ?? new Date());
|
setStartDate(initialDate ?? new Date());
|
||||||
setEndDate(editEvent?.end ?? initialDate ?? new Date());
|
setEndDate(editEvent?.end ?? initialDate ?? new Date());
|
||||||
setSelectedAttendees(editEvent?.attendees ?? []);
|
setSelectedAttendees(editEvent?.attendees ?? [user?.uid]);
|
||||||
setLocation(editEvent?.location ?? "");
|
setLocation(editEvent?.location ?? "");
|
||||||
setRepeatInterval([]);
|
setRepeatInterval([]);
|
||||||
}, [editEvent, selectedNewEventDate]);
|
}, [editEvent, selectedNewEventDate]);
|
||||||
@ -247,10 +249,10 @@ export const ManuallyAddEventModal = () => {
|
|||||||
Alert.alert("Alert", "Title field cannot be empty");
|
Alert.alert("Alert", "Title field cannot be empty");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// if (!selectedAttendees || selectedAttendees?.length === 0) {
|
if (!selectedAttendees || selectedAttendees?.length === 0) {
|
||||||
// Alert.alert('Alert', 'Cannot have an event without any attendees');
|
Alert.alert('Alert', 'Cannot have an event without any attendees');
|
||||||
// return false;
|
return false;
|
||||||
// }
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -25,6 +25,7 @@ const GroceryItem = ({
|
|||||||
const { profileData } = useAuthContext();
|
const { profileData } = useAuthContext();
|
||||||
const { data: creator } = useGetUserById(item.creatorId);
|
const { data: creator } = useGetUserById(item.creatorId);
|
||||||
const isParent = profileData?.userType === ProfileType.PARENT;
|
const isParent = profileData?.userType === ProfileType.PARENT;
|
||||||
|
const isCaregiver = profileData?.userType === ProfileType.CAREGIVER;
|
||||||
|
|
||||||
const [openFreqEdit, setOpenFreqEdit] = useState<boolean>(false);
|
const [openFreqEdit, setOpenFreqEdit] = useState<boolean>(false);
|
||||||
const [isEditingTitle, setIsEditingTitle] = useState<boolean>(false);
|
const [isEditingTitle, setIsEditingTitle] = useState<boolean>(false);
|
||||||
@ -36,7 +37,7 @@ const GroceryItem = ({
|
|||||||
const closeEdit = () => setIsEditingTitle(false);
|
const closeEdit = () => setIsEditingTitle(false);
|
||||||
|
|
||||||
const getInitials = (firstName: string, lastName: string) => {
|
const getInitials = (firstName: string, lastName: string) => {
|
||||||
return `${firstName.charAt(0)}${lastName.charAt(0)}`;
|
return `${firstName.charAt(0).toUpperCase()}${lastName.charAt(0).toUpperCase()}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -81,7 +82,7 @@ const GroceryItem = ({
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<View flex>
|
<View flex>
|
||||||
{isParent ? (
|
{(isParent || isCaregiver) && !item.bought ? (
|
||||||
<TouchableOpacity onPress={() => setIsEditingTitle(true)}>
|
<TouchableOpacity onPress={() => setIsEditingTitle(true)}>
|
||||||
<Text
|
<Text
|
||||||
text70T
|
text70T
|
||||||
@ -98,7 +99,7 @@ const GroceryItem = ({
|
|||||||
) : (
|
) : (
|
||||||
<Text
|
<Text
|
||||||
text70T
|
text70T
|
||||||
style={[styles.title, { color: item.bought ? "red" : "black" }]}
|
style={[styles.title, { textDecorationLine: item.bought ? "line-through" : "none", }]}
|
||||||
>
|
>
|
||||||
{item.title}
|
{item.title}
|
||||||
</Text>
|
</Text>
|
||||||
@ -108,7 +109,7 @@ const GroceryItem = ({
|
|||||||
|
|
||||||
{!item.approved ? (
|
{!item.approved ? (
|
||||||
<View row centerV>
|
<View row centerV>
|
||||||
{isParent && (
|
{isParent || isCaregiver && (
|
||||||
<>
|
<>
|
||||||
<AntDesign
|
<AntDesign
|
||||||
name="check"
|
name="check"
|
||||||
@ -132,7 +133,7 @@ const GroceryItem = ({
|
|||||||
</View>
|
</View>
|
||||||
) : (
|
) : (
|
||||||
!isEditingTitle &&
|
!isEditingTitle &&
|
||||||
isParent && (
|
(isParent || isCaregiver) && (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
value={item.bought}
|
value={item.bought}
|
||||||
containerStyle={[styles.checkbox, { borderRadius: 50 }]}
|
containerStyle={[styles.checkbox, { borderRadius: 50 }]}
|
||||||
@ -180,7 +181,7 @@ const GroceryItem = ({
|
|||||||
width: 24.64,
|
width: 24.64,
|
||||||
aspectRatio: 1,
|
aspectRatio: 1,
|
||||||
marginRight: 8,
|
marginRight: 8,
|
||||||
backgroundColor: "#ccc",
|
backgroundColor: creator?.eventColor || "gray",
|
||||||
borderRadius: 100,
|
borderRadius: 100,
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
|
|||||||
@ -62,7 +62,7 @@ const GroceryList = ({onInputFocus}: {onInputFocus: (y: number) => void}) => {
|
|||||||
id: "",
|
id: "",
|
||||||
title: title,
|
title: title,
|
||||||
category: category,
|
category: category,
|
||||||
approved: profileData?.userType === ProfileType.PARENT,
|
approved: profileData?.userType === ProfileType.PARENT || profileData?.userType === ProfileType.CAREGIVER,
|
||||||
recurring: false,
|
recurring: false,
|
||||||
frequency: GroceryFrequency.Never,
|
frequency: GroceryFrequency.Never,
|
||||||
bought: false,
|
bought: false,
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import {Ionicons} from "@expo/vector-icons";
|
|||||||
import {PanningDirectionsEnum} from "react-native-ui-lib/src/incubator/panView";
|
import {PanningDirectionsEnum} from "react-native-ui-lib/src/incubator/panView";
|
||||||
import {Alert, Dimensions, KeyboardAvoidingView, StyleSheet} from "react-native";
|
import {Alert, Dimensions, KeyboardAvoidingView, StyleSheet} from "react-native";
|
||||||
import DropModalIcon from "@/assets/svgs/DropModalIcon";
|
import DropModalIcon from "@/assets/svgs/DropModalIcon";
|
||||||
import {IToDo} from "@/hooks/firebase/types/todoData";
|
import {IToDo, REPEAT_TYPE} from "@/hooks/firebase/types/todoData";
|
||||||
import AssigneesDisplay from "@/components/shared/AssigneesDisplay";
|
import AssigneesDisplay from "@/components/shared/AssigneesDisplay";
|
||||||
import {useGetFamilyMembers} from "@/hooks/firebase/useGetFamilyMembers";
|
import {useGetFamilyMembers} from "@/hooks/firebase/useGetFamilyMembers";
|
||||||
import CalendarIcon from "@/assets/svgs/CalendarIcon";
|
import CalendarIcon from "@/assets/svgs/CalendarIcon";
|
||||||
@ -39,7 +39,7 @@ const defaultTodo = {
|
|||||||
points: 10,
|
points: 10,
|
||||||
date: new Date(),
|
date: new Date(),
|
||||||
rotate: false,
|
rotate: false,
|
||||||
repeatType: "Every week",
|
repeatType: REPEAT_TYPE.NONE,
|
||||||
assignees: [],
|
assignees: [],
|
||||||
repeatDays: []
|
repeatDays: []
|
||||||
};
|
};
|
||||||
@ -138,6 +138,7 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => {
|
|||||||
padding: 0,
|
padding: 0,
|
||||||
paddingTop: 4,
|
paddingTop: 4,
|
||||||
margin: 0,
|
margin: 0,
|
||||||
|
maxWidth: 600
|
||||||
}}
|
}}
|
||||||
visible={addChoreDialogProps.isVisible}
|
visible={addChoreDialogProps.isVisible}
|
||||||
>
|
>
|
||||||
@ -260,7 +261,7 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => {
|
|||||||
))}
|
))}
|
||||||
</Picker>
|
</Picker>
|
||||||
</View>
|
</View>
|
||||||
{todo.repeatType == "Every week" && <RepeatFreq handleRepeatDaysChange={handleRepeatDaysChange}
|
{todo.repeatType == REPEAT_TYPE.EVERY_WEEK && <RepeatFreq handleRepeatDaysChange={handleRepeatDaysChange}
|
||||||
repeatDays={todo.repeatDays ?? []}/>}
|
repeatDays={todo.repeatDays ?? []}/>}
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.divider}/>
|
<View style={styles.divider}/>
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import {IToDo} from "@/hooks/firebase/types/todoData";
|
|||||||
import DropdownIcon from "@/assets/svgs/DropdownIcon";
|
import DropdownIcon from "@/assets/svgs/DropdownIcon";
|
||||||
import {Dropdown} from "react-native-element-dropdown";
|
import {Dropdown} from "react-native-element-dropdown";
|
||||||
import {useGetFamilyMembers} from "@/hooks/firebase/useGetFamilyMembers";
|
import {useGetFamilyMembers} from "@/hooks/firebase/useGetFamilyMembers";
|
||||||
import {useAuthContext} from "@/contexts/AuthContext";
|
import {ProfileType, useAuthContext} from "@/contexts/AuthContext";
|
||||||
import {StyleSheet} from "react-native";
|
import {StyleSheet} from "react-native";
|
||||||
|
|
||||||
const FILTER_OPTIONS = {
|
const FILTER_OPTIONS = {
|
||||||
@ -17,7 +17,12 @@ const FILTER_OPTIONS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const groupToDosByDate = (toDos: IToDo[]) => {
|
const groupToDosByDate = (toDos: IToDo[]) => {
|
||||||
let sortedTodos = toDos.sort((a, b) => a.date - b.date);
|
let sortedTodos = toDos.sort((a, b) => {
|
||||||
|
const dateA = a.date === null ? new Date() : a.date;
|
||||||
|
const dateB = b.date === null ? new Date() : b.date;
|
||||||
|
return dateA - dateB;
|
||||||
|
});
|
||||||
|
|
||||||
return sortedTodos.reduce(
|
return sortedTodos.reduce(
|
||||||
(groups, toDo) => {
|
(groups, toDo) => {
|
||||||
let dateKey;
|
let dateKey;
|
||||||
@ -36,9 +41,15 @@ const groupToDosByDate = (toDos: IToDo[]) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (toDo.date === null) {
|
const isOverdue = (date: Date) => {
|
||||||
dateKey = "No Date";
|
const today = new Date();
|
||||||
} else if (isToday(toDo.date)) {
|
today.setHours(0, 0, 0, 0);
|
||||||
|
return date < today;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isOverdue(toDo.date) && !toDo.done) {
|
||||||
|
dateKey = "Overdue";
|
||||||
|
} else if (toDo.date === null || isToday(toDo.date)) {
|
||||||
dateKey = "Today";
|
dateKey = "Today";
|
||||||
} else if (isTomorrow(toDo.date)) {
|
} else if (isTomorrow(toDo.date)) {
|
||||||
dateKey = "Tomorrow";
|
dateKey = "Tomorrow";
|
||||||
@ -48,7 +59,8 @@ const groupToDosByDate = (toDos: IToDo[]) => {
|
|||||||
dateKey = "Next 30 Days";
|
dateKey = "Next 30 Days";
|
||||||
subDateKey = format(toDo.date, "MMM d");
|
subDateKey = format(toDo.date, "MMM d");
|
||||||
} else {
|
} else {
|
||||||
return groups;
|
dateKey = "Later";
|
||||||
|
subDateKey = format(toDo.date, "MMM d, yyyy");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!groups[dateKey]) {
|
if (!groups[dateKey]) {
|
||||||
@ -58,7 +70,7 @@ const groupToDosByDate = (toDos: IToDo[]) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dateKey === "Next 30 Days" && subDateKey) {
|
if ((dateKey === "Next 30 Days" || dateKey === "Later") && subDateKey) {
|
||||||
if (!groups[dateKey].subgroups[subDateKey]) {
|
if (!groups[dateKey].subgroups[subDateKey]) {
|
||||||
groups[dateKey].subgroups[subDateKey] = [];
|
groups[dateKey].subgroups[subDateKey] = [];
|
||||||
}
|
}
|
||||||
@ -80,12 +92,16 @@ const groupToDosByDate = (toDos: IToDo[]) => {
|
|||||||
|
|
||||||
const resolveFilterOptions = (members, user) => {
|
const resolveFilterOptions = (members, user) => {
|
||||||
|
|
||||||
let options = members?.map((member) => {
|
let options = [];
|
||||||
|
members?.forEach((member) => {
|
||||||
let label = member?.firstName;
|
let label = member?.firstName;
|
||||||
if (member.uid === user?.uid) {
|
if (member.uid === user?.uid) {
|
||||||
label = FILTER_OPTIONS.ME;
|
label = FILTER_OPTIONS.ME;
|
||||||
}
|
}
|
||||||
return {value: member?.uid, label: label};
|
|
||||||
|
if (member.userType !== ProfileType.FAMILY_DEVICE) {
|
||||||
|
options.push({value: member?.uid, label: label});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
options.push({value: FILTER_OPTIONS.EVERYONE, label: FILTER_OPTIONS.EVERYONE})
|
options.push({value: FILTER_OPTIONS.EVERYONE, label: FILTER_OPTIONS.EVERYONE})
|
||||||
|
|
||||||
@ -138,14 +154,17 @@ const ToDosList = ({ isSettings }: { isSettings?: boolean }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const noDateToDos = groupedToDos["No Date"]?.items || [];
|
const noDateToDos = groupedToDos["No Date"]?.items || [];
|
||||||
const datedToDos = Object.keys(groupedToDos).filter(
|
const datedToDos = Object.keys(groupedToDos)
|
||||||
(key) => key !== "No Date"
|
.filter((key) => key !== "No Date")
|
||||||
);
|
.sort((a, b) => {
|
||||||
|
const order = ["Overdue", "Today", "Tomorrow", "Next 7 Days", "Next 30 Days", "Later"];
|
||||||
|
return order.indexOf(a) - order.indexOf(b);
|
||||||
|
});
|
||||||
|
|
||||||
const renderTodoGroup = (dateKey: string) => {
|
const renderTodoGroup = (dateKey: string) => {
|
||||||
const isExpanded = expandedGroups[dateKey] || false;
|
const isExpanded = expandedGroups[dateKey] || false;
|
||||||
|
|
||||||
if (dateKey === "Next 30 Days") {
|
if (dateKey === "Next 30 Days" || dateKey === "Later") {
|
||||||
const subgroups = Object.entries(groupedToDos[dateKey].subgroups).sort(
|
const subgroups = Object.entries(groupedToDos[dateKey].subgroups).sort(
|
||||||
([dateA], [dateB]) => {
|
([dateA], [dateB]) => {
|
||||||
const dateAObj = new Date(dateA);
|
const dateAObj = new Date(dateA);
|
||||||
|
|||||||
67
components/shared/RefreshButton.tsx
Normal file
67
components/shared/RefreshButton.tsx
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import React, { useRef, useEffect } from 'react';
|
||||||
|
import { TouchableOpacity, Animated, Easing } from 'react-native';
|
||||||
|
import { Feather } from '@expo/vector-icons';
|
||||||
|
|
||||||
|
interface RefreshButtonProps {
|
||||||
|
onRefresh: () => Promise<void>;
|
||||||
|
isSyncing: boolean;
|
||||||
|
size?: number;
|
||||||
|
color?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RefreshButton = ({
|
||||||
|
onRefresh,
|
||||||
|
isSyncing,
|
||||||
|
size = 24,
|
||||||
|
color = "#83807F"
|
||||||
|
}: RefreshButtonProps) => {
|
||||||
|
const rotateAnim = useRef(new Animated.Value(0)).current;
|
||||||
|
const rotationLoop = useRef<Animated.CompositeAnimation | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isSyncing) {
|
||||||
|
startContinuousRotation();
|
||||||
|
} else {
|
||||||
|
stopRotation();
|
||||||
|
}
|
||||||
|
}, [isSyncing]);
|
||||||
|
|
||||||
|
const startContinuousRotation = () => {
|
||||||
|
rotateAnim.setValue(0);
|
||||||
|
rotationLoop.current = Animated.loop(
|
||||||
|
Animated.timing(rotateAnim, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 1000,
|
||||||
|
easing: Easing.linear,
|
||||||
|
useNativeDriver: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
rotationLoop.current.start();
|
||||||
|
};
|
||||||
|
|
||||||
|
const stopRotation = () => {
|
||||||
|
rotationLoop.current?.stop();
|
||||||
|
rotateAnim.setValue(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
const rotate = rotateAnim.interpolate({
|
||||||
|
inputRange: [0, 1],
|
||||||
|
outputRange: ['0deg', '360deg'],
|
||||||
|
});
|
||||||
|
|
||||||
|
const handlePress = async () => {
|
||||||
|
if (!isSyncing) {
|
||||||
|
await onRefresh();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TouchableOpacity onPress={handlePress} disabled={isSyncing}>
|
||||||
|
<Animated.View style={{ transform: [{ rotate }] }}>
|
||||||
|
<Feather name="refresh-cw" size={size} color={color} />
|
||||||
|
</Animated.View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RefreshButton;
|
||||||
Reference in New Issue
Block a user