1import{Q as p,p as g,r as h,j as e,D as x,u as f,n as y,a as v,N as b,Y as m,b as j}from"./index-CBlrF05f.js";import{T,M as k}from"./MapCard-Dlkd07J7.js";import{R as S,C as H,X as L,Y as R,T as w}from"./CartesianChart-B43KCWNC.js";import{L as C}from"./LineChart-DK_7usio.js";import{L as D}from"./Line-B3byoFk9.js";import{I as M}from"./InvestmentDisclaimer-5Lws-ZyO.js";import{F}from"./flame-BR9M2_wT.js";import"./maplibre-gl-EKlSNkuy.js";import"./index-BNgfD7Pl.js";import"./refresh-cw-DsPZrxsL.js";async function I(t="en"){return p.get(`/api/roi-heatmap?language=${encodeURIComponent(t)}`)}async function z(t="en"){return p.get(`/api/roi-trend?language=${encodeURIComponent(t)}`)}const A={year:"2-digit",month:"short"},W=15e3;function K({language:t,theme:a,t:r}){const{data:n,isLoading:l,error:s}=g({queryKey:["roi-trend",t],queryFn:()=>z(t),staleTime:36e5,refetchInterval:i=>i.state.data?.status==="computing"?W:!1}),o=n?.status==="computing",d=h.useMemo(()=>(n?.points||[]).map(i=>({date:i.date,label:new Date(`${i.date}T00:00:00Z`).toLocaleDateString(t,{...A,timeZone:"UTC"}),value:i.value})),[n,t]),u={background:"var(--bg-card)",border:"1px solid var(--border)",borderRadius:"var(--radius-lg, 16px)",padding:"var(--sp-5)"},c={fontSize:11,fill:a.textMuted};return e.jsxs("div",{style:u,children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:"var(--sp-2)"},children:[e.jsx(x,{size:18,style:{color:a.accent},"aria-hidden":!0}),e.jsx("h2",{style:{fontSize:"var(--fs-16)",fontWeight:600,margin:0},children:r("roiHeatmap.trendTitle","Return over time")})]}),e.jsx("p",{style:{color:"var(--text-secondary)",fontSize:"var(--fs-13)",margin:"var(--sp-2) 0 var(--sp-4)",maxWidth:"78ch"},children:r("roiHeatmap.trendDesc","What a flat bought outright to rent out earns in its first year after costs and rental tax, as a share of everything paid, month by month.")}),(l||o)&&e.jsx("div",{style:{height:280,display:"grid",placeItems:"center",color:"var(--text-muted)",textAlign:"center",padding:"0 var(--sp-4)"},children:o?r("roiHeatmap.computing","Valuing every listing that has left the market. This runs once a month and takes a few minutes."):r("common.loading","Loadingâ¦")}),s&&!o&&e.jsx("div",{style:{height:280,display:"grid",placeItems:"center",color:"var(--text-muted)",textAlign:"center",padding:"0 var(--sp-4)"},children:s?.detail||r("roiHeatmap.trendUnavailable","The return curve has not been built on this host yet.")}),!l&&!o&&!s&&d.length>0&&e.jsx("div",{style:{width:"100%",height:280},children:e.jsx(S,{children:e.jsxs(C,{data:d,margin:{top:8,right:16,left:8,bottom:8},children:[e.jsx(H,{stroke:a.border,strokeDasharray:"3 3",vertical:!1}),e.jsx(L,{dataKey:"label",tick:c,axisLine:{stroke:a.border},tickLine:!1,minTickGap:24}),e.jsx(R,{tick:c,axisLine:!1,tickLine:!1,width:48,tickFormatter:i=>`${i.toFixed(1)}%`,domain:["dataMin - 0.3","dataMax + 0.3"]}),e.jsx(w,{formatter:i=>[`${i.toFixed(2)}%`,n?.label||r("roiHeatmap.trendTitle","Return over time")],contentStyle:{background:a.bgCardSolid,border:`1px solid ${a.borderStrong}`,borderRadius:"8px",fontSize:"12px"}}),e.jsx(D,{type:"monotone",dataKey:"value",stroke:a.accent,strokeWidth:2,dot:!1,activeDot:{r:4}})]})})})]})}function Y(){const{t,i18n:a}=f(),{isDark:r}=y(),{user:n,permissions:l}=v(),s=a.language||"en",o=h.useMemo(()=>({name:"roi_heatmap",icon:F,titleKey:"roiHeatmap.title",descKey:"roiHeatmap.desc",computingKey:"roiHeatmap.computing",colorStops:T,formatValue:d=>`${d.toFixed(1)}%`,circlePaint:{"circle-radius":["interpolate",["linear"],["zoom"],6,2,10,5,14,10],"circle-opacity":.35,"circle-stroke-width":0}}),[]);return e.jsxs("div",{style:{minHeight:"100vh",display:"flex",flexDirection:"column",background:"var(--bg)"},children:[e.jsx(b,{user:n,permissions:l}),e.jsx("main",{style:{flex:1,paddingTop:"calc(var(--nav-clearance) + 2em)"},children:e.jsxs("div",{className:"pq-container",style:{display:"flex",flexDirection:"column",gap:"var(--sp-6)",paddingBottom:"var(--sp-12)"},children:[e.jsxs("div",{style:{textAlign:"center"},children:[e.jsx("h1",{style:{fontFamily:"var(--font-display)",fontSize:"clamp(28px, 4.5vw, 52px)",fontWeight:400,lineHeight:1,margin:0},children:t("roiHeatmap.title","Rental return map")}),e.jsx("p",{style:{color:"var(--text-secondary)",margin:"var(--sp-3) auto 0",maxWidth:"62ch"},children:t("roiHeatmap.subtitle","Median first-year net rental yield after tax of listings that have left the market, each bought outright at the modelsâ valuation on their latest date, so that only location and the flat itself differ.")})]}),e.jsx(k,{mapConfig:o,queryKey:["roi-heatmap",s],queryFn:()=>I(s),theme:m,isDark:r,t}),e.jsx(K,{language:s,theme:m,t}),e.jsx(M,{t,style:{maxWidth:"78ch"}}),e.jsx("p",{style:{fontSize:"var(--fs-13)",color:"var(--text-muted)",maxWidth:"78ch"},children:t("roiHeatmap.caveat","One point per address. A listing counts as delisted when it stops being re-scraped, which covers withdrawals and expiries as well as sales. The yield is measured against the modelâs valuation plus stamp duty and fees, after 90% occupancy, 1% of the value a year for maintenance, the listingâs common charges and 15% rental income tax under the cheaper cost method â the same buy-to-let model as the rent browser. Half of the addresses carry a single listing, so their figure is that one listingâs yield.")})]})}),e.jsx(j,{})]})}
1export{Y 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.