4.3 KiB
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:
<button onClick={() => router.back()} className="flex items-center gap-1 text-sm text-muted-foreground mb-3 hover:text-foreground">
<ArrowLeft className="w-4 h-4" /> Back
</button>
Was replaced with the D-18 three-slot header bar (25 lines). The replacement lives inside the existing <div className="px-4 pt-4 pb-3 border-b"> 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 |
<h1 className="text-base font-bold leading-snug"> 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