mirror of
https://github.com/urosran/cally.git
synced 2025-07-09 22:57:16 +00:00
362 lines
11 KiB
TypeScript
362 lines
11 KiB
TypeScript
import React, {memo, useCallback, useMemo} from "react";
|
|
import {Drawer} from "expo-router/drawer";
|
|
import {
|
|
DrawerContentComponentProps,
|
|
DrawerContentScrollView,
|
|
DrawerNavigationOptions,
|
|
DrawerNavigationProp
|
|
} from "@react-navigation/drawer";
|
|
import {ImageBackground, Pressable, StyleSheet} from "react-native";
|
|
import {Button, ButtonSize, Text, View} from "react-native-ui-lib";
|
|
import * as Device from "expo-device";
|
|
import {DeviceType} from "expo-device";
|
|
import {useSetAtom} from "jotai";
|
|
import {Ionicons} from "@expo/vector-icons";
|
|
import {ParamListBase, RouteProp, Theme} from '@react-navigation/native';
|
|
|
|
import {useSignOut} from "@/hooks/firebase/useSignOut";
|
|
import {CalendarHeader} from "@/components/pages/calendar/CalendarHeader";
|
|
import DrawerButton from "@/components/shared/DrawerButton";
|
|
import DrawerIcon from "@/assets/svgs/DrawerIcon";
|
|
import NavGroceryIcon from "@/assets/svgs/NavGroceryIcon";
|
|
import NavToDosIcon from "@/assets/svgs/NavToDosIcon";
|
|
import NavBrainDumpIcon from "@/assets/svgs/NavBrainDumpIcon";
|
|
import NavCalendarIcon from "@/assets/svgs/NavCalendarIcon";
|
|
import NavSettingsIcon from "@/assets/svgs/NavSettingsIcon";
|
|
import FeedbackNavIcon from "@/assets/svgs/FeedbackNavIcon";
|
|
import {
|
|
isFamilyViewAtom,
|
|
settingsPageIndex,
|
|
toDosPageIndex,
|
|
userSettingsView,
|
|
} from "@/components/pages/calendar/atoms";
|
|
import ViewSwitch from "@/components/pages/(tablet_pages)/ViewSwitch";
|
|
|
|
const isTablet = Device.deviceType === DeviceType.TABLET;
|
|
|
|
type DrawerParamList = {
|
|
index: undefined;
|
|
calendar: undefined;
|
|
brain_dump: undefined;
|
|
settings: undefined;
|
|
grocery: undefined;
|
|
reminders: undefined;
|
|
todos: undefined;
|
|
notifications: undefined;
|
|
feedback: undefined;
|
|
};
|
|
|
|
type DrawerScreenNavigationProp = DrawerNavigationProp<DrawerParamList>;
|
|
|
|
interface DrawerButtonConfig {
|
|
id: string;
|
|
title: string;
|
|
color: string;
|
|
bgColor: string;
|
|
icon: React.FC;
|
|
route: keyof DrawerParamList;
|
|
}
|
|
|
|
const DRAWER_BUTTONS: DrawerButtonConfig[] = [
|
|
{
|
|
id: 'calendar',
|
|
title: 'Calendar',
|
|
color: 'rgb(7, 184, 199)',
|
|
bgColor: 'rgb(231, 248, 250)',
|
|
icon: NavCalendarIcon,
|
|
route: 'calendar'
|
|
},
|
|
{
|
|
id: 'grocery',
|
|
title: 'Groceries',
|
|
color: '#50be0c',
|
|
bgColor: '#eef9e7',
|
|
icon: NavGroceryIcon,
|
|
route: 'grocery'
|
|
},
|
|
{
|
|
id: 'feedback',
|
|
title: 'Feedback',
|
|
color: '#ea156d',
|
|
bgColor: '#fdedf4',
|
|
icon: FeedbackNavIcon,
|
|
route: 'feedback'
|
|
},
|
|
{
|
|
id: 'todos',
|
|
title: 'To Dos',
|
|
color: '#8005eb',
|
|
bgColor: '#f3e6fd',
|
|
icon: NavToDosIcon,
|
|
route: 'todos'
|
|
},
|
|
{
|
|
id: 'brain_dump',
|
|
title: 'Brain Dump',
|
|
color: '#e0ca03',
|
|
bgColor: '#fffacb',
|
|
icon: NavBrainDumpIcon,
|
|
route: 'brain_dump'
|
|
},
|
|
{
|
|
id: 'notifications',
|
|
title: 'Notifications',
|
|
color: '#ffa200',
|
|
bgColor: '#ffdda1',
|
|
icon: () => <Ionicons name="notifications-outline" size={24} color="#ffa200"/>,
|
|
route: 'notifications'
|
|
}
|
|
];
|
|
|
|
interface DrawerContentProps {
|
|
props: DrawerContentComponentProps;
|
|
}
|
|
|
|
const DrawerContent: React.FC<DrawerContentProps> = ({props}) => {
|
|
const {mutateAsync: signOut} = useSignOut();
|
|
const setIsFamilyView = useSetAtom(isFamilyViewAtom);
|
|
const setPageIndex = useSetAtom(settingsPageIndex);
|
|
const setUserView = useSetAtom(userSettingsView);
|
|
const setToDosIndex = useSetAtom(toDosPageIndex);
|
|
|
|
const handleNavigation = useCallback((route: keyof DrawerParamList) => {
|
|
props.navigation.navigate(route);
|
|
setPageIndex(0);
|
|
setToDosIndex(0);
|
|
setUserView(true);
|
|
setIsFamilyView(false);
|
|
}, [props.navigation, setPageIndex, setToDosIndex, setUserView, setIsFamilyView]);
|
|
|
|
const renderDrawerButtons = () => {
|
|
const midPoint = Math.ceil(DRAWER_BUTTONS.length / 2);
|
|
const leftButtons = DRAWER_BUTTONS.slice(0, midPoint);
|
|
const rightButtons = DRAWER_BUTTONS.slice(midPoint);
|
|
|
|
return (
|
|
<View row paddingH-30>
|
|
<View flex-1 paddingR-5>
|
|
{leftButtons.map(button => (
|
|
<DrawerButton
|
|
key={button.id}
|
|
title={button.title}
|
|
color={button.color}
|
|
bgColor={button.bgColor}
|
|
pressFunc={() => handleNavigation(button.route)}
|
|
icon={<button.icon/>}
|
|
/>
|
|
))}
|
|
</View>
|
|
<View flex-1>
|
|
{rightButtons.map(button => (
|
|
<DrawerButton
|
|
key={button.id}
|
|
title={button.title}
|
|
color={button.color}
|
|
bgColor={button.bgColor}
|
|
pressFunc={() => handleNavigation(button.route)}
|
|
icon={<button.icon/>}
|
|
/>
|
|
))}
|
|
</View>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<DrawerContentScrollView {...props}>
|
|
<View centerV marginH-30 marginT-20 marginB-20 row>
|
|
<ImageBackground
|
|
source={require("../../assets/images/splash.png")}
|
|
style={styles.logo}
|
|
/>
|
|
<Text style={styles.title}>Welcome to Cally</Text>
|
|
</View>
|
|
|
|
{renderDrawerButtons()}
|
|
|
|
<Button
|
|
onPress={() => handleNavigation('settings')}
|
|
label="Manage Settings"
|
|
labelStyle={styles.label}
|
|
iconSource={() => (
|
|
<View style={styles.settingsIcon}>
|
|
<NavSettingsIcon/>
|
|
</View>
|
|
)}
|
|
backgroundColor="white"
|
|
color="#464039"
|
|
paddingV-30
|
|
marginH-30
|
|
borderRadius={18.55}
|
|
style={{elevation: 0}}
|
|
/>
|
|
|
|
<Button
|
|
size={ButtonSize.large}
|
|
style={styles.signOutButton}
|
|
label="Sign out of Cally"
|
|
color="#fd1775"
|
|
labelStyle={styles.signOut}
|
|
onPress={() => signOut()}
|
|
/>
|
|
</DrawerContentScrollView>
|
|
);
|
|
};
|
|
|
|
interface HeaderRightProps {
|
|
route: RouteProp<DrawerParamList>;
|
|
navigation: DrawerScreenNavigationProp;
|
|
}
|
|
|
|
const HeaderRight: React.FC<HeaderRightProps> = memo(({route, navigation}) => {
|
|
const showViewSwitch = ["calendar", "todos", "index"].includes(route.name);
|
|
const isCalendarPage = ["calendar", "index"].includes(route.name);
|
|
|
|
if (!isTablet || !showViewSwitch) {
|
|
return isCalendarPage ? <CalendarHeader/> : null;
|
|
}
|
|
|
|
return (
|
|
<View marginR-16 row centerV>
|
|
{isTablet && isCalendarPage && (
|
|
<View flex-1 center>
|
|
<CalendarHeader/>
|
|
</View>
|
|
)}
|
|
<ViewSwitch navigation={navigation}/>
|
|
</View>
|
|
)
|
|
});
|
|
|
|
interface DrawerScreen {
|
|
name: keyof DrawerParamList;
|
|
title: string;
|
|
hideInDrawer?: boolean;
|
|
}
|
|
|
|
const DRAWER_SCREENS: DrawerScreen[] = [
|
|
{name: 'index', title: 'Calendar'},
|
|
{name: 'calendar', title: 'Calendar', hideInDrawer: true},
|
|
{name: 'brain_dump', title: 'Brain Dump'},
|
|
{name: 'settings', title: 'Settings'},
|
|
{name: 'grocery', title: 'Groceries'},
|
|
{name: 'reminders', title: 'Reminders'},
|
|
{name: 'todos', title: isTablet ? 'Family To Dos' : 'To Dos'},
|
|
{name: 'notifications', title: 'Notifications'},
|
|
{name: 'feedback', title: 'Feedback'}
|
|
];
|
|
|
|
const TabLayout: React.FC = () => {
|
|
const screenOptions = useMemo(() => {
|
|
return ({route, navigation}: {
|
|
route: RouteProp<ParamListBase, string>;
|
|
navigation: DrawerNavigationProp<ParamListBase, string>;
|
|
theme: Theme;
|
|
}): DrawerNavigationOptions => ({
|
|
lazy: true,
|
|
headerShown: true,
|
|
headerTitleAlign: "left",
|
|
headerTitle: ({children}) => {
|
|
const isCalendarRoute = ["calendar", "index"].includes(route.name);
|
|
if (isCalendarRoute) return null;
|
|
|
|
return (
|
|
<View flexG centerV paddingL-10>
|
|
<Text style={styles.headerTitle}>
|
|
{children}
|
|
</Text>
|
|
</View>
|
|
);
|
|
},
|
|
headerLeft: () => (
|
|
<Pressable
|
|
onPress={() => navigation.toggleDrawer()}
|
|
hitSlop={{top: 10, bottom: 10, left: 10, right: 10}}
|
|
style={({pressed}) => [styles.drawerTrigger, {opacity: pressed ? 0.4 : 1}]}
|
|
>
|
|
<DrawerIcon/>
|
|
</Pressable>
|
|
),
|
|
headerRight: () => <HeaderRight
|
|
route={route as RouteProp<DrawerParamList>}
|
|
navigation={navigation as DrawerNavigationProp<DrawerParamList>}
|
|
/>,
|
|
drawerStyle: styles.drawer,
|
|
});
|
|
}, []);
|
|
|
|
|
|
return (
|
|
<Drawer
|
|
initialRouteName="index"
|
|
detachInactiveScreens
|
|
screenOptions={screenOptions}
|
|
drawerContent={(props) => <DrawerContent props={props}/>}
|
|
>
|
|
{DRAWER_SCREENS.map(screen => (
|
|
<Drawer.Screen
|
|
key={screen.name}
|
|
name={screen.name}
|
|
options={{
|
|
drawerLabel: screen.title,
|
|
title: screen.title,
|
|
...(screen.hideInDrawer && {drawerItemStyle: {display: 'none'}}),
|
|
}}
|
|
/>
|
|
))}
|
|
</Drawer>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
drawer: {
|
|
width: isTablet ? "30%" : "90%",
|
|
backgroundColor: "#f9f8f7",
|
|
height: "100%",
|
|
},
|
|
drawerTrigger: {
|
|
marginLeft: 16,
|
|
},
|
|
headerTitle: {
|
|
fontFamily: "Manrope_600SemiBold",
|
|
fontSize: isTablet ? 22 : 17,
|
|
},
|
|
logo: {
|
|
backgroundColor: "transparent",
|
|
height: 51.43,
|
|
aspectRatio: 1,
|
|
marginRight: 8,
|
|
},
|
|
settingsIcon: {
|
|
backgroundColor: "#ededed",
|
|
width: 60,
|
|
height: 60,
|
|
borderRadius: 50,
|
|
marginRight: 10,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
},
|
|
signOutButton: {
|
|
marginTop: 50,
|
|
marginHorizontal: 10,
|
|
paddingVertical: 15,
|
|
backgroundColor: "transparent",
|
|
borderWidth: 1.3,
|
|
borderColor: "#fd1775",
|
|
},
|
|
signOut: {
|
|
fontFamily: "Poppins_500Medium",
|
|
fontSize: 15,
|
|
},
|
|
label: {
|
|
fontFamily: "Poppins_400Medium",
|
|
fontSize: 15,
|
|
},
|
|
title: {
|
|
fontSize: 26.13,
|
|
fontFamily: "Manrope_600SemiBold",
|
|
color: "#262627",
|
|
},
|
|
});
|
|
|
|
export default TabLayout; |