import React, { useId, useState } from 'react'; import Box from '@mui/material/Box'; import useMediaQuery from '@mui/material/useMediaQuery'; import { useTheme } from '@mui/material/styles'; import Tooltip from '@mui/material/Tooltip'; import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'; import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'; import LocationOnOutlinedIcon from '@mui/icons-material/LocationOnOutlined'; import StarRoundedIcon from '@mui/icons-material/StarRounded'; import VerifiedOutlinedIcon from '@mui/icons-material/VerifiedOutlined'; import ShareOutlinedIcon from '@mui/icons-material/ShareOutlined'; import PrintOutlinedIcon from '@mui/icons-material/PrintOutlined'; import type { SxProps, Theme } from '@mui/material/styles'; import { Typography } from '../../atoms/Typography'; import { Button } from '../../atoms/Button'; import { Badge } from '../../atoms/Badge'; import { Divider } from '../../atoms/Divider'; import { Card } from '../../atoms/Card'; import { WizardLayout } from '../../templates/WizardLayout'; import { ComparisonTable, type ComparisonPackage, type ComparisonCellValue, } from '../../organisms/ComparisonTable'; // ─── Types ─────────────────────────────────────────────────────────────────── /** Props for the ComparisonPage */ export interface ComparisonPageProps { /** User-selected packages to compare (max 3) */ packages: ComparisonPackage[]; /** System-recommended package — always shown as an additional column */ recommendedPackage?: ComparisonPackage; /** Called when user clicks CTA on a package */ onArrange: (packageId: string) => void; /** Called when user removes a package from comparison */ onRemove: (packageId: string) => void; /** Called when user clicks Back */ onBack: () => void; /** Called when user clicks Share */ onShare?: () => void; /** Called when user clicks Print */ onPrint?: () => void; /** Navigation bar slot */ navigation?: React.ReactNode; /** MUI sx prop */ sx?: SxProps; } // ─── Helpers ──────────────────────────────────────────────────────────────── function formatPrice(amount: number): string { return `$${amount.toLocaleString('en-AU', { minimumFractionDigits: amount % 1 !== 0 ? 2 : 0 })}`; } function MobileCellValue({ value }: { value: ComparisonCellValue }) { switch (value.type) { case 'price': return ( {formatPrice(value.amount)} ); case 'allowance': return ( {formatPrice(value.amount)}* ); case 'complimentary': return ( Complimentary ); case 'included': return ( Included ); case 'poa': return ( Price On Application ); case 'unknown': return ( Unknown ); case 'unavailable': return ( ); } } // ─── Mobile card view ─────────────────────────────────────────────────────── function MobilePackageCard({ pkg, onArrange, }: { pkg: ComparisonPackage; onArrange: (id: string) => void; }) { return ( {/* Recommended banner */} {pkg.isRecommended && ( Recommended )} {/* Provider header */} {/* Verified badge */} {pkg.provider.verified && ( } sx={{ mb: 1 }} > Verified )} {/* Provider name */} {pkg.provider.name} {/* Location + Rating */} {pkg.provider.location} {pkg.provider.rating != null && ( {pkg.provider.rating} {pkg.provider.reviewCount != null && ` (${pkg.provider.reviewCount})`} )} {/* Package name + price */} {pkg.name} Total package price {formatPrice(pkg.price)} {/* Sections — with left accent borders on headings */} {pkg.itemizedAvailable === false ? ( Itemised pricing not available for this provider. ) : ( pkg.sections.map((section, sIdx) => ( {/* Section heading with left accent */} 0 ? 1 : 0, }} > {section.heading} {section.items.map((item) => ( {item.name} {item.info && ( {'\u00A0'} )} ))} )) )} ); } // ─── Component ────────────────────────────────────────────────────────────── /** * Package comparison page for the FA design system. * * Desktop: Full ComparisonTable with info card, floating verified badges, * section tables with left accent borders. * Mobile: Tabbed card view with horizontal chip rail. * * Share + Print utility actions in the page header. */ export const ComparisonPage = React.forwardRef( ( { packages, recommendedPackage, onArrange, onRemove, onBack, onShare, onPrint, navigation, sx }, ref, ) => { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down('md')); const tablistId = useId(); const allPackages = React.useMemo(() => { const result = [...packages]; if (recommendedPackage) { result.push({ ...recommendedPackage, isRecommended: true }); } return result; }, [packages, recommendedPackage]); const [activeTabIdx, setActiveTabIdx] = useState(0); const activePackage = allPackages[activeTabIdx] ?? allPackages[0]; const providerCount = new Set(allPackages.map((p) => p.provider.name)).size; const subtitle = providerCount > 1 ? `Comparing ${packages.length} package${packages.length !== 1 ? 's' : ''} from different providers` : `Comparing ${packages.length} package${packages.length !== 1 ? 's' : ''}`; return ( {/* Page header with Share/Print actions */} Compare packages {subtitle} {/* Share + Print */} {(onShare || onPrint) && ( {onShare && ( )} {onPrint && ( )} )} {/* Desktop: ComparisonTable */} {!isMobile && ( )} {/* Mobile: Tab rail + card view */} {isMobile && allPackages.length > 0 && ( <> {/* Tab rail — mini cards showing provider + package name */} {allPackages.map((pkg, idx) => { const isActive = idx === activeTabIdx; return ( setActiveTabIdx(idx)} interactive sx={{ flexShrink: 0, minWidth: 150, maxWidth: 200, cursor: 'pointer', ...(pkg.isRecommended && !isActive && { borderColor: 'var(--fa-color-brand-500)', }), }} > {pkg.isRecommended ? `★ ${pkg.provider.name}` : pkg.provider.name} {pkg.name} ); })} {activePackage && ( )} )} ); }, ); ComparisonPage.displayName = 'ComparisonPage'; export default ComparisonPage;