- Add DialogShell atom — shared dialog container (header, scrollable body, footer)
- Refactor FilterPanel to use DialogShell (Popover → centered Dialog)
- Refactor ArrangementDialog to use DialogShell
- Remove PreviewStep + AuthGateStep pages (consolidated into ArrangementDialog, D-E)
- IntroStep: static subheading, top-left aligned toggle button content
- ProvidersStep: h4 heading "Find a funeral director", location search with pin icon,
filter moved below search right-aligned, map fill fix, hover scrollbar
- VenueStep: same consistency fixes (h4 heading, filter layout, location icon, map fix)
- PackagesStep: grouped packages ("Matching your preferences" / "Other packages from
[Provider]"), removed budget filter + Most Popular badge, clickable provider card,
onArrange replaces onContinue, h4 heading
- WizardLayout: list-map left panel gets thin scrollbar visible on hover
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
186 lines
6.3 KiB
TypeScript
186 lines
6.3 KiB
TypeScript
import React from 'react';
|
|
import Box from '@mui/material/Box';
|
|
import type { SxProps, Theme } from '@mui/material/styles';
|
|
import { WizardLayout } from '../../templates/WizardLayout';
|
|
import { ToggleButtonGroup } from '../../atoms/ToggleButtonGroup';
|
|
import { Collapse } from '../../atoms/Collapse';
|
|
import { Typography } from '../../atoms/Typography';
|
|
import { Button } from '../../atoms/Button';
|
|
import { Divider } from '../../atoms/Divider';
|
|
|
|
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
|
|
/** Form values for the intro step */
|
|
export interface IntroStepValues {
|
|
/** Who the funeral is being arranged for */
|
|
forWhom: 'myself' | 'someone' | null;
|
|
/** Whether the person has passed away (only relevant when forWhom="someone") */
|
|
hasPassedAway: 'yes' | 'no' | null;
|
|
}
|
|
|
|
/** Field-level error messages */
|
|
export interface IntroStepErrors {
|
|
/** Error for the forWhom field */
|
|
forWhom?: string;
|
|
/** Error for the hasPassedAway field */
|
|
hasPassedAway?: string;
|
|
}
|
|
|
|
/** Props for the IntroStep page component */
|
|
export interface IntroStepProps {
|
|
/** Current form values */
|
|
values: IntroStepValues;
|
|
/** Callback when any field value changes */
|
|
onChange: (values: IntroStepValues) => void;
|
|
/** Callback when the Continue button is clicked */
|
|
onContinue: () => void;
|
|
/** Field-level validation errors */
|
|
errors?: IntroStepErrors;
|
|
/** Whether the Continue button is in a loading state */
|
|
loading?: boolean;
|
|
/** Navigation bar — passed through to WizardLayout */
|
|
navigation?: React.ReactNode;
|
|
/** Hide the help bar */
|
|
hideHelpBar?: boolean;
|
|
/** MUI sx prop for the root */
|
|
sx?: SxProps<Theme>;
|
|
}
|
|
|
|
// ─── Constants ──────────────────────────────────────────────────────────────
|
|
|
|
const SUBHEADING =
|
|
"We'll guide you through arranging a funeral, step by step. You can save your progress and come back anytime.";
|
|
|
|
// ─── Component ───────────────────────────────────────────────────────────────
|
|
|
|
/**
|
|
* Step 1 — Intro page for the FA arrangement wizard.
|
|
*
|
|
* Entry point with urgency-sensitive segmentation. User selects who
|
|
* the funeral is for, and (if arranging for someone else) whether
|
|
* that person has passed away.
|
|
*
|
|
* Uses the Centered Form layout variant. Progressive disclosure:
|
|
* selecting "Someone else" reveals the hasPassedAway question.
|
|
* Selecting "Myself" auto-sets hasPassedAway to "no" (pre-planning).
|
|
*
|
|
* Pure presentation component — props in, callbacks out.
|
|
* No routing, state management, or API calls.
|
|
*
|
|
* Spec: documentation/steps/steps/01_intro.yaml
|
|
*/
|
|
export const IntroStep: React.FC<IntroStepProps> = ({
|
|
values,
|
|
onChange,
|
|
onContinue,
|
|
errors,
|
|
loading = false,
|
|
navigation,
|
|
hideHelpBar,
|
|
sx,
|
|
}) => {
|
|
const handleForWhomChange = (newValue: string | null) => {
|
|
const forWhom = newValue as IntroStepValues['forWhom'];
|
|
if (forWhom === 'myself') {
|
|
// Auto-set hasPassedAway to 'no' — user is alive, pre-planning
|
|
onChange({ forWhom, hasPassedAway: 'no' });
|
|
} else {
|
|
// Reset hasPassedAway when switching to "someone"
|
|
onChange({ forWhom, hasPassedAway: null });
|
|
}
|
|
};
|
|
|
|
const handleHasPassedAwayChange = (newValue: string | null) => {
|
|
onChange({ ...values, hasPassedAway: newValue as IntroStepValues['hasPassedAway'] });
|
|
};
|
|
|
|
const showHasPassedAway = values.forWhom === 'someone';
|
|
|
|
return (
|
|
<WizardLayout variant="centered-form" navigation={navigation} hideHelpBar={hideHelpBar} sx={sx}>
|
|
{/* Page heading — receives focus on entry for screen readers */}
|
|
<Typography variant="display3" component="h1" sx={{ mb: 1 }} tabIndex={-1}>
|
|
Let's get started
|
|
</Typography>
|
|
|
|
<Typography variant="body1" color="text.secondary" sx={{ mb: 5 }}>
|
|
{SUBHEADING}
|
|
</Typography>
|
|
|
|
<Box
|
|
component="form"
|
|
noValidate
|
|
aria-busy={loading}
|
|
onSubmit={(e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
if (!loading) onContinue();
|
|
}}
|
|
>
|
|
{/* forWhom field */}
|
|
<Box sx={{ mb: 3 }}>
|
|
<ToggleButtonGroup
|
|
label="Who is this funeral being arranged for?"
|
|
options={[
|
|
{
|
|
value: 'myself',
|
|
label: 'Myself',
|
|
description: 'I want to plan my own funeral',
|
|
},
|
|
{
|
|
value: 'someone',
|
|
label: 'Someone else',
|
|
description: 'I am arranging for a family member or friend',
|
|
},
|
|
]}
|
|
value={values.forWhom}
|
|
onChange={handleForWhomChange}
|
|
error={!!errors?.forWhom}
|
|
helperText={errors?.forWhom}
|
|
required
|
|
fullWidth
|
|
/>
|
|
</Box>
|
|
|
|
{/* hasPassedAway field — revealed when forWhom="someone" */}
|
|
<Collapse in={showHasPassedAway}>
|
|
<Box sx={{ mb: 3 }}>
|
|
<ToggleButtonGroup
|
|
label="Has this person passed away?"
|
|
options={[
|
|
{
|
|
value: 'yes',
|
|
label: 'Yes',
|
|
description: 'I need to arrange a funeral now',
|
|
},
|
|
{
|
|
value: 'no',
|
|
label: 'No',
|
|
description: 'I am planning ahead',
|
|
},
|
|
]}
|
|
value={values.hasPassedAway}
|
|
onChange={handleHasPassedAwayChange}
|
|
error={!!errors?.hasPassedAway}
|
|
helperText={errors?.hasPassedAway}
|
|
required
|
|
fullWidth
|
|
/>
|
|
</Box>
|
|
</Collapse>
|
|
|
|
<Divider sx={{ my: 4 }} />
|
|
|
|
{/* CTA */}
|
|
<Box sx={{ display: 'flex', justifyContent: 'flex-end' }}>
|
|
<Button type="submit" variant="contained" size="large" loading={loading}>
|
|
Continue
|
|
</Button>
|
|
</Box>
|
|
</Box>
|
|
</WizardLayout>
|
|
);
|
|
};
|
|
|
|
IntroStep.displayName = 'IntroStep';
|
|
export default IntroStep;
|