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:
2026-03-25 22:51:40 +11:00
parent 6f59468057
commit 377ff41aac
10 changed files with 925 additions and 0 deletions

View File

@@ -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;