diff --git a/app/properties/[id]/fmv/page.tsx b/app/properties/[id]/fmv/page.tsx new file mode 100644 index 0000000..3f468e3 --- /dev/null +++ b/app/properties/[id]/fmv/page.tsx @@ -0,0 +1,351 @@ +'use client'; +import { useState } from 'react'; +import Link from 'next/link'; +import { use } from 'react'; + +const N = '#0F3460'; +const TEAL = '#00D4AA'; +const TEAL_DARK = '#00A886'; +const TEAL_LIGHT = '#E0FAF5'; +const BG = '#F0F4FF'; +const BORDER = '#E0E6F0'; +const INK_MID = '#4A5068'; +const INK_MUTED = '#8892A4'; +const WARN_BG = '#FFF9E6'; +const WARN_BORDER = '#F5D67A'; + +// TODO: Replace with real data fetched by property id +const SAMPLE_PROPERTY = { + address: '12B Maple Ave, Oakland CA 94601', + unit: 'Unit 2B', + fmvEstimate: 2850, + compsUsed: 7, + estimatedAt: 'May 16, 2026', +}; + +export default function FmvOverridePage({ params }: { params: Promise<{ id: string }> }) { + const { id } = use(params); + + // TODO: fetch real property + FMV estimate from Supabase by `id` + const property = SAMPLE_PROPERTY; + + const [overrideRaw, setOverrideRaw] = useState(String(property.fmvEstimate)); + const [confirmOpen, setConfirmOpen] = useState(false); + const [applied, setApplied] = useState(false); + + const overrideVal = parseInt(overrideRaw.replace(/\D/g, ''), 10) || 0; + const diff = overrideVal - property.fmvEstimate; + const diffAbs = Math.abs(diff); + const diffLabel = + diff === 0 + ? 'Matches the local estimate.' + : diff > 0 + ? `You're setting rent $${diffAbs.toLocaleString()} above the local estimate.` + : `You're setting rent $${diffAbs.toLocaleString()} below the local estimate.`; + + const handleApply = () => { + // TODO: write overrideVal to property record via API + setConfirmOpen(false); + setApplied(true); + }; + + return ( +
+ + + {/* Nav */} + + +
+ {/* Header */} +
+
+ Fair Market Value +
+

+ {property.address} +

+

{property.unit}

+
+ + {/* FMV Estimate card */} +
+
+ AI Estimate +
+ {/* TODO: render real FMV estimate + confidence band from AI output */} +
+ + ${property.fmvEstimate.toLocaleString()} + + /mo +
+

+ Based on {property.compsUsed} comparable units · estimated {property.estimatedAt} +

+ {/* TODO: show comp breakdown / map link */} +
+ + {/* Override input card */} +
+ +

+ AI suggests ${property.fmvEstimate.toLocaleString()} — adjust if you know your unit + better. +

+ + {/* Currency input */} +
+ + $ + + { + setApplied(false); + setOverrideRaw(e.target.value.replace(/[^0-9]/g, '')); + }} + style={{ + width: '100%', + boxSizing: 'border-box', + border: `1.5px solid ${BORDER}`, + borderRadius: 10, + padding: '12px 14px 12px 28px', + fontSize: 22, + fontWeight: 700, + color: N, + fontFamily: 'inherit', + outline: 'none', + background: '#fff', + }} + placeholder={String(property.fmvEstimate)} + aria-label="Target monthly rent" + /> +
+ + {/* Neutral comparison nudge */} + {overrideVal > 0 && ( +

+ {diffLabel} +

+ )} + + {/* Apply CTA */} + +
+ + {/* Confirmation modal (inline) */} + {confirmOpen && ( +
+

+ Set rent to ${overrideVal.toLocaleString()}/mo for {property.unit},{' '} + {property.address}? +

+

+ This won't notify tenants. +

+ {/* TODO: wire handleApply to real API call (PATCH /api/properties/[id]) */} +
+ + +
+
+ )} + + {/* Applied success */} + {applied && ( +
+ ✓ Target rent saved. You can update this any time before collecting rent. +
+ )} + + {/* TODO: show rent history / changelog for this property */} +
+
+ ); +}