Split AdditionalServicesStep into IncludedServicesStep + ExtrasStep

- IncludedServicesStep: package inclusions at no cost (dressing, viewing,
  prayers, funeral announcement). Sub-options render inside parent card.
- ExtrasStep: optional paid extras for lead generation (catering, music,
  coffin bearing, newspaper notice). POA support, tally of priced items.
- AddOnOption: children prop (sub-options inside card), priceLabel prop
  (custom text like "Price on application" in brand copper italic)
- Flattened sub-option pattern: inline toggle rows inside parent card
  instead of nested card-in-card ("Russian doll") pattern
- Coffin bearing now uses toggle + bearer type radio (consistent UX)
- Removed old AdditionalServicesStep (replaced by two new pages)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-31 12:10:26 +11:00
parent c7a8d9e906
commit 6cb3184130
11 changed files with 815 additions and 415 deletions

View File

@@ -2,6 +2,8 @@ import React from 'react';
import Box from '@mui/material/Box';
import type { SxProps, Theme } from '@mui/material/styles';
import { Card } from '../../atoms/Card';
import { Collapse } from '../../atoms/Collapse';
import { Divider } from '../../atoms/Divider';
import { Typography } from '../../atoms/Typography';
import { Switch } from '../../atoms/Switch';
import { Link } from '../../atoms/Link';
@@ -16,6 +18,8 @@ export interface AddOnOptionProps {
description?: string;
/** Price in dollars — shown below the heading */
price?: number;
/** Custom price label (e.g. "Price on application") — overrides formatted price */
priceLabel?: string;
/** Whether this add-on is currently enabled */
checked?: boolean;
/** Called when the toggle changes */
@@ -24,6 +28,8 @@ export interface AddOnOptionProps {
disabled?: boolean;
/** Max visible lines for description before "View more" toggle. Omit for no limit. */
maxDescriptionLines?: number;
/** Sub-options rendered inside the card when checked. Appears below a divider. */
children?: React.ReactNode;
/** MUI sx prop for style overrides */
sx?: SxProps<Theme>;
}
@@ -59,10 +65,12 @@ export const AddOnOption = React.forwardRef<HTMLDivElement, AddOnOptionProps>(
name,
description,
price,
priceLabel,
checked = false,
onChange,
disabled = false,
maxDescriptionLines,
children,
sx,
},
ref,
@@ -141,10 +149,16 @@ export const AddOnOption = React.forwardRef<HTMLDivElement, AddOnOptionProps>(
</Box>
{/* Price — tucks directly under heading */}
{price != null && (
<Typography variant="body2" color="primary">
${price.toLocaleString('en-AU')}
{priceLabel ? (
<Typography variant="body2" color="primary" sx={{ fontStyle: 'italic' }}>
{priceLabel}
</Typography>
) : (
price != null && (
<Typography variant="body2" color="primary">
${price.toLocaleString('en-AU')}
</Typography>
)
)}
{/* Description with optional line clamping */}
@@ -182,6 +196,14 @@ export const AddOnOption = React.forwardRef<HTMLDivElement, AddOnOptionProps>(
)}
</>
)}
{/* Sub-options — rendered inside the card when checked */}
{children && (
<Collapse in={checked}>
<Divider sx={{ my: 1.5 }} />
<Box onClick={(e) => e.stopPropagation()}>{children}</Box>
</Collapse>
)}
</Card>
);
},