VenueDetailStep: move services to informational cards on left panel

- Removed service toggles from right panel (selection moves to next step)
- Added informational service cards on left panel with name, description, price
- Intro text: "You can choose which ones to include in the next step"
- Removed VenueDetailStepValues type, values/onChange props, handleToggle
- Simplified stories (no more useState for service state)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-30 20:53:02 +11:00
parent 289dc18025
commit 5ccb7ccb8e
3 changed files with 88 additions and 151 deletions

View File

@@ -1,7 +1,6 @@
import { useState } from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { VenueDetailStep } from './VenueDetailStep';
import type { VenueDetailStepValues, VenueDetail, VenueService } from './VenueDetailStep';
import type { VenueDetail, VenueService } from './VenueDetailStep';
import { Navigation } from '../../organisms/Navigation';
import Box from '@mui/material/Box';
@@ -57,17 +56,26 @@ const sampleVenue: VenueDetail = {
};
const sampleServices: VenueService[] = [
{ id: 'photo', name: 'Photo presentation', price: 150 },
{ id: 'streaming', name: 'Livestream', price: 200 },
{ id: 'recording', name: 'Recording', price: 100 },
{
id: 'photo',
name: 'Photo presentation',
description: 'Display a photo slideshow during the service',
price: 150,
},
{
id: 'streaming',
name: 'Livestream',
description: 'Allow family and friends to watch the service remotely',
price: 200,
},
{
id: 'recording',
name: 'Recording',
description: 'Receive a recording of the service to keep',
price: 100,
},
];
const defaultValues: VenueDetailStepValues = {
photoDisplay: false,
streaming: false,
recording: false,
};
// ─── Meta ────────────────────────────────────────────────────────────────────
const meta: Meta<typeof VenueDetailStep> = {
@@ -84,48 +92,15 @@ type Story = StoryObj<typeof VenueDetailStep>;
// ─── Default ───────────────────────────────────────────────────────────────
/** Full venue detail with service toggles */
/** Full venue detail with available services */
export const Default: Story = {
render: () => {
const [values, setValues] = useState<VenueDetailStepValues>({ ...defaultValues });
return (
<VenueDetailStep
venue={sampleVenue}
values={values}
onChange={setValues}
onAddVenue={() => alert('Venue added!')}
onBack={() => alert('Back')}
onSaveAndExit={() => alert('Save and exit')}
services={sampleServices}
navigation={nav}
/>
);
},
};
// ─── With services selected ────────────────────────────────────────────────
/** Services already toggled on */
export const WithServices: Story = {
render: () => {
const [values, setValues] = useState<VenueDetailStepValues>({
photoDisplay: true,
streaming: true,
recording: false,
});
return (
<VenueDetailStep
venue={sampleVenue}
values={values}
onChange={setValues}
onAddVenue={() => alert('Venue added!')}
onBack={() => alert('Back')}
services={sampleServices}
navigation={nav}
/>
);
args: {
venue: sampleVenue,
onAddVenue: () => alert('Venue added!'),
onBack: () => alert('Back'),
onSaveAndExit: () => alert('Save and exit'),
services: sampleServices,
navigation: nav,
},
};
@@ -133,21 +108,13 @@ export const WithServices: Story = {
/** Pre-planning variant */
export const PrePlanning: Story = {
render: () => {
const [values, setValues] = useState<VenueDetailStepValues>({ ...defaultValues });
return (
<VenueDetailStep
venue={sampleVenue}
values={values}
onChange={setValues}
onAddVenue={() => alert('Venue selected!')}
onBack={() => alert('Back')}
services={sampleServices}
isPrePlanning
navigation={nav}
/>
);
args: {
venue: sampleVenue,
onAddVenue: () => alert('Venue selected!'),
onBack: () => alert('Back'),
services: sampleServices,
isPrePlanning: true,
navigation: nav,
},
};
@@ -155,26 +122,17 @@ export const PrePlanning: Story = {
/** Venue with minimal data (no features, religions, services) */
export const Minimal: Story = {
render: () => {
const [values, setValues] = useState<VenueDetailStepValues>({ ...defaultValues });
return (
<VenueDetailStep
venue={{
args: {
venue: {
id: 'basic',
name: 'Community Hall',
imageUrl:
'https://images.unsplash.com/photo-1519167758481-83f550bb49b3?w=800&h=600&fit=crop',
imageUrl: 'https://images.unsplash.com/photo-1519167758481-83f550bb49b3?w=800&h=600&fit=crop',
location: 'Parramatta',
price: 500,
address: '10 Church Street, Parramatta NSW 2150',
}}
values={values}
onChange={setValues}
onAddVenue={() => alert('Venue added!')}
onBack={() => alert('Back')}
navigation={nav}
/>
);
},
onAddVenue: () => alert('Venue added!'),
onBack: () => alert('Back'),
navigation: nav,
},
};

View File

@@ -6,7 +6,6 @@ import PeopleOutlinedIcon from '@mui/icons-material/PeopleOutlined';
import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';
import type { SxProps, Theme } from '@mui/material/styles';
import { WizardLayout } from '../../templates/WizardLayout';
import { AddOnOption } from '../../molecules/AddOnOption';
import { Card } from '../../atoms/Card';
import { Chip } from '../../atoms/Chip';
import { Typography } from '../../atoms/Typography';
@@ -40,21 +39,10 @@ export interface VenueService {
price?: number;
}
/** Form values for service toggles */
export interface VenueDetailStepValues {
photoDisplay: boolean;
streaming: boolean;
recording: boolean;
}
/** Props for the VenueDetailStep page component */
export interface VenueDetailStepProps {
/** The venue to display */
venue: VenueDetail;
/** Current service toggle values */
values: VenueDetailStepValues;
/** Callback when service toggles change */
onChange: (values: VenueDetailStepValues) => void;
/** Callback when "Add Venue" is clicked */
onAddVenue: () => void;
/** Callback for back navigation */
@@ -111,8 +99,6 @@ const MetaRow: React.FC<{ icon: React.ReactNode; children: React.ReactNode }> =
*/
export const VenueDetailStep: React.FC<VenueDetailStepProps> = ({
venue,
values,
onChange,
onAddVenue,
onBack,
onSaveAndExit,
@@ -125,14 +111,6 @@ export const VenueDetailStep: React.FC<VenueDetailStepProps> = ({
hideHelpBar,
sx,
}) => {
const handleToggle = (field: keyof VenueDetailStepValues, checked: boolean) => {
const next = { ...values, [field]: checked };
if (field === 'streaming' && !checked) {
next.recording = false;
}
onChange(next);
};
return (
<WizardLayout
variant="detail-toggles"
@@ -238,41 +216,6 @@ export const VenueDetailStep: React.FC<VenueDetailStepProps> = ({
</Box>
</Box>
)}
{/* ─── Service toggles ─── */}
{services.length > 0 && (
<>
<Divider sx={{ my: 3 }} />
<Typography variant="h5" sx={{ mb: 2 }}>
Venue services
</Typography>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
<AddOnOption
name="Photo presentation"
description="Display a photo slideshow during the service"
price={services.find((s) => s.id === 'photo')?.price}
checked={values.photoDisplay}
onChange={(c) => handleToggle('photoDisplay', c)}
/>
<AddOnOption
name="Livestream"
description="Allow family and friends to watch the service remotely"
price={services.find((s) => s.id === 'streaming')?.price}
checked={values.streaming}
onChange={(c) => handleToggle('streaming', c)}
/>
{values.streaming && (
<AddOnOption
name="Recording"
description="Receive a recording of the service to keep"
price={services.find((s) => s.id === 'recording')?.price}
checked={values.recording}
onChange={(c) => handleToggle('recording', c)}
/>
)}
</Box>
</>
)}
</Box>
}
>
@@ -359,6 +302,47 @@ export const VenueDetailStep: React.FC<VenueDetailStepProps> = ({
</Typography>
</Box>
)}
{/* ─── Available services (informational) ─── */}
{services.length > 0 && (
<>
<Divider sx={{ my: 3 }} />
<Typography variant="h5" sx={{ mb: 1 }}>
Available venue services
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
This venue offers the following optional services. You can choose which ones to include
in the next step.
</Typography>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>
{services.map((service) => (
<Card key={service.id} variant="outlined" padding="compact">
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'flex-start',
}}
>
<Box>
<Typography variant="label">{service.name}</Typography>
{service.description && (
<Typography variant="body2" color="text.secondary">
{service.description}
</Typography>
)}
</Box>
{service.price != null && (
<Typography variant="labelSm" color="primary" sx={{ whiteSpace: 'nowrap' }}>
${service.price.toLocaleString('en-AU')}
</Typography>
)}
</Box>
</Card>
))}
</Box>
</>
)}
</WizardLayout>
);
};

View File

@@ -1,7 +1,2 @@
export { VenueDetailStep, default } from './VenueDetailStep';
export type {
VenueDetailStepProps,
VenueDetailStepValues,
VenueDetail,
VenueService,
} from './VenueDetailStep';
export type { VenueDetailStepProps, VenueDetail, VenueService } from './VenueDetailStep';