PageSourceSearch

https://hellojimo.com/assets/Properties-Cc9ZRfNY.js

js hellojimo.com collected 2026-10-09 22:02:19 UTC 15,743 bytes, 1 lines download raw bytes

1import{j as t,r as a}from"./react-Bwt1xbxH.js";import{d as ye,u as Ne}from"./router-BNQw1M6O.js";import{i as D,s as $,B as J,I as _e,S as F,n as E,o as O,p as U,q as m,d as Se}from"./index-npYIF1Cu.js";import{T as re,a as V}from"./toggle-group-D2PIxW8-.js";import{u as Ce}from"./UnitCard-BcDNH-eA.js";import{P as ie}from"./PortfolioCard-DVpeLy4e.js";import{C as Le}from"./card-BRwga5uZ.js";import{B as Ie}from"./badge-sYAW1rF8.js";import{T as Me,a as Ae,b as ne,c as q,d as ke,e as G}from"./table-B3RCpm3b.js";import{m as $e}from"./melSeverity-Yvf0NuuT.js";import{H as oe}from"./house-BH0cpA_T.js";import{B as Pe}from"./building-2-Dn9H_Pz_.js";import{u as Te}from"./usePortfolioImages-UH_E88Zi.js";import{A as Be}from"./AddPropertyDialog-olUy4wXB.js";import{a as Fe}from"./useProperties-kkYmXkP7.js";import{u as Ee}from"./useEntities-C_YE4bNz.js";import{P as Oe}from"./plus-9Ubnrunu.js";import{B as Ue}from"./building-Bqmeq343.js";import{S as Ve}from"./search-BHW_pAM-.js";import{F as qe}from"./filter-BXNCWizm.js";import{S as Ge}from"./settings-2-DQd8qMcJ.js";import{L as Re}from"./landmark-C2d-A9Yw.js";import{T as He}from"./triangle-alert-h178_mHH.js";import{L as ze}from"./layout-grid-8uiUIkdu.js";import{L as Ke}from"./list-Zg6pnezv.js";import{A as Qe}from"./archive-Fefy2JGK.js";import"./vendor-Cpj98o6Y.js";import"./jspdf-Bi_e3ESl.js";import"./radix-i14q2oaY.js";import"./charts-BnGLdBFA.js";import"./ManagementBadges-DAx-lFn_.js";import"./shield-DBcSbGqI.js";import"./zap-C0_2nhmo.js";import"./AutopiloteUpsellButton-BdLo6oRU.js";import"./AutopiloteActivationDialog-CLdLKAGJ.js";import"./useAdminViewMode-XzGjeUa8.js";import"./autopilotePlans-CmZEd0o4.js";import"./sparkles-r_FjJCKP.js";import"./AutopiloteLimitDialog-DyORUozU.js";import"./JimoPricingGrid-DQOj40Y-.js";import"./GestionIntegraleRequestDialog-19ZpOQTy.js";import"./checkbox-DQnjaQhH.js";import"./scroll-area-D2MniAOt.js";import"./useBasePath-Cpb6rLY2.js";import"./useRentalMovements-DfQUXh0p.js";import"./layers-CckyFV4L.js";import"./users-Bb-GG5bK.js";import"./circle-alert-BGsHJ5cg.js";import"./trash-2-zDbTado7.js";import"./chevron-right-BkaZ9219.js";import"./octagon-alert-DT43okAO.js";import"./info-g4JRp16c.js";import"./sheet-tJrp0f1D.js";import"./arrow-right-CBcqDMWT.js";import"./AddTenantToUnitDialog-yXyWFe_M.js";import"./switch-Bmt8G_nu.js";import"./useTenants-CgmgaHru.js";import"./useRentGeneration-hYvcFyj4.js";import"./file-text-5SCb-fAv.js";import"./user-Cl1aWP8N.js";import"./mail-BkggEvKf.js";import"./phone-DAlqf0HB.js";import"./calendar-Cum5cp15.js";import"./euro-Dsa4ooPx.js";import"./calculator-Cx8ypyQL.js";import"./settings-Nrf3Io-u.js";import"./external-link-DJ2i7_fw.js";import"./user-check-DNjBNjf6.js";import"./OwnershipStep-CVYwmTxy.js";import"./radio-group-C_gDYn6h.js";import"./circle-EfUJypic.js";import"./map-pin-BdQZNC2_.js";import"./thermometer-DGrT1P73.js";import"./useEntityScope-CcGZG0YN.js";const le=({items:P,kpiHeaders:v})=>t.jsx(Le,{className:"overflow-x-auto",children:t.jsxs(Me,{children:[t.jsx(Ae,{children:t.jsxs(ne,{children:[t.jsx(q,{children:"Bien"}),t.jsx(q,{children:"Statut"}),v.map(n=>t.jsx(q,{className:"text-right",children:n},n)),t.jsx(q,{children:"Prochaine action"})]})}),t.jsx(ke,{children:P.map(n=>{const N=$e[n.alert?.severity??"neutral"],_=N.Icon,R=n.kind==="unit"?oe:Pe;return t.jsxs(ne,{className:"cursor-pointer",onClick:n.onOpen,children:[t.jsx(G,{children:t.jsxs("div",{className:"flex items-center gap-3 min-w-0",children:[t.jsx("div",{className:"w-10 h-10 rounded-md bg-muted overflow-hidden shrink-0 flex items-center justify-center",children:n.imageUrl?t.jsx("img",{src:n.imageUrl,alt:`Photo de ${n.title}`,loading:"lazy",className:"w-full h-full object-cover"}):t.jsx(R,{className:"w-4 h-4 text-muted-foreground opacity-60"})}),t.jsxs("div",{className:"min-w-0",children:[t.jsx("p",{className:"font-medium truncate",children:n.title}),n.subtitle&&t.jsx("p",{className:"text-xs text-muted-foreground truncate",children:n.subtitle})]})]})}),t.jsx(G,{children:n.statusBadge?t.jsx(Ie,{className:n.statusBadge.className,children:n.statusBadge.label}):t.jsx("span",{className:"text-sm text-muted-foreground",children:"—"})}),v.map((u,T)=>t.jsx(G,{className:"text-right text-sm",children:n.kpis[T]?.value??"—"},u)),t.jsx(G,{children:n.alert?t.jsxs("span",{className:`inline-flex items-start gap-1.5 text-sm ${N.text}`,children:[t.jsx(_,{className:"w-4 h-4 mt-0.5 shrink-0"}),n.alert.label]}):t.jsx("span",{className:"text-sm text-muted-foreground",children:"—"})})]},n.id)})})]})}),hs=()=>
1{const[P]=ye(),v=Ne(),[n,N]=a.useState(!1),[_,R]=a.useState(""),[u,T]=a.useState("all"),[b,ce]=a.useState("all"),[w,W]=a.useState("all"),[H,de]=a.useState("grid"),[L,me]=a.useState(()=>(typeof window<"u"?localStorage.getItem("properties-scope"):null)==="buildings"?"buildings":"units"),[I,ue]=a.useState("all"),[M,pe]=a.useState(!1),{data:f,isLoading:he}=Fe(),{data:X=[]}=Ee(),xe={apartment:"Appartement",house:"Maison",building:"Immeuble",colocation:"Colocation",commercial:"Local commercial",parking:"Stationnement / Garage"};a.useEffect(()=>{P.get("status")==="vacant"&&T("vacant")},[P]);const S=a.useMemo(()=>{const e=new Map;return(f||[]).forEach(s=>{s.owner_entity_id&&e.set(s.owner_entity_id,(e.get(s.owner_entity_id)||0)+1)}),e},[f]),z=a.useMemo(()=>X.filter(e=>S.has(e.id)),[X,S]),fe=a.useMemo(()=>{const e=[{value:"all",label:"Tous les propriétaires"},{value:"personal",label:"Personnel (nom propre)"}];return z.forEach(s=>{e.push({value:`entity:${s.id}`,label:`${s.name} (${S.get(s.id)||0})`})}),e},[z,S]);a.useEffect(()=>{localStorage.setItem("properties-scope",L)},[L]),a.useEffect(()=>{if(!w.startsWith("entity:"))return;const e=w.replace("entity:","");S.has(e)||W("all")},[w,S]);const Y=f?.filter(e=>e.status==="archived").length||0,g=a.useMemo(()=>f?.flatMap(e=>e.units?.map(s=>s.id)||[])||[],[f]),{data:Z=[]}=D({queryKey:["property-marketplace-listings",g],queryFn:async()=>{if(g.length===0)return[];const{data:e,error:s}=await $.from("marketplace_listings").select("unit_id").eq("is_active",!0).in("unit_id",g);if(s)throw s;return(e||[]).map(r=>r.unit_id)},enabled:g.length>0}),y=a.useMemo(()=>new Set(Z),[Z]),{data:ee=[]}=D({queryKey:["properties-active-exit-movements",g],queryFn:async()=>{if(g.length===0)return[];const{data:e,error:s}=await $.from("rental_movements").select("unit_id").eq("movement_type","exit").is("closed_at",null).in("unit_id",g);if(s)throw s;return[...new Set((e||[]).map(r=>r.unit_id))]},enabled:g.length>0}),te=a.useMemo(()=>new Set(ee),[ee]),j=f?.filter(e=>{const s=e.status||"active";if(M){if(s!=="archived")return!1}else if(s==="archived")return!1;const r=_.toLowerCase(),h=(e.units||[]).flatMap(o=>(o.tenants||[]).map(k=>`${k.first_name} ${k.last_name}`.toLowerCase())),l=e.entity?.name?.toLowerCase()||[e.owner_profile?.first_name,e.owner_profile?.last_name].filter(Boolean).join(" ").toLowerCase()||"",c=e.name.toLowerCase().includes(r)||e.address.toLowerCase().includes(r)||e.city.toLowerCase().includes(r)||l.includes(r)||h.some(o=>o.includes(r));let d=!0;const i=e.units||[];u==="vacant"?d=i.some(o=>o.status!=="occupied"):u==="occupied"?d=i.length>0&&i.every(o=>o.status==="occupied"):u==="marketplace"&&(d=i.some(o=>y.has(o.id)));let x=!0;b!=="all"&&(x=i.some(o=>{const k=!!o.autopilote_enabled;return b==="integrale"?o.management_mode==="integrale":b==="autopilote"?o.management_mode==="autopilote"&&k:o.management_mode==="autopilote"&&!k}));let Q=!0;if(w==="personal")Q=e.owner_type==="user";else if(w.startsWith("entity:")){const o=w.replace("entity:","");Q=e.owner_entity_id===o}return c&&d&&x&&Q})||[],C=a.useMemo(()=>(j||[]).flatMap(e=>(e.units||[]).map(s=>({unit:s,property:e}))),[j]),ge=a.useMemo(()=>(f||[]).filter(e=>(e.status||"active")==="archived"===M).reduce((e,s)=>e+(s.units?.length||0),0),[f,M]),B=a.useMemo(()=>C.map(({unit:e})=>e.id),[C]),{data:p={incidents:new Set,rentLate:new Set}}=D({queryKey:["properties-units-alerts",B],enabled:B.length>0,queryFn:async()=>{const[{data:e},{data:s}]=await Promise.all([$.from("incidents").select("unit_id").in("unit_id",B).not("status","in","(cloture,supprime)"),$.from("leases").select("id, unit_id").in("unit_id",B).eq("status","active")]),r=new Map;(s||[]).forEach(l=>r.set(l.id,l.unit_id));const h=new Set;if(r.size>0){const{data:l}=await $.from("rent_schedules").select("lease_id, status").in("lease_id",Array.from(r.keys())).in("status",["late","unpaid"]);(l||[]).forEach(c=>{const d=r.get(c.lease_id);d&&h.add(d)})}
1return{incidents:new Set((e||[]).map(l=>l.unit_id)),rentLate:h}}}),je=e=>e.management_mode==="integrale"?"integrale":e.autopilote_enabled?"autopilote":"libre",K=a.useMemo(()=>{const e=_.toLowerCase();return C.filter(({unit:s,property:r})=>{const h=(s.tenants||[]).map(x=>`${x.first_name} ${x.last_name}`.toLowerCase()).join(" "),l=!e||[s.name,r.name,r.address,r.city,h].filter(Boolean).some(x=>x.toLowerCase().includes(e));let c=!0;u==="vacant"?c=s.status!=="occupied":u==="occupied"?c=s.status==="occupied":u==="marketplace"&&(c=y.has(s.id));const d=b==="all"||je(s)===b;let i=!0;return I==="rent"?i=p.rentLate.has(s.id):I==="incident"?i=p.incidents.has(s.id):I==="action"&&(i=p.rentLate.has(s.id)||p.incidents.has(s.id)),l&&c&&d&&i})},[C,_,u,b,I,p,y]),ve=a.useMemo(()=>(j||[]).map(e=>e.id),[j]),be=a.useMemo(()=>C.map(({unit:e})=>e.id),[C]),{data:A}=Te(ve,be),we=e=>p.rentLate.has(e)?{label:"Impayé — loyer en retard",severity:"red"}:p.incidents.has(e)?{label:"Incident en cours à traiter",severity:"red"}:null,se=a.useMemo(()=>K.map(({unit:e,property:s})=>{const r=(e.monthly_rent||0)+(e.charges||0),h=(e.tenants||[]).map(i=>`${i.first_name} ${i.last_name}`).join(", "),l=e.status==="occupied",c=te.has(e.id),d=e.management_mode==="integrale"?"JIMO":e.autopilote_enabled?"Autopilote":"Libre";return{id:e.id,kind:"unit",title:e.name,subtitle:`${s.name}${s.city?` · ${s.city}`:""}`,meta:s.address,imageUrl:A?.byUnit[e.id]||A?.byProperty[s.id]||null,statusBadge:{label:c?"Sortie en cours":Ce[e.status||"vacant"]?.label||"Vacant",className:c?"bg-warning text-warning-foreground border-transparent":l?"bg-success text-success-foreground border-transparent":"bg-warning text-warning-foreground border-transparent"},cornerBadge:y.has(e.id)?"En diffusion":void 0,kpis:[{label:"Loyer CC",value:r>0?`${r.toLocaleString("fr-FR")} €`:"—"},{label:l?"Locataire":"Ancien locataire",value:h||"—"},{label:"Gestion",value:d}],alert:we(e.id),ctaLabel:"Ouvrir le lot",onOpen:()=>v(`/dashboard/properties/${s.id}/units/${e.id}`)}}),[K,A,y,te,p,v]),ae=a.useMemo(()=>(j||[]).map(e=>{const s=e.units||[],r=s.reduce((i,x)=>i+(x.monthly_rent||0)+(x.charges||0),0),h=s.filter(i=>i.status==="occupied").length,l=s.length>0?Math.round(h/s.length*100):0,c=s.some(i=>p.incidents.has(i.id)),d=s.some(i=>p.rentLate.has(i.id));return{id:e.id,kind:"building",title:e.name,subtitle:`${e.address}${e.city?`, ${e.city}`:""}`,meta:xe[e.property_type]||e.property_type,imageUrl:A?.byProperty[e.id]||null,statusBadge:{label:l===100?"Complet":l>=50?"À surveiller":"Vacance",className:l===100?"bg-success text-success-foreground border-transparent":l>=50?"bg-warning text-warning-foreground border-transparent":"bg-destructive text-destructive-foreground border-transparent"},cornerBadge:s.some(i=>y.has(i.id))?"En diffusion":void 0,kpis:[{label:"Lots",value:s.length},{label:"Loyer CC",value:r>0?`${r.toLocaleString("fr-FR")} €`:"—"},{label:"Occupation",value:`${l}%`}],alert:c?{label:"Incident en cours sur un lot",severity:"red"}:d?{label:"Loyer en retard sur un lot",severity:"amber"}:null,ctaLabel:"Ouvrir le bien",onOpen:()=>v(`/dashboard/properties/${e.id}`)}}),[j,A,y,p,v]);return t.jsxs("div",{className:"space-y-6",children:[t.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:[t.jsxs("div",{children:[t.jsx("h1",{className:"text-2xl font-display font-semibold text-foreground",children:"Mes biens"}),t.jsx("p",{className:"text-muted-foreground",children:"Gérez votre portefeuille immobilier"})]}),t.jsxs(J,{variant:"accent",onClick:()=>N(!0),children:[t.jsx(Oe,{className:"w-4 h-4 mr-2"}),"Ajouter un bien"]})]}),t.jsxs(re,{type:"single",value:L,onValueChange:e=>e&&me(e),className:"justify-start",children:[t.jsxs(V,{value:"buildings","aria-label":"Vue immeubles",className:"gap-2 px-4",children:[t.jsx(Ue,{className:"h-4 w-4"}),"Immeubles (",j.length,")"]}),t.jsxs(V,{value:"units","aria-label":"Vue lots",className:"gap-2 px-4",children:[t.jsx(oe,{className:"h-4 w-4"}),"Lots (",ge,")"]})]}),t.jsxs("div",{className:"flex flex-col sm:flex-row flex-wrap gap-3",children:[t.jsxs("div",{className:"relative flex-1 min-w-[200px]",children:[t.jsx(Ve,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground"}),t.jsx(_e,{placeholder:"Rechercher un bien...",className:"pl-10",value:_,onCh
1ange:e=>R(e.target.value)})]}),t.jsxs(F,{value:u,onValueChange:T,children:[t.jsxs(E,{className:"w-[160px]",children:[t.jsx(qe,{className:"w-4 h-4 mr-2"}),t.jsx(O,{placeholder:"Statut"})]}),t.jsxs(U,{children:[t.jsx(m,{value:"all",children:"Tous"}),t.jsx(m,{value:"vacant",children:"Vacants"}),t.jsx(m,{value:"occupied",children:"Occupés"}),t.jsx(m,{value:"marketplace",children:"En diffusion"})]})]}),t.jsxs(F,{value:b,onValueChange:ce,children:[t.jsxs(E,{className:"w-[180px]",children:[t.jsx(Ge,{className:"w-4 h-4 mr-2"}),t.jsx(O,{placeholder:"Mode de gestion"})]}),t.jsxs(U,{children:[t.jsx(m,{value:"all",children:"Tous les modes"}),t.jsx(m,{value:"integrale",children:"Gestion intégrale JIMO"}),t.jsx(m,{value:"libre",children:"Gestion libre"}),t.jsx(m,{value:"autopilote",children:"Autopilote"})]})]}),z.length>0&&t.jsxs(F,{value:w,onValueChange:W,children:[t.jsxs(E,{className:"w-[200px]",children:[t.jsx(Re,{className:"w-4 h-4 mr-2"}),t.jsx(O,{placeholder:"Propriétaire"})]}),t.jsx(U,{children:fe.map(e=>t.jsx(m,{value:e.value,children:e.label},e.value))})]}),L==="units"&&t.jsxs(F,{value:I,onValueChange:ue,children:[t.jsxs(E,{className:"w-[190px]",children:[t.jsx(He,{className:"w-4 h-4 mr-2"}),t.jsx(O,{placeholder:"Alertes"})]}),t.jsxs(U,{children:[t.jsx(m,{value:"all",children:"Toutes les alertes"}),t.jsx(m,{value:"rent",children:"Retard de loyer"}),t.jsx(m,{value:"incident",children:"Incident en cours"}),t.jsx(m,{value:"action",children:"Nécessite une action"})]})]}),t.jsxs(re,{type:"single",value:H,onValueChange:e=>e&&de(e),children:[t.jsx(V,{value:"grid","aria-label":"Vue grille",children:t.jsx(ze,{className:"h-4 w-4"})}),t.jsx(V,{value:"list","aria-label":"Vue liste",children:t.jsx(Ke,{className:"h-4 w-4"})})]}),Y>0&&t.jsxs(J,{variant:M?"default":"outline",size:"sm",onClick:()=>pe(!M),children:[t.jsx(Qe,{className:"w-4 h-4 mr-2"}),"Archivés (",Y,")"]})]}),he?t.jsx("div",{className:"flex items-center justify-center py-12",children:t.jsx(Se,{className:"w-8 h-8 animate-spin text-muted-foreground"})}):L==="units"?K.length===0?t.jsx("div",{className:"text-center py-12 text-muted-foreground",children:t.jsx("p",{children:"Aucun lot ne correspond à cette recherche"})}):H==="grid"?t.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4",children:se.map(e=>t.jsx(ie,{data:e},e.id))}):t.jsx(le,{items:se,kpiHeaders:["Loyer CC","Locataire","Gestion"]}):j.length===0?t.jsxs("div",{className:"text-center py-12 text-muted-foreground",children:[t.jsx("p",{children:u==="vacant"?"Aucun bien vacant":"Aucun bien trouvé"}),u==="all"&&t.jsx(J,{variant:"link",onClick:()=>N(!0),children:"Ajouter votre premier bien"})]}):H==="grid"?t.jsx("div",{className:"grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-4",children:ae.map(e=>t.jsx(ie,{data:e},e.id))}):t.jsx(le,{items:ae,kpiHeaders:["Lots","Loyer CC","Occupation"]}),t.jsx(Be,{open:n,onOpenChange:N})]})};export{hs 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.