diff --git a/plans/bottom-nav-and-header-restructure.md b/plans/bottom-nav-and-header-restructure.md
new file mode 100644
index 0000000..7a637e0
--- /dev/null
+++ b/plans/bottom-nav-and-header-restructure.md
@@ -0,0 +1,282 @@
+# 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`.
diff --git a/public/sw.js b/public/sw.js
index 8cf56d0..83bbbb5 100644
--- a/public/sw.js
+++ b/public/sw.js
@@ -1,5 +1,5 @@
-const CACHE_NAME = 'greenhome-1766182760520';
-const STATIC_CACHE_NAME = 'greenhome-static-1766182760520';
+const CACHE_NAME = 'greenhome-1778524870692';
+const STATIC_CACHE_NAME = 'greenhome-static-1778524870692';
// Static assets to cache on install
const STATIC_FILES_TO_CACHE = [
diff --git a/public/version.json b/public/version.json
index 9b633ad..da8a2a6 100644
--- a/public/version.json
+++ b/public/version.json
@@ -1,3 +1,3 @@
{
- "version": "1766182760520"
+ "version": "1778524870692"
}
\ No newline at end of file
diff --git a/src/app/alert-settings/page.tsx b/src/app/alert-settings/page.tsx
index 8125ead..2d4cbfe 100644
--- a/src/app/alert-settings/page.tsx
+++ b/src/app/alert-settings/page.tsx
@@ -1,13 +1,14 @@
"use client"
import { useEffect, useState, useCallback, Suspense } from 'react'
import { useSearchParams } from 'next/navigation'
-import { api, AlertConditionDto, UpdateAlertConditionDto, CreateAlertConditionDto, CreateAlertRuleRequest } from '@/lib/api'
+import { api, AlertConditionDto, CreateAlertConditionDto, CreateAlertRuleRequest } from '@/lib/api'
import { Bell, Plus, AlertTriangle } from 'lucide-react'
import Loading from '@/components/Loading'
-import { PageHeader, EmptyState } from '@/components/common'
+import { EmptyState } from '@/components/common'
import { confirmDialog } from '@/components/utils'
import { AlertListItem } from '@/components/alert-settings/AlertListItem'
import { AlertFormModal } from '@/components/alert-settings/AlertFormModal'
+import { AppShell } from '@/components/layout'
function AlertSettingsContent() {
const searchParams = useSearchParams()
@@ -102,39 +103,36 @@ function AlertSettingsContent() {
if (loading) return
+ {user.name} {user.family} ({user.mobile}) +
+ )} +