winofy-front/src/components/home/bottom-nav.tsx
Afra ‌ 3609c97e34 feat: guest-home/C04 shell, location onboarding (L01/L04/L06), profile placeholder
Implements winofyfrontenddoc (1).md §3-4: unified guest-home/authenticated-home
screen (header with login chip vs cart badge, pill search bar, dismissible
location-reminder banner, category chips, store cards, interleaved seller
promo card, sticky bottom nav), plus the full post-OTP location-onboarding
sub-flow (geolocation permission -> error/retry -> manual neighborhood
search, unified idle/results/empty states per the doc's own recommendation).

Location state persists in a plain (non-httpOnly) cookie readable both
client- and server-side, since it drives SSR store queries (neighborhood
or lat/lng) as well as client interactions.

Moved cart/checkout/store/product/orders/addresses under a new (shop) route
group so the new home-shell header doesn't double up with the existing
simple nav header on inner pages.

Real bug caught via live staging data: Neighborhood.city is a nested
{uuid, name, slug} object, not a bare uuid string as typed -- broke both
the address form's city filter and the new neighborhood search. Fixed and
verified against real API responses, not just assumed from the guide.
2026-08-17 17:24:27 +03:30

40 lines
1.4 KiB
TypeScript

import Link from "next/link";
import { Home, Search, ShoppingBag, User } from "lucide-react";
import { cn } from "@/lib/utils/cn";
type Tab = "profile" | "orders" | "search" | "home";
const TABS: { key: Tab; href: string; label: string; icon: typeof Home }[] = [
{ key: "profile", href: "/profile", label: "پروفایل", icon: User },
{ key: "orders", href: "/orders", label: "سفارش‌ها", icon: ShoppingBag },
{ key: "search", href: "/", label: "جستجو", icon: Search },
{ key: "home", href: "/", label: "خانه", icon: Home },
];
/** winofyfrontenddoc (1).md §3.6 — sticky bottom nav, 4 equal-width tabs. */
export function BottomNav({ active }: { active: Tab }) {
return (
<nav
className="fixed inset-x-0 bottom-0 z-10 mx-auto flex w-full max-w-[390px] items-stretch border-t border-gray-300 bg-white"
style={{ paddingBottom: "env(safe-area-inset-bottom)" }}
>
{TABS.map((tab) => {
const Icon = tab.icon;
const isActive = tab.key === active;
return (
<Link
key={tab.key}
href={tab.href}
className={cn(
"flex flex-1 flex-col items-center gap-1 py-3 text-label",
isActive ? "text-primary-action" : "text-gray-500",
)}
>
<Icon className="h-5 w-5" />
<span>{tab.label}</span>
</Link>
);
})}
</nav>
);
}