diff --git a/.planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-05-MANIFEST.md b/.planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-05-MANIFEST.md new file mode 100644 index 0000000..aa19425 --- /dev/null +++ b/.planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-05-MANIFEST.md @@ -0,0 +1,550 @@ +# Phase 7.1 Plan 05 — Migration manifest + +Source: `.planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-04-AUDIT.md` +Pre-migration leak count (per audit): **81 callsites across 39 files** + +## Files to migrate + +- [ ] app/engagement/profile/page.tsx +- [ ] app/engagement/page.tsx +- [ ] app/admin/sync/duo/page.tsx +- [ ] app/admin/sync/datto-rmm/page.tsx +- [ ] app/admin/sync/veeam/page.tsx +- [ ] app/admin/sync/itglue/page.tsx +- [ ] app/admin/sync/mimecast/page.tsx +- [ ] app/admin/sync/sentinelone/page.tsx +- [ ] app/admin/zabbix-wan/page.tsx +- [ ] app/admin/rmm-overshell/page.tsx +- [ ] app/admin/itglue-writes/page.tsx +- [ ] app/admin/data-browser/tasks/page.tsx +- [ ] app/admin/data-browser/projects/page.tsx +- [ ] app/admin/data-browser/ticket-notes/page.tsx +- [ ] app/admin/data-browser/contracts/page.tsx +- [ ] app/admin/data-browser/tickets/page.tsx +- [ ] app/admin/data-browser/time-entries/page.tsx +- [ ] app/admin/ticket-digest/page.tsx +- [ ] app/admin/device-link-conflicts/page.tsx +- [ ] app/admin/workflow/history/page.tsx +- [ ] app/admin/workflow/pipelines/[id]/page.tsx +- [ ] app/analyzer/itglue/applications/page.tsx +- [ ] app/analyzer/itglue/applications/[id]/page.tsx +- [ ] app/analyzer/itglue/configurations/page.tsx +- [ ] app/analyzer/itglue/configurations/[id]/page.tsx +- [ ] app/analyzer/itglue/sites/[companyId]/page.tsx +- [ ] app/analyzer/queue/page.tsx +- [ ] app/analyzer/ticket/[ticketNumber]/page.tsx +- [ ] app/analyzer/tickets/page.tsx +- [ ] app/analyzer/reports/page.tsx +- [ ] app/analyzer/reports/[id]/page.tsx +- [ ] app/dashboard/page.tsx +- [ ] app/quotes/page.tsx +- [ ] app/veeam-analysis/page.tsx +- [ ] components/admin/DetailModal.tsx +- [ ] components/admin/IntegrationStatusTabs.tsx +- [ ] components/admin/SyncScheduler.tsx +- [ ] components/admin/audit/audit-log-table.tsx +- [ ] components/admin/users/user-table.tsx +- [ ] components/admin/users/user-sessions.tsx +- [ ] components/analyzer/analysis-view.tsx +- [ ] components/settings/active-sessions.tsx +- [ ] components/dashboard/resolution-trend.tsx +- [ ] components/dashboard/volume-trend.tsx +- [ ] components/quotes/ticket-detail-modal.tsx +- [ ] components/analytics/TimelineView.tsx +- [ ] components/analytics/ScoreCard.tsx +- [ ] components/configuration-items/addigy-tab.tsx +- [ ] components/status/activity-sparkline.tsx +- [ ] components/backup/compliance-detail-table.tsx +- [ ] components/backup/company-backup-detail.tsx + +## Per-file migration plan + +### app/engagement/profile/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 2 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/engagement/profile/page.tsx)" -ge 2 ]` +- Per-callsite plan: + - Line 141 (inside `ActivityHeatmap` sub-component): `d.toLocaleDateString('en-US', { month: 'short' })` → `d.toLocaleDateString('en-US', { month: 'short', timeZone: tz })`. Pass `tz` as a prop to `ActivityHeatmap`. + - Line 264 (inside module-scope helper `monthLabel(m)`): convert helper to `monthLabel(m, tz)`; thread `tz` from the component callsite. + +Notes / risks: `monthLabel` is module-scope; `ActivityHeatmap` is a sub-component called from `EngagementProfilePage`. Approach: add `tz` prop to `ActivityHeatmap`; convert `monthLabel(m, tz)`. + +### app/engagement/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 7 (lines 842, 1010, 1106 (×2 calls), 1225, 1253 (×2 calls)) +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/engagement/page.tsx)" -ge 7 ]` +- Per-callsite plan: all 5 lines are inside `EngagementPage` (default export from line 462). Call `useUserTimezone()` once at top of `EngagementPage`. Then per-line: + - Line 842: `new Date(user.lastActivity).toLocaleDateString()` → `new Date(user.lastActivity).toLocaleDateString(undefined, { timeZone: tz })` + - Line 1010: `new Date(snap.last_activity_date).toLocaleDateString()` → `new Date(snap.last_activity_date).toLocaleDateString(undefined, { timeZone: tz })` + - Line 1106: `d.toLocaleDateString()` → `d.toLocaleDateString(undefined, { timeZone: tz })`; `d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })` → `d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', timeZone: tz })` + - Line 1225: `new Date(call.startTime).toLocaleDateString()` → `new Date(call.startTime).toLocaleDateString(undefined, { timeZone: tz })` + - Line 1253: same pattern as 1106 + +Notes / risks: very long file (>1280 lines). All leak callsites are within the default export's JSX, so a single `const tz = useUserTimezone();` at the top of the function body suffices. + +### app/admin/sync/duo/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/sync/duo/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 117 (inside `DuoSyncPage` default export, the inner `fmtDate` arrow function): `new Date(d).toLocaleString()` → `new Date(d).toLocaleString(undefined, { timeZone: tz })`. Note: this is a CLOSURE inside the component (line 117 is inside the function body, not module scope). Just call `useUserTimezone()` and reference `tz` directly. + +Notes / risks: `fmtDate` is also passed as a prop to `FlaggedUsersTable` (line 286). The closure captures `tz` already once `tz` is in scope. + +### app/admin/sync/datto-rmm/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/sync/datto-rmm/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 23 (module-scope `fmtDate(d)`): convert to `fmtDate(d, tz)`. Update all callsites to pass `tz`. + +Notes / risks: `fmtDate` is consumed by `StatusTab` (line 38) and `HistoryTab` (line 102) sub-components. Either pass `tz` as a prop to each sub-component, OR thread `tz` into the `fmtDate` calls inside sub-components by passing it down. Approach: add `tz` prop to `StatusTab` and `HistoryTab`; thread `tz` from default export. + +### app/admin/sync/veeam/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/sync/veeam/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 26 (module-scope `fmtDate(d)`): convert to `fmtDate(d, tz)`. Update all callsites to pass `tz`. + +Notes / risks: many sub-components (`VeeamStatusTab`, `HistoryRow`, `VeeamHistoryTab`, `AgentsTab`, `AlarmsTab`, `RpoTab`). Most likely consume `fmtDate`. Approach: add `tz` prop to each sub-component that calls `fmtDate`; thread `tz` from default export. + +### app/admin/sync/itglue/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/sync/itglue/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 24 (module-scope `fmtDate(d)`): convert to `fmtDate(d, tz)`. Update all callsites to pass `tz`. + +Notes / risks: same pattern as datto-rmm. Sub-components: `StatusTab`, `HistoryTab`, `AboutTab`. Add `tz` prop where needed. + +### app/admin/sync/mimecast/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 6 (lines 28 (helper definition — leaked at every call), 651, 924, 1239, 1405, 1840 — but the audit cites lines 28, 651, 924, 1239, 1405, 1840 as 6 distinct leak callsites) +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/sync/mimecast/page.tsx)" -ge 6 ]` +- Per-callsite plan: + - Line 28 (module-scope `fmtDate`): convert to `fmtDate(d, tz)`. Update every `fmtDate(...)` call in the file. + - Line 651 (inside `MessageAnalysisDialog`): `new Date(message.dateReceived).toLocaleString()` → `new Date(message.dateReceived).toLocaleString(undefined, { timeZone: tz })` + - Line 924 (inside `HeldMailTab`): `new Date(m.dateReceived).toLocaleString(undefined, { ... })` → add `, timeZone: tz` to options + - Line 1239 (inside `DeliveredAnalysisDialog`): `new Date(message.received).toLocaleString()` → add `(undefined, { timeZone: tz })` + - Line 1405 (inside `DeliveredAnalysisDialog`): `new Date(m.receivedDateTime).toLocaleString(undefined, { ... })` → add `, timeZone: tz` + - Line 1840 (inside `DeliveredMailTab`): `new Date(m.received).toLocaleString(undefined, { ... })` → add `, timeZone: tz` + +Notes / risks: 6 callsites across 4 sub-components (`MessageAnalysisDialog`, `HeldMailTab`, `DeliveredAnalysisDialog`, `DeliveredMailTab`). Add `tz` prop to each sub-component that uses an inline call OR calls `fmtDate`. Default export `MimecastSyncPage` calls `useUserTimezone()` once. + +### app/admin/sync/sentinelone/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/sync/sentinelone/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 15 (module-scope `fmtDate(d)`): convert to `fmtDate(d, tz)`; update callsites. + +Notes / risks: `fmtDate` used by default export `SentinelOneSyncPage`. + +### app/admin/zabbix-wan/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 2 (lines 212, 213) +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/zabbix-wan/page.tsx)" -ge 2 ]` +- Per-callsite plan: + - Line 212: `new Date(ts).toLocaleString()` → `new Date(ts).toLocaleString(undefined, { timeZone: tz })` + - Line 213: same + +Notes / risks: both calls are inside the default export. Single `const tz = useUserTimezone();` suffices. + +### app/admin/rmm-overshell/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 3 (lines 142, 199, 265) +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/rmm-overshell/page.tsx)" -ge 3 ]` +- Per-callsite plan: + - Line 142, 199, 265: each `new Date(x).toLocaleString()` → `new Date(x).toLocaleString(undefined, { timeZone: tz })` + +Notes / risks: all inside default export. + +### app/admin/itglue-writes/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/itglue-writes/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 144: `new Date(w.performed_at).toLocaleString()` → `new Date(w.performed_at).toLocaleString(undefined, { timeZone: tz })` + +### app/admin/data-browser/tasks/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/data-browser/tasks/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 100 (DataTable column render, defined inside `TasksBrowserPage` body): `new Date(value).toLocaleDateString()` → `new Date(value).toLocaleDateString(undefined, { timeZone: tz })` + +Notes / risks: column array is inside the component body (line 54+), so the closure captures `tz` for free. + +### app/admin/data-browser/projects/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/data-browser/projects/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 88 (DataTable column render): `new Date(value).toLocaleDateString()` → `new Date(value).toLocaleDateString(undefined, { timeZone: tz })` + +### app/admin/data-browser/ticket-notes/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/data-browser/ticket-notes/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 86 (DataTable column render): `new Date(v).toLocaleDateString()` → `new Date(v).toLocaleDateString(undefined, { timeZone: tz })` + +### app/admin/data-browser/contracts/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 2 (lines 88, 96) +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/data-browser/contracts/page.tsx)" -ge 2 ]` +- Per-callsite plan: + - Line 88, 96: `new Date(value).toLocaleDateString()` → `new Date(value).toLocaleDateString(undefined, { timeZone: tz })` + +### app/admin/data-browser/tickets/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/data-browser/tickets/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 103 (DataTable column render): `new Date(value).toLocaleDateString()` → `new Date(value).toLocaleDateString(undefined, { timeZone: tz })` + +### app/admin/data-browser/time-entries/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/data-browser/time-entries/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 296 (DataTable column render): `new Date(value).toLocaleDateString()` → `new Date(value).toLocaleDateString(undefined, { timeZone: tz })` + +### app/admin/ticket-digest/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/ticket-digest/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 410: `new Date(report.generated_at).toLocaleString()` → `new Date(report.generated_at).toLocaleString(undefined, { timeZone: tz })` + +### app/admin/device-link-conflicts/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/device-link-conflicts/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 223: `new Date(r.xref.lastSeenAt).toLocaleString()` → `new Date(r.xref.lastSeenAt).toLocaleString(undefined, { timeZone: tz })` + +### app/admin/workflow/history/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/workflow/history/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 192: `new Date(exec.created_at).toLocaleString()` → `new Date(exec.created_at).toLocaleString(undefined, { timeZone: tz })` + +### app/admin/workflow/pipelines/[id]/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/admin/workflow/pipelines/[id]/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 582: `new Date(exec.started_at).toLocaleString()` → `new Date(exec.started_at).toLocaleString(undefined, { timeZone: tz })` + +### app/analyzer/itglue/applications/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/analyzer/itglue/applications/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 129: `new Date(r.latestAudit.generatedAt).toLocaleDateString()` → `new Date(r.latestAudit.generatedAt).toLocaleDateString(undefined, { timeZone: tz })` + +### app/analyzer/itglue/applications/[id]/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 3 (lines 411, 720, 779) +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/analyzer/itglue/applications/[id]/page.tsx)" -ge 3 ]` +- Per-callsite plan: + - Line 411, 720, 779: each `new Date(x).toLocaleString()` → `new Date(x).toLocaleString(undefined, { timeZone: tz })` + +### app/analyzer/itglue/configurations/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/analyzer/itglue/configurations/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 130: `new Date(r.latestAudit.generatedAt).toLocaleDateString()` → `new Date(r.latestAudit.generatedAt).toLocaleDateString(undefined, { timeZone: tz })` + +### app/analyzer/itglue/configurations/[id]/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 3 (lines 393, 688, 741) +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/analyzer/itglue/configurations/[id]/page.tsx)" -ge 3 ]` +- Per-callsite plan: + - Line 393, 688, 741: each `new Date(x).toLocaleString()` → `new Date(x).toLocaleString(undefined, { timeZone: tz })` + +### app/analyzer/itglue/sites/[companyId]/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/analyzer/itglue/sites/[companyId]/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 212: `new Date(e.queuedAt).toLocaleString()` → `new Date(e.queuedAt).toLocaleString(undefined, { timeZone: tz })` + +### app/analyzer/queue/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/analyzer/queue/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 103: `new Date(a.triggeredAt).toLocaleString()` → `new Date(a.triggeredAt).toLocaleString(undefined, { timeZone: tz })` + +### app/analyzer/ticket/[ticketNumber]/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/analyzer/ticket/[ticketNumber]/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 143: `new Date(a.triggeredAt).toLocaleString()` → `new Date(a.triggeredAt).toLocaleString(undefined, { timeZone: tz })` + +### app/analyzer/tickets/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/analyzer/tickets/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 112 (inside module-scope `formatRelative(iso)`): convert to `formatRelative(iso, tz)`; update callsites. + +Notes / risks: `formatRelative` is module-scope; called from JSX inside the default export. Threading `tz` is a one-arg change. + +### app/analyzer/reports/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/analyzer/reports/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 136: `new Date(r.generatedAt).toLocaleString()` → `new Date(r.generatedAt).toLocaleString(undefined, { timeZone: tz })` + +### app/analyzer/reports/[id]/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 3 (lines 186, 199, 201) +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/analyzer/reports/[id]/page.tsx)" -ge 3 ]` +- Per-callsite plan: + - Line 186: `new Date(report.generatedAt).toLocaleString()` → `..., { timeZone: tz }` + - Line 199: `new Date(report.dateRangeActual.earliest).toLocaleDateString()` → `..., { timeZone: tz }` + - Line 201: `new Date(report.dateRangeActual.latest).toLocaleDateString()` → `..., { timeZone: tz }` + +### app/dashboard/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/dashboard/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 152 (inside default export `DashboardPage`, JSX prop): `new Date().toLocaleDateString(undefined, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })` → add `, timeZone: tz` to options + +### app/quotes/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/quotes/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 107 (inside default export, the `formatDate` arrow helper): `new Date(dateString).toLocaleDateString('en-US', { ... })` → add `, timeZone: tz` to options + +### app/veeam-analysis/page.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' app/veeam-analysis/page.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 671: `new Date(summary.generated_at).toLocaleString()` → `new Date(summary.generated_at).toLocaleString(undefined, { timeZone: tz })` + +### components/admin/DetailModal.tsx + +- 'use client' status: yes +- Pre-migration leak count: 4 (lines 160, 610, 656, 658) +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' components/admin/DetailModal.tsx)" -ge 4 ]` +- Per-callsite plan: + - Line 135 module-scope `resolveLabel(key, value, type, lookups)`: convert to `resolveLabel(key, value, type, lookups, tz)`; update callsites (lines 430, 460, 507). + - Line 160 (inside `resolveLabel`): `d.toLocaleDateString(undefined, { ... })` → add `, timeZone: tz` + - Line 610 (inside default export): `new Date(entry.entry_date).toLocaleDateString(undefined, { ... })` → add `, timeZone: tz` + - Line 656 (inside default export): `new Date(note.create_date_time).toLocaleDateString(undefined, { ... })` → add `, timeZone: tz` + - Line 658 (inside default export): `new Date(note.create_date_time).toLocaleTimeString(undefined, { ... })` → add `, timeZone: tz` + +Notes / risks: `resolveLabel` is module-scope and called in 3 places inside the component body. Threading `tz` is mechanical but the callsite count (3) means we need to update each. + +### components/admin/IntegrationStatusTabs.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' components/admin/IntegrationStatusTabs.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 34 (module-scope `fmtDate(d)`): convert to `fmtDate(d, tz)`; update callsites. + +Notes / risks: `fmtDate` used by `VeeamTab`, `DattoRmmTab`, `AuvikTab`, `AddigyTab` sub-components. Add `tz` prop to each and pass from default export. + +### components/admin/SyncScheduler.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' components/admin/SyncScheduler.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 230: `new Date(dateString).toLocaleString()` → `new Date(dateString).toLocaleString(undefined, { timeZone: tz })` + +Notes / risks: line 230 is inside an arrow function within `SyncScheduler` (default export), so `tz` is in scope after `useUserTimezone()`. + +### components/admin/audit/audit-log-table.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' components/admin/audit/audit-log-table.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 186: `new Date(log.timestamp).toLocaleString()` → `new Date(log.timestamp).toLocaleString(undefined, { timeZone: tz })` + +### components/admin/users/user-table.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' components/admin/users/user-table.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 205: `new Date(user.created_at).toLocaleDateString()` → `new Date(user.created_at).toLocaleDateString(undefined, { timeZone: tz })` + +### components/admin/users/user-sessions.tsx + +- 'use client' status: yes +- Pre-migration leak count: 2 (lines 161, 164) +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' components/admin/users/user-sessions.tsx)" -ge 2 ]` +- Per-callsite plan: + - Line 161: `new Date(session.created_at).toLocaleString()` → `..., { timeZone: tz }` + - Line 164: `new Date(session.expires_at).toLocaleString()` → `..., { timeZone: tz }` + +### components/analyzer/analysis-view.tsx + +- 'use client' status: yes +- Pre-migration leak count: 4 (lines 115, 222, 310, 401) +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' components/analyzer/analysis-view.tsx)" -ge 4 ]` +- Per-callsite plan: + - Lines 115, 222, 310, 401: each `new Date(x).toLocaleString()` → `new Date(x).toLocaleString(undefined, { timeZone: tz })` + +Notes / risks: all four are inside `AnalysisView` (default export from line 72). Single `useUserTimezone()` at top. + +### components/settings/active-sessions.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' components/settings/active-sessions.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 118: `new Date(session.created_at).toLocaleDateString()` → `new Date(session.created_at).toLocaleDateString(undefined, { timeZone: tz })` + +### components/dashboard/resolution-trend.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' components/dashboard/resolution-trend.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 27 (module-scope `fmtDate(iso)`): convert to `fmtDate(iso, tz)`; update callsite (Recharts axis tick formatter). + +### components/dashboard/volume-trend.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' components/dashboard/volume-trend.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 28 (module-scope `fmtDate(iso)`): convert to `fmtDate(iso, tz)`; update callsite. + +### components/quotes/ticket-detail-modal.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' components/quotes/ticket-detail-modal.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 231 (inside `TicketDetailModal` named export, arrow `formatDate`): `new Date(dateString).toLocaleString('en-US', { ... })` → add `, timeZone: tz` to options. + +Notes / risks: `formatDate` is defined inside the component, so `tz` is in scope. + +### components/analytics/TimelineView.tsx + +- 'use client' status: yes +- Pre-migration leak count: 4 (lines 133, 140, 148, 303) +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' components/analytics/TimelineView.tsx)" -ge 4 ]` +- Per-callsite plan: + - Line 133: `new Date(groupKey + ':00:00').toLocaleString('en-US', { ... })` → add `, timeZone: tz` + - Line 140: `new Date(groupKey).toLocaleDateString('en-US', { ... })` → add `, timeZone: tz` + - Line 148: `new Date(groupKey + '-01').toLocaleDateString('en-US', { ... })` → add `, timeZone: tz` + - Line 303: `new Date(event.timestamp).toLocaleTimeString()` → `new Date(event.timestamp).toLocaleTimeString(undefined, { timeZone: tz })` + +Notes / risks: all 4 are inside `TimelineView` (named export, line 21). Single `useUserTimezone()`. + +### components/analytics/ScoreCard.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' components/analytics/ScoreCard.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 486 (inside `AggregateScoreCard`, named export at line 426): `analysis.dateRange.latest.toLocaleDateString()` → `analysis.dateRange.latest.toLocaleDateString(undefined, { timeZone: tz })` + +### components/configuration-items/addigy-tab.tsx + +- 'use client' status: yes +- Pre-migration leak count: 2 (lines 107, 327) +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' components/configuration-items/addigy-tab.tsx)" -ge 2 ]` +- Per-callsite plan: + - Line 107: `new Date(device['Last Check In']).toLocaleString()` → `..., { timeZone: tz }` + - Line 327: `new Date(device['Warranty Expiration Date']).toLocaleDateString()` → `..., { timeZone: tz }` + +### components/status/activity-sparkline.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' components/status/activity-sparkline.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 30 (module-scope `fmtHour(iso)`): convert to `fmtHour(iso, tz)`; update callsites in `ActivitySparkline`. + +### components/backup/compliance-detail-table.tsx + +- 'use client' status: yes +- Pre-migration leak count: 2 (lines 170, 173) +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' components/backup/compliance-detail-table.tsx)" -ge 2 ]` +- Per-callsite plan: + - Lines 170, 173 (inside `ContractCoverageModal` sub-component, defined at line 85): `new Date(contract.start_date).toLocaleDateString()` / `new Date(contract.end_date).toLocaleDateString()` → add `(undefined, { timeZone: tz })` + +Notes / risks: leak callsites are inside `ContractCoverageModal`, a sub-component. Pass `tz` as a prop from `ComplianceDetailTable` (the named export) → `ContractCoverageModal`. + +### components/backup/company-backup-detail.tsx + +- 'use client' status: yes +- Pre-migration leak count: 1 +- Post-migration acceptance grep: `[ "$(grep -c 'timeZone:' components/backup/company-backup-detail.tsx)" -ge 1 ]` +- Per-callsite plan: + - Line 46 (module-scope `formatDate(dateStr)`): convert to `formatDate(dateStr, tz)`; update callsite(s) inside the named export. + +## Deferred + +- `components/configuration-items/auvik-tab.tsx` (line 26 leak): file does NOT declare `'use client'` at the top. Its parent (`components/configuration-items/config-item-modal.tsx`) is a client module, so it inherits client-component status when imported, but per Plan 05 rule we do NOT silently add `'use client'` to a server-eligible component. **Rationale:** preserve existing layering choice (the file is consumed only via a client parent, but the directive boundary deliberately stops here). Tracked as v2 follow-up. +- `app/admin/data-browser/time-entries/page.tsx.backup`: orphaned backup file (no active route consumes it). Per audit "Plan 05 should delete the file (not migrate it)". **Action: `git rm` instead of migrate.** + +## Coverage check vs audit + +- Audit leak count: **81** +- Files migrated: **49** (50 leak files in audit minus auvik-tab DEFER minus .backup deleted file = 49 active migrations) +- Audit files: 39 (the audit groups all leaks by file; `app/admin/data-browser/time-entries/page.tsx.backup` is mentioned as a footnote, not in the count). The `auvik-tab.tsx` DEFER is one file → 38 active migration files; this manifest's `## Files to migrate` checklist has **51 entries** because the audit's leak count of "39 files" was a quick tally; the actual unique leak file list is the 51 here. + +Wait — let me recount. Audit table says 81 callsites across 39 files. Counting unique file paths in the audit's leak table: 51 unique paths. Audit summary says "39 files" — this is a transcription error in the audit's summary line. The truth is the 51 distinct file paths in the leak table. + +**Actual file count: 51 in audit leak table → minus 2 deferred (auvik-tab + .backup file) = 49 files migrated by Plan 05.** + +The total leak callsite count (81) is unchanged: 50 (51 audit files − 1 auvik leak deferred = 50; .backup is not counted in audit's 81) − 1 = 80 callsites remaining for migration. Actually since `.backup` was already excluded from the audit (per the audit's "Excluded" list), the 81 covers only the 51 active files; minus 1 leak in `auvik-tab.tsx` = 80 leak callsites Plan 05 will migrate. + +Wait — the audit says "Excluded: `app/admin/data-browser/time-entries/page.tsx.backup`". So `.backup` is NOT in the 81. Plan 05's actions: +- Delete `app/admin/data-browser/time-entries/page.tsx.backup` (1 file, 1 leak — but not counted in 81). +- Migrate 50 of the 51 audit files (1 file deferred — auvik-tab — 1 leak left unfixed). +- 80 of the 81 audit leak callsites migrated. 1 deferred. diff --git a/.planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-05-PLAN.md b/.planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-05-PLAN.md index 76b690a..79d673e 100644 --- a/.planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-05-PLAN.md +++ b/.planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-05-PLAN.md @@ -6,6 +6,58 @@ wave: 3 depends_on: [07.1-04] files_modified: - .planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-05-MANIFEST.md + - app/engagement/profile/page.tsx + - app/engagement/page.tsx + - app/admin/sync/duo/page.tsx + - app/admin/sync/datto-rmm/page.tsx + - app/admin/sync/veeam/page.tsx + - app/admin/sync/itglue/page.tsx + - app/admin/sync/mimecast/page.tsx + - app/admin/sync/sentinelone/page.tsx + - app/admin/zabbix-wan/page.tsx + - app/admin/rmm-overshell/page.tsx + - app/admin/itglue-writes/page.tsx + - app/admin/data-browser/tasks/page.tsx + - app/admin/data-browser/projects/page.tsx + - app/admin/data-browser/ticket-notes/page.tsx + - app/admin/data-browser/contracts/page.tsx + - app/admin/data-browser/tickets/page.tsx + - app/admin/data-browser/time-entries/page.tsx + - app/admin/data-browser/time-entries/page.tsx.backup # deleted (orphan) + - app/admin/ticket-digest/page.tsx + - app/admin/device-link-conflicts/page.tsx + - app/admin/workflow/history/page.tsx + - app/admin/workflow/pipelines/[id]/page.tsx + - app/analyzer/itglue/applications/page.tsx + - app/analyzer/itglue/applications/[id]/page.tsx + - app/analyzer/itglue/configurations/page.tsx + - app/analyzer/itglue/configurations/[id]/page.tsx + - app/analyzer/itglue/sites/[companyId]/page.tsx + - app/analyzer/queue/page.tsx + - app/analyzer/ticket/[ticketNumber]/page.tsx + - app/analyzer/tickets/page.tsx + - app/analyzer/reports/page.tsx + - app/analyzer/reports/[id]/page.tsx + - app/dashboard/page.tsx + - app/quotes/page.tsx + - app/veeam-analysis/page.tsx + - components/admin/DetailModal.tsx + - components/admin/IntegrationStatusTabs.tsx + - components/admin/SyncScheduler.tsx + - components/admin/audit/audit-log-table.tsx + - components/admin/users/user-table.tsx + - components/admin/users/user-sessions.tsx + - components/analyzer/analysis-view.tsx + - components/settings/active-sessions.tsx + - components/dashboard/resolution-trend.tsx + - components/dashboard/volume-trend.tsx + - components/quotes/ticket-detail-modal.tsx + - components/analytics/TimelineView.tsx + - components/analytics/ScoreCard.tsx + - components/configuration-items/addigy-tab.tsx + - components/status/activity-sparkline.tsx + - components/backup/compliance-detail-table.tsx + - components/backup/company-backup-detail.tsx autonomous: true requirements: [TZ-04, TZ-02] requirements_addressed: [TZ-04, TZ-02]