Files
GreenHomeUI/plans/bottom-nav-and-header-restructure.md
alireza 9da69c96b1
Some checks failed
Deploy MyApp on Same Server / build-and-deploy (push) Has been cancelled
refactor(alert-settings): integrate AppShell layout and update cache version
- Replace custom page layout with AppShell component for consistent UI
- Remove unused PageHeader and UpdateAlertConditionDto imports
- Update service worker cache names and version.json to new timestamp
2026-05-11 22:19:30 +03:30

12 KiB

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 — 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 — 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:

type TopHeaderProps = {
  deviceName: string
  pageTitle: string
  pageIcon: LucideIcon
  pageInfo?: string  // e.g., "۱۴۰۴/۰۲/۲۱" for date
  iconGradient?: string
}

3. 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 — 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 — NEW

User profile page showing:

  • User name, family, mobile
  • Logout button
  • Link to device settings

6. src/app/weather/page.tsx — NEW

Dedicated weather page (extracted from the weather tab inside daily-report):

  • Shows forecast weather data
  • Reuses existing WeatherTab 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

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 Main layout shell with header + bottom nav
src/components/layout/TopHeader.tsx Global top header component
src/components/layout/BottomNav.tsx Bottom navigation bar
src/components/layout/DeviceProvider.tsx Device context provider
src/components/layout/index.ts Barrel exports
src/app/profile/page.tsx Profile page
src/app/weather/page.tsx Weather page

Files to Modify

File Changes
src/app/layout.tsx Wrap children with DeviceProvider for authenticated routes
src/app/daily-report/page.tsx Remove standalone PageHeader, use AppShell instead. Remove BackLink.
src/app/alert-settings/page.tsx Remove standalone PageHeader, use AppShell. Remove BackLink.
src/app/calendar/page.tsx Remove standalone PageHeader, use AppShell. Remove BackLink.
src/app/day-details/page.tsx Remove standalone PageHeader, use AppShell. Remove BackLink.
src/app/device-settings/page.tsx Remove standalone PageHeader, use AppShell. Remove BackLink.
src/app/devices/page.tsx After device selection, set DeviceProvider context before redirecting
src/app/globals.css Add styles for bottom nav (safe-area padding, fixed positioning)

Implementation Steps (Ordered)

Step 1: Create Layout Components

Step 2: Update Root Layout

Step 3: Create New Pages

Step 4: Refactor Existing Pages to Use AppShell

Step 5: Update Device Selection Flow

  • Modify 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

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

flowchart LR
    Login[/login] --> Verify[/verify-code]
    Verify --> Devices[/devices]
    Devices -->|select device + set context| DailyReport[/daily-report<br/>Tab: Report]
    
    DailyReport -->|BottomNav: Alerts| AlertSettings[/alert-settings<br/>Tab: Alerts]
    DailyReport -->|BottomNav: Profile| Profile[/profile<br/>Tab: Profile]
    DailyReport -->|BottomNav: Weather| Weather[/weather<br/>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.