import React from "react"; import { ChevronRight } from "lucide-react"; import { cn } from "@/lib/utils"; import { formatCurrency } from "@/lib/format-currency"; import { Button } from "./button"; import { Skeleton } from "./skeleton"; /** * Organism — "Top 3 Loans Available" section for the Borrowing Capacity page. * * Layout: * - Heading row: "Top 3 Loans Available" (left) + "See All Options" link (right) * - Two-column body: * - Left: up to 3 `TopThreeProductItem` rows (lender logo, rate, max loan, repayment) * - Right: Outcome panel (descriptive text + CTA buttons) * * All values are pre-formatted / typed — business logic stays in the app layer. */ // ─── Sub-types ─────────────────────────────────────────────────────────────── export interface TopThreeProductItem { /** Lender display name (e.g. "ANZ") */ lender: string; /** URL for the lender logo image. Falls back to initials if omitted. */ lenderLogoUrl?: string; /** Interest rate as a percentage (e.g. 5.5 → displayed as "5.50%") */ interestRate: number; /** true = Variable rate, false = Fixed rate */ isVariable: boolean; /** Maximum loan amount in AUD dollars */ maxLoanAmount: number; /** Monthly repayment in AUD dollars */ monthlyRepayment: number; } export interface TopThreeProductProps { /** Up to 3 loan products to display */ items?: TopThreeProductItem[]; /** Outcome summary text shown in the right panel */ outcomeText?: string; /** Called when "See All Options" is clicked */ onSeeAllOptions?: () => void; /** Called when "Talk To Your Broker" CTA is clicked */ onTalkToBroker?: () => void; /** Called when "Start Loan Application" CTA is clicked */ onStartLoanApplication?: () => void; /** Replace content with a skeleton loading state */ isLoading?: boolean; className?: string; } // ─── Internal stat cell ────────────────────────────────────────────────────── function StatCell({ value, label }: { value: React.ReactNode; label: string }) { return (
{value} {label}
); } // ─── Internal product row ───────────────────────────────────────────────────── function ProductRow({ item }: { item: TopThreeProductItem }) { const initials = item.lender .split(" ") .map((w) => w[0]) .slice(0, 2) .join(""); return (
{/* Lender logo / initials fallback */}
{item.lenderLogoUrl ? ( {item.lender} ) : ( initials )}
{/* Stats — rate, max loan, repayment */}
); } // ─── Main component ─────────────────────────────────────────────────────────── export function TopThreeProduct({ items = [], outcomeText, onSeeAllOptions, onTalkToBroker, onStartLoanApplication, isLoading = false, className, }: TopThreeProductProps) { const showOutcome = Boolean( outcomeText || onTalkToBroker || onStartLoanApplication, ); return (
{/* Heading row */}
Top 3 Loans Available {onSeeAllOptions && ( )}
{/* Body — products + outcome */}
{/* Product list */}
{isLoading ? Array.from({ length: 3 }).map((_, i) => (
)) : items.length > 0 ? items .slice(0, 3) .map((item, i) => ( )) : !isLoading && (

No lender options available for this scenario.

)}
{/* Outcome panel */} {showOutcome && (
Outcome {outcomeText && (

{outcomeText}

)}
{onTalkToBroker && ( )} {onStartLoanApplication && ( )}
)}
); }