feat(dashboard): local-time greeting + timezone-drift banner
Greeting - The "Good morning / afternoon / evening, Matt" line now derives from the browser's local time, computed inside a useEffect so the rendered HTML can't lock to the server's clock during hydration. Until the effect fires, the header reads "Welcome" — a neutral phrase that's correct at every hour and never produces a hydration warning. The phrase re-evaluates hourly so a rep leaving the dashboard open across a boundary (5am, noon, 6pm) doesn't keep stale text on screen. Timezone-drift banner - New <TimezoneDriftBanner> on the dashboard surfaces when the browser's resolved timezone (Intl.DateTimeFormat().resolvedOptions().timeZone, which follows the OS — and the OS usually follows physical location) doesn't match the user's stored CRM preference. The rep gets a one-tap "Update to Tokyo" button and a dismiss × that's sticky per browser via localStorage. - Why a banner rather than auto-update: the stored timezone drives reminder firing time, daily-digest delivery, and due-date rendering. Silently pinning it to a transient travel location would shift their reminder schedule underfoot. The banner gives them control. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -129,9 +129,7 @@ export function Topbar({ ports, user }: TopbarProps) {
|
||||
straight at the new path. The Reminders section's
|
||||
useCreateFromUrl handler still picks up ?create=1. */}
|
||||
<DropdownMenuItem
|
||||
onClick={() =>
|
||||
router.push(`${base}/inbox?create=1#reminders` as unknown as Route)
|
||||
}
|
||||
onClick={() => router.push(`${base}/inbox?create=1#reminders` as unknown as Route)}
|
||||
>
|
||||
New Reminder
|
||||
</DropdownMenuItem>
|
||||
|
||||
Reference in New Issue
Block a user