# Plan: Bottom Navigation Bar & Global Header Restructure ## Overview Restructure the GreenHomeUI app to have an Android-style layout with: - A **persistent Bottom Navigation Bar** (4 tabs: Profile, Alerts, Report, Weather) - A **global Top Header** showing device title, page title with icon, and page info - Applied to all authenticated pages (after device selection) --- ## Current Architecture ``` App Flow: / (login) → /verify-code → /devices → /daily-report?deviceId=X&date=Y ├── /alert-settings?deviceId=X ├── /calendar?deviceId=X ├── /day-details?deviceId=X&year=Y&month=Z └── /device-settings?deviceId=X ``` Each page currently has its own `PageHeader` and manages its own layout independently. There is no shared shell/layout for authenticated pages. --- ## Target Architecture ``` Authenticated Shell (Layout) ┌──────────────────────────────────┐ │ Top Header │ │ [Device Name] [Page Icon+Title]│ │ [Page-specific info] │ ├──────────────────────────────────┤ │ │ │ Page Content │ │ (children) │ │ │ ├──────────────────────────────────┤ │ [Profile] [Alerts] [Report] [W] │ │ Bottom Navigation Bar │ └──────────────────────────────────┘ ``` ### Route Mapping | Bottom Nav Tab | Route | Page Component | Icon | |---|---|---|---| | Profile | `/profile?deviceId=X` | New `src/app/profile/page.tsx` | `User` | | Alerts | `/alert-settings?deviceId=X` | Existing (refactored) | `Bell` | | Report | `/daily-report?deviceId=X&date=Y` | Existing (refactored) | `BarChart3` | | Weather | `/weather?deviceId=X` | New `src/app/weather/page.tsx` | `CloudSun` | ### Pages OUTSIDE the shell (no bottom nav/header): - `/` (login page) - `/login` - `/verify-code` - `/devices` (device selection - this is the gateway before entering the shell) ### Pages INSIDE the shell (with bottom nav + header): - `/daily-report` (Report tab) - `/alert-settings` (Alerts tab) - `/profile` (Profile tab - NEW) - `/weather` (Weather tab - NEW) - `/calendar` (calendar navigation) - `/day-details` (day detail view) - `/device-settings` (device configuration) --- ## Component Architecture ### 1. [`src/components/layout/AppShell.tsx`](src/components/layout/AppShell.tsx) — NEW The main layout wrapper for authenticated pages. Provides: - Top header bar - Bottom navigation bar - Main content area (children) ### 2. [`src/components/layout/TopHeader.tsx`](src/components/layout/TopHeader.tsx) — NEW Global top header component showing: - **Left side**: Device name (from context/query param) - **Center/Right**: Page title with icon - **Optional**: Page-specific info (e.g., selected date for daily-report) Props: ```typescript type TopHeaderProps = { deviceName: string pageTitle: string pageIcon: LucideIcon pageInfo?: string // e.g., "۱۴۰۴/۰۲/۲۱" for date iconGradient?: string } ``` ### 3. [`src/components/layout/BottomNav.tsx`](src/components/layout/BottomNav.tsx) — NEW Bottom navigation bar with 4 tabs: - Uses `lucide-react` icons - Highlights active tab based on current route - Fixed at bottom, safe-area aware for notched devices - Each tab navigates via `next/navigation` `useRouter` ### 4. [`src/components/layout/DeviceProvider.tsx`](src/components/layout/DeviceProvider.tsx) — NEW React Context provider that stores the currently selected `deviceId` and `deviceName` so all pages within the shell can access them without passing through query params everywhere. ### 5. [`src/app/profile/page.tsx`](src/app/profile/page.tsx) — NEW User profile page showing: - User name, family, mobile - Logout button - Link to device settings ### 6. [`src/app/weather/page.tsx`](src/app/weather/page.tsx) — NEW Dedicated weather page (extracted from the weather tab inside daily-report): - Shows forecast weather data - Reuses existing [`WeatherTab`](src/components/daily-report/WeatherTab.tsx) or creates a standalone version --- ## Data Flow ``` User logs in → /devices (selects device) → Stores deviceId + deviceName in DeviceProvider context → Redirects to /daily-report?deviceId=X&date=today → AppShell renders with TopHeader + BottomNav + page content → BottomNav tab changes update the route → DeviceProvider persists across tab switches ``` ### DeviceProvider Context ```typescript type DeviceContextType = { deviceId: number deviceName: string setDevice: (id: number, name: string) => void } ``` The provider wraps all authenticated pages. When a user selects a device on `/devices`, it sets the context. The `AppShell` reads from this context to display the device name in the header. --- ## File Changes Summary ### New Files to Create | File | Purpose | |---|---| | [`src/components/layout/AppShell.tsx`](src/components/layout/AppShell.tsx) | Main layout shell with header + bottom nav | | [`src/components/layout/TopHeader.tsx`](src/components/layout/TopHeader.tsx) | Global top header component | | [`src/components/layout/BottomNav.tsx`](src/components/layout/BottomNav.tsx) | Bottom navigation bar | | [`src/components/layout/DeviceProvider.tsx`](src/components/layout/DeviceProvider.tsx) | Device context provider | | [`src/components/layout/index.ts`](src/components/layout/index.ts) | Barrel exports | | [`src/app/profile/page.tsx`](src/app/profile/page.tsx) | Profile page | | [`src/app/weather/page.tsx`](src/app/weather/page.tsx) | Weather page | ### Files to Modify | File | Changes | |---|---| | [`src/app/layout.tsx`](src/app/layout.tsx) | Wrap children with `DeviceProvider` for authenticated routes | | [`src/app/daily-report/page.tsx`](src/app/daily-report/page.tsx) | Remove standalone `PageHeader`, use `AppShell` instead. Remove `BackLink`. | | [`src/app/alert-settings/page.tsx`](src/app/alert-settings/page.tsx) | Remove standalone `PageHeader`, use `AppShell`. Remove `BackLink`. | | [`src/app/calendar/page.tsx`](src/app/calendar/page.tsx) | Remove standalone `PageHeader`, use `AppShell`. Remove `BackLink`. | | [`src/app/day-details/page.tsx`](src/app/day-details/page.tsx) | Remove standalone `PageHeader`, use `AppShell`. Remove `BackLink`. | | [`src/app/device-settings/page.tsx`](src/app/device-settings/page.tsx) | Remove standalone `PageHeader`, use `AppShell`. Remove `BackLink`. | | [`src/app/devices/page.tsx`](src/app/devices/page.tsx) | After device selection, set `DeviceProvider` context before redirecting | | [`src/app/globals.css`](src/app/globals.css) | Add styles for bottom nav (safe-area padding, fixed positioning) | --- ## Implementation Steps (Ordered) ### Step 1: Create Layout Components - Create [`DeviceProvider`](src/components/layout/DeviceProvider.tsx) context - Create [`TopHeader`](src/components/layout/TopHeader.tsx) component - Create [`BottomNav`](src/components/layout/BottomNav.tsx) component - Create [`AppShell`](src/components/layout/AppShell.tsx) that composes them - Create barrel export [`index.ts`](src/components/layout/index.ts) ### Step 2: Update Root Layout - Modify [`src/app/layout.tsx`](src/app/layout.tsx) to wrap with `DeviceProvider` - Add bottom nav CSS to [`src/app/globals.css`](src/app/globals.css) ### Step 3: Create New Pages - Create [`src/app/profile/page.tsx`](src/app/profile/page.tsx) — user info + logout - Create [`src/app/weather/page.tsx`](src/app/weather/page.tsx) — dedicated weather page ### Step 4: Refactor Existing Pages to Use AppShell - [`src/app/daily-report/page.tsx`](src/app/daily-report/page.tsx) — remove standalone PageHeader, wrap content in AppShell - [`src/app/alert-settings/page.tsx`](src/app/alert-settings/page.tsx) — same - [`src/app/calendar/page.tsx`](src/app/calendar/page.tsx) — same - [`src/app/day-details/page.tsx`](src/app/day-details/page.tsx) — same - [`src/app/device-settings/page.tsx`](src/app/device-settings/page.tsx) — same ### Step 5: Update Device Selection Flow - Modify [`src/app/devices/page.tsx`](src/app/devices/page.tsx) to set device context on selection - Ensure single-device auto-redirect also sets context ### Step 6: Polish & Testing - Ensure bottom nav highlights correct tab based on route - Ensure safe-area padding for notched phones - Test navigation between all tabs - Verify header shows correct device name and page info --- ## Mermaid Diagram: Component Tree ```mermaid flowchart TD RootLayout[RootLayout] --> DeviceProvider[DeviceProvider] DeviceProvider --> AuthPages[Auth Pages Group] subgraph AuthPages[Authenticated Pages] AppShell[AppShell] --> TopHeader[TopHeader] AppShell --> PageContent[Page Content] AppShell --> BottomNav[BottomNav] PageContent --> DailyReport[/daily-report] PageContent --> AlertSettings[/alert-settings] PageContent --> Profile[/profile] PageContent --> Weather[/weather] PageContent --> Calendar[/calendar] PageContent --> DayDetails[/day-details] PageContent --> DeviceSettings[/device-settings] end NonAuth[Non-Auth Pages] -.-> Login[/login] NonAuth -.-> VerifyCode[/verify-code] NonAuth -.-> Devices[/devices] Devices -.->|select device| AppShell ``` ## Mermaid Diagram: Navigation Flow ```mermaid flowchart LR Login[/login] --> Verify[/verify-code] Verify --> Devices[/devices] Devices -->|select device + set context| DailyReport[/daily-report
Tab: Report] DailyReport -->|BottomNav: Alerts| AlertSettings[/alert-settings
Tab: Alerts] DailyReport -->|BottomNav: Profile| Profile[/profile
Tab: Profile] DailyReport -->|BottomNav: Weather| Weather[/weather
Tab: Weather] AlertSettings -->|BottomNav: Report| DailyReport AlertSettings -->|BottomNav: Profile| Profile AlertSettings -->|BottomNav: Weather| Weather Profile -->|BottomNav: Report| DailyReport Profile -->|BottomNav: Alerts| AlertSettings Profile -->|BottomNav: Weather| Weather Weather -->|BottomNav: Report| DailyReport Weather -->|BottomNav: Alerts| AlertSettings Weather -->|BottomNav: Profile| Profile DailyReport -->|internal link| Calendar[/calendar] Calendar -->|select day| DayDetails[/day-details] DayDetails -->|select date| DailyReport DailyReport -->|settings icon| DeviceSettings[/device-settings] Profile -->|settings link| DeviceSettings ``` --- ## Key Design Decisions 1. **DeviceProvider Context**: Rather than passing `deviceId` as a query param on every navigation, we use React Context. This simplifies all page components and makes the header always aware of the current device. 2. **AppShell as a wrapper**: Each page inside the shell imports `AppShell` and wraps its content. The shell provides the header and bottom nav. This keeps pages clean and focused on their content. 3. **BottomNav uses route matching**: The active tab is determined by matching `usePathname()` against known routes. This is simpler than managing state across pages. 4. **Safe-area handling**: The bottom nav uses `env(safe-area-inset-bottom)` CSS to avoid overlapping with system navigation bars on notched devices. 5. **Existing PageHeader component**: The existing `PageHeader` component can still be used inside page content if needed (e.g., for sub-headers within a page), but the main header is now provided by `AppShell`.