Skip to content

feat: ConversionResult component — unified post-conversion UX with named variants #2278

@aalemayhu

Description

@aalemayhu

What

A single React component that owns every post-conversion state on My Decks / job rows, replacing the current ad-hoc mix of error strings, paywall banners, and "download" rows with one consistent surface.

Why

From the W20 retro (docs/retros/2026-W19.md):

  • 73 % of users who hit a Python conversion crash never log back in (37 of 51 in the last 90 days).
  • 65 % of users who hit the paywall cap never return — the cancel message has no upgrade CTA today.

Both bounce paths are caused by the same UX gap: raw error strings + no recovery action.

Variants (8)

Each variant: one-line headline (user voice, no UUIDs / no stack traces), one-line "what to do next", one primary action, one secondary action. Variants:

  1. success — "34 cards in Pharmacology. Ready to download." + Download / Open in Anki guide
  2. processing — "Converting your Notion page…" + (no actions)
  3. paywalled — "You've hit 100 cards this month. Upgrade for unlimited." + Upgrade / Plans
  4. failed-empty — Notion page had no content. Try a different page / Help
  5. failed-permissions — Notion didn't share the page. Re-share / Notion permissions guide
  6. failed-unsupported — File type isn't supported. Use a supported format / Help
  7. failed-timeout — Conversion took too long. Try splitting / Contact support
  8. failed-other — Generic fallback. Try again / Contact support (no raw error string)

The five failed-* variants cover ~95 % of all failures from the 90-day retro window.

Where it lands

  • web/src/pages/DownloadsPage/components/ConversionResult.tsx (new)
  • Replaces the inline error rendering in UploadObjectEntry.tsx
  • Reuses the PaywallBanner visual pattern (already validated by users)

Acceptance

  • All 8 variants render in Storybook / vite preview
  • Every variant has user-voice copy reviewed against VOICE.md (no "Oops", no exclamation, no implementation jargon)
  • No raw error message, no ISO timestamp, no job UUID in body copy
  • 30-day metric after ship: "never returned after failure" rate drops from 73 % toward < 40 %

Out of scope

Effort: M (~1 week). From the W20 trio analysis; closed PR #2206 is the source of these numbers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions