Batch 2: List-map layout rework — 420px fixed column, sticky headers

- WizardLayout ListMapLayout: 420px fixed left column (D-B), flex:1
  right panel, back link rendered inside left panel instead of above
  the split (eliminates gap above map)
- LAYOUT_MAP type updated to accept backLink prop for list-map variant
- ProvidersStep: heading + search + filters wrapped in sticky Box
  that pins at top of scrollable left panel while card list scrolls
- VenueStep: same sticky header treatment, heading moved inside form
  for consistent wrapper structure

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-29 22:18:52 +11:00
parent 6ebd52f36f
commit 1c3cdbc101
3 changed files with 134 additions and 94 deletions

View File

@@ -193,17 +193,6 @@ export const VenueStep: React.FC<VenueStepProps> = ({
)
}
>
{/* Page heading */}
<Typography variant="display3" component="h1" sx={{ mb: 0.5 }} tabIndex={-1}>
Where would you like the service?
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
{isPrePlanning
? 'Browse available venues. Your choice can be changed later.'
: 'Choose a venue for the funeral service. You can filter by location, features, and religion.'}
</Typography>
<Box
component="form"
noValidate
@@ -213,40 +202,63 @@ export const VenueStep: React.FC<VenueStepProps> = ({
if (!loading) onContinue();
}}
>
{/* ─── Search + Filters ─── */}
<Box sx={{ mb: 3 }}>
<TextField
placeholder="Search a town or suburb..."
value={values.search}
onChange={(e) => onChange({ ...values, search: e.target.value })}
fullWidth
InputProps={{
startAdornment: (
<InputAdornment position="start">
<SearchIcon sx={{ color: 'text.secondary' }} />
</InputAdornment>
),
}}
sx={{ mb: 2 }}
/>
{/* Sticky header — stays pinned while card list scrolls */}
<Box
sx={{
position: 'sticky',
top: 0,
zIndex: 1,
bgcolor: 'background.default',
pb: 1,
mx: -3,
px: 3,
}}
>
<Typography variant="display3" component="h1" sx={{ mb: 0.5 }} tabIndex={-1}>
Where would you like the service?
</Typography>
<Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap' }}>
{filterOptions.map((filter) => (
<Chip
key={filter.key}
label={filter.label}
onClick={() => handleFilterToggle(filter.key)}
selected={values.activeFilters.includes(filter.key)}
/>
))}
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
{isPrePlanning
? 'Browse available venues. Your choice can be changed later.'
: 'Choose a venue for the funeral service. You can filter by location, features, and religion.'}
</Typography>
{/* ─── Search + Filters ─── */}
<Box sx={{ mb: 2 }}>
<TextField
placeholder="Search a town or suburb..."
value={values.search}
onChange={(e) => onChange({ ...values, search: e.target.value })}
fullWidth
InputProps={{
startAdornment: (
<InputAdornment position="start">
<SearchIcon sx={{ color: 'text.secondary' }} />
</InputAdornment>
),
}}
sx={{ mb: 2 }}
/>
<Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap' }}>
{filterOptions.map((filter) => (
<Chip
key={filter.key}
label={filter.label}
onClick={() => handleFilterToggle(filter.key)}
selected={values.activeFilters.includes(filter.key)}
/>
))}
</Box>
</Box>
</Box>
{/* ─── Results count ─── */}
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }} aria-live="polite">
Found {venues.length} venue{venues.length !== 1 ? 's' : ''}
{locationName ? ` near ${locationName}` : ''}
</Typography>
{/* ─── Results count ─── */}
<Typography variant="body2" color="text.secondary" sx={{ mb: 0 }} aria-live="polite">
Found {venues.length} venue{venues.length !== 1 ? 's' : ''}
{locationName ? ` near ${locationName}` : ''}
</Typography>
</Box>
{/* ─── Venue card grid ─── */}
<Box