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:
@@ -95,7 +95,12 @@ export function AdminSectionsBrowser({ portSlug, groups }: AdminSectionsBrowserP
|
||||
</p>
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{filteredMatches.map((s) => (
|
||||
<SectionCard key={`${s.href}-${s.groupTitle}`} portSlug={portSlug} section={s} groupTitle={s.groupTitle} />
|
||||
<SectionCard
|
||||
key={`${s.href}-${s.groupTitle}`}
|
||||
portSlug={portSlug}
|
||||
section={s}
|
||||
groupTitle={s.groupTitle}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@@ -138,7 +143,11 @@ function SectionCard({
|
||||
href={`/${portSlug}/admin/${section.href}` as any}
|
||||
className="block group"
|
||||
>
|
||||
<Card className={cn('h-full transition-colors group-hover:border-primary/50 group-hover:bg-muted/30')}>
|
||||
<Card
|
||||
className={cn(
|
||||
'h-full transition-colors group-hover:border-primary/50 group-hover:bg-muted/30',
|
||||
)}
|
||||
>
|
||||
<CardHeader className="flex flex-row items-start gap-3 space-y-0 pb-2">
|
||||
<Icon className="h-5 w-5 mt-0.5 text-muted-foreground group-hover:text-primary" />
|
||||
<div className="flex-1">
|
||||
|
||||
Reference in New Issue
Block a user