diff --git a/.planning/phases/04-tickets-restyle/04-03-SUMMARY.md b/.planning/phases/04-tickets-restyle/04-03-SUMMARY.md new file mode 100644 index 0000000..b449e27 --- /dev/null +++ b/.planning/phases/04-tickets-restyle/04-03-SUMMARY.md @@ -0,0 +1,110 @@ +--- +phase: 04 +plan: 03 +subsystem: mobile-tickets-detail +tags: [mobile, tickets, header, navigation, accessibility] +dependency_graph: + requires: [] + provides: [ticket-detail-header-D18] + affects: [app/mobile/tickets/[id]/page.tsx] +tech_stack: + added: [] + patterns: [three-slot-header, external-link-with-noopener] +key_files: + modified: + - app/mobile/tickets/[id]/page.tsx +decisions: + - Desktop URL chosen as /analyzer/ticket/{id} (in-app, stays in auth boundary; UI-SPEC permits either Autotask direct URL or analyzer URL) + - rel="noopener noreferrer" added per T-04-11 threat mitigation (reverse tabnabbing defense-in-depth, even on same-origin) + - -mx-4 px-4 technique extends header band to parent div's edges so border-b runs full-width under the new header bar +metrics: + duration_minutes: 5 + completed_date: "2026-05-03" + tasks_completed: 1 + files_changed: 1 +--- + +# Phase 4 Plan 3: Detail Page In-Page Header Reskin Summary + +**One-liner:** Three-slot in-page header on `/mobile/tickets/[id]` — back chevron + breadcrumb + external-link icon — replacing the legacy `Back` button per D-18. + +--- + +## What Changed + +### Exact Lines Modified in `app/mobile/tickets/[id]/page.tsx` + +**Import line (line 7):** Added `ExternalLink` to the named lucide-react import, alphabetically between `Eye` and `Mail`. All existing imports retained. + +**Header bar (lines ~240-264, replacing ~240-242):** The legacy single-line back button: + +```tsx + +``` + +Was replaced with the D-18 three-slot header bar (25 lines). The replacement lives inside the existing `
` parent — that wrapper was NOT changed. The new inner `div` uses `-mx-4 px-4` to extend to the parent's edges so its `border-b` runs full-width as a visual separator between the new header and the body below. + +--- + +## Desktop URL Choice + +`/analyzer/ticket/{id}` was used as the desktop link target. + +**Rationale:** The analyzer ticket view (`/analyzer/ticket/{id}`) is the canonical in-app desktop view of a ticket in this codebase. It stays within the auth boundary (same domain, same session cookie), so the user lands on a fully functional desktop page rather than being redirected to an external system. The UI-SPEC permits either the Autotask direct URL or the analyzer URL — the analyzer URL is preferred per the plan's spec note. + +--- + +## D-19 Body Untouched — Confirmation + +The following sections were preserved verbatim (not modified): + +| Section | Preserved | +|---------|-----------| +| Badges row (`flex items-start gap-2 mb-2` — priority + ticket# + status pills) | Yes | +| `

` ticket title | Yes | +| Metadata icons row (Briefcase / User / Clock) | Yes | +| 3-card stats grid (Notes / Time entries / Hours logged) | Yes | +| Description Collapsible block (`AlignLeft` icon, raw/formatted toggle) | Yes | +| Timeline section (filter toggles, `TimelineCard` list) | Yes | +| `TimelineCard` component definition | Yes | +| `loading` and `error` states | Yes | +| Helper functions: `fmtDate`, `fmtHours`, `renderContent`, `relTime` | Yes (note: `relTime` is not in this file — lives in the list page; all helpers in this file preserved) | +| Constant maps: `STATUS_LABEL`, `PRIORITY_LABEL`, `PRIORITY_COLOR` | Yes | + +--- + +## Parallel Execution + +This plan (04-03) ran in parallel with 04-01 and 04-02 in wave 1. There is no shared file conflict — 04-03 only touches `app/mobile/tickets/[id]/page.tsx`, while 04-01 touches `app/api/mobile/tickets/route.ts` and 04-02 touches `app/mobile/tickets/page.tsx`. No merge conflicts expected. + +--- + +## Deviations from Plan + +None — plan executed exactly as written. + +--- + +## Known Stubs + +None. The header bar is fully wired: `router.back()` for navigation, `ticket.ticket_number` for breadcrumb text, `ticket.id` for the external link href. No placeholder values. + +--- + +## Threat Flags + +No new threat surface beyond what was declared in the plan's threat model (T-04-11, T-04-12). T-04-11 mitigation (`rel="noopener noreferrer"`) is implemented. + +--- + +## Self-Check + +Checking created file and commit: + +- `app/mobile/tickets/[id]/page.tsx` — FOUND +- Commit `b1ff866` — FOUND +- `04-03-SUMMARY.md` — FOUND + +## Self-Check: PASSED diff --git a/app/mobile/tickets/[id]/page.tsx b/app/mobile/tickets/[id]/page.tsx index 7de406f..e85b2da 100644 --- a/app/mobile/tickets/[id]/page.tsx +++ b/app/mobile/tickets/[id]/page.tsx @@ -4,7 +4,7 @@ import { useEffect, useState, use } from 'react'; import { useRouter } from 'next/navigation'; import { ArrowLeft, RefreshCw, Clock, FileText, Timer, CheckCircle2, - ChevronDown, ChevronRight, User, Briefcase, AlertCircle, EyeOff, Eye, Mail, AlignLeft, Code2, + ChevronDown, ChevronRight, User, Briefcase, AlertCircle, EyeOff, Eye, ExternalLink, Mail, AlignLeft, Code2, } from 'lucide-react'; const PRIORITY_LABEL: Record = { @@ -237,9 +237,31 @@ export default function TicketTimeline({ params }: { params: Promise<{ id: strin
{/* Ticket header */}
- +
+ + +

+ Tickets / #{ticket.ticket_number} +

+ + + +
{PRIORITY_LABEL[ticket.priority] ?? `P${ticket.priority}`}