feat(dashboard): focus same-page Start Session input from NextStep CTA and checklist
The "Start a session" CTAs on the NextStepCard and SetupChecklist used to Link-navigate, which left the user on the same page (the Start Session input lives on the dashboard) without any visible response. Replace those CTAs with a custom window-event dispatch (FOCUS_START_SESSION_EVENT) that the StartSessionInput listens for: scroll the input into view, focus the textarea, and pulse a ring for 900ms so the click feels intentional. The NextStepCard also locally hides itself after firing so the user isn't double-prompted while typing. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import type { OnboardingStatus } from '@/api/onboarding'
|
||||
import { useTrialBanner } from '@/hooks/useTrialBanner'
|
||||
import type { TrialBannerStage } from '@/hooks/useTrialBanner'
|
||||
import { useOnboardingStatus } from '@/hooks/useOnboardingStatus'
|
||||
import { FOCUS_START_SESSION_EVENT } from '@/components/dashboard/StartSessionInput'
|
||||
|
||||
/**
|
||||
* Next-step card — surfaces the single highest-priority incomplete onboarding
|
||||
@@ -114,9 +115,10 @@ export function pickNextStep(
|
||||
export function NextStepCard() {
|
||||
const status = useOnboardingStatus()
|
||||
const [locallyDismissed, setLocallyDismissed] = useState(false)
|
||||
const [locallyHidden, setLocallyHidden] = useState(false)
|
||||
const { stage } = useTrialBanner()
|
||||
|
||||
if (!status || status.dismissed || locallyDismissed) return null
|
||||
if (!status || status.dismissed || locallyDismissed || locallyHidden) return null
|
||||
|
||||
const next = pickNextStep(status, stage)
|
||||
if (!next) return null
|
||||
@@ -154,14 +156,29 @@ export function NextStepCard() {
|
||||
</button>
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
<Link
|
||||
to={next.ctaPath}
|
||||
data-testid="next-step-cta"
|
||||
className="inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground transition-colors hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1"
|
||||
>
|
||||
{next.ctaLabel}
|
||||
<ArrowRight size={14} />
|
||||
</Link>
|
||||
{next.key === 'ran_session' ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
window.dispatchEvent(new Event(FOCUS_START_SESSION_EVENT))
|
||||
setLocallyHidden(true)
|
||||
}}
|
||||
data-testid="next-step-cta"
|
||||
className="inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground transition-colors hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1"
|
||||
>
|
||||
{next.ctaLabel}
|
||||
<ArrowRight size={14} />
|
||||
</button>
|
||||
) : (
|
||||
<Link
|
||||
to={next.ctaPath}
|
||||
data-testid="next-step-cta"
|
||||
className="inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground transition-colors hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1"
|
||||
>
|
||||
{next.ctaLabel}
|
||||
<ArrowRight size={14} />
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user