import Ionicons from "@expo/vector-icons/Ionicons";
import {
DrawerContentComponentProps,
DrawerContentScrollView,
DrawerItem,
} from "@react-navigation/drawer";
import { Href, useNavigation, useRouter, useSegments } from "expo-router";
import { Drawer } from "expo-router/drawer";
import {
memo,
useCallback,
useLayoutEffect,
useMemo,
useState,
} from "react";
import {
Image,
ImageSourcePropType,
Pressable,
StyleSheet,
View,
} from "react-native";
import { IoniconsType } from "../../lib/types";
export type CustomDrawerRoute = {
name: string;
href: string;
icon?: IoniconsType;
};
const styles = StyleSheet.create({
logo: {
width: 107,
height: 20,
resizeMode: "contain",
},
});
const DrawerHeader = memo(
({
onClose,
LOGO_SOURCE,
}: {
onClose: () => void;
LOGO_SOURCE: ImageSourcePropType;
}) => (
)
);
const CustomDrawerItem = memo(
({
route,
isActive,
onPress,
}: {
route: CustomDrawerRoute;
isActive: boolean;
onPress: () => void;
}) => (
(
)}
label={route.name}
focused={isActive}
onPress={onPress}
activeTintColor="#DC2626"
activeBackgroundColor="#FEE2E2"
inactiveTintColor="#6B7280"
/>
)
);
const StaticDrawerItem = memo(
({
name,
icon,
onPress,
}: {
name: string;
href: string;
icon: string;
onPress: () => void;
}) => (
(
)}
label={name}
onPress={onPress}
/>
)
);
const DrawerContent = memo(
({
state,
navigation,
FooterContent,
CUSTOM_DRAWER_ROUTES,
STATIC_ROUTES,
LOGO_SOURCE,
...rest
}: DrawerContentComponentProps & {
CUSTOM_DRAWER_ROUTES: CustomDrawerRoute[];
STATIC_ROUTES: Required[];
FooterContent?: React.ReactNode;
LOGO_SOURCE: ImageSourcePropType;
}) => {
const router = useRouter();
const segments = useSegments();
const focusedRoute = state.routes[state.index];
const focusedDescriptor = rest.descriptors[focusedRoute.key];
const focusedOptions = focusedDescriptor.options;
const currentRoute = useMemo(() => {
return "/" + segments.slice(1).join("/");
}, [segments]);
const isRouteActive = useCallback(
(href: string) => {
if (currentRoute === href) return true;
if (href !== "/(tabs)" && currentRoute.startsWith(href))
return true;
if (
href === "/(tabs)/tags/list-tags" &&
currentRoute.includes("/tags/")
)
return true;
return false;
},
[currentRoute]
);
const handleCloseDrawer = useCallback(() => {
navigation.closeDrawer();
}, [navigation]);
const handleRoutePress = useCallback(
(href: string) => {
router.push(href as Href);
},
[router]
);
const { drawerContentStyle, drawerContentContainerStyle } =
focusedOptions;
return (
{CUSTOM_DRAWER_ROUTES.map((route) => (
handleRoutePress(route.href)}
/>
))}
{STATIC_ROUTES.map((route) => (
handleRoutePress(route.href)}
/>
))}
{FooterContent}
);
}
);
const useRouteTitle = ({
ALL_ROUTES,
}: {
ALL_ROUTES: CustomDrawerRoute[];
}) => {
const segments: string[] = useSegments();
const navigation = useNavigation();
const [title, setTitle] = useState(ALL_ROUTES[0].name);
const findRouteByHref = (href: string) =>
ALL_ROUTES.find((route) => route.href === href);
useLayoutEffect(() => {
const activeRoute = "/" + segments.slice(1).join("/");
let route = findRouteByHref(activeRoute);
if (!route) {
route = ALL_ROUTES.find((r) =>
activeRoute.startsWith(r.href.replace(/\/[^/]*$/, ""))
);
}
if (!route && segments.length >= 2) {
const mainSection = `/(tabs)/${segments[1]}`;
route = ALL_ROUTES.find((r) => r.href.startsWith(mainSection));
}
if (route) {
setTitle(route.name);
navigation.setOptions({
headerTitle: route.name,
});
}
}, [segments, navigation]);
return title;
};
export function MainDrawer({
ALL_ROUTES,
STATIC_ROUTES,
CUSTOM_DRAWER_ROUTES,
FooterContent,
HeaderRight,
LOGO_SOURCE,
}: {
ALL_ROUTES: CustomDrawerRoute[];
STATIC_ROUTES: Required[];
CUSTOM_DRAWER_ROUTES: CustomDrawerRoute[];
FooterContent?: React.ReactNode;
HeaderRight?: React.ReactNode;
LOGO_SOURCE: ImageSourcePropType;
}) {
const title = useRouteTitle({ ALL_ROUTES });
const drawerContent = useCallback(
(props: DrawerContentComponentProps) => (
),
[CUSTOM_DRAWER_ROUTES]
);
const screenOptions = useMemo(
() => ({
headerStatusBarHeight: 0,
drawerContentContainerStyle: { paddingTop: 20, flex: 1 },
headerTitleStyle: { fontSize: 16 },
headerStyle: { height: 50 },
headerRight: () => HeaderRight,
}),
[HeaderRight]
);
const drawerScreenOptions = useMemo(
() => ({
title,
drawerLabel: "Home",
}),
[title]
);
return (
);
}