diff --git a/PROGRESS.md b/PROGRESS.md index ef50973..bacdd0c 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -51,6 +51,21 @@ All 4 phases done. Tailwind utility clone deleted, all templates migrated to sem | 70 | Margin guard on sales (prevent discounts that breach minimum profit threshold) | 69 | 1h | planned | | 71 | Announcement bar (dismissable shop banner for active sales) | 69 | 1.5h | planned | +### Onboarding UX improvements ([plan](docs/plans/onboarding-ux.md)) + +| # | Task | Priority | Est | Status | +|---|------|----------|-----|--------| +| 1 | Redirect to dashboard after wizard completion with welcome flash | High | 30m | planned | +| 2 | Add shipping setup to checklist, gate "Go live" on shipping existing | High | 1h | planned | +| 3 | Add shop settings to checklist (name, currency) | High | 45m | planned | +| 4 | Make checklist collapsible instead of dismissable | Medium | 15m | planned | +| 5 | Add test order guidance (test card number, what to expect) | Medium | 45m | planned | +| 6 | Skip completed wizard steps on revisit | Medium | 1h | planned | +| 7 | Better provider connection error messages with help links | Medium | 30m | planned | +| 8 | Add theme customisation tips to checklist | Low | 15m | planned | +| 9 | Smarter "Sync products" checklist link | Low | 15m | planned | +| 10 | Add email setup as optional checklist item | Low | 30m | planned | + ### Platform site | # | Task | Depends on | Est | Status | @@ -93,4 +108,5 @@ All plans in [docs/plans/](docs/plans/). Completed plans are kept as architectur | [favicon.md](docs/plans/favicon.md) | Complete | | [legal-page-generator.md](docs/plans/legal-page-generator.md) | Complete | | [url-redirects.md](docs/plans/url-redirects.md) | Complete | +| [onboarding-ux.md](docs/plans/onboarding-ux.md) | Planned | | [profit-aware-pricing.md](docs/plans/profit-aware-pricing.md) | Planned | diff --git a/assets/css/admin/components.css b/assets/css/admin/components.css index cdbe20f..f8af23a 100644 --- a/assets/css/admin/components.css +++ b/assets/css/admin/components.css @@ -1958,10 +1958,11 @@ .block-card-info { flex: 1; - min-width: 0; + min-width: 6rem; } .block-card-name { + display: block; font-size: 0.875rem; font-weight: 500; white-space: nowrap; @@ -1983,6 +1984,7 @@ align-items: center; gap: 0.125rem; flex-shrink: 0; + margin-left: auto; } .block-remove-btn { @@ -2119,7 +2121,8 @@ .block-card-header { display: flex; align-items: center; - gap: 0.5rem; + gap: 0.25rem 0.5rem; + flex-wrap: wrap; width: 100%; } diff --git a/docs/plans/onboarding-ux.md b/docs/plans/onboarding-ux.md new file mode 100644 index 0000000..34210a2 --- /dev/null +++ b/docs/plans/onboarding-ux.md @@ -0,0 +1,109 @@ +# Onboarding UX improvements + +Status: Planned + +## Context + +The setup wizard and dashboard launch checklist work, but there are gaps that leave new users guessing. Goal: make onboarding totally fool-proof and guided so a non-technical seller can go from zero to live store without confusion. + +## Current flow + +1. **Setup wizard** (`lib/berrypod_web/live/setup/onboarding.ex`): 3 cards — admin account → provider API key → Stripe connection. Gated by secret in prod, auto-login after account creation. +2. **Dashboard checklist** (`lib/berrypod_web/live/admin/dashboard.ex`): 5 items with progress bar — sync products, connect Stripe, customise theme, place test order, go live. Visible when `site_live` is false and not dismissed. +3. **Coming soon page**: blocks public access before launch. +4. **Setup status** (`lib/berrypod/setup.ex`): `setup_status/0` returns booleans for each milestone. + +## Gaps identified + +### High priority + +#### 1. Dead end after setup wizard +The wizard ends at Stripe connection with no redirect or next-steps message. User has to figure out where to go. + +**Fix:** After completing the final wizard step, redirect to `/admin` with a flash message like "You're in! Here's your launch checklist." (~30m) + +**Files:** `lib/berrypod_web/live/setup/onboarding.ex` + +#### 2. No shipping rate setup in checklist +Checkout requires shipping rates. There's no checklist item for configuring shipping, and no warning that checkout will fail without it. A user could "Go live" with no shipping rates. + +**Fix:** Add "Set up shipping" checklist item that links to `/admin/settings` (shipping section). Gate "Go live" on at least one shipping profile existing. (~1h) + +**Files:** `lib/berrypod_web/live/admin/dashboard.ex`, `lib/berrypod/setup.ex` + +#### 3. No shop settings in checklist +Shop name, currency, country are critical but not in the checklist. User could go live with "My Shop" as the name. + +**Fix:** Add "Configure your shop" as the first checklist item, linking to `/admin/settings`. Mark complete when shop name differs from default. (~45m) + +**Files:** `lib/berrypod_web/live/admin/dashboard.ex`, `lib/berrypod/setup.ex` + +### Medium priority + +#### 4. Checklist dismissable and gone forever +Once dismissed, no way to get it back. Stored as `checklist_dismissed` setting. + +**Fix:** Replace dismiss with a collapse/expand toggle. Or add a "Show launch checklist" link in the dashboard sidebar when dismissed but site isn't live yet. (~15m) + +**Files:** `lib/berrypod_web/live/admin/dashboard.ex`, possibly `lib/berrypod_web/components/layouts/admin.html.heex` + +#### 5. "Place a test order" has zero guidance +Links to the shop home page. No mention of Stripe test mode, test card numbers, or what a successful test looks like. + +**Fix:** Add inline help text under the checklist item: "Use card number 4242 4242 4242 4242 with any future expiry and CVC. You'll see the order appear in Orders when it works." (~45m) + +**Files:** `lib/berrypod_web/live/admin/dashboard.ex` + +#### 6. Skip completed wizard steps on revisit +If a user closes their browser mid-setup and comes back, the wizard restarts from scratch (session-based). Should detect existing state and skip completed steps. + +**Fix:** In `mount/3`, call `Setup.setup_status/0` and set `current_step` to the first incomplete step. (~1h) + +**Files:** `lib/berrypod_web/live/setup/onboarding.ex` + +#### 7. Better provider connection error messages +If the API key is wrong, the error is generic. No link to where to find the key, no troubleshooting. + +**Fix:** Add provider-specific help text: "Find your Printify API key at Printify → Settings → Connections" (with link). Show the actual API error when it's user-facing (auth failure vs server error). (~30m) + +**Files:** `lib/berrypod_web/live/setup/onboarding.ex`, `lib/berrypod_web/live/admin/providers.ex` + +### Low priority + +#### 8. Guide theme customisation +`theme_customised` is true if any setting differs from defaults. Changing one colour counts. No guidance on what to customise. + +**Fix:** Add a brief tip under the checklist item: "Upload your logo, pick your colours, and choose a font that matches your brand." (~15m) + +**Files:** `lib/berrypod_web/live/admin/dashboard.ex` + +#### 9. Clarify "Sync your products" checklist step +Links to `/admin/providers` but user needs to click "Sync" on an already-connected provider. Confusing if they connected during the wizard. + +**Fix:** If provider is connected but no products synced, link directly to the provider detail page with a prompt to sync. If products exist, mark as complete. (~15m) + +**Files:** `lib/berrypod_web/live/admin/dashboard.ex` + +#### 10. Move email setup into checklist as optional step +The orange "email not configured" banner appears on every page but isn't in the checklist. Email is needed for abandoned cart, order confirmations, contact form. + +**Fix:** Add as a non-blocking checklist item (doesn't gate "Go live" but shows as recommended). (~30m) + +**Files:** `lib/berrypod_web/live/admin/dashboard.ex`, `lib/berrypod/setup.ex` + +## Task breakdown + +| # | Task | Priority | Est | Status | +|---|------|----------|-----|--------| +| 1 | Redirect to dashboard after wizard completion with welcome flash | High | 30m | planned | +| 2 | Add shipping setup to checklist, gate "Go live" on shipping existing | High | 1h | planned | +| 3 | Add shop settings to checklist (name, currency) | High | 45m | planned | +| 4 | Make checklist collapsible instead of dismissable | Medium | 15m | planned | +| 5 | Add test order guidance (test card number, what to expect) | Medium | 45m | planned | +| 6 | Skip completed wizard steps on revisit | Medium | 1h | planned | +| 7 | Better provider connection error messages with help links | Medium | 30m | planned | +| 8 | Add theme customisation tips to checklist | Low | 15m | planned | +| 9 | Smarter "Sync products" checklist link | Low | 15m | planned | +| 10 | Add email setup as optional checklist item | Low | 30m | planned | + +Total estimate: ~5.5h diff --git a/lib/berrypod/pages/block_types.ex b/lib/berrypod/pages/block_types.ex index 925cb05..41826b0 100644 --- a/lib/berrypod/pages/block_types.ex +++ b/lib/berrypod/pages/block_types.ex @@ -96,7 +96,6 @@ defmodule Berrypod.Pages.BlockTypes do %SettingsField{key: "title", label: "Title", type: :text, default: ""}, %SettingsField{key: "description", label: "Description", type: :textarea, default: ""}, %SettingsField{key: "image_id", label: "Image", type: :image, default: nil}, - %SettingsField{key: "image_url", label: "Image URL (legacy)", type: :text, default: ""}, %SettingsField{key: "link_text", label: "Link text", type: :text, default: ""}, %SettingsField{key: "link_href", label: "Link URL", type: :text, default: ""} ] @@ -344,14 +343,7 @@ defmodule Berrypod.Pages.BlockTypes do allowed_on: :all, settings_schema: [ %SettingsField{key: "content", label: "Content", type: :textarea, default: ""}, - %SettingsField{key: "image_id", label: "Image", type: :image, default: nil}, - %SettingsField{key: "image_src", label: "Image URL (legacy)", type: :text, default: ""}, - %SettingsField{ - key: "image_alt", - label: "Image alt text (legacy)", - type: :text, - default: "" - } + %SettingsField{key: "image_id", label: "Image", type: :image, default: nil} ] }, diff --git a/lib/berrypod/pages/defaults.ex b/lib/berrypod/pages/defaults.ex index f8382bc..eb35fd2 100644 --- a/lib/berrypod/pages/defaults.ex +++ b/lib/berrypod/pages/defaults.ex @@ -42,9 +42,9 @@ defmodule Berrypod.Pages.Defaults do defp blocks("home") do [ block("hero", %{ - "title" => "Original designs, printed on demand", + "title" => "Your headline goes here", "description" => - "Welcome to the Berrypod demo store. This is where your hero text goes \u2013 something short and punchy about what makes your shop worth a browse.", + "Write something short and punchy about your shop \u2013 what you sell and why it's worth a look.", "cta_text" => "Shop the collection", "cta_href" => "/collections/all", "variant" => "default" @@ -55,11 +55,10 @@ defmodule Berrypod.Pages.Defaults do "product_count" => 8 }), block("image_text", %{ - "title" => "Made with passion, printed with care", + "title" => "Your story in a nutshell", "description" => - "This is an example content section. Use it to share your story, highlight what makes your products special, or link to your about page.", - "image_url" => "/mockups/mountain-sunrise-print-3-800.webp", - "link_text" => "Learn more about the studio \u2192", + "Use this section to share what makes your products special, your creative process, or a bit about you. Pick an image from your media library to go alongside it.", + "link_text" => "Read more about us \u2192", "link_href" => "/about" }) ] @@ -68,13 +67,14 @@ defmodule Berrypod.Pages.Defaults do defp blocks("about") do [ block("hero", %{ - "title" => "About the studio", - "description" => "Your story goes here \u2013 this is sample content for the demo shop", + "title" => "About us", + "description" => "Share a bit about who you are and what you do", "variant" => "sunken" }), block("content_body", %{ - "image_src" => "/mockups/night-sky-blanket-3", - "image_alt" => "Night sky blanket draped over a chair" + "content" => + "Tell your customers who you are and what inspired your shop. What's the story behind your designs?\n\n" <> + "This is placeholder text \u2013 edit it to make it your own. You can also add an image from your media library using the block settings." }) ] end @@ -116,8 +116,7 @@ defmodule Berrypod.Pages.Defaults do [ block("hero", %{ "title" => "Get in touch", - "description" => - "Sample contact page for the demo store. Add your own message here \u2013 something friendly about how customers can reach you.", + "description" => "Add a friendly message about how customers can reach you", "variant" => "page" }), block("contact_form", %{"email" => "hello@example.com"}), @@ -125,9 +124,9 @@ defmodule Berrypod.Pages.Defaults do block("info_card", %{ "title" => "Handy to know", "items" => [ - %{"label" => "Printing", "value" => "Example: 2-5 business days"}, - %{"label" => "Delivery", "value" => "Example: 3-7 business days after printing"}, - %{"label" => "Issues", "value" => "Example: Reprints for any defects"} + %{"label" => "Printing", "value" => "Update with your printing times"}, + %{"label" => "Delivery", "value" => "Update with your delivery times"}, + %{"label" => "Issues", "value" => "Update with your returns policy"} ] }), block("newsletter_card"), diff --git a/lib/berrypod_web/page_renderer.ex b/lib/berrypod_web/page_renderer.ex index bdd01f9..9664fa5 100644 --- a/lib/berrypod_web/page_renderer.ex +++ b/lib/berrypod_web/page_renderer.ex @@ -112,15 +112,12 @@ defmodule BerrypodWeb.PageRenderer do > Reset - @@ -280,7 +277,7 @@ defmodule BerrypodWeb.PageRenderer do defp render_block(%{block: %{"type" => "image_text"}} = assigns) do settings = assigns.block["settings"] || %{} - image_url = resolve_block_image_url(settings["image_id"], settings["image_url"]) + image_url = resolve_block_image_url(settings["image_id"]) assigns = assigns @@ -634,11 +631,12 @@ defmodule BerrypodWeb.PageRenderer do defp render_block(%{block: %{"type" => "content_body"}} = assigns) do settings = assigns.block["settings"] || %{} content = settings["content"] || "" - {image_src, image_alt} = resolve_content_image(settings) + {image_src, source_width, image_alt} = resolve_content_image(settings) assigns = assigns |> assign(:image_src, image_src) + |> assign(:image_source_width, source_width || 1200) |> assign(:image_alt, image_alt) |> assign(:content, content) @@ -648,7 +646,7 @@ defmodule BerrypodWeb.PageRenderer do