import * as React from "react"; import { Check } from "lucide-react"; import { cn } from "@/lib/utils"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { LoanOptionGroup, type LoanOptionItem, } from "@/components/ui/loan-option-group"; import { MoneyInputWithSlider } from "@/components/ui/money-input-with-slider"; import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList, ComboboxTrigger, ComboboxValue, } from "@/components/ui/combobox"; import { YES_NO_OPTIONS as YES_NO } from "@/lib/loan-constants"; // ─── Shared option constants ──────────────────────────────────────────────── function scaleOptions(min: number, max: number): LoanOptionItem[] { return Array.from({ length: max - min + 1 }, (_, i) => { const v = String(min + i); return { value: v, label: v }; }); } /** 1–10 scale reused by the fixed-rate and rate-rise concern steps. */ const SCALE_1_10: LoanOptionItem[] = scaleOptions(1, 10); // ─── 1. LoanPurposeStep ────────────────────────────────────────────────────── export const LENDING_TYPE_OPTIONS: LoanOptionItem[] = [ { value: "owner-occupier", label: "Owner Occupier" }, { value: "investment", label: "Investment" }, { value: "both", label: "Both" }, ]; export const LOAN_PURPOSE_OPTIONS: LoanOptionItem[] = [ { value: "buy", label: "Buy a New Property" }, { value: "refinance", label: "Refinance" }, { value: "equity", label: "Equity Release" }, { value: "construction", label: "Construction" }, ]; export type LoanPurposeStepProps = { lendingType: string | null; loanPurpose: string | null; onLendingTypeChange: (v: string) => void; onLoanPurposeChange: (v: string) => void; className?: string; }; export function LoanPurposeStep({ lendingType, loanPurpose, onLendingTypeChange, onLoanPurposeChange, className, }: LoanPurposeStepProps) { // No in-content nav here — the wizard shell owns the bottom Prev/Next controls. return (
onLendingTypeChange(v as string)} /> onLoanPurposeChange(v as string)} />
); } // ─── 2. LoanDetailsBuyStep ─────────────────────────────────────────────────── // Slider ranges for the Buy-a-property value inputs (whole dollars). const PROPERTY_VALUE_MIN = 100_000; const PROPERTY_VALUE_MAX = 3_000_000; const LOAN_AMOUNT_MIN = 50_000; const LOAN_AMOUNT_MAX = 2_500_000; const VALUE_SLIDER_STEP = 10_000; export type LoanDetailsBuyStepProps = { isPropertyKnown: string | null; propertyAddress?: string; propertyEstimate?: number; loanAmount?: number; /** Address suggestions for the autocomplete search (e.g. from a places API). */ addressOptions?: string[]; onIsPropertyKnownChange: (v: string) => void; onPropertyAddressChange: (v: string) => void; onPropertyEstimateChange: (v: number) => void; onLoanAmountChange: (v: number) => void; className?: string; }; export function LoanDetailsBuyStep({ isPropertyKnown, propertyAddress = "", propertyEstimate = 0, loanAmount = 0, addressOptions = [], onIsPropertyKnownChange, onPropertyAddressChange, onPropertyEstimateChange, onLoanAmountChange, className, }: LoanDetailsBuyStepProps) { return (
onIsPropertyKnownChange(v as string)} /> {isPropertyKnown === "yes" && (
onPropertyAddressChange((val as string | null) ?? "") } > {(item: string) => ( {item} )} No matching address.
)}
); } // ─── 3. LoanDetailsRefinanceStep ───────────────────────────────────────────── export type RefinanceProperty = { id: string; address: string; estimateValue?: number; }; export type LoanDetailsRefinanceStepProps = { properties: RefinanceProperty[]; selectedIds: string[]; onToggle: (id: string) => void; className?: string; }; export function LoanDetailsRefinanceStep({ properties, selectedIds, onToggle, className, }: LoanDetailsRefinanceStepProps) { const selectedSet = new Set(selectedIds); return (

Select What Properties You Would Like to Refinance

{properties.length === 0 ? (

No properties found. Add properties in the Assets section first.

) : (
{properties.map((prop) => ( ))}
)}
); } // ─── 4. LoanFixedRateConcernStep ───────────────────────────────────────────── export type LoanFixedRateConcernStepProps = { fixedRateConcern: string | null; jobSecurityScale: string | null; onFixedRateConcernChange: (v: string) => void; onJobSecurityScaleChange: (v: string) => void; className?: string; }; export function LoanFixedRateConcernStep({ fixedRateConcern, jobSecurityScale, onFixedRateConcernChange, onJobSecurityScaleChange, className, }: LoanFixedRateConcernStepProps) { return (
onFixedRateConcernChange(v as string)} /> {fixedRateConcern && ( onJobSecurityScaleChange(v as string)} /> )}
); } // ─── 5. LoanBorrowIntendStep ───────────────────────────────────────────────── export type LoanBorrowIntendStepProps = { borrowIntend: string | null; onBorrowIntendChange: (v: string) => void; className?: string; }; export function LoanBorrowIntendStep({ borrowIntend, onBorrowIntendChange, className, }: LoanBorrowIntendStepProps) { return (
onBorrowIntendChange(v as string)} />
); } // ─── 6. LoanPriorityStep ───────────────────────────────────────────────────── export const LOAN_PRIORITY_OPTIONS: LoanOptionItem[] = [ { value: "lowest-rate", label: "Lowest Rate" }, { value: "offset-account", label: "Offset Account" }, { value: "redraw-facility", label: "Redraw Facility" }, { value: "repayment-flexibility", label: "Repayment Flexibility" }, { value: "lender-stability", label: "Lender Stability" }, { value: "customer-service", label: "Customer Service" }, ]; export type LoanPriorityStepProps = { priorities: string[]; onPrioritiesChange: (v: string[]) => void; className?: string; }; export function LoanPriorityStep({ priorities, onPrioritiesChange, className, }: LoanPriorityStepProps) { return (
onPrioritiesChange(v as string[])} />
); } // ─── 7. LoanRetirementPlanStep ─────────────────────────────────────────────── export type LoanRetirementPlanStepProps = { retirementAge: number; hasRetirementPlan: string | null; retirementAgeError?: string; onRetirementAgeChange: (v: number) => void; onHasRetirementPlanChange: (v: string) => void; className?: string; }; export function LoanRetirementPlanStep({ retirementAge, hasRetirementPlan, retirementAgeError, onRetirementAgeChange, onHasRetirementPlanChange, className, }: LoanRetirementPlanStepProps) { return (
onRetirementAgeChange(Number(e.target.value))} placeholder="e.g. 65" aria-invalid={Boolean(retirementAgeError)} className="w-32" /> {retirementAgeError && (

{retirementAgeError}

)}
onHasRetirementPlanChange(v as string)} />
); } // ─── 8. LoanInterestRateRaiseConcernStep ───────────────────────────────────── export type LoanInterestRateRaiseConcernStepProps = { raiseConcern: string | null; raiseConcernScale: string | null; onRaiseConcernChange: (v: string) => void; onRaiseConcernScaleChange: (v: string) => void; className?: string; }; export function LoanInterestRateRaiseConcernStep({ raiseConcern, raiseConcernScale, onRaiseConcernChange, onRaiseConcernScaleChange, className, }: LoanInterestRateRaiseConcernStepProps) { return (
onRaiseConcernChange(v as string)} /> {raiseConcern === "yes" && ( onRaiseConcernScaleChange(v as string)} /> )}
); } // ─── 9. LoanFeaturesStep ───────────────────────────────────────────────────── export const LOAN_FEATURE_OPTIONS: LoanOptionItem[] = [ { value: "offset", label: "Offset Account" }, { value: "redraw", label: "Redraw" }, { value: "split", label: "Split Loan" }, { value: "extra-repayments", label: "Extra Repayments" }, { value: "interest-only", label: "Interest Only" }, ]; export type LoanFeaturesStepProps = { featuresAcknowledge: string | null; feature: string | null; onFeaturesAcknowledgeChange: (v: string) => void; onFeatureChange: (v: string) => void; className?: string; }; export function LoanFeaturesStep({ featuresAcknowledge, feature, onFeaturesAcknowledgeChange, onFeatureChange, className, }: LoanFeaturesStepProps) { return (
onFeaturesAcknowledgeChange(v as string)} /> {featuresAcknowledge === "yes" && ( onFeatureChange(v as string)} /> )}
); } // ─── Icon helpers ──────────────────────────────────────────────────────────── /** * SelectionCheckIndicator — a purely decorative checkmark box matching the * shared Checkbox component's visual language (border-input / bg-primary), * used inside rows where the ROW itself (not the indicator) is the clickable * element. Not the real Checkbox component: nesting an interactive Checkbox * inside an already-clickable row would create invalid nested interactive * controls. */ function SelectionCheckIndicator({ checked, className, }: { checked: boolean; className?: string; }) { return ( ); }