CemeteryStep: freetext search input replaces static dropdown
- MUI Autocomplete with static list replaced by Input atom with search icon — parent wires to Google Places or geocoding API - Optional searchSlot prop for custom autocomplete integration - Removed CemeteryOption type and cemeteries prop - cemeterySearch field stores freetext, not a selected ID Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import type { Meta, StoryObj } from '@storybook/react';
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
import { CemeteryStep } from './CemeteryStep';
|
import { CemeteryStep } from './CemeteryStep';
|
||||||
import type { CemeteryStepValues, CemeteryOption } from './CemeteryStep';
|
import type { CemeteryStepValues } from './CemeteryStep';
|
||||||
import { Navigation } from '../../organisms/Navigation';
|
import { Navigation } from '../../organisms/Navigation';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
|
|
||||||
@@ -34,19 +34,10 @@ const nav = (
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const sampleCemeteries: CemeteryOption[] = [
|
|
||||||
{ value: 'rookwood', label: 'Rookwood Cemetery' },
|
|
||||||
{ value: 'northern-suburbs', label: 'Northern Suburbs Memorial Gardens' },
|
|
||||||
{ value: 'macquarie-park', label: 'Macquarie Park Cemetery' },
|
|
||||||
{ value: 'pinegrove', label: 'Pinegrove Memorial Park' },
|
|
||||||
{ value: 'waverley', label: 'Waverley Cemetery' },
|
|
||||||
{ value: 'botany', label: 'Botany Cemetery' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const defaultValues: CemeteryStepValues = {
|
const defaultValues: CemeteryStepValues = {
|
||||||
ownPlot: null,
|
ownPlot: null,
|
||||||
hasPreference: null,
|
hasPreference: null,
|
||||||
selectedCemetery: '',
|
cemeterySearch: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
// ─── Meta ────────────────────────────────────────────────────────────────────
|
// ─── Meta ────────────────────────────────────────────────────────────────────
|
||||||
@@ -76,7 +67,6 @@ export const Default: Story = {
|
|||||||
onContinue={() => alert('Continue')}
|
onContinue={() => alert('Continue')}
|
||||||
onBack={() => alert('Back')}
|
onBack={() => alert('Back')}
|
||||||
onSaveAndExit={() => alert('Save')}
|
onSaveAndExit={() => alert('Save')}
|
||||||
cemeteries={sampleCemeteries}
|
|
||||||
navigation={nav}
|
navigation={nav}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -99,7 +89,6 @@ export const OwnsPlot: Story = {
|
|||||||
onContinue={() => alert('Continue')}
|
onContinue={() => alert('Continue')}
|
||||||
onBack={() => alert('Back')}
|
onBack={() => alert('Back')}
|
||||||
onSaveAndExit={() => alert('Save')}
|
onSaveAndExit={() => alert('Save')}
|
||||||
cemeteries={sampleCemeteries}
|
|
||||||
navigation={nav}
|
navigation={nav}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -123,7 +112,6 @@ export const HasPreference: Story = {
|
|||||||
onContinue={() => alert('Continue')}
|
onContinue={() => alert('Continue')}
|
||||||
onBack={() => alert('Back')}
|
onBack={() => alert('Back')}
|
||||||
onSaveAndExit={() => alert('Save')}
|
onSaveAndExit={() => alert('Save')}
|
||||||
cemeteries={sampleCemeteries}
|
|
||||||
navigation={nav}
|
navigation={nav}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -147,7 +135,6 @@ export const NoPreference: Story = {
|
|||||||
onContinue={() => alert('Continue')}
|
onContinue={() => alert('Continue')}
|
||||||
onBack={() => alert('Back')}
|
onBack={() => alert('Back')}
|
||||||
onSaveAndExit={() => alert('Save')}
|
onSaveAndExit={() => alert('Save')}
|
||||||
cemeteries={sampleCemeteries}
|
|
||||||
navigation={nav}
|
navigation={nav}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -166,7 +153,6 @@ export const PrePlanning: Story = {
|
|||||||
onChange={setValues}
|
onChange={setValues}
|
||||||
onContinue={() => alert('Continue')}
|
onContinue={() => alert('Continue')}
|
||||||
onBack={() => alert('Back')}
|
onBack={() => alert('Back')}
|
||||||
cemeteries={sampleCemeteries}
|
|
||||||
isPrePlanning
|
isPrePlanning
|
||||||
navigation={nav}
|
navigation={nav}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import Autocomplete from '@mui/material/Autocomplete';
|
|
||||||
import TextField from '@mui/material/TextField';
|
|
||||||
import SearchOutlinedIcon from '@mui/icons-material/SearchOutlined';
|
import SearchOutlinedIcon from '@mui/icons-material/SearchOutlined';
|
||||||
import InputAdornment from '@mui/material/InputAdornment';
|
|
||||||
import type { SxProps, Theme } from '@mui/material/styles';
|
import type { SxProps, Theme } from '@mui/material/styles';
|
||||||
import { WizardLayout } from '../../templates/WizardLayout';
|
import { WizardLayout } from '../../templates/WizardLayout';
|
||||||
|
import { Input } from '../../atoms/Input';
|
||||||
import { ToggleButtonGroup } from '../../atoms/ToggleButtonGroup';
|
import { ToggleButtonGroup } from '../../atoms/ToggleButtonGroup';
|
||||||
import { Collapse } from '../../atoms/Collapse';
|
import { Collapse } from '../../atoms/Collapse';
|
||||||
import { Typography } from '../../atoms/Typography';
|
import { Typography } from '../../atoms/Typography';
|
||||||
@@ -14,27 +12,21 @@ import { Divider } from '../../atoms/Divider';
|
|||||||
|
|
||||||
// ─── Types ───────────────────────────────────────────────────────────────────
|
// ─── Types ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/** A cemetery option for the dropdown */
|
|
||||||
export interface CemeteryOption {
|
|
||||||
value: string;
|
|
||||||
label: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Form values for the cemetery step */
|
/** Form values for the cemetery step */
|
||||||
export interface CemeteryStepValues {
|
export interface CemeteryStepValues {
|
||||||
/** Does the family already own a burial plot? */
|
/** Does the family already own a burial plot? */
|
||||||
ownPlot: 'yes' | 'no' | 'unsure' | null;
|
ownPlot: 'yes' | 'no' | 'unsure' | null;
|
||||||
/** Do they have a preference for a cemetery? (when ownPlot ≠ yes) */
|
/** Do they have a preference for a cemetery? (when ownPlot ≠ yes) */
|
||||||
hasPreference: 'yes' | 'no' | 'unsure' | null;
|
hasPreference: 'yes' | 'no' | 'unsure' | null;
|
||||||
/** Selected cemetery ID */
|
/** Cemetery search text (freetext — parent wires to Places API) */
|
||||||
selectedCemetery: string;
|
cemeterySearch: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Field-level error messages */
|
/** Field-level error messages */
|
||||||
export interface CemeteryStepErrors {
|
export interface CemeteryStepErrors {
|
||||||
ownPlot?: string;
|
ownPlot?: string;
|
||||||
hasPreference?: string;
|
hasPreference?: string;
|
||||||
selectedCemetery?: string;
|
cemeterySearch?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Props for the CemeteryStep page component */
|
/** Props for the CemeteryStep page component */
|
||||||
@@ -53,8 +45,8 @@ export interface CemeteryStepProps {
|
|||||||
errors?: CemeteryStepErrors;
|
errors?: CemeteryStepErrors;
|
||||||
/** Whether Continue is loading */
|
/** Whether Continue is loading */
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
/** Available cemeteries for the dropdown */
|
/** Slot for a location autocomplete (e.g. Google Places) — rendered below the search input */
|
||||||
cemeteries: CemeteryOption[];
|
searchSlot?: React.ReactNode;
|
||||||
/** Whether this is a pre-planning flow */
|
/** Whether this is a pre-planning flow */
|
||||||
isPrePlanning?: boolean;
|
isPrePlanning?: boolean;
|
||||||
/** Navigation bar */
|
/** Navigation bar */
|
||||||
@@ -95,7 +87,7 @@ export const CemeteryStep: React.FC<CemeteryStepProps> = ({
|
|||||||
onSaveAndExit,
|
onSaveAndExit,
|
||||||
errors,
|
errors,
|
||||||
loading = false,
|
loading = false,
|
||||||
cemeteries,
|
searchSlot,
|
||||||
isPrePlanning = false,
|
isPrePlanning = false,
|
||||||
navigation,
|
navigation,
|
||||||
progressStepper,
|
progressStepper,
|
||||||
@@ -113,7 +105,7 @@ export const CemeteryStep: React.FC<CemeteryStepProps> = ({
|
|||||||
ownPlot: (value ?? null) as CemeteryStepValues['ownPlot'],
|
ownPlot: (value ?? null) as CemeteryStepValues['ownPlot'],
|
||||||
// Reset dependent fields
|
// Reset dependent fields
|
||||||
hasPreference: null,
|
hasPreference: null,
|
||||||
selectedCemetery: '',
|
cemeterySearch: '',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -121,7 +113,7 @@ export const CemeteryStep: React.FC<CemeteryStepProps> = ({
|
|||||||
onChange({
|
onChange({
|
||||||
...values,
|
...values,
|
||||||
hasPreference: (value ?? null) as CemeteryStepValues['hasPreference'],
|
hasPreference: (value ?? null) as CemeteryStepValues['hasPreference'],
|
||||||
selectedCemetery: '',
|
cemeterySearch: '',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -181,32 +173,17 @@ export const CemeteryStep: React.FC<CemeteryStepProps> = ({
|
|||||||
Tell us where the burial plot is located.
|
Tell us where the burial plot is located.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Autocomplete
|
{searchSlot ?? (
|
||||||
options={cemeteries}
|
<Input
|
||||||
getOptionLabel={(option) => option.label}
|
value={values.cemeterySearch}
|
||||||
value={cemeteries.find((c) => c.value === values.selectedCemetery) ?? null}
|
onChange={(e) => onChange({ ...values, cemeterySearch: e.target.value })}
|
||||||
onChange={(_, option) =>
|
placeholder="Search for a cemetery or location..."
|
||||||
onChange({ ...values, selectedCemetery: option?.value ?? '' })
|
startIcon={<SearchOutlinedIcon />}
|
||||||
}
|
error={!!errors?.cemeterySearch}
|
||||||
renderInput={(params) => (
|
helperText={errors?.cemeterySearch}
|
||||||
<TextField
|
|
||||||
{...params}
|
|
||||||
placeholder="Search for a cemetery..."
|
|
||||||
error={!!errors?.selectedCemetery}
|
|
||||||
helperText={errors?.selectedCemetery}
|
|
||||||
InputProps={{
|
|
||||||
...params.InputProps,
|
|
||||||
startAdornment: (
|
|
||||||
<InputAdornment position="start">
|
|
||||||
<SearchOutlinedIcon sx={{ fontSize: 20, color: 'text.secondary' }} />
|
|
||||||
</InputAdornment>
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
noOptionsText="No cemeteries found"
|
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
|
||||||
@@ -232,32 +209,17 @@ export const CemeteryStep: React.FC<CemeteryStepProps> = ({
|
|||||||
{/* ─── Preference: search cemetery ─── */}
|
{/* ─── Preference: search cemetery ─── */}
|
||||||
<Collapse in={showCemeteryForPreference}>
|
<Collapse in={showCemeteryForPreference}>
|
||||||
<Box sx={{ mb: 4 }}>
|
<Box sx={{ mb: 4 }}>
|
||||||
<Autocomplete
|
{searchSlot ?? (
|
||||||
options={cemeteries}
|
<Input
|
||||||
getOptionLabel={(option) => option.label}
|
value={values.cemeterySearch}
|
||||||
value={cemeteries.find((c) => c.value === values.selectedCemetery) ?? null}
|
onChange={(e) => onChange({ ...values, cemeterySearch: e.target.value })}
|
||||||
onChange={(_, option) =>
|
placeholder="Search for a cemetery or location..."
|
||||||
onChange({ ...values, selectedCemetery: option?.value ?? '' })
|
startIcon={<SearchOutlinedIcon />}
|
||||||
}
|
error={!!errors?.cemeterySearch}
|
||||||
renderInput={(params) => (
|
helperText={errors?.cemeterySearch}
|
||||||
<TextField
|
|
||||||
{...params}
|
|
||||||
placeholder="Search for a cemetery..."
|
|
||||||
error={!!errors?.selectedCemetery}
|
|
||||||
helperText={errors?.selectedCemetery}
|
|
||||||
InputProps={{
|
|
||||||
...params.InputProps,
|
|
||||||
startAdornment: (
|
|
||||||
<InputAdornment position="start">
|
|
||||||
<SearchOutlinedIcon sx={{ fontSize: 20, color: 'text.secondary' }} />
|
|
||||||
</InputAdornment>
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
noOptionsText="No cemeteries found"
|
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,2 @@
|
|||||||
export { CemeteryStep, default } from './CemeteryStep';
|
export { CemeteryStep, default } from './CemeteryStep';
|
||||||
export type {
|
export type { CemeteryStepProps, CemeteryStepValues, CemeteryStepErrors } from './CemeteryStep';
|
||||||
CemeteryStepProps,
|
|
||||||
CemeteryStepValues,
|
|
||||||
CemeteryStepErrors,
|
|
||||||
CemeteryOption,
|
|
||||||
} from './CemeteryStep';
|
|
||||||
|
|||||||
Reference in New Issue
Block a user