Add LineItem, ProviderCardCompact, PackageDetail for Package Select page
LineItem (molecule): - Name + optional info tooltip + optional price - Allowance asterisk, total variant (bold + top border) - Reusable for package contents, order summaries, invoices ProviderCardCompact (molecule): - Horizontal layout: image left, name + location + rating right - Used at top of Package Select page to show selected provider PackageDetail (organism): - Right-side detail panel for Package Select page - Name/price header, Make Arrangement + Compare CTAs - Grouped LineItem sections, total row, T&C footer - PackageSelectPage story: full page with filter chips, package list (ServiceOption), sticky detail panel, and Navigation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
import React from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import type { SxProps, Theme } from '@mui/material/styles';
|
||||
import LocationOnOutlinedIcon from '@mui/icons-material/LocationOnOutlined';
|
||||
import StarRoundedIcon from '@mui/icons-material/StarRounded';
|
||||
import { Card } from '../../atoms/Card';
|
||||
import { Typography } from '../../atoms/Typography';
|
||||
|
||||
// ─── Types ───────────────────────────────────────────────────────────────────
|
||||
|
||||
/** Props for the FA ProviderCardCompact molecule */
|
||||
export interface ProviderCardCompactProps {
|
||||
/** Provider display name */
|
||||
name: string;
|
||||
/** Location text (suburb, city) */
|
||||
location: string;
|
||||
/** Hero image URL — shown on the left */
|
||||
imageUrl?: string;
|
||||
/** Average rating (e.g. 4.5). Omit to hide. */
|
||||
rating?: number;
|
||||
/** Number of reviews. Omit to hide review count. */
|
||||
reviewCount?: number;
|
||||
/** Click handler — makes the card interactive */
|
||||
onClick?: () => void;
|
||||
/** MUI sx prop for the root element */
|
||||
sx?: SxProps<Theme>;
|
||||
}
|
||||
|
||||
// ─── Component ───────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Compact horizontal provider card for the FA design system.
|
||||
*
|
||||
* Used at the top of the Package Select page to show which provider
|
||||
* the user has selected. Horizontal layout with image on the left,
|
||||
* name + meta on the right.
|
||||
*
|
||||
* For the full vertical listing card, use ProviderCard instead.
|
||||
*
|
||||
* Composes Card + Typography.
|
||||
*
|
||||
* Usage:
|
||||
* ```tsx
|
||||
* <ProviderCardCompact
|
||||
* name="H.Parsons"
|
||||
* location="Wentworth"
|
||||
* imageUrl="/images/parsons.jpg"
|
||||
* rating={4.5}
|
||||
* reviewCount={11}
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
export const ProviderCardCompact = React.forwardRef<HTMLDivElement, ProviderCardCompactProps>(
|
||||
({ name, location, imageUrl, rating, reviewCount, onClick, sx }, ref) => {
|
||||
return (
|
||||
<Card
|
||||
ref={ref}
|
||||
variant="outlined"
|
||||
interactive={!!onClick}
|
||||
padding="none"
|
||||
onClick={onClick}
|
||||
sx={[
|
||||
{
|
||||
display: 'flex',
|
||||
overflow: 'hidden',
|
||||
minHeight: 110,
|
||||
},
|
||||
...(Array.isArray(sx) ? sx : [sx]),
|
||||
]}
|
||||
>
|
||||
{/* Image */}
|
||||
{imageUrl && (
|
||||
<Box
|
||||
role="img"
|
||||
aria-label={`${name} photo`}
|
||||
sx={{
|
||||
width: { xs: 120, sm: 160 },
|
||||
flexShrink: 0,
|
||||
backgroundImage: `url(${imageUrl})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Content */}
|
||||
<Box
|
||||
sx={{
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
gap: 0.5,
|
||||
p: 2,
|
||||
minWidth: 0,
|
||||
}}
|
||||
>
|
||||
<Typography variant="h6" component="span">
|
||||
{name}
|
||||
</Typography>
|
||||
|
||||
{/* Location */}
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
|
||||
<LocationOnOutlinedIcon
|
||||
sx={{ fontSize: 16, color: 'text.secondary' }}
|
||||
aria-hidden
|
||||
/>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{location}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{/* Rating */}
|
||||
{rating != null && (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
|
||||
<StarRoundedIcon
|
||||
sx={{ fontSize: 16, color: 'var(--fa-color-brand-500)' }}
|
||||
aria-hidden
|
||||
/>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
{rating} Rating{reviewCount != null ? ` (${reviewCount} ${reviewCount === 1 ? 'Review' : 'Reviews'})` : ''}
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Card>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
ProviderCardCompact.displayName = 'ProviderCardCompact';
|
||||
export default ProviderCardCompact;
|
||||
Reference in New Issue
Block a user