Skip to content

feat(web): keyboard-education — onboarding, connect/trial CTAs, shortcut tips - #2736

Merged
tyler-dane merged 7 commits into
mainfrom
claude/keyboard-education-onboarding-9cc41b
Aug 10, 2026
Merged

feat(web): keyboard-education — onboarding, connect/trial CTAs, shortcut tips#2736
tyler-dane merged 7 commits into
mainfrom
claude/keyboard-education-onboarding-9cc41b

Conversation

@tyler-dane

@tyler-dane tyler-dane commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Brief 01 — extended onboarding tour

  • Extends the existing Start Now coachmark tour with four new lessons: moving focus between events (arrow keys), the E-then-field edit sequence, Shift-tap event targeting, and Shift+Arrow nudge, plus undo.
  • Adds a basics/advanced fork after the original 5-step lesson set ("Keep going" / "I'm done") so the required-feeling part stays short and extra shortcuts are opt-in.
  • Fixes a real bug: any welcome-modal exit into signup (not just Start Now) permanently marked the tour seen, so signup-first users could only reach it via the command palette. It's now offered once, right after signup actually completes (email or Google).
  • Relabels the palette's "Restart onboarding tour" item to "Practice shortcuts" with matching search keywords.
  • Widens the PostHog ProductEvent union and instruments tour start/task-completed/segment-reached/skip/finish/replay end to end.

Brief 02 — connect-Google and trial CTAs

  • Once the tour ends (finish or skip), anonymous users see a skippable "Connect Google Calendar" CTA (import runs in the background, never blocks) followed by a "ready to try it for real?" trial CTA. Skipping connect goes straight to the trial step.
  • Stage is persisted in localStorage so it survives the full-page redirect through Google OAuth.
  • Billing does not exist yet (see keyboard-education/03), so accepting the trial CTA opens signup for anonymous users; for an already-authenticated user (arrived via Connect Google, which signs up on its own) it's a stub no-op until checkout ships.
  • A 4s grace-period guard prevents stranding users on the connect step if Google auth isn't configured for a deployment, without racing the async config fetch.

Brief 04 — quiet shortcut tips in the sidebar

  • Rotates a single-line tip (edit-sequence, nudge, targeting, edge cycle) into the sidebar's status strip when an event is focused with no form open — reuses the exact CALENDAR_VIEW_INTERACTION_ID_ATTRIBUTES selector the app already uses for view-agnostic event lookups, so it works across Day/Week without importing either view's internals.
  • Lowest priority in the status bar, behind keyboard-only mode, event-jump mode, edge-focus, and any real sync-status text.
  • Capped to one rotation per 45s regardless of how often focus toggles (the cooldown is tracked independently of the visible tip so rapid refocus can't bypass it), biased toward the edit-sequence tip after 3 consecutive mouse-driven edits (via the existing draft activity discriminator), muted permanently on click, and tracked via shortcut_tip_shown/shortcut_tip_acted_on.

All three briefs are part of the keyboard-education project spec (compass-calendar-internal/projects/keyboard-education/). Mouse-disable-during-practice and ephemeral, non-persisted synthetic sandbox events (the full "game" framing from brief 01) are intentionally deferred to brief 06 — they touch shared query/interaction code that deserves its own focused review rather than riding along here.

Known limitations

  • Brief 01/04: several advance/acted-on triggers (Arrow, Shift, Tab, Mod+Z, E) are "encouragement-based" like the existing tour save step — pressing the key counts without verifying the resulting action landed, and unlike the app's real detectors they don't check for an editable-input target. Not a functional bug, just a pedagogy/tracking-accuracy gap worth tightening later.
  • Brief 02: no automated test/e2e coverage yet for the OAuth-redirect stage-persistence path (verified by code inspection of the storage-backed store hydration, not a live redirect).

Test plan

  • bun test src/components/OnboardingTour/ — 20/20 passing
  • bun test src/components/PostOnboardingFlow/ — 4/4 passing
  • bun test src/shortcuts/tips/ src/components/Sidebar/SidebarStatusBar.test.tsx — 21/21 passing
  • bun run type-check — clean
  • biome check on all touched files — clean
  • bunx knip — no new unused exports introduced
  • Live browser verification — not possible in this worktree: the backend requires SYNC_SERVICE_URL/SYNC_INTERNAL_AUTH_TOKEN env vars not present here (pre-existing environment gap, unrelated to this change)

🤖 Generated with Claude Code

Adds four new lessons (move focus, edit-sequence jump, Shift-tap
targeting, Shift+Arrow nudge, undo) behind a basics/advanced fork so
new users get the required-feeling basics and can opt into extra
credit without ever being held hostage. Also fixes a bug where any
welcome-modal exit into signup permanently burned the tour-seen flag;
it's now offered once right after signup completes. Widens the
PostHog ProductEvent union and instruments the tour end to end.

Keyboard-only mouse-disable and ephemeral synthetic sandbox events
are deferred to a fast-follow (see keyboard-education/01 brief) since
they touch shared query/interaction code that deserves its own pass.
Once the onboarding tour ends (finish or skip), anonymous users now
see a skippable "Connect Google Calendar" CTA (import runs in the
background) followed by a "ready to try it for real?" trial CTA.
Skipping connect goes straight to the trial step. Stage is persisted
across the Google OAuth full-page redirect. Billing does not exist
yet, so accepting the trial CTA opens signup for anonymous users and
is a no-op stub for authenticated ones until the checkout brief lands.
@tyler-dane tyler-dane changed the title feat(web): extend onboarding tour into a fuller shortcut lesson set feat(web): keyboard-education — onboarding tour extension + connect/trial flow Aug 10, 2026
Rotates a single-line tip (edit-sequence, nudge, targeting, edge
cycle) into the sidebar's status strip when an event is focused with
no form open, at lowest priority behind keyboard-only/event-jump/
edge-focus/sync-status. Capped to one rotation per 45s regardless of
focus churn, biased toward the edit-sequence tip after 3 consecutive
mouse-driven edits, muted permanently on click, and tracked via the
tour's shortcut_tip_shown/acted_on events.
@tyler-dane tyler-dane changed the title feat(web): keyboard-education — onboarding tour extension + connect/trial flow feat(web): keyboard-education — onboarding, connect/trial CTAs, shortcut tips Aug 10, 2026
Palette label test still asserted "Restart onboarding tour" after
the rename to "Practice shortcuts". The interactive-tour e2e happy
path only exercised the original 5 steps; walks the new moveFocus/
editSequence steps and the fork's "I'm done" exit now.
With only one event on the calendar, ArrowRight (no adjacent target)
doesn't reliably leave DOM focus on it. Mirrors the existing pattern
in e2e/timed/edit-sequence-title.spec.ts.
PostOnboardingFlow rendered purely off the persisted stage, with no
authenticated check: a user who reached "connect"/"trial" anonymously
and then logged in by any path other than the Connect Google button
(email/password, Google auth elsewhere) would still see the CTA on
their next load, since nothing reset the stale localStorage stage.

Fixes it two ways: PostOnboardingFlow now gates its own render on
authenticated (defense in depth), and usePostOnboardingFlowTrigger
resolves a stale connect/trial stage to done the moment authenticated
flips true, so it can never resurface later either.

Found via independent review before merge.
@tyler-dane
tyler-dane merged commit 9107d4b into main Aug 10, 2026
20 checks passed
@tyler-dane
tyler-dane deleted the claude/keyboard-education-onboarding-9cc41b branch August 10, 2026 19:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant