Replace the profile tab with prescription management (inline reminders and family invite), add a shared tab top bar, separate notifications from orders, and support any-branch guest checkout with GSH codes. Co-authored-by: Cursor <cursoragent@cursor.com>
144 lines
3.7 KiB
TypeScript
144 lines
3.7 KiB
TypeScript
import { Ionicons } from "@expo/vector-icons";
|
|
import { Tabs } from "expo-router";
|
|
import { View } from "react-native";
|
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
import { useTranslation } from "react-i18next";
|
|
import { Text } from "@/components/ui/Text";
|
|
import { colors, fonts, radii, shadows } from "@/lib/theme";
|
|
import { useCartStore } from "@/lib/stores/cartStore";
|
|
|
|
function TabIcon({
|
|
name,
|
|
focused,
|
|
badge,
|
|
}: {
|
|
name: keyof typeof Ionicons.glyphMap;
|
|
focused: boolean;
|
|
badge?: number;
|
|
}) {
|
|
return (
|
|
<View style={{ width: 46, height: 40, alignItems: "center", justifyContent: "center" }}>
|
|
<View
|
|
style={{
|
|
width: 40,
|
|
height: 32,
|
|
borderRadius: radii.pill,
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
backgroundColor: focused ? colors.brandSoft : "transparent",
|
|
}}
|
|
>
|
|
<Ionicons
|
|
name={name}
|
|
size={20}
|
|
color={focused ? colors.brandText : colors.subtle}
|
|
/>
|
|
</View>
|
|
{badge ? (
|
|
<View
|
|
style={{
|
|
position: "absolute",
|
|
top: -2,
|
|
right: 2,
|
|
minWidth: 17,
|
|
height: 17,
|
|
paddingHorizontal: 4,
|
|
borderRadius: 9,
|
|
backgroundColor: colors.danger,
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
borderWidth: 2,
|
|
borderColor: colors.surface,
|
|
}}
|
|
>
|
|
<Text variant="micro" color={colors.surface} style={{ fontSize: 9, lineHeight: 12 }}>
|
|
{badge > 9 ? "9+" : badge}
|
|
</Text>
|
|
</View>
|
|
) : null}
|
|
</View>
|
|
);
|
|
}
|
|
|
|
export function FloatingTabBar() {
|
|
const insets = useSafeAreaInsets();
|
|
const { t } = useTranslation();
|
|
const cartCount = useCartStore((s) => s.totalItems());
|
|
|
|
return (
|
|
<Tabs
|
|
screenOptions={{
|
|
headerShown: false,
|
|
tabBarActiveTintColor: colors.brandText,
|
|
tabBarInactiveTintColor: colors.subtle,
|
|
tabBarLabelStyle: {
|
|
fontFamily: fonts.semibold,
|
|
fontSize: 11,
|
|
marginTop: 2,
|
|
},
|
|
tabBarItemStyle: { paddingTop: 8 },
|
|
tabBarStyle: [
|
|
{
|
|
position: "absolute",
|
|
left: 16,
|
|
right: 16,
|
|
bottom: Math.max(insets.bottom, 12),
|
|
height: 68,
|
|
borderRadius: radii.xl,
|
|
backgroundColor: colors.surface,
|
|
borderTopWidth: 0,
|
|
borderWidth: 1,
|
|
borderColor: colors.line,
|
|
paddingBottom: 8,
|
|
},
|
|
shadows.md,
|
|
],
|
|
}}
|
|
>
|
|
<Tabs.Screen
|
|
name="index"
|
|
options={{
|
|
title: t("common.home"),
|
|
tabBarIcon: ({ focused }) => (
|
|
<TabIcon name={focused ? "home" : "home-outline"} focused={focused} />
|
|
),
|
|
}}
|
|
/>
|
|
<Tabs.Screen
|
|
name="favorites"
|
|
options={{
|
|
title: t("common.favorites"),
|
|
tabBarIcon: ({ focused }) => (
|
|
<TabIcon name={focused ? "heart" : "heart-outline"} focused={focused} />
|
|
),
|
|
}}
|
|
/>
|
|
<Tabs.Screen
|
|
name="cart"
|
|
options={{
|
|
title: t("common.cart"),
|
|
tabBarIcon: ({ focused }) => (
|
|
<TabIcon
|
|
name={focused ? "bag-handle" : "bag-handle-outline"}
|
|
focused={focused}
|
|
badge={cartCount}
|
|
/>
|
|
),
|
|
}}
|
|
/>
|
|
<Tabs.Screen
|
|
name="prescriptions"
|
|
options={{
|
|
title: t("common.prescriptions"),
|
|
tabBarIcon: ({ focused }) => (
|
|
<TabIcon
|
|
name={focused ? "medkit" : "medkit-outline"}
|
|
focused={focused}
|
|
/>
|
|
),
|
|
}}
|
|
/>
|
|
</Tabs>
|
|
);
|
|
}
|