Add UnverifiedPackageT2/T3 pages, FuneralFinder pre-planning timeframe, PackageDetail variants

- UnverifiedPackageT3: package step for unverified providers (no image,
  estimated pricing disclaimer, "Make an enquiry" CTA, nearby verified
  providers section)
- UnverifiedPackageT2: same but with "Itemised Pricing Unavailable" notice
  replacing the line-item breakdown
- PackageDetail: new props — arrangeLabel, priceDisclaimer, itemizedUnavailable
- FuneralFinderV3: pre-planning follow-up question ("How soon might you
  need this?"), responsive sizing fixes, compulsory validation
- HomePage: fix finder container width (flex stretch + 500px cap)
- .gitignore: exclude Claude/Playwright artifacts, working docs, screenshots

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-02 10:35:28 +11:00
parent eb6cf6a185
commit 68889af9c2
10 changed files with 1320 additions and 36 deletions

View File

@@ -1,5 +1,6 @@
import React from 'react';
import Box from '@mui/material/Box';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import type { SxProps, Theme } from '@mui/material/styles';
import { Typography } from '../../atoms/Typography';
import { Button } from '../../atoms/Button';
@@ -50,6 +51,12 @@ export interface PackageDetailProps {
arrangeDisabled?: boolean;
/** Whether the compare button is in loading state */
compareLoading?: boolean;
/** Custom label for the arrange CTA button (default: "Make Arrangement") */
arrangeLabel?: string;
/** Disclaimer shown below the price (e.g. for unverified/estimated pricing) */
priceDisclaimer?: string;
/** When true, replaces the itemised breakdown with an "Itemised Pricing Unavailable" notice */
itemizedUnavailable?: boolean;
/** MUI sx prop for the root element */
sx?: SxProps<Theme>;
}
@@ -116,6 +123,9 @@ export const PackageDetail = React.forwardRef<HTMLDivElement, PackageDetailProps
onCompare,
arrangeDisabled = false,
compareLoading = false,
arrangeLabel = 'Make Arrangement',
priceDisclaimer,
itemizedUnavailable = false,
sx,
},
ref,
@@ -159,6 +169,32 @@ export const PackageDetail = React.forwardRef<HTMLDivElement, PackageDetailProps
${price.toLocaleString('en-AU')}
</Typography>
{/* Price disclaimer */}
{priceDisclaimer && (
<Box
sx={{
display: 'flex',
alignItems: 'flex-start',
gap: 1,
mt: 1.5,
px: 1.5,
py: 1,
bgcolor: 'var(--fa-color-surface-cool, #F5F7FA)',
borderRadius: 'var(--fa-border-radius-sm, 6px)',
border: '1px solid',
borderColor: 'divider',
}}
>
<InfoOutlinedIcon
sx={{ fontSize: 16, color: 'text.secondary', mt: '1px', flexShrink: 0 }}
aria-hidden
/>
<Typography variant="body2" color="text.secondary" sx={{ lineHeight: 1.4 }}>
{priceDisclaimer}
</Typography>
</Box>
)}
{/* CTA buttons */}
<Box
sx={{ display: 'flex', flexDirection: { xs: 'column', sm: 'row' }, gap: 1.5, mt: 2.5 }}
@@ -170,7 +206,7 @@ export const PackageDetail = React.forwardRef<HTMLDivElement, PackageDetailProps
disabled={arrangeDisabled}
onClick={onArrange}
>
Make Arrangement
{arrangeLabel}
</Button>
{onCompare && (
<Button
@@ -189,24 +225,55 @@ export const PackageDetail = React.forwardRef<HTMLDivElement, PackageDetailProps
{/* Package contents */}
<Box sx={{ px: { xs: 2, sm: 3 }, py: 3 }}>
{/* Main sections — included in the package price */}
{sections.map((section, idx) => (
<Box key={section.heading} sx={{ mb: idx < sections.length - 1 ? 3 : 0 }}>
<SectionBlock section={section} />
</Box>
))}
{/* Total — separates included content from extras */}
{total != null && <LineItem name="Total" price={total} variant="total" />}
{/* Extras — additional cost items after the total */}
{extras && extras.items.length > 0 && (
<>
<Divider sx={{ my: 3 }} />
<SectionBlock
section={extras}
subtext="These items can be added to your package at additional cost."
{itemizedUnavailable ? (
<Box
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
textAlign: 'center',
bgcolor: 'var(--fa-color-surface-warm, #FEF9F5)',
borderRadius: 'var(--fa-border-radius-md, 8px)',
border: '1px solid',
borderColor: 'divider',
px: 3,
py: 4,
}}
>
<InfoOutlinedIcon
sx={{ fontSize: 28, color: 'var(--fa-color-brand-500)', mb: 1.5 }}
aria-hidden
/>
<Typography variant="h6" component="p" sx={{ mb: 1 }}>
Itemised Pricing Unavailable
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ maxWidth: 360 }}>
This provider has shared their overall package price, but has not provided a
detailed breakdown of what is included.
</Typography>
</Box>
) : (
<>
{/* Main sections — included in the package price */}
{sections.map((section, idx) => (
<Box key={section.heading} sx={{ mb: idx < sections.length - 1 ? 3 : 0 }}>
<SectionBlock section={section} />
</Box>
))}
{/* Total — separates included content from extras */}
{total != null && <LineItem name="Total" price={total} variant="total" />}
{/* Extras — additional cost items after the total */}
{extras && extras.items.length > 0 && (
<>
<Divider sx={{ my: 3 }} />
<SectionBlock
section={extras}
subtext="These items can be added to your package at additional cost."
/>
</>
)}
</>
)}
</Box>