PageSourceSearch

https://homelensais.com/assets/OwnedPropertyDetail-D9oE1V3k.js

js homelensais.com collected 2026-10-02 01:31:58 UTC 34,014 bytes, 8 lines download raw bytes

1import{r as h,a2 as f,q as e,aG as le,aH as oe,aI as ie,aJ as ce,ba as de,ar as Y,ay as J,aM as se,aN as ue,B as M,ac as g,s as b,F as N,aq as K,z as H,t as I,v as B,w as U,b0 as me,O as pe,aC as xe,W as he,bd as fe,Z as ge,_ as ve,aF as V,a3 as ye,at as _e,au as je,av as be,aw as we,ax as Ne,be as Ce,bf as Se,bg as ke,ad as De,ae as Ee,V as Te,al as Me,Q as $e,T as Re,H as Ae,I as R,J as A,b3 as Pe}from"./index-RQZfdGSV.js";import{c as qe,a as Ie,b as Be,d as Oe,e as Fe,f as Le,m as ze,g as Ue,h as Ve,C as Ye}from"./ConsoleSidebar-CrydHVXV.js";import{I as He}from"./info-CLo2Gbx1.js";import{p as Ge,i as Je}from"./edgeErrors-DMjWY08H.js";import{u as Ke,C as We}from"./useConversationalIntelligenceState-BK9ABOUv.js";import{T as re}from"./trash-2-B5L3aDOx.js";import{S as Xe}from"./send-DUJfWrBL.js";import{U as W}from"./upload-m2RN-fw7.js";import{D as Ze,a as Qe,b as et,d as tt,e as st,c as rt}from"./dropdown-menu-D9mbcrJs.js";import{P as at}from"./types-ewSoxauB.js";import{T as nt}from"./TierGate-B342dcPq.js";import{A as lt}from"./arrow-left-B0jdwYg2.js";import{P as ot}from"./pencil-DZwwnk3k.js";import"./settings-Cl1wpAwS.js";function it(s){const[n,t]=h.useState(null),[o,p]=h.useState(!0),[c,d]=h.useState(null),x=h.useCallback(async()=>{if(!s)return;p(!0),d(null);const{data:u,error:_}=await f.from("investor_owned_properties").select("*").eq("id",s).maybeSingle();if(_||!u){d((_==null?void 0:_.message)??"Property not found"),p(!1);return}if(u.primary_photo_url&&!/^https?:\/\//i.test(u.primary_photo_url)){const{data:y}=await f.storage.from("owned-property-photos").createSignedUrl(u.primary_photo_url,3600);y!=null&&y.signedUrl&&(u.primary_photo_url=y.signedUrl)}const[a,l,m,w,E,D,i]=await Promise.all([f.from("investor_owned_property_rental").select("*").eq("property_id",s).maybeSingle(),f.from("investor_owned_property_photos").select("*").eq("property_id",s).order("ordinal"),f.from("investor_owned_property_improvements").select("*").eq("property_id",s).order("improvement_date",{ascending:!1}),f.from("investor_owned_property_events").select("*").eq("property_id",s).order("event_date",{ascending:!1}),f.from("investor_owned_property_valuations").select("*").eq("property_id",s).order("observed_at",{ascending:!1}).limit(20),f.from("investor_owned_property_alerts").select("*").eq("property_id",s).eq("status","active").order("surfaced_at",{ascending:!1}),f.from("investor_owned_property_documents").select("*").eq("property_id",s).order("uploaded_at",{ascending:!1})]),r=a.data??null,j=qe(u),S=Ie(u);t({property:u,rental:r,photos:l.data??[],improvements:m.data??[],events:w.data??[],valuations:E.data??[],alerts:D.data??[],documents:i.data??[],metrics:{currentValue:j.currentValue,loanBalance:Be(u),equity:j.equity,equityPct:j.equityPct,appreciation:S.absolute,appreciationPct:S.pct,monthlyCashFlow:Oe(u,r),capRate:Fe(u,r),returns:Le(u,r)}}),p(!1)},[s]);return h.useEffect(()=>{x()},[x]),{data:n,loading:o,error:c,reload:x}}function ct({open:s,onOpenChange:n,property:t,onSaved:o}){var E,D,i;const[p,c]=h.useState(((E=t.current_value_manual_override)==null?void 0:E.toString())??((D=t.current_value_estimate)==null?void 0:D.toString())??""),[d,x]=h.useState(t.current_value_manual_note??""),[u,_]=h.useState(((i=t.current_value_manual_expires_at)==null?void 0:i.slice(0,10))??""),[a,l]=h.useState(!1);async function m(){const r=Number(p);if(!r||r<=0){g.error("Enter a valid value");return}l(!0);const j={current_value_estimate:r,current_value_source:"manual_override",current_value_manual_override:r,current_value_manual_note:d||null,current_value_manual_expires_at:u?new Date(u).toISOString():null,current_value_refreshed_at:new Date().toISOString()},{error:S}=await f.from("investor_owned_properties").update(j).eq("id",t.id);if(S){g.error(S.message),l(!1);return}await f.from("investor_owned_property_valuations").insert({property_id:t.id,value:r,source:"manual_override",note:d||null}),g.success("Valuation updated"),l(!1),n(!1),o==null||o()}async function w(){l(!0);const{error:r}=await f.from("investor_owned_properties").update({current_value_manual_override:null,current_value_manual_note:null,current_value_manual_expires_at:null}).eq("id",t.id);if(r){g.error(r.message),l(!1);return}g.success("Manual override cleared"),l(!1),n(!1),o==null||o()}return e.jsx(le,{open:s,onOpenChange:n,children:e.jsxs(oe,{children:[e.jsxs(ie,{children:[e.jsx(ce,{children:"Edit valuation"}),e.jsx(de,{children:"Override the auto-estimate with your own number (e.g. a recent appraisal). The override applies until the expiry date — after that we fall back to auto-valuation."})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{children:[e.jsx(Y,{htmlFor:"val",children:"Current value"}),e.jsx(J,{id:"val",type:"number",value:p,onChange:r=>c(r.target.value),placeholder:"450000"})]}),e.jsxs("div",{children:[e.jsx(Y,{htmlFor:"exp",children:"Expires (optional)"}),e.jsx(J,{id:"exp",type:"date",value:u,onChange:r=>_(r.target.value)})]}),e.jsxs("div",{children:[e.jsx(Y,{htmlFor:"note",children:"Note (optional)"}),e.jsx(se,{id:"note",value:d,onChange:r=>x(r.target.value),placeholder:"Appraisal from May 2026, comps adjusted for new roof…",rows:3})]})]}),e.jsxs(ue,{className:"gap-2",children:[t.current_value_manual_override!=null&&e.jsx(M,{variant:"ghost",onClick:w,disabled:a,children:"Clear override"}),e.jsx(M,{variant:"outline",onClick:()=>n(!1),disabled:a,children:"Cancel"}),e.jsx(M,{onClick:m,disabled:a,children:a?"Saving…":"Save"})]})]})})}const X={opportunity:{icon:pe,classes:"border-emerald-300/50 bg-emerald-50/40 dark:bg-emerald-950/10",label:"Opportunity"},warning:{icon:xe,classes:"border-amber-300/50 bg-amber-50/40 dark:bg-amber-950/10",label:"Warning"},info:{icon:He,classes:"border-sky-300/50 bg-sky-50/40 dark:bg-sky-950/10",label:"Info"}};function dt({propertyId:s,alerts:n,onChanged:t}){const[o,p]=h.useState(!1),[c,d]=h.useState(null),x=n.filter(a=>a.status==="active");async function u(a){d(a);const{error:l}=await f.from("investor_owned_property_alerts").update({status:"dismissed",dismissed_at:new Date().toISOString()}).eq("id",a);if(d(null),l){g.error(l.message);return}g.success("Alert dismissed"),t()}async function _(){p(!0);const{data:a,error:l}=await f.functions.invoke("property-alerts-evaluate",{body:{}});if(p(!1),l){g.error(l.message??"Could not re-evaluate alerts");return}g.success(`Re-evaluated (${(a==null?void 0:a.inserted)??0} new, ${(a==null?void 0:a.resolved)??0} resolved)`),t()}return x.length===0?e.jsx(b,{children:e.jsxs(N,{className:"p-4 flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2 text-sm text-muted-foreground",children:[e.jsx(K,{className:"h-4 w-4"}),"No active alerts on this property."]}),e.jsxs(M,{size:"sm",variant:"ghost",onClick:_,disabled:o,children:[e.jsx(H,{className:`h-3.5 w-3.5 mr-1 ${o?"animate-spin":""}`}),"Re-evaluate"]})]})}):e.jsxs(b,{children:[e.jsxs(I,{className:"pb-2 flex flex-row items-center justify-between",children:[e.jsxs(B,{className:"text-sm flex items-center gap-2",children:[e.jsx(K,{className:"h-4 w-4 text-amber-600"}),x.length," active alert",x.length===1?"":"s"]}),e.jsxs(M,{size:"sm",variant:"ghost",onClick:_,disabled:o,children:[e.jsx(H,{className:`h-3.5 w-3.5 mr-1 ${o?"animate-spin":""}`}),"Re-evaluate"]})]}),e.jsx(N,{className:"space-y-2",children:x.map(a=>{const l=X[a.severity]??X.info,m=l.icon;return e.jsxs("div",{className:`flex items-start gap-3 rounded-md border p-3 ${l.classes}`,children:[e.jsx(m,{className:"h-4 w-4 mt-0.5 shrink-0"}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsx("div",{className:"text-sm font-medium",children:a.title}),e.jsx(U,{variant:"outline",className:"text-[10px] capitalize",children:l.label})]}),e.jsx("div",{className:"text-xs text-muted-foreground mt-0.5",children:a.description})]}),e.jsx("button",{onClick:()=>u(a.id),disabled:c===a.id,className:"text-muted-foreground hover:text-foreground p-1 -m-1 disabled:opacity-50","aria-label":"Dismiss alert",children:e.jsx(me,{className:"h-3.5 w-3.5"})})]},a.id)})})]})}const G="homelens.ownedPropertyChat.v1.",ut=["Should I refinance this property?","Is rent under market r
1ight now?","What would my returns look like if I sold today?","How much equity could I tap with a HELOC?"];function Z(s){try{const n=localStorage.getItem(G+s);if(!n)return[];const t=JSON.parse(n);return Array.isArray(t)?t:[]}catch{return[]}}function mt(s,n){try{localStorage.setItem(G+s,JSON.stringify(n.slice(-40)))}catch{}}function pt({propertyId:s}){const[n,t]=h.useState(()=>Z(s)),[o,p]=h.useState(""),[c,d]=h.useState(!1),x=h.useRef(null),u=h.useRef(null),_=he(),a=_.warningLevel==="exceeded",[l,m]=h.useState(null);h.useEffect(()=>{let r=!1;return f.auth.getUser().then(({data:j})=>{var S;r||m(((S=j.user)==null?void 0:S.id)??null)}),()=>{r=!0}},[]);const w=Ke(l);h.useEffect(()=>{t(Z(s))},[s]),h.useEffect(()=>{var r;mt(s,n),(r=x.current)==null||r.scrollTo({top:x.current.scrollHeight,behavior:"smooth"})},[n,s]),h.useEffect(()=>{var r;(r=u.current)==null||r.focus()},[s,c]);async function E(r){const j=r.trim();if(!j||c)return;const S=[...n,{role:"user",content:j}];t(S),p(""),d(!0);try{const{data:y,error:T}=await f.functions.invoke("owned-property-chat",{body:{property_id:s,messages:S}});if(T)throw T;const C=(y==null?void 0:y.message)??"";if(!C)throw new Error("Empty response");const $=y==null?void 0:y.signals;t([...S,{role:"assistant",content:C,signals:$&&typeof $=="object"?$:void 0}])}catch(y){if(await ye(y,"owned_property_chat")){t(n);return}const T=await Ge(y);if(Je(T)){const C=T.body&&typeof T.body=="object"&&T.body.message||"You've reached your monthly AI limit on this plan.";g.error(C,{action:{label:"Upgrade",onClick:()=>{window.location.href="/pricing?source=feature_quota_owned_property_chat"}}}),t(n);return}g.error((y==null?void 0:y.message)??"Chat failed"),t(n)}finally{d(!1)}}function D(){t([]),localStorage.removeItem(G+s)}function i(r){r.key==="Enter"&&!r.shiftKey&&(r.preventDefault(),E(o))}return e.jsx(b,{children:e.jsxs(N,{className:"p-0 flex flex-col h-[560px]",children:[e.jsxs("div",{className:"flex items-center justify-between px-4 py-3 border-b",children:[e.jsxs("div",{className:"flex items-center gap-2 text-sm font-medium",children:[e.jsx(fe,{className:"h-4 w-4 text-primary"}),"Ask about this property"]}),n.length>0&&e.jsxs(M,{size:"sm",variant:"ghost",onClick:D,className:"h-7 text-xs",children:[e.jsx(re,{className:"h-3 w-3 mr-1"})," Clear"]})]}),e.jsxs("div",{ref:x,className:"flex-1 overflow-y-auto px-4 py-4 space-y-4",children:[_.warningLevel==="approaching"&&e.jsx(ge,{surface:"owned_property_chat"}),a&&e.jsx(ve,{surface:"owned_property_chat",compact:!0}),n.length===0?e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-sm text-muted-foreground",children:"Ask anything about this property — refinance, equity, rent, returns, hold vs sell. The AI has your numbers loaded."}),e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-2",children:ut.map(r=>e.jsx("button",{onClick:()=>E(r),disabled:a,className:"text-left text-xs rounded-md border bg-muted/40 hover:bg-muted px-3 py-2 transition disabled:opacity-50 disabled:cursor-not-allowed",children:r},r))})]}):n.map((r,j)=>e.jsx("div",{className:r.role==="user"?"flex justify-end":"flex justify-start",children:r.role==="user"?e.jsx("div",{className:"max-w-[85%] rounded-2xl px-4 py-2 text-sm bg-primary text-primary-foreground whitespace-pre-wrap",children:r.content}):e.jsx("div",{className:"max-w-[90%] text-sm text-foreground whitespace-pre-wrap leading-relaxed",children:r.content})},j)),c&&e.jsxs("div",{className:"flex items-center gap-2 text-sm text-muted-foreground",children:[e.jsx(V,{className:"h-3.5 w-3.5 animate-spin"})," Thinking…"]})]}),e.jsxs("div",{className:"border-t p-3",children:[w.loaded&&w.smartSuggestionsEnabled&&e.jsx(We,{active:{kind:"owned_property",propertyId:s},thread:n,preferences:w.preferences,dismissals:w.dismissals,enabled:w.smartSuggestionsEnabled,onSendMessage:r=>void E(r),onAcceptFollowup:w.onAccept,onDismissFollowup:w.onDismiss,onSaveException:w.onSaveException,onGenerateArtifact:w.generateArtifact}),e.jsxs("div",{className:"flex items-end gap-2",children:[e.jsx(se,{ref:u,value:o,onChange:r=>p(r.target.value),onKeyDown:i,placeholder:a?"Daily AI cap reached. Resets at midnight UTC.":"Ask something about this property…",rows:2,className:"resize-none min-h-[44px]",disabled:c||a}),e.jsx(M,{size:"icon",onClick:()=>E(o),disabled:c||!o.trim()||a,"aria-label":"Send",children:e.jsx(Xe,{className:"h-4 w-4"})})]})]})]})})}async function O(s,n={}){var t;try{const{data:o}=await f.auth.getUser(),p=(t=o==null?void 0:o.user)==null?void 0:t.id;if(!p)return;await f.from("investor_persona_telemetry").insert({user_id:p,event_type:s,payload:n})}catch{}}const xt=[{value:"lease",label:"Lease"},{value:"insurance",label:"Insurance"},{value:"tax_bill",label:"Tax bill"},{value:"closing",label:"Closing docs"}
1,{value:"receipt",label:"Receipt / invoice"},{value:"inspection",label:"Inspection"},{value:"other",label:"Other"}],ht=15*1024*1024;function ft(s){return s?new Date(s).toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"}):"—"}function gt(s){return!s||s<=0?"":s<1024?`${s} B`:s<1024*1024?`${(s/1024).toFixed(0)} KB`:`${(s/(1024*1024)).toFixed(1)} MB`}function vt({propertyId:s,documents:n,onChanged:t}){const o=h.useRef(null),[p,c]=h.useState(!1),[d,x]=h.useState(!1),[u,_]=h.useState("other"),[a,l]=h.useState(null),m=h.useCallback(async i=>{var T;const r=Array.from(i);if(r.length===0)return;const{data:j}=await f.auth.getUser(),S=(T=j==null?void 0:j.user)==null?void 0:T.id;if(!S){g.error("You must be signed in");return}x(!0);let y=0;for(const C of r){if(C.size>ht){g.error(`${C.name} is over 15 MB`);continue}const $=C.name.replace(/[^A-Za-z0-9._-]+/g,"_"),P=`${S}/${s}/${Date.now()}_${$}`,{error:F}=await f.storage.from("owned-property-documents").upload(P,C,{upsert:!1,contentType:C.type||void 0});if(F){g.error(`${C.name}: ${F.message}`);continue}const{error:L}=await f.from("investor_owned_property_documents").insert({property_id:s,document_type:u,filename:C.name,storage_path:P,size_bytes:C.size,mime_type:C.type||null});if(L){await f.storage.from("owned-property-documents").remove([P]),g.error(`${C.name}: ${L.message}`);continue}y++,O("owned_property_document_uploaded",{property_id:s,document_type:u,size_bytes:C.size})}x(!1),y>0&&(g.success(`${y} document${y>1?"s":""} uploaded`),t()),o.current&&(o.current.value="")},[s,u,t]);function w(i){var r;i.preventDefault(),c(!1),(r=i.dataTransfer.files)!=null&&r.length&&m(i.dataTransfer.files)}async function E(i){l(i.id);const{data:r,error:j}=await f.storage.from("owned-property-documents").createSignedUrl(i.storage_path,60);if(l(null),j||!(r!=null&&r.signedUrl)){g.error((j==null?void 0:j.message)??"Could not generate download link");return}window.open(r.signedUrl,"_blank","noopener,noreferrer"),O("owned_property_document_downloaded",{property_id:s,document_type:i.document_type})}async function D(i){if(!confirm(`Delete ${i.filename}?`))return;l(i.id),await f.storage.from("owned-property-documents").remove([i.storage_path]);const{error:r}=await f.from("investor_owned_property_documents").delete().eq("id",i.id);if(l(null),r){g.error(r.message);return}g.success("Document deleted"),O("owned_property_document_deleted",{property_id:s,document_type:i.document_type}),t()}return e.jsxs("div",{className:"space-y-4",children:[e.jsx(b,{children:e.jsxs(N,{className:"p-4 space-y-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:"Category"}),e.jsxs(_e,{value:u,onValueChange:_,children:[e.jsx(je,{className:"h-8 w-40 text-xs",children:e.jsx(be,{})}),e.jsx(we,{children:xt.map(i=>e.jsx(Ne,{value:i.value,className:"text-xs",children:i.label},i.value))})]})]}),e.jsxs(M,{size:"sm",variant:"outline",onClick:()=>{var i;return(i=o.current)==null?void 0:i.click()},disabled:d,className:"h-8",children:[d?e.jsx(V,{className:"h-3.5 w-3.5 mr-1 animate-spin"}):e.jsx(W,{className:"h-3.5 w-3.5 mr-1"}),"Choose files"]}),e.jsx("input",{ref:o,type:"file",multiple:!0,hidden:!0,onChange:i=>i.target.files&&m(i.target.files)})]}),e.jsxs("div",{onDragOver:i=>{i.preventDefault(),c(!0)},onDragLeave:()=>c(!1),onDrop:w,className:`rounded-lg border-2 border-dashed p-6 text-center text-sm transition ${p?"border-primary bg-primary/5 text-foreground":"border-muted-foreground/30 text-muted-foreground"}`,children:[e.jsx(W,{className:"h-5 w-5 mx-auto mb-2 opacity-60"}),"Drag & drop files here, or use the button above. Max 15 MB each."]})]})}),n.length===0?e.jsx(b,{className:"border-dashed",children:e.jsx(N,{className:"p-8 text-center text-sm text-muted-foreground",children:"No documents yet. Upload leases, tax bills, insurance, closing docs and more."})}):e.jsx(b,{children:e.jsx(N,{className:"p-0 divide-y",children:n.map(i=>e.jsxs("div",{className:"flex items-center justify-between gap-3 p-4 text-sm",children:[e.jsxs("div",{className:"flex items-center gap-3 min-w-0",children:[e.jsx(Ce,{className:"h-4 w-4 text-muted-foreground flex-shrink-0"}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"font-medium truncate",children:i.filename}),e.jsxs("div",{className:"text-xs text-muted-foreground",children:[e.jsx("span",{className:"capitalize",children:i.document_type.replace(/_/g," ")})," · ",ft(i.uploaded_at),i.size_bytes?` · ${gt(i.size_bytes)}`:""]})]})]}),e.jsxs("div",{className:"flex items-center gap-1 flex-shrink-0",children:[e.jsx(M,{size:"sm",variant:"ghost",className:"h-8 w-8 p-0",disabled:a===i.id,onClick:()=>E(i),"aria-label":"Download",children:a===i.id?e.jsx(V,{className:"h-4 w-4 animate-spin"}):e.jsx(Se,{className:"h-4 w-4"})}),e.jsx(M,{size:"sm",variant:"ghost",className:"h-8 w-8 p-0 text-muted-foreground hover:text-destructive",disabled:a===i.id,onClick:()=>D(i),"aria-label":"Delete",children:e.jsx(re,{className:"h-4 w-4"})})]})]},i.id))})})]})}function yt(s,n,t,o){const p=t?new Date(t):s,c=o?new Date(o):n,d=p>s?p:s,x=c<n?c:n;
1if(x<=d)return 0;const u=(x.getFullYear()-d.getFullYear())*12+(x.getMonth()-d.getMonth())+(x.getDate()>=d.getDate()?1:0);return Math.max(0,Math.min(12,u))}function _t(s,n){if(!s.has_mortgage)return 0;const t=Number(s.loan_original_principal??0),o=Number(s.loan_rate_apr??0),p=Number(s.loan_term_years??0),c=s.loan_start_date;if(!t||!o||!p||!c)return 0;const d=new Date(c),x=Ue(t,o,p),u=o/12;let _=0;const a=new Date(n+1,0,1);for(let l=0;l<12;l++){const m=new Date(n,l,1);if(m<d||m>=a)continue;const w=ze(d,m),D=Ve(t,o,p,w)*u;D>0&&x>0&&(_+=Math.min(D,x))}return Math.round(_)}async function jt(s,n){const{data:t}=await f.from("investor_owned_properties").select("*").eq("user_id",s).eq("is_rented",!0).neq("status","archived");if(!t||t.length===0)return[];const o=t.map(a=>a.id),[{data:p},{data:c}]=await Promise.all([f.from("investor_owned_property_rental").select("*").in("property_id",o),f.from("investor_owned_property_improvements").select("*").in("property_id",o)]),d=new Map;(p??[]).forEach(a=>d.set(a.property_id,a));const x=new Map;(c??[]).forEach(a=>{if(new Date(a.improvement_date).getFullYear()!==n)return;const m=x.get(a.property_id)??[];m.push(a),x.set(a.property_id,m)});const u=new Date(n,0,1),_=new Date(n+1,0,1);return t.map(a=>{const l=d.get(a.id),m=Number((l==null?void 0:l.monthly_rent)??0),E=(l?yt(u,_,l.lease_start,l.lease_end):12)||12,D=m*E,i=Number((l==null?void 0:l.vacancy_pct)??.05),r=Math.round(D*(1-i)),j=_t(a,n),S=Math.round(Number((l==null?void 0:l.property_tax_yearly)??0)),y=Math.round(Number((l==null?void 0:l.insurance_yearly)??0)),T=Math.round(Number((l==null?void 0:l.hoa_monthly)??0)*12),C=Math.round(D*Number((l==null?void 0:l.management_pct_of_rent)??0)),$=Math.round(D*Number((l==null?void 0:l.maintenance_pct_of_rent)??0)),P=j+S+y+T+C+$,F=r-P,L=Math.round((x.get(a.id)??[]).reduce((ae,ne)=>ae+Number(ne.cost??0),0));return{property:a.address_line1,address:[a.address_line1,a.address_line2].filter(Boolean).join(" "),city_state:`${a.city}, ${a.state} ${a.zip}`,rents_received:r,mortgage_interest:j,property_tax:S,insurance:y,hoa:T,management_fees:C,maintenance:$,total_expenses:P,net_income:F,capitalized_improvements:L}})}const Q=[{key:"property",label:"Property"},{key:"address",label:"Address"},{key:"city_state",label:"City/State/ZIP"},{key:"rents_received",label:"Rents received"},{key:"mortgage_interest",label:"Mortgage interest"},{key:"property_tax",label:"Property tax"},{key:"insurance",label:"Insurance"},{key:"hoa",label:"HOA"},{key:"management_fees",label:"Management fees"},{key:"maintenance",label:"Repairs & maintenance"},{key:"total_expenses",label:"Total expenses"},{key:"net_income",label:"Net rental income"},{key:"capitalized_improvements",label:"Capitalized improvements (not expensed)"}];function ee(s){if(s==null)return"";const n=String(s);return/[",\n]/.test(n)?`"${n.replace(/"/g,'""')}"`:n}function bt(s,n){const t=Q.map(c=>ee(c.label)).join(","),o=s.map(c=>Q.map(d=>ee(c[d.key])).join(",")).join(`
2`);return`Schedule E summary - Tax year ${n}
3Generated ${new Date().toISOString().slice(0,10)} - HomeLens AI
4Note: figures are estimates derived from your saved rental data. Verify with your accountant before filing.
5
6`+t+`
7`+o+`
8`}function wt(s,n){const t=bt(s,n),o=new Blob([t],{type:"text/csv;charset=utf-8;"}),p=URL.createObjectURL(o),c=document.createElement("a");c.href=p,c.download=`schedule-e-${n}.csv`,document.body.appendChild(c),c.click(),document.body.removeChild(c),URL.revokeObjectURL(p)}function Nt({variant:s="outline"}){const[n,t]=h.useState(null),o=new Date().getFullYear(),p=[o-1,o,o-2];async function c(d){var x;t(d);try{const{data:u}=await f.auth.getUser(),_=(x=u==null?void 0:u.user)==null?void 0:x.id;if(!_){g.error("You must be signed in");return}const a=await jt(_,d);if(a.length===0){g.info(`No rented properties found for ${d}.`);return}wt(a,d),g.success(`Schedule E for ${d} exported`),O("owned_property_tax_export",{year:d,property_count:a.length})}catch(u){g.error((u==null?void 0:u.message)??"Export failed")}finally{t(null)}}return e.jsxs(Ze,{children:[e.jsx(Qe,{asChild:!0,children:e.jsxs(M,{size:"sm",variant:s,className:"gap-2",children:[n!==null?e.jsx(V,{className:"h-4 w-4 animate-spin"}):e.jsx(ke,{className:"h-4 w-4"}),"Tax export"]})}),e.jsxs(et,{align:"end",className:"w-56",children:[e.jsx(tt,{children:"Schedule E (CSV)"}),e.jsx(st,{}),p.map(d=>e.jsxs(rt,{onClick:()=>c(d),disabled:n===d,className:"cursor-pointer",children:["Tax year ",d]},d))]})]})}function k(s,n={}){if(!Number.isFinite(s))return"$0";const{compact:t=!1,sign:o=!1}=n,p=s<0?"-":o&&s>0?"+":"",c=Math.abs(s);return t&&c>=1e6?`${p}$${(c/1e6).toFixed(2)}M`:t&&c>=1e3?`${p}$${Math.round(c/1e3)}
8k`:`${p}$${Math.round(c).toLocaleString()}`}function q(s,n=1){return s==null||!Number.isFinite(s)?"—":`${(s*100).toFixed(n)}%`}function z(s){return s?new Date(s).toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"}):"—"}function Ot(){var l;const{id:s}=De(),n=Ee(),{data:t,loading:o,reload:p}=it(s),[c,d]=h.useState(!1),[x,u]=h.useState(!1),{loading:_}=Te();h.useEffect(()=>{s&&O("owned_property_viewed",{property_id:s})},[s]);async function a(){if(!s)return;u(!0);const{data:m,error:w}=await f.functions.invoke("property-valuation",{body:{property_id:s}});if(u(!1),w){g.error(w.message??"Could not refresh valuation");return}if(m!=null&&m.error){g.error(m.message??m.error);return}if(m!=null&&m.skipped){g.info(m.reason);return}g.success("Valuation refreshed"),p()}return e.jsxs("div",{className:"min-h-screen bg-background flex flex-col",children:[e.jsx(Me,{}),e.jsxs("div",{className:"flex flex-row flex-1",children:[e.jsx(Ye,{}),e.jsx("main",{className:"flex-1 min-w-0",children:e.jsxs("div",{className:"container mx-auto px-4 py-6 lg:py-8 max-w-6xl space-y-6",children:[e.jsx("div",{children:e.jsxs(M,{variant:"ghost",size:"sm",className:"gap-1 -ml-2",onClick:()=>n("/investor/properties"),children:[e.jsx(lt,{className:"h-4 w-4"})," My properties"]})}),_?e.jsx(b,{className:"h-96 animate-pulse bg-muted/30"}):e.jsx(nt,{feature:"INVESTOR_CALCULATOR",featureName:"Property Details",description:"Track equity, refi opportunities, rental income, alerts and tax exports for this property — included with the Investor plan.",children:o||!t?e.jsx(b,{className:"h-96 animate-pulse bg-muted/30"}):e.jsxs(e.Fragment,{children:[e.jsxs("header",{className:"flex flex-wrap items-start justify-between gap-4",children:[e.jsxs("div",{className:"flex gap-4 items-start",children:[e.jsx("div",{className:"w-32 h-24 rounded-lg overflow-hidden bg-muted flex-shrink-0",children:t.property.primary_photo_url?e.jsx("img",{src:t.property.primary_photo_url,alt:t.property.address_line1,className:"w-full h-full object-cover"}):e.jsx("div",{className:"w-full h-full flex items-center justify-center text-muted-foreground",children:e.jsx($e,{className:"h-8 w-8"})})}),e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-semibold tracking-tight",children:t.property.address_line1}),e.jsxs("div",{className:"text-sm text-muted-foreground mt-1",children:[t.property.city,", ",t.property.state," ",t.property.zip," ·"," ",at[t.property.property_type]]}),e.jsxs("div",{className:"flex gap-2 mt-2",children:[t.property.is_primary_residence&&e.jsx(U,{variant:"secondary",children:"Primary residence"}),t.property.is_rented&&e.jsx(U,{variant:"secondary",children:"Rented"}),!t.property.has_mortgage&&e.jsx(U,{variant:"outline",children:"Owned outright"})]})]})]}),t.property.is_rented&&e.jsx("div",{className:"flex items-center gap-2",children:e.jsx(Nt,{})})]}),s&&e.jsx(dt,{propertyId:s,alerts:t.alerts,onChanged:p}),e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-4 gap-3",children:[e.jsx(b,{children:e.jsxs(N,{className:"p-4",children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:"Current value"}),e.jsx("div",{className:"text-xl font-semibold mt-1",children:k(t.metrics.currentValue,{compact:!0})}),e.jsxs("div",{className:"flex items-center gap-2 mt-1",children:[e.jsxs("button",{onClick:()=>d(!0),className:"text-[11px] text-primary inline-flex items-center gap-1 hover:underline",children:[e.jsx(ot,{className:"h-3 w-3"})," Edit"]}),e.jsxs("button",{onClick:a,disabled:x,className:"text-[11px] text-muted-foreground inline-flex items-center gap-1 hover:text-foreground disabled:opacity-50",children:[e.jsx(H,{className:`h-3 w-3 ${x?"animate-spin":""}`}),x?"Refreshing…":"Refresh"]})]}),t.property.current_value_source&&e.jsx("div",{className:"text-[10px] text-muted-foreground mt-1 capitalize",children:t.property.current_value_source.replace(/_/g," ")})]})}),e.jsx(b,{children:e.jsxs(N,{className:"p-4",children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:"Equity"}),e.jsx("div",{className:"text-xl font-semibold mt-1",children:k(t.metrics.equity,{compact:!0})}),e.jsxs("div",{className:"text-[11px] text-muted-foreground mt-1",children:[q(t.metrics.equityPct)," of value"]})]})}),e.jsx(b,{children:e.jsxs(N,{className:"p-4",children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:"Monthly cash flow"}),e.jsx("div",{className:`text-xl font-semibold mt-1 ${t.property.is_rented&&t.metrics.monthlyCashFlow<0?"text-destructive":t.property.is_rented&&t.metrics.monthlyCashFlow>0?"text-emerald-600":""}`,children:t.property.is_rented?k(t.metrics.monthlyCashFlow,{sign:!0}):"—"}),e.jsx("div",{className:"text-[11px] text-muted-foreground mt-1",children:t.property.is_rented?"After PITI + expenses":"Not rented"})]})}),e.jsx(b,{children:e.jsxs(N,{className:"p-4",children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:"Cap rate"}),e.jsx("div",{className:"text-xl font-semibold mt-1",children:q(t.metrics.capRate)}),e.jsx("div",{className:"text-[11px] text-muted-foreground mt-1",children:"NOI / value"})]})})]}),e.jsxs(Re,{defaultValue:"overview",children:[e.jsxs(Ae,{className:"flex-wrap h-auto",children:[e.jsx(R,{value:"overview",children:"Overview"}),e.jsx(R,{value:"acquisition",children:"Acquisition & loan"}),e.jsx(R,{value:"rental",children:"Rental"}),e.jsx(R,{value:"improvements",children:"Improvements"}),e.jsx(R,{value:"events",children:"Events"}),e.jsx(R,{value:"documents",children:"Documents"}),e.jsx(R,{value:"chat",children:"Ask AI"})]}
8),e.jsxs(A,{value:"overview",className:"space-y-4 mt-4",children:[e.jsxs(b,{children:[e.jsx(I,{children:e.jsx(B,{className:"text-base",children:"Returns since purchase"})}),e.jsxs(N,{className:"grid grid-cols-2 md:grid-cols-4 gap-4 text-sm",children:[e.jsx(v,{label:"Appreciation",value:k(t.metrics.returns.appreciation,{sign:!0,compact:!0})}),e.jsx(v,{label:"Loan paydown",value:k(t.metrics.returns.principalPaydown,{compact:!0})}),e.jsx(v,{label:"Cash flow",value:k(t.metrics.returns.cashFlow,{sign:!0,compact:!0})}),e.jsx(v,{label:"Total return",value:k(t.metrics.returns.total,{sign:!0,compact:!0}),accent:!0}),e.jsx(v,{label:"Cash invested",value:k(t.metrics.returns.cashInvested,{compact:!0})}),e.jsx(v,{label:"Total ROI on cash",value:q(t.metrics.returns.totalROI)})]})]}),e.jsxs(b,{children:[e.jsx(I,{children:e.jsx(B,{className:"text-base",children:"Property facts"})}),e.jsxs(N,{className:"grid grid-cols-2 md:grid-cols-4 gap-4 text-sm",children:[e.jsx(v,{label:"Beds",value:t.property.beds??"—"}),e.jsx(v,{label:"Baths",value:t.property.baths??"—"}),e.jsx(v,{label:"Sqft",value:((l=t.property.sqft)==null?void 0:l.toLocaleString())??"—"}),e.jsx(v,{label:"Year built",value:t.property.year_built??"—"})]})]})]}),e.jsxs(A,{value:"acquisition",className:"space-y-4 mt-4",children:[e.jsxs(b,{children:[e.jsx(I,{children:e.jsx(B,{className:"text-base",children:"Acquisition"})}),e.jsxs(N,{className:"grid grid-cols-2 md:grid-cols-3 gap-4 text-sm",children:[e.jsx(v,{label:"Purchase price",value:k(t.property.purchase_price,{compact:!0})}),e.jsx(v,{label:"Purchase date",value:z(t.property.purchase_date)}),e.jsx(v,{label:"Down payment",value:k(Number(t.property.down_payment??0),{compact:!0})}),e.jsx(v,{label:"Closing costs",value:k(Number(t.property.closing_costs??0),{compact:!0})})]})]}),t.property.has_mortgage?e.jsxs(b,{children:[e.jsx(I,{children:e.jsx(B,{className:"text-base",children:"Loan"})}),e.jsxs(N,{className:"grid grid-cols-2 md:grid-cols-3 gap-4 text-sm",children:[e.jsx(v,{label:"Original principal",value:k(Number(t.property.loan_original_principal??0),{compact:!0})}),e.jsx(v,{label:"Rate (APR)",value:t.property.loan_rate_apr!=null?`${(Number(t.property.loan_rate_apr)*100).toFixed(3)}%`:"—"}),e.jsx(v,{label:"Term",value:t.property.loan_term_years?`${t.property.loan_term_years} yrs`:"—"}),e.jsx(v,{label:"Start date",value:z(t.property.loan_start_date)}),e.jsx(v,{label:"Current balance",value:k(t.metrics.loanBalance,{compact:!0}),accent:!0})]})]}):e.jsx(b,{children:e.jsx(N,{className:"p-4 text-sm text-muted-foreground",children:"Owned outright — no mortgage."})})]}),e.jsx(A,{value:"rental",className:"space-y-4 mt-4",children:t.property.is_rented&&t.rental?e.jsxs(b,{children:[e.jsx(I,{children:e.jsx(B,{className:"text-base",children:"Rental details"})}),e.jsxs(N,{className:"grid grid-cols-2 md:grid-cols-3 gap-4 text-sm",children:[e.jsx(v,{label:"Monthly rent",value:k(Number(t.rental.monthly_rent??0))}),e.jsx(v,{label:"Property tax / yr",value:k(Number(t.rental.property_tax_yearly??0))}),e.jsx(v,{label:"Insurance / yr",value:k(Number(t.rental.insurance_yearly??0))}),e.jsx(v,{label:"HOA / mo",value:k(Number(t.rental.hoa_monthly??0))}),e.jsx(v,{label:"Maintenance",value:q(Number(t.rental.maintenance_pct_of_rent??.08))}),e.jsx(v,{label:"Management",value:q(Number(t.rental.management_pct_of_rent??.08))}),e.jsx(v,{label:"Vacancy",value:q(Number(t.rental.vacancy_pct??.05))})]})]}):e.jsx(b,{children:e.jsx(N,{className:"p-6 text-center text-sm text-muted-foreground",children:t.property.is_primary_residence?"This is your primary residence — not currently rented.":"Not currently rented. Add rental details to track cash flow."})})}),e.jsx(A,{value:"improvements",className:"mt-4",children:t.improvements.length===0?e.jsx(te,{text:"No improvements logged yet."}):e.jsx(b,{children:e.jsx(N,{className:"p-0 divide-y",children:t.improvements.map(m=>e.jsxs("div",{className:"flex justify-between p-4 text-sm",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-medium",children:m.description}),e.jsxs("div",{className:"text-xs text-muted-foreground",children:[z(m.improvement_date),m.category?` · ${m.category}`:""]})]}),e.jsx("div",{className:"font-semibold",children:k(Number(m.cost))})]},m.id))})})}),e.jsx(A,{value:"events",className:"mt-4",children:t.events.length===0?e.jsx(te,{text:"No timeline events yet."}):e.jsx(b,{children:e.jsx(N,{className:"p-0 divide-y",children:t.events.map(m=>e.jsxs("div",{className:"flex justify-between p-4 text-sm",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-medium capitalize",children:m.event_type.replace(/_/g," ")}),m.note&&e.jsx("div",{className:"text-xs text-muted-foreground",children:m.note})]}),e.jsx("div",{className:"text-xs text-muted-foreground",children:z(m.event_date)})]},m.id))})})}),e.jsx(A,{value:"documents",className:"mt-4",children:s&&e.jsx(vt,{propertyId:s,documents:t.documents,onChanged:p})}),e.jsx(A,{value:"chat",className:"mt-4",children:s&&e.jsx(pt,{propertyId:s})})]}),e.jsx(ct,{open:c,onOpenChange:d,property:t.property,onSaved:()=>p()})]})})]})})]})]})}function v({label:s,value:n,accent:t}){return e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:s}),e.jsx("div",{className:`mt-0.5 font-semibold ${t?"text-primary":""}`,children:n})]})}function te({text:s}){return e.jsx(b,{className:"border-dashed",children:e.jsxs(N,{className:"p-8 text-center text-sm text-muted-foreground flex flex-col items-center gap-2",children:[e.jsx(Pe,{className:"h-5 w-5 opacity-50"}),s]})})}export{Ot as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.