diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 96eca43..7f4642c 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -85,10 +85,10 @@ Requirements for beta-ready release. Each maps to roadmap phases. - [ ] **MOB-01**: All portal pages render correctly and are usable on mobile (320px–480px) and tablet (768px–1024px) screens - [ ] **MOB-02**: Sidebar collapses to a hamburger menu on mobile with smooth open/close animation -- [ ] **MOB-03**: Chat interface is fully functional on mobile — send messages, see streaming responses, scroll history +- [x] **MOB-03**: Chat interface is fully functional on mobile — send messages, see streaming responses, scroll history - [ ] **MOB-04**: Portal installable as a PWA with app icon, splash screen, and service worker for offline shell caching - [ ] **MOB-05**: Push notifications for new messages when PWA is installed (or service worker caches app shell for instant load) -- [ ] **MOB-06**: All touch interactions feel native — no hover-dependent UI that breaks on touch devices +- [x] **MOB-06**: All touch interactions feel native — no hover-dependent UI that breaks on touch devices ## v2 Requirements @@ -188,10 +188,10 @@ Which phases cover which requirements. Updated during roadmap creation. | MOB-01 | Phase 8 | Pending | | MOB-02 | Phase 8 | Pending | -| MOB-03 | Phase 8 | Pending | +| MOB-03 | Phase 8 | Complete | | MOB-04 | Phase 8 | Pending | | MOB-05 | Phase 8 | Pending | -| MOB-06 | Phase 8 | Pending | +| MOB-06 | Phase 8 | Complete | **Coverage:** - v1 requirements: 25 total (all complete) diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index a11755a..f34f362 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -142,7 +142,7 @@ Phases execute in numeric order: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 | 5. Employee Design | 4/4 | Complete | 2026-03-25 | | 6. Web Chat | 3/3 | Complete | 2026-03-25 | | 7. Multilanguage | 4/4 | Complete | 2026-03-25 | -| 8. Mobile + PWA | 0/4 | In progress | - | +| 8. Mobile + PWA | 1/4 | In Progress| | --- diff --git a/.planning/STATE.md b/.planning/STATE.md index 0c515e8..393e047 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,14 +3,14 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: completed -stopped_at: Phase 8 context gathered -last_updated: "2026-03-26T02:08:35.108Z" +stopped_at: Completed 08-mobile-pwa/08-02-PLAN.md +last_updated: "2026-03-26T03:19:05.675Z" last_activity: 2026-03-23 — Completed 03-02 onboarding wizard, Slack OAuth, BYO API keys progress: total_phases: 8 completed_phases: 7 - total_plans: 29 - completed_plans: 29 + total_plans: 33 + completed_plans: 30 percent: 100 --- @@ -81,6 +81,7 @@ Progress: [██████████] 100% | Phase 07-multilanguage P02 | 9min | 2 tasks | 14 files | | Phase 07-multilanguage P03 | 45min | 2 tasks | 48 files | | Phase 07-multilanguage P04 | verification | 1 tasks | 0 files | +| Phase 08-mobile-pwa P02 | 6m 15s | 1 tasks | 12 files | ## Accumulated Context @@ -181,6 +182,9 @@ Recent decisions affecting current work: - [Phase 07-multilanguage]: LanguageSwitcher isPreAuth prop skips DB PATCH and session.update() on login page - [Phase 07-multilanguage]: onboarding/page.tsx uses getTranslations() not useTranslations() — Server Component requires next-intl/server import - [Phase 07-multilanguage]: billing-status.tsx trialEnds key uses only {date} param — boolean ICU params rejected by TypeScript strict mode +- [Phase 08-mobile-pwa]: mobileShowChat state toggles chat view on mobile — CSS handles desktop, state handles mobile nav pattern (WhatsApp-style) +- [Phase 08-mobile-pwa]: 100dvh for mobile chat container height — handles iOS Safari bottom chrome shrinking the layout viewport +- [Phase 08-mobile-pwa]: Serwist v9 uses new Serwist() class + addEventListeners() — installSerwist() was removed in v9 API ### Roadmap Evolution @@ -196,6 +200,6 @@ None — all phases complete. ## Session Continuity -Last session: 2026-03-26T02:08:35.105Z -Stopped at: Phase 8 context gathered -Resume file: .planning/phases/08-mobile-pwa/08-CONTEXT.md +Last session: 2026-03-26T03:19:05.672Z +Stopped at: Completed 08-mobile-pwa/08-02-PLAN.md +Resume file: None diff --git a/.planning/phases/08-mobile-pwa/08-02-SUMMARY.md b/.planning/phases/08-mobile-pwa/08-02-SUMMARY.md new file mode 100644 index 0000000..31e8bbb --- /dev/null +++ b/.planning/phases/08-mobile-pwa/08-02-SUMMARY.md @@ -0,0 +1,98 @@ +--- +phase: 08-mobile-pwa +plan: 02 +subsystem: portal/chat +tags: [mobile, pwa, chat, ios, keyboard, navigation] +dependency_graph: + requires: [08-01] + provides: [mobile-chat-ux, visual-viewport-hook, mobile-more-sheet] + affects: [packages/portal/app/(dashboard)/chat/page.tsx, packages/portal/components/chat-window.tsx] +tech_stack: + added: [] + patterns: [visual-viewport-api, ios-keyboard-offset, whatsapp-style-navigation, touch-targets-44px] +key_files: + created: + - packages/portal/lib/use-visual-viewport.ts + - packages/portal/components/mobile-chat-header.tsx + - packages/portal/components/mobile-more-sheet.tsx + - packages/portal/components/mobile-nav.tsx + modified: + - packages/portal/app/(dashboard)/chat/page.tsx + - packages/portal/components/chat-window.tsx + - packages/portal/components/chat-sidebar.tsx + - packages/portal/app/(dashboard)/layout.tsx + - packages/portal/app/sw.ts + - packages/portal/messages/en.json + - packages/portal/messages/es.json + - packages/portal/messages/pt.json +decisions: + - mobileShowChat state set on handleSelectConversation (not media query in JS) — CSS handles desktop visibility, state handles mobile routing + - 100dvh for mobile container height — handles iOS Safari bottom chrome shrinking viewport + - keyboardOffset added to useEffect deps in chat-window — triggers auto-scroll when keyboard opens + - Serwist v9 uses class constructor not installSerwist — breaking API change from v8 +metrics: + duration: "6m 15s" + completed_date: "2026-03-25" + tasks_completed: 1 + files_changed: 12 +requirements_satisfied: [MOB-03, MOB-06] +--- + +# Phase 8 Plan 02: Mobile Chat UX Summary + +**One-liner:** WhatsApp-style mobile chat with full-screen conversation view, Visual Viewport iOS keyboard handling, and 44px touch targets throughout. + +## What Was Built + +Mobile chat experience where tapping a conversation on small screens shows a full-screen chat view with a back arrow header. The desktop two-column layout is unchanged. The iOS virtual keyboard no longer hides the message input — Visual Viewport API tracks keyboard height and applies it as bottom padding. + +## Tasks + +| # | Name | Status | Commit | +|---|------|--------|--------| +| 1 | Mobile full-screen chat toggle and Visual Viewport keyboard hook | Complete | acba978 | + +## Key Artifacts + +**`packages/portal/lib/use-visual-viewport.ts`** +Exports `useVisualViewport()` — listens to `visualViewport` resize/scroll events and returns the gap between `window.innerHeight` and the visual viewport (keyboard height). Returns 0 when no keyboard is open. + +**`packages/portal/components/mobile-chat-header.tsx`** +Exports `MobileChatHeader` — sticky `md:hidden` header with ArrowLeft back button (44x44 tap target) and agent name + avatar. Shown only when `mobileShowChat` is true. + +**`packages/portal/components/mobile-more-sheet.tsx`** +Exports `MobileMoreSheet` — bottom drawer for secondary navigation (Billing, API Keys, Users, Platform) with role-based filtering and LanguageSwitcher. Triggered by "More" tab in mobile nav. + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 1 - Bug] Fixed `sw.ts` — `installSerwist` renamed to `Serwist` class in serwist v9** +- **Found during:** Task 1 (build verification) +- **Issue:** `app/sw.ts` was calling `installSerwist()` which doesn't exist in serwist v9.5.7 — function was replaced with `new Serwist()` class + `addEventListeners()` method +- **Fix:** Rewrote `sw.ts` to use `new Serwist({...}).addEventListeners()`, added `/// `, declared `__SW_MANIFEST` type on `ServiceWorkerGlobalScope` +- **Files modified:** `packages/portal/app/sw.ts` +- **Commit:** acba978 + +**2. [Rule 3 - Blocking] Created missing `mobile-more-sheet.tsx` referenced by `mobile-nav.tsx`** +- **Found during:** Task 1 (build verification) +- **Issue:** `components/mobile-nav.tsx` (created in Phase 08-01) imports `MobileMoreSheet` from `@/components/mobile-more-sheet` which didn't exist — TypeScript error +- **Fix:** Created `MobileMoreSheet` component — bottom drawer with RBAC-filtered navigation items, LanguageSwitcher, and sign-out +- **Files modified:** `packages/portal/components/mobile-more-sheet.tsx` (new) +- **Commit:** acba978 + +**3. [Rule 3 - Blocking] Staged `mobile-nav.tsx` and `layout.tsx` from Phase 08-01 unstaged changes** +- **Found during:** Task 1 (git status review) +- **Issue:** `mobile-nav.tsx` and dashboard `layout.tsx` had Phase 08-01 work that was never committed — both referenced `MobileMoreSheet` and integrated mobile nav into the layout +- **Fix:** Included both files in the task commit alongside the 08-02 changes +- **Files modified:** `components/mobile-nav.tsx`, `app/(dashboard)/layout.tsx` +- **Commit:** acba978 + +## Self-Check: PASSED + +- `use-visual-viewport.ts`: FOUND +- `mobile-chat-header.tsx`: FOUND +- `mobile-more-sheet.tsx`: FOUND +- `mobile-nav.tsx`: FOUND +- Commit `acba978`: FOUND +- Build: PASSED (TypeScript clean, all 22 routes generated)