import React, { useEffect, useState } from "react"; import { createMaterialTopTabNavigator, MaterialTopTabNavigationOptions, MaterialTopTabNavigationEventMap, MaterialTopTabBarProps, } from "@react-navigation/material-top-tabs"; import { withLayoutContext } from "expo-router"; import { ParamListBase, TabNavigationState } from "@react-navigation/native"; import { useAuthStore } from "~/lib/stores/authStore"; import { useUserProfileStore } from "~/lib/stores/userProfileStore"; import { router } from "expo-router"; import { View, Pressable, StyleSheet, Image, Platform } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { useTabStore } from "~/lib/stores"; import { Icons } from "~/assets/icons"; import { History, CalendarClock, ListChecks, CalendarRange, ListChecksIcon, } from "lucide-react-native"; const { Navigator } = createMaterialTopTabNavigator(); // Wrap the navigator with expo-router's layout context export const MaterialTopTabs = withLayoutContext< MaterialTopTabNavigationOptions, typeof Navigator, TabNavigationState, MaterialTopTabNavigationEventMap >(Navigator); // Screen title mapping - automatically includes all screens in (tabs) folder // Add new screens here as you create them in the (tabs) folder const screenTitles: Record = { index: "Home", schedules: "Schedules", requests: "Requests", listrecipient: "Recipients", history: "Transactions", }; const TAB_BAR_HEIGHT = 72; const tabIcons: Record React.ReactNode> = { index: (color: string) => ( ), schedules: (color: string) => , requests: (color: string) => , listrecipient: (color: string) => ( ), history: (color: string) => , }; const getHrefForRoute = (routeName: string) => routeName === "index" ? "/" : `/(tabs)/${routeName}`; // Primary green color used across the app (matches app's light theme) const PRIMARY_COLOR = "hsl(147,55%,28%)"; const INACTIVE_COLOR = "#d1d5db"; function CustomTabBar({ state, navigation }: MaterialTopTabBarProps) { const { setLastVisitedTab } = useTabStore(); const [selectedIndex, setSelectedIndex] = React.useState(state.index); const insets = useSafeAreaInsets(); React.useEffect(() => { setSelectedIndex(state.index); }, [state.index]); // App uses light theme - use primary green color const activeColor = PRIMARY_COLOR; const inactiveColor = INACTIVE_COLOR; // Calculate bottom padding: use reduced safe area inset on iOS, or 16px on Android const bottomPadding = Platform.OS === "ios" ? Math.max(insets.bottom * 0.6, 8) : 16; return ( {state.routes.map((route, index) => { const focused = selectedIndex === index; const href = getHrefForRoute(route.name); const Icon = tabIcons[route.name]; const onPress = () => { setSelectedIndex(index); const event = navigation.emit({ type: "tabPress", target: route.key, canPreventDefault: true, }); if (!focused && !event.defaultPrevented) { setLastVisitedTab(href); navigation.navigate(route.name); } }; return ( {Icon ? Icon(focused ? activeColor : inactiveColor) : null} ); })} ); } export default function TabLayout() { const { user, loading } = useAuthStore(); const { profiles } = useUserProfileStore(); const [isAgent, setIsAgent] = React.useState(null); const [checkingAgent, setCheckingAgent] = React.useState(false); // Get the current user's profile entry const profileEntry = user?.uid ? profiles[user.uid] : null; const profile = profileEntry?.profile; const profileLoading = profileEntry?.loading ?? false; const isDevEmulatorUser = __DEV__ && user?.uid === "dev-emulator-user"; // Check if user is an agent when profile is not available useEffect(() => { if (!user || profile || checkingAgent || isAgent !== null) { return; } const checkAgent = async () => { setCheckingAgent(true); try { const { AuthService } = await import("~/lib/services/authServices"); const agentExists = await AuthService.checkAgentExists(user.uid); setIsAgent(agentExists); } catch (error) { console.error('TabLayout - error checking agent:', error); setIsAgent(false); } finally { setCheckingAgent(false); } }; checkAgent(); }, [user, profile, checkingAgent, isAgent]); // Redirect to agent signup if not authenticated or no profile/agent useEffect(() => { if (!loading && !profileLoading && !checkingAgent) { // In dev, allow the fake emulator user even without a profile if (isDevEmulatorUser) { return; } if (!user || (!profile && isAgent === false)) { console.log( "TabLayout - redirecting to agent signin, user:", !!user, "profile:", !!profile, "isAgent:", isAgent ); router.replace("/auth/agent-signin"); } } }, [user, loading, profile, profileLoading, isDevEmulatorUser, isAgent, checkingAgent]); // Don't render tabs if not authenticated or no profile/agent // In dev, still render for the emulator user even without profile if (!isDevEmulatorUser && (loading || profileLoading || checkingAgent || !user || (!profile && isAgent !== true))) { return null; } return ( } > {Object.entries(screenTitles).map(([name, title]) => ( ))} ); } const styles = StyleSheet.create({ tabBarContainer: { position: "absolute", left: 0, right: 0, bottom: 0, flexDirection: "row", alignItems: "center", justifyContent: "space-around", paddingTop: 16, paddingHorizontal: 4, backgroundColor: "#ffffff", // tailwind gray-50 borderTopWidth: StyleSheet.hairlineWidth, borderTopColor: "#e5e7eb", // tailwind gray-200 zIndex: 10, }, tabButton: { flex: 1, alignItems: "center", }, });