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" && (
Property Address
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) => (
onToggle(prop.id)}
className={cn(
"flex items-center justify-between border p-4 text-left transition-colors",
selectedSet.has(prop.id)
? "border-primary bg-primary/5"
: "border-border bg-background hover:bg-accent",
)}
>
{prop.address}
{prop.estimateValue != null && (
Est. ${prop.estimateValue.toLocaleString("en-AU")}
)}
))}
)}
);
}
// ─── 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 (
What age are you planning to retire?
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 (
);
}