- Step flow, state management, conditional logic map - Smart defaults and CTA submit behaviour - Props reference and sub-component index - Guide for adding new steps Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
8.5 KiB
FuneralFinder — Flow Logic Reference
Technical reference for the FuneralFinder stepped search widget. Use this when modifying the flow, adding steps, or integrating with a backend.
Architecture Overview
The widget is a single React component with internal state. No external state
management required. The parent only needs to provide funeralTypes, optional
themeOptions, and an onSearch callback.
┌─────────────────────────────────────────┐
│ Header (h2 display + subheading) │
│ ───────────────────────────────── │
│ │
│ CompletedRows (stack of answered steps)│
│ │
│ Active Step (one at a time, Collapse) │
│ Step 1 │ Step 2 │ Step 3 │ Step 4 │
│ │
│ ─── always visible ─────────────────── │
│ Location input │
│ [Find funeral providers] CTA │
│ Free to use · No obligation │
└─────────────────────────────────────────┘
State
| State variable | Type | Default | Purpose |
|---|---|---|---|
intent |
'arrange' | 'preplan' | null |
null |
Step 1 answer |
planningFor |
'myself' | 'someone-else' | null |
null |
Step 2 answer (preplan only) |
typeSelection |
string | null |
null |
Step 3 answer — funeral type ID or 'all' |
servicePref |
'with-service' | 'without-service' | 'either' |
'either' |
Step 4 answer |
serviceAnswered |
boolean |
false |
Whether step 4 was explicitly answered |
selectedThemes |
string[] |
[] |
Optional theme filter IDs (multi-select) |
location |
string |
'' |
Location input value |
locationError |
string |
'' |
Validation error for location |
showIntentPrompt |
boolean |
false |
Show nudge when CTA clicked without intent |
editingStep |
number | null |
null |
Which step is being re-edited (via "Change") |
Step Flow
Active Step Calculation
const activeStep = (() => {
if (editingStep !== null) return editingStep; // User clicked "Change"
if (!intent) return 1; // Need intent
if (needsPlanningFor && !planningFor) return 2; // Need planning-for (preplan only)
if (!typeSelection) return 3; // Need funeral type
if (showServiceStep && !serviceAnswered) return 4; // Need service pref
return 0; // All complete
})();
activeStep === 0 means all optional steps are answered. Only CompletedRows +
location + CTA are visible.
Step Details
| Step | Question | Options | Auto-advances? | Conditional? |
|---|---|---|---|---|
| 1 | How can we help you today? | Arrange now / Pre-plan | Yes, on click | Always shown |
| 2 | Who are you planning for? | Myself / Someone else | Yes, on click | Only when intent === 'preplan' |
| 3 | What type of funeral? | TypeCards + Explore All + theme chips | Yes, on type card click | Always shown |
| 4 | Would you like a service? | With / No / Flexible (chips) | Yes, on chip click | Only when selected type has hasServiceOption: true |
Auto-advance Mechanic
Steps 1, 2, and 4 auto-advance because selecting an option sets the state and
clears editingStep. The activeStep recalculation on the next render
determines the new step.
Step 3 also auto-advances when a type card is clicked. Theme preferences within step 3 are optional — they're captured at whatever state they're in when the type card click triggers collapse.
Editing (reverting to a previous step)
Clicking "Change" on a CompletedRow calls revertTo(stepNumber), which sets
editingStep. This overrides the activeStep calculation, reopening that step.
When the user makes a new selection, the handler clears editingStep and the
flow recalculates.
Key behaviour: Editing a step does NOT reset downstream answers. If you
change from Cremation to Burial (both have hasServiceOption), the service
preference carries forward. If you change to a type without hasServiceOption
(or to "Explore all"), servicePref resets to 'either' and serviceAnswered
resets to false.
CTA and Search Logic
Minimum Requirements
The CTA button is always visible and always enabled (except during loading). Minimum search requirements: intent + location (3+ chars).
Submit Behaviour
User clicks "Find funeral providers"
│
├─ intent is null?
│ → Show intent prompt (role="alert"), keep step 1 visible
│ → Return (don't search)
│
├─ location < 3 chars?
│ → Show error on location input
│ → Return (don't search)
│
└─ Both present?
→ Call onSearch() with smart defaults for missing optional fields
Smart Defaults
| Field | If not explicitly answered | Default value |
|---|---|---|
funeralTypeId |
User didn't select a type | null (= show all types) |
servicePreference |
User didn't answer service step | 'either' (= show all) |
themes |
User didn't select any themes | [] (= no filter) |
planningFor |
User on preplan path but didn't answer step 2 | undefined |
This means a user can: select intent → type location → click CTA. Everything else defaults to "show all."
Search Params Shape
interface FuneralSearchParams {
intent: 'arrange' | 'preplan';
planningFor?: 'myself' | 'someone-else'; // Only on preplan path
funeralTypeId: string | null; // null = all types
servicePreference: 'with-service' | 'without-service' | 'either';
themes: string[]; // May be empty
location: string; // Trimmed, 3+ chars
}
Conditional Logic Map
intent === 'preplan'
└─ Shows step 2 (planning-for)
typeSelection !== 'all' && selectedType.hasServiceOption === true
└─ Shows step 4 (service preference)
typeSelection !== null
└─ CompletedRow for type shows (with theme summary if any selected)
serviceAnswered && showServiceStep
└─ CompletedRow for service shows
themeOptions.length > 0
└─ Theme chips appear within step 3 (always, not gated by type selection)
loading === true
└─ CTA button shows spinner, button disabled
Props Reference
| Prop | Type | Default | Notes |
|---|---|---|---|
funeralTypes |
FuneralTypeOption[] |
required | Each has id, label, optional description, note, hasServiceOption |
themeOptions |
ThemeOption[] |
[] |
Each has id, label. Shown as optional chips in step 3 |
onSearch |
(params: FuneralSearchParams) => void |
— | Called on valid submit |
loading |
boolean |
false |
Shows spinner on CTA, disables button |
heading |
string |
'Find funeral directors near you' |
Main h2 heading |
subheading |
string |
'Tell us a little about...' |
Below heading |
showExploreAll |
boolean |
true |
Show "Explore all options" TypeCard |
sx |
SxProps<Theme> |
— | MUI sx override on root card |
Sub-components (internal)
| Component | Purpose | Used in |
|---|---|---|
StepHeading |
Centered bodyLg heading with bottom margin | Steps 1-4 |
ChoiceCard |
Full-width radio card with label + description | Steps 1, 2 |
TypeCard |
Compact radio card with label + optional description/note | Step 3 |
CompletedRow |
Summary row: question + bold answer + "Change" link | All completed steps |
Adding a New Step
- Add state variable(s) for the new step's answer
- Add a condition in
activeStepcalculation (between existing steps) - Add a
<Collapse in={activeStep === N}>block in the render - Add a
<Collapse>for the CompletedRow (with appropriate visibility condition) - Include the new data in
handleSubmit→onSearch()params - Update
FuneralSearchParamstype
Known Limitations (deferred)
- No progress indicator — users can't see how many steps remain
- No roving tabindex — radiogroups use button elements with
role="radio"but arrow-key navigation between options is not implemented - No location autocomplete — free text input only, validated on length
- CSS vars used directly — some styling uses
var(--fa-*)tokens instead of MUI theme paths; works but doesn't support dynamic theme switching