Skip to content

fix(ui): unbreak Storybook stories + auth-title sizing + storybook VAPID env - #69

Merged
agjs merged 2 commits into
mainfrom
ui/storybook-audit-and-fixes
May 30, 2026
Merged

agjs merged 2 commits into
mainfrom
ui/storybook-audit-and-fixes

Conversation

@agjs

@agjs agjs commented May 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Three classes of UI breakage caught in Storybook review, batched here so they ship together:

Broken stories (unable to render)

  • WebPushCard stories were bare export const Default: IStory = {} with no providers. Component reads useCapabilities() (TanStack Query) so the story crashed with "No QueryClient set". Now wrapped with QueryClientProvider + I18nextProvider, plus a seeded CAPABILITIES_QUERY_KEY for two realistic states: server not configured (Default) vs. server + browser ready (Ready to subscribe).
  • MfaSection had a QueryClient but no I18nextProvider, so the card rendered with raw i18n keys. Only had one Default story despite the component having four UI states. Now has three states seeded via AUTH_QUERY_KEYS.mfaStatus: Disabled (Default), Loading, Enabled.
  • LoginCredentialsForm renders <Link to="/forgot-password"> and <Link to="/signup">. No router context in the story → "Cannot destructure property 'basename' of useContext as it is null". Wrapped story render in MemoryRouter.

Storybook env wiring

WebPushCard's configured-branch check is env.VITE_VAPID_PUBLIC_KEY !== "", read at module-import time. Per-story decorators can't influence it. Added a Storybook viteFinal hook that injects a synthetic placeholder VAPID public key into process.env before Vite resolves env, so the "Ready to subscribe" story actually renders the configured branch. Stories never call pushManager.subscribe(), so the dummy is never exercised.

Auth page title sizing

All six auth pages (SignUp, Login form, ForgotPassword, ResetPassword, VerifyEmail, OAuthCallback) used text-4xl md:text-5xl for h1. Multi-word titles like "Create your account" wrapped to two lines in the max-w-md panel at most viewport widths. Bumped down one notch to text-3xl md:text-4xl so every title fits a single line.

Test plan

  • bun run typecheck (apps/ui): clean.
  • bun run lint: clean on the touched files.
  • bun run test (apps/ui): no regressions.
  • Manual: open Storybook, confirm WebPushCard / MfaSection / LoginCredentialsForm stories render without errors and the new state stories actually differ visually.

agjs added 2 commits May 30, 2026 21:27
…ies; shrink auth titles

Three independent fixes batched together because they were flagged
together in review:

- **WebPushCard stories**: were a bare `export const Default: IStory =
  {}` with no providers. Component reads `useCapabilities()` (TanStack
  Query) so the story rendered the "No QueryClient set" error screen.
  Add QueryClient + I18nextProvider decorators, plus a seeded
  `CAPABILITIES_QUERY_KEY` so the card actually shows a real state.
  Two stories cover the realistic dev paths: server not configured
  (Default) and server ready, awaiting user subscribe.

- **MfaSection stories**: had QueryClient but no I18nextProvider so
  the card rendered with literal `accounts.settings.mfa.*` keys. Also
  only had one Default story despite the component implementing 4
  view states. Add I18nextProvider and seed `AUTH_QUERY_KEYS.mfaStatus`
  for three states: Disabled (Default), Loading, Enabled.

- **LoginCredentialsForm stories**: form renders <Link to=/...> which
  needs a router context. Both `Default` and `PendingVerification`
  were crashing with "Cannot destructure property 'basename' of
  useContext as it is null". Wrap the meta render in MemoryRouter.

- **Auth page titles**: SignUpPage, LoginCredentialsForm, ForgotPassword,
  ResetPassword, VerifyEmail, OAuthCallback all used
  `text-4xl md:text-5xl` for h1, which wraps multi-word titles like
  "Create your account" onto two lines inside the max-w-md panel.
  Downsize one notch to `text-3xl md:text-4xl` so titles fit a single
  line at all viewport widths.
…ushCard story

WebPushCard's `isConfigured` branch checks
`env.VITE_VAPID_PUBLIC_KEY !== ""`. The env is read at module-import
time, so Storybook's per-story decorators can't influence it: even
with `capabilities.webPush=true` seeded, the "Ready to subscribe"
story rendered the same "Web Push is not configured" notice as the
"Server not configured" story.

Wire a Storybook viteFinal hook that sets `VITE_VAPID_PUBLIC_KEY` to
a synthetic P-256 placeholder before Vite reads `process.env`. Now:

- "Server not configured" still renders the unconfigured state
  (because `serverWebPushEnabled` from the seeded capabilities is
  false → `isConfigured = true && false = false`).
- "Ready to subscribe" renders the configured branch with the
  "Subscribe" CTA, because both halves of `isConfigured` are true.

Stories never call `pushManager.subscribe()`, so the dummy key isn't
exercised anywhere it would matter.
@agjs
agjs merged commit 58ff6e7 into main May 30, 2026
26 checks passed
@agjs
agjs deleted the ui/storybook-audit-and-fixes branch May 30, 2026 21:29
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