1import{o as A,s as L,r as N,dU as Y,bz as G,bP as J,j as e,Q as W,Y as X,w as I,a9 as Z,B as E,ak as T,ch as ee,an as $,af as te,ag as re,ah as M,ai as K,aj as ae,am as g,cB as se,be as ne}from"./index-payoMPV_.js";import{a as oe,A as ie}from"./AdminLayout-BR8ZUW_V.js";import{d as F}from"./differenceInDays-Da8x-smq.js";import{T as le}from"./trending-down-CqvsCql_.js";import{A as ce}from"./arrow-up-down-BEeSQCR7.js";import{B as de}from"./BaseFilterBar-CBsZJkri.js";import"./layout-dashboard-J8mXpsr5.js";import"./gift-CxKhZXlR.js";import"./calendar-days-jGlrtffW.js";function ue(s){return s>=70?"healthy":s>=40?"at-risk":"churning"}function me(s,o){if(o.length===0)return 0;const t=[...o].sort((l,p)=>l-p),m=t.findIndex(l=>l>=s);return m===-1?1:m/t.length}function he(){const s=A({queryKey:["client-health","organizations"],queryFn:async()=>{const{data:d,error:u}=await L.from("organizations").select("id, name, created_at");if(u)throw u;return d}}),o=A({queryKey:["client-health","orders"],queryFn:async()=>{const{data:d,error:u}=await L.from("orders").select("id, organization_id, type, created_at, order_products(price, modified_price, quantity)");if(u)throw u;return d}}),t=A({queryKey:["client-health","members"],queryFn:async()=>{const{data:d,error:u}=await L.from("organization_members").select("organization_id, state");if(u)throw u;return d}}),m=s.isLoading||o.isLoading||t.isLoading,l=s.error||o.error||t.error,{clients:p,summary:h,recentOrdersByOrg:b}=N.useMemo(()=>{if(!s.data||!o.data||!t.data)return{clients:[],summary:{totalActive:0,averageScore:0,atRiskCount:0,churningCount:0},recentOrdersByOrg:{}};const d=new Date,u=new Date;u.setMonth(u.getMonth()-6);const w=new Date;w.setDate(w.getDate()-90);const v={},c={};for(const a of o.data){const n=a.organization_id;if(!n)continue;v[n]||(v[n]={lastOrderDate:null,ordersLast6Months:0,totalRevenue:0,requestDates:[],orderDates:[]});const x=v[n],y=a.created_at;if((!x.lastOrderDate||y>x.lastOrderDate)&&(x.lastOrderDate=y),new Date(y)>=u&&x.ordersLast6Months++,a.order_products)for(const D of a.order_products){const O=D.modified_price??D.price??0;x.totalRevenue+=O*(D.quantity??1)}a.type===1&&x.requestDates.push(y),a.type===2&&x.orderDates.push(y),c[n]||(c[n]=[]),c[n].push({id:a.id,name:a.name||a.id.slice(0,8),created_at:y,type:a.type??0})}for(const a of Object.keys(c))c[a].sort((n,x)=>x.created_at.localeCompare(n.created_at)),c[a]=c[a].slice(0,5);const C={};for(const a of t.data)a.state===Y.Active&&(C[a.organization_id]=(C[a.organization_id]||0)+1);const r=Object.values(v).map(a=>a.totalRevenue),i=s.data.map(a=>{const n=v[a.id]||{lastOrderDate:null,ordersLast6Months:0,totalRevenue:0,requestDates:[],orderDates:[]},x=n.lastOrderDate?F(d,new Date(n.lastOrderDate)):180,y=Math.max(0,Math.round(100-x/180*100)),D=Math.min(100,Math.round(n.ordersLast6Months/10*100)),O=Math.round(me(n.totalRevenue,r)*100);let R=null,z=50;if(n.requestDates.length>0&&n.orderDates.length>0){const U=[...n.requestDates].sort(),V=[...n.orderDates].sort();let _=0,k=0;for(const B of U){const H=V.find(P=>P>=B);H&&(_+=F(new Date(H),new Date(B)),k++)}k>0&&(R=Math.round(_/k),z=Math.max(0,Math.round(100-R/30*100)))}const q=Math.round(y*.3+D*.25+O*.25+z*.2);return{organizationId:a.id,organizationName:a.name,healthScore:q,tier:ue(q),recencyScore:y,frequencyScore:D,valueScore:O,responsivenessScore:z,lastOrderDate:n.lastOrderDate,ordersLast6Months:n.ordersLast6Months,totalRevenue:n.totalRevenue,avgResponseDays:R,memberCount:C[a.id]||0}}),S=i.filter(a=>a.lastOrderDate&&new Date(a.lastOrderDate)>=w).length,f=i.length>0?Math.round(i.reduce((a,n)=>a+n.healthScore,0)/i.length):0,j=i.filter(a=>a.tier==="at-risk").length,Q=i.filter(a=>a.tier==="churning").length;return{clients:i,summary:{totalActive:S,averageScore:f,atRiskCount:j,churningCount:Q},recentOrdersByOrg:c}},[s.data,o.data,t.data]);return{clients:p,summary:h,recentOrdersByOrg:b,isLoading:m,error:l}}function xe({summary:s}){const o=[{label:"Active Clients (90d)",value:s.totalActive,icon:G,color:"text-primary"},{label:"Avg Health Score",value:s.averageScore,icon:oe,color:"text-success"},{label:"At Risk",value:s.atRiskCount,icon:J,color:"text-warning"},{label:"Churning",value:s.churningCount,icon:le,color:"text-destructive"}];return e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4",children:o.map(t=>e.jsx(W,{children:e.jsx(X,{className:"pt-6",children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm text-muted-foreground",children:t.label}),e.jsx("p",{className:"text-2xl font-bold mt-1",children:t.value})]}),e.jsx(t.icon,{className:`h-8 w-8 ${t.color} opacity-70`})]})})},t.label))})}const ge={healthy:{label:"Healthy",barColor:"bg-success",variant:"success"},"at-risk":{label:"At Risk",barColor:"bg-warning",variant:"warning"},churning:{label:"Churning",barColor:"bg-destructive",variant:"destructive"}};
1function fe({score:s,tier:o,showBar:t=!1,className:m}){const l=ge[o];return e.jsxs("div",{className:I("flex items-center gap-2",m),children:[t&&e.jsx("div",{className:"w-20 h-2 rounded-full bg-secondary overflow-hidden",children:e.jsx("div",{className:I("h-full rounded-full transition-all",l.barColor),style:{width:`${s}%`}})}),e.jsx("span",{className:"text-sm font-medium tabular-nums",children:s}),e.jsx(Z,{variant:l.variant,className:"text-[10px] px-1.5 py-0",children:l.label})]})}const ye=[{key:"recencyScore",label:"Recency",weight:"30%"},{key:"frequencyScore",label:"Frequency",weight:"25%"},{key:"valueScore",label:"Value",weight:"25%"},{key:"responsivenessScore",label:"Responsiveness",weight:"20%"}];function pe(s){return s>=70?"bg-success":s>=40?"bg-warning":"bg-destructive"}function je({client:s,recentOrders:o}){return e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-6 p-4",children:[e.jsxs("div",{children:[e.jsx("h4",{className:"text-sm font-semibold mb-3 text-foreground",children:"Score Breakdown"}),e.jsx("div",{className:"space-y-3",children:ye.map(t=>e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("span",{className:"text-xs text-muted-foreground w-28",children:[t.label," (",t.weight,")"]}),e.jsx("div",{className:"flex-1 h-2 rounded-full bg-secondary overflow-hidden",children:e.jsx("div",{className:I("h-full rounded-full",pe(s[t.key])),style:{width:`${s[t.key]}%`}})}),e.jsx("span",{className:"text-xs font-medium w-8 text-right tabular-nums",children:s[t.key]})]},t.key))})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-3",children:[e.jsx("h4",{className:"text-sm font-semibold text-foreground",children:"Recent Orders"}),e.jsx(E,{variant:"ghost",size:"sm",asChild:!0,children:e.jsxs(T,{to:"/admin/organizations/$id",params:{id:s.organizationId},children:["View Organization ",e.jsx(ee,{className:"ml-1 h-3 w-3"})]})})]}),o.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No orders found"}):e.jsx("div",{className:"space-y-2",children:o.map(t=>e.jsxs(T,{to:"/admin/orders/$orderId",params:{orderId:t.id},className:"flex items-center justify-between rounded-md border border-border px-3 py-2 text-sm hover:bg-accent transition-colors",children:[e.jsx("span",{className:"font-medium",children:t.name}),e.jsx("span",{className:"text-muted-foreground text-xs",children:$(new Date(t.created_at),"MMM d, yyyy")})]},t.id))})]})]})}function be({clients:s,recentOrdersByOrg:o,search:t,tierFilter:m}){const[l,p]=N.useState("healthScore"),[h,b]=N.useState(!0),[d,u]=N.useState(null),w=N.useMemo(()=>{let r=s;if(m!=="all"&&(r=r.filter(i=>i.tier===m)),t){const i=t.toLowerCase();r=r.filter(S=>S.organizationName.toLowerCase().includes(i))}return r=[...r].sort((i,S)=>{let f=i[l],j=S[l];return f==null&&(f=h?1/0:-1/0),j==null&&(j=h?1/0:-1/0),typeof f=="string"?h?f.localeCompare(j):j.localeCompare(f):h?f-j:j-f}),r},[s,t,m,l,h]),v=r=>{l===r?b(!h):(p(r),b(r==="healthScore"))},c=({label:r,sortKeyName:i})=>e.jsx(K,{className:"cursor-pointer select-none whitespace-nowrap",onClick:()=>v(i),children:e.jsxs("div",{className:"flex items-center gap-1",children:[r,e.jsx(ce,{className:"h-3 w-3 text-muted-foreground"})]})}),C=r=>new Intl.NumberFormat("en-EU",{style:"currency",currency:"EUR",maximumFractionDigits:0}).format(r);return e.jsx("div",{className:"rounded-md border border-border",children:e.jsxs(te,{children:[e.jsx(re,{children:e.jsxs(M,{children:[e.jsx(K,{className:"w-8"}),e.jsx(c,{label:"Organization",sortKeyName:"organizationName"}),e.jsx(c,{label:"Health Score",sortKeyName:"healthScore"}),e.jsx(c,{label:"Last Order",sortKeyName:"lastOrderDate"}),e.jsx(c,{label:"Orders (6mo)",sortKeyName:"ordersLast6Months"}),e.jsx(c,{label:"Total Revenue",sortKeyName:"totalRevenue"}
1),e.jsx(c,{label:"Avg Response",sortKeyName:"avgResponseDays"}),e.jsx(c,{label:"Members",sortKeyName:"memberCount"})]})}),e.jsx(ae,{children:w.length===0?e.jsx(M,{children:e.jsx(g,{colSpan:8,className:"text-center text-muted-foreground py-8",children:"No organizations found"})}):w.map(r=>{const i=d===r.organizationId;return e.jsxs(e.Fragment,{children:[e.jsxs(M,{className:"cursor-pointer",onClick:()=>u(i?null:r.organizationId),children:[e.jsx(g,{className:"w-8 px-2",children:i?e.jsx(se,{className:"h-4 w-4"}):e.jsx(ne,{className:"h-4 w-4"})}),e.jsx(g,{className:"font-medium",children:r.organizationName}),e.jsx(g,{children:e.jsx(fe,{score:r.healthScore,tier:r.tier,showBar:!0})}),e.jsx(g,{className:"text-muted-foreground",children:r.lastOrderDate?$(new Date(r.lastOrderDate),"MMM d, yyyy"):"â"}),e.jsx(g,{children:r.ordersLast6Months}),e.jsx(g,{children:C(r.totalRevenue)}),e.jsx(g,{children:r.avgResponseDays!=null?`${r.avgResponseDays}d`:"â"}),e.jsx(g,{children:r.memberCount})]},r.organizationId),i&&e.jsx(M,{children:e.jsx(g,{colSpan:8,className:"bg-muted/30 p-0",children:e.jsx(je,{client:r,recentOrders:o[r.organizationId]||[]})})},`${r.organizationId}-detail`)]})})})]})})}const ve=[{value:"all",label:"All"},{value:"healthy",label:"Healthy"},{value:"at-risk",label:"At Risk"},{value:"churning",label:"Churning"}];function Ne(){const{clients:s,summary:o,recentOrdersByOrg:t,isLoading:m}=he(),[l,p]=N.useState(""),[h,b]=N.useState("all");return e.jsx(ie,{children:e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold text-foreground",children:"Client Health"}),e.jsx("p",{className:"text-muted-foreground mt-1",children:"Monitor organization engagement and identify at-risk clients"})]}),!m&&e.jsx(xe,{summary:o}),e.jsxs("div",{className:"space-y-4",children:[e.jsx("div",{className:"flex flex-wrap gap-2",children:ve.map(d=>e.jsx(E,{variant:h===d.value?"default":"outline",size:"sm",onClick:()=>b(d.value),className:"min-h-9",children:d.label},d.value))}),e.jsx(de,{searchValue:l,searchPlaceholder:"Search organizations...",onSearchChange:p,onClear:()=>{p(""),b("all")},hasActiveFilters:l!==""||h!=="all"})]}),m?e.jsx("div",{className:"flex items-center justify-center py-12",children:e.jsx("div",{className:"animate-spin rounded-full h-8 w-8 border-b-2 border-primary"})}):e.jsx(be,{clients:s,recentOrdersByOrg:t,search:l,tierFilter:h})]})})}const Ae=Ne;export{Ae as component};
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.