Grapevine_Disease_Detection/VinEye/src/navigation/BottomTabNavigator.tsx
Yanis 001658898e refactor navigation: classic bottom tab bar with FAB + header icons
- Replace floating pill tab bar with classic anchored bottom bar (Home | FAB Scan | Map)
- Add central FAB button (green, elevated) for Scanner
- Move History → Notifications and Profile → Settings (accessible via header icons)
- Add SearchHeader with bell (notifications) and settings icons
- Add MapScreen placeholder
- Extract SearchHeader component from HomeScreen
- Switch to lucide-react-native icons for bottom tab bar
- Fix react-dom version mismatch (19.2.4 → 19.1.0)
- Clean up unused imports in homeheader.tsx
- Update navigation types, deep links, and i18n keys

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 20:14:27 +02:00

165 lines
4.6 KiB
TypeScript

import React from "react";
import { View, Text, TouchableOpacity, Platform } from "react-native";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { useTranslation } from "react-i18next";
import * as Haptics from "expo-haptics";
import { House, ScanLine, MapPin } from "lucide-react-native";
import HomeScreen from "@/screens/HomeScreen";
import ScannerScreen from "@/screens/ScannerScreen";
import MapScreen from "@/screens/MapScreen";
import { colors } from "@/theme/colors";
const Tab = createBottomTabNavigator();
const TAB_ICONS: Record<string, any> = {
Home: House,
Map: MapPin,
};
function MyCustomTabBar({ state, descriptors, navigation }: any) {
const insets = useSafeAreaInsets();
return (
<View
style={{
flexDirection: "row",
backgroundColor: colors.surface,
borderTopWidth: 1,
borderTopColor: colors.neutral[300],
paddingBottom: insets.bottom,
paddingTop: 8,
alignItems: "flex-end",
}}
>
{state.routes.map((route: any, index: number) => {
const { options } = descriptors[route.key];
const isFocused = state.index === index;
const label = options.tabBarLabel || route.name;
const isScanner = route.name === "Scanner";
const onPress = () => {
if (Platform.OS !== "web") {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
}
const event = navigation.emit({
type: "tabPress",
target: route.key,
canPreventDefault: true,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name);
}
};
// FAB central pour Scanner
if (isScanner) {
return (
<TouchableOpacity
key={route.key}
onPress={onPress}
activeOpacity={0.8}
accessibilityRole="button"
accessibilityLabel={label}
style={{
flex: 1,
alignItems: "center",
justifyContent: "center",
}}
>
<View
style={{
width: 56,
height: 56,
borderRadius: 28,
backgroundColor: colors.primary[800],
alignItems: "center",
justifyContent: "center",
marginTop: -28,
shadowColor: colors.primary[900],
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.3,
shadowRadius: 8,
elevation: 8,
}}
>
<ScanLine size={26} color="#FFFFFF" />
</View>
</TouchableOpacity>
);
}
// Onglets classiques (Home, Map)
const Icon = TAB_ICONS[route.name];
const tintColor = isFocused ? colors.primary[700] : colors.neutral[400];
return (
<TouchableOpacity
key={route.key}
onPress={onPress}
activeOpacity={0.7}
accessibilityRole="button"
accessibilityState={isFocused ? { selected: true } : {}}
accessibilityLabel={label}
style={{
flex: 1,
alignItems: "center",
justifyContent: "center",
paddingVertical: 6,
}}
>
{Icon && (
<Icon
size={22}
color={tintColor}
strokeWidth={isFocused ? 2.5 : 1.8}
/>
)}
<Text
numberOfLines={1}
style={{
fontSize: 11,
marginTop: 4,
color: tintColor,
fontWeight: isFocused ? "600" : "400",
}}
>
{label}
</Text>
</TouchableOpacity>
);
})}
</View>
);
}
export default function BottomTabNavigator() {
const { t } = useTranslation();
return (
<Tab.Navigator
tabBar={(props) => <MyCustomTabBar {...props} />}
screenOptions={{ headerShown: false }}
>
<Tab.Screen
name="Home"
component={HomeScreen}
options={{ tabBarLabel: t("common.home") }}
/>
<Tab.Screen
name="Scanner"
component={ScannerScreen}
options={{ tabBarLabel: t("common.scan") }}
/>
<Tab.Screen
name="Map"
component={MapScreen}
options={{ tabBarLabel: t("common.map") }}
/>
</Tab.Navigator>
);
}