Refine FuneralFinder v1 — full stepped flow, always-visible CTA
- Extend one-question-at-a-time pattern through all steps (type, service, location) - CTA + location always visible at bottom; smart defaults for missing optional fields - Minimum search requirements: intent + location; type/service/themes default to "all" - Funeral types: Cremation, Burial, Water Burial (QLD only) + Explore All as TypeCard - Service preference step (conditional): With a service / No service / I'm flexible - Theme preferences (eco-friendly, budget-friendly, religious specialisation) as optional sub-option within type step - StepHeading sub-component: bodyLg centered, distinct from card labels - CompletedRows: generous py:1.5 spacing, caption-size "Change" with aria-label - Loading prop on CTA button, location validation (3+ chars) - Divider under subheading for visual structure - Main heading upgraded to h2 with display font - Audit: 14/20 (Good), Critique: 29/40 (Good) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,26 +4,31 @@ import { FuneralFinder } from './FuneralFinder';
|
||||
import { Navigation } from '../Navigation';
|
||||
import { Typography } from '../../atoms/Typography';
|
||||
|
||||
// ─── Shared data ────────────────────────────────────────────────────────────
|
||||
|
||||
const funeralTypes = [
|
||||
{ id: 'cremation', label: 'Cremation' },
|
||||
{ id: 'burial', label: 'Burial' },
|
||||
{ id: 'memorial', label: 'Memorial' },
|
||||
{ id: 'catholic', label: 'Catholic' },
|
||||
{ id: 'direct-cremation', label: 'Direct Cremation' },
|
||||
{ id: 'natural-burial', label: 'Natural Burial' },
|
||||
{ id: 'cremation', label: 'Cremation', hasServiceOption: true },
|
||||
{ id: 'burial', label: 'Burial', hasServiceOption: true },
|
||||
{ id: 'water-burial', label: 'Water Burial', note: 'Available in QLD only', hasServiceOption: false },
|
||||
];
|
||||
|
||||
const themeOptions = [
|
||||
{ id: 'eco-friendly', label: 'Eco-friendly' },
|
||||
{ id: 'budget-friendly', label: 'Budget-friendly' },
|
||||
{ id: 'religious', label: 'Religious specialisation' },
|
||||
];
|
||||
|
||||
const FALogoNav = () => (
|
||||
<Box component="img" src="/brandlogo/logo-full.svg" alt="Funeral Arranger" sx={{ height: 28 }} />
|
||||
);
|
||||
|
||||
// ─── Meta ───────────────────────────────────────────────────────────────────
|
||||
|
||||
const meta: Meta<typeof FuneralFinder> = {
|
||||
title: 'Organisms/FuneralFinder',
|
||||
component: FuneralFinder,
|
||||
tags: ['autodocs'],
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
parameters: { layout: 'centered' },
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<Box sx={{ maxWidth: 520, width: '100%' }}>
|
||||
@@ -36,41 +41,67 @@ const meta: Meta<typeof FuneralFinder> = {
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof FuneralFinder>;
|
||||
|
||||
// --- Default -----------------------------------------------------------------
|
||||
// ─── Default ────────────────────────────────────────────────────────────────
|
||||
|
||||
/** Initial state — step 1 active, all others locked */
|
||||
/** Initial state — full feature set with types, themes, and explore-all. */
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
funeralTypes,
|
||||
themeOptions,
|
||||
onSearch: (params) => alert(JSON.stringify(params, null, 2)),
|
||||
},
|
||||
};
|
||||
|
||||
// --- Fewer Funeral Types -----------------------------------------------------
|
||||
// ─── Without Themes ─────────────────────────────────────────────────────────
|
||||
|
||||
/** With only 3 funeral types — shows compact chip row */
|
||||
export const FewerTypes: Story = {
|
||||
/** No theme options — skips the preferences section on the final step. */
|
||||
export const WithoutThemes: Story = {
|
||||
args: {
|
||||
funeralTypes: funeralTypes.slice(0, 3),
|
||||
funeralTypes,
|
||||
onSearch: (params) => alert(JSON.stringify(params, null, 2)),
|
||||
},
|
||||
};
|
||||
|
||||
// --- Custom Heading ----------------------------------------------------------
|
||||
// ─── Without Explore All ────────────────────────────────────────────────────
|
||||
|
||||
/** With custom heading and subheading */
|
||||
/** Explore-all option hidden — users must pick a specific type. */
|
||||
export const WithoutExploreAll: Story = {
|
||||
args: {
|
||||
funeralTypes,
|
||||
themeOptions,
|
||||
showExploreAll: false,
|
||||
onSearch: (params) => alert(JSON.stringify(params, null, 2)),
|
||||
},
|
||||
};
|
||||
|
||||
// ─── Loading State ──────────────────────────────────────────────────────────
|
||||
|
||||
/** CTA in loading state — shows spinner, button disabled. */
|
||||
export const Loading: Story = {
|
||||
args: {
|
||||
funeralTypes,
|
||||
themeOptions,
|
||||
loading: true,
|
||||
onSearch: (params) => alert(JSON.stringify(params, null, 2)),
|
||||
},
|
||||
};
|
||||
|
||||
// ─── Custom Heading ─────────────────────────────────────────────────────────
|
||||
|
||||
/** Custom heading and subheading for alternate page contexts. */
|
||||
export const CustomHeading: Story = {
|
||||
args: {
|
||||
funeralTypes,
|
||||
themeOptions,
|
||||
heading: 'Compare funeral directors in your area',
|
||||
subheading: 'Transparent pricing · No hidden fees · 24/7',
|
||||
onSearch: (params) => alert(JSON.stringify(params, null, 2)),
|
||||
},
|
||||
};
|
||||
|
||||
// --- In Hero Context (Desktop) -----------------------------------------------
|
||||
// ─── In Hero Context (Desktop) ──────────────────────────────────────────────
|
||||
|
||||
/** As it appears in the homepage hero — desktop layout */
|
||||
/** As it appears in the homepage hero — desktop layout. */
|
||||
export const InHeroDesktop: Story = {
|
||||
decorators: [
|
||||
(Story) => (
|
||||
@@ -90,8 +121,6 @@ export const InHeroDesktop: Story = {
|
||||
{ label: 'Log in', href: '/login' },
|
||||
]}
|
||||
/>
|
||||
|
||||
{/* Hero section */}
|
||||
<Box
|
||||
sx={{
|
||||
display: 'grid',
|
||||
@@ -100,7 +129,6 @@ export const InHeroDesktop: Story = {
|
||||
bgcolor: 'var(--fa-color-brand-100)',
|
||||
}}
|
||||
>
|
||||
{/* Left: heading + search widget */}
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
@@ -115,11 +143,7 @@ export const InHeroDesktop: Story = {
|
||||
<Typography
|
||||
variant="displaySm"
|
||||
component="h1"
|
||||
sx={{
|
||||
textAlign: 'center',
|
||||
mb: 2,
|
||||
color: 'var(--fa-color-brand-950)',
|
||||
}}
|
||||
sx={{ textAlign: 'center', mb: 2, color: 'var(--fa-color-brand-950)' }}
|
||||
>
|
||||
Discover, Explore, and Plan Funerals in Minutes
|
||||
</Typography>
|
||||
@@ -131,20 +155,19 @@ export const InHeroDesktop: Story = {
|
||||
Whether you're thinking ahead or arranging for a loved one, find
|
||||
trusted local providers with transparent pricing.
|
||||
</Typography>
|
||||
|
||||
<FuneralFinder
|
||||
funeralTypes={funeralTypes}
|
||||
themeOptions={themeOptions}
|
||||
onSearch={(params) => alert(JSON.stringify(params, null, 2))}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Right: hero image placeholder */}
|
||||
<Box
|
||||
sx={{
|
||||
display: { xs: 'none', md: 'block' },
|
||||
bgcolor: 'var(--fa-color-brand-200)',
|
||||
backgroundImage: 'url(https://images.unsplash.com/photo-1516733968668-dbdce39c0571?w=800&h=600&fit=crop)',
|
||||
backgroundImage:
|
||||
'url(https://images.unsplash.com/photo-1516733968668-dbdce39c0571?w=800&h=600&fit=crop)',
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
}}
|
||||
@@ -154,9 +177,9 @@ export const InHeroDesktop: Story = {
|
||||
),
|
||||
};
|
||||
|
||||
// --- In Hero Context (Mobile) ------------------------------------------------
|
||||
// ─── In Hero Context (Mobile) ───────────────────────────────────────────────
|
||||
|
||||
/** Mobile viewport — stacked layout with image above search */
|
||||
/** Mobile viewport — stacked layout with image above search. */
|
||||
export const InHeroMobile: Story = {
|
||||
decorators: [
|
||||
(Story) => (
|
||||
@@ -175,29 +198,14 @@ export const InHeroMobile: Story = {
|
||||
{ label: 'Log in', href: '/login' },
|
||||
]}
|
||||
/>
|
||||
|
||||
{/* Hero heading */}
|
||||
<Box
|
||||
sx={{
|
||||
bgcolor: 'var(--fa-color-brand-100)',
|
||||
px: 3,
|
||||
py: 4,
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="h3"
|
||||
component="h1"
|
||||
sx={{ mb: 1.5, color: 'var(--fa-color-brand-950)' }}
|
||||
>
|
||||
<Box sx={{ bgcolor: 'var(--fa-color-brand-100)', px: 3, py: 4, textAlign: 'center' }}>
|
||||
<Typography variant="h3" component="h1" sx={{ mb: 1.5, color: 'var(--fa-color-brand-950)' }}>
|
||||
Discover, Explore, and Plan Funerals in Minutes
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Find trusted local providers with transparent pricing, at your own pace.
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{/* Hero image */}
|
||||
<Box
|
||||
sx={{
|
||||
height: 180,
|
||||
@@ -207,11 +215,10 @@ export const InHeroMobile: Story = {
|
||||
backgroundPosition: 'center',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Search widget — overlaps image slightly */}
|
||||
<Box sx={{ px: 2, mt: -3, pb: 4, bgcolor: 'var(--fa-color-brand-100)' }}>
|
||||
<FuneralFinder
|
||||
funeralTypes={funeralTypes}
|
||||
themeOptions={themeOptions}
|
||||
onSearch={(params) => alert(JSON.stringify(params, null, 2))}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
Reference in New Issue
Block a user