1import{j as e,r as l}from"./index-CL_TZ6iC.js";import{u as B,a as H,f as v,b as z,c as N}from"./metrics-WRgmV86D.js";import{u as O,f as K,U as V,a as G,b as J}from"./adminStaff-C_42Hcnk.js";import{K as j}from"./KpiCard-BYsvanuK.js";import{C as S,T as P,a as A,D as W,b as X}from"./Charts-Dz91TPg5.js";import{M as Y}from"./MetricsView-DkNfMAr1.js";import{D as Z}from"./DataTable-D-wdO5Pz.js";const Q={Pro:"sbadge-ok",Elite:"sbadge-ok",Explore:"sbadge-stale"};function ee({status:a}){return e.jsx("span",{className:`sbadge ${Q[a]??"sbadge-never"}`,children:a})}function ae(a){switch(a.kind){case"subscription":return"Subscription";case"ends":return`Ends ${N(a.date)}`;case"on":return N(a.date);case"no_expiry":return"No expiry";default:return"â"}}const b=e.jsx("span",{className:"muted",children:"â"}),te=[{key:"created",header:"Joined",render:a=>N(a.createdAt)},{key:"email",header:"Email",render:a=>a.email??b},{key:"role",header:"Role",render:a=>a.role},{key:"country",header:"Country",render:a=>a.country??b},{key:"verified",header:"Verified",render:a=>a.verified?"â":b},{key:"status",header:"Status",render:a=>e.jsx(ee,{status:a.status})},{key:"method",header:"Payment method",render:a=>a.paymentMethod},{key:"renewed",header:"Renewed",render:a=>N(a.renewedAt)},{key:"charged",header:"Last charged",render:a=>K(a.lastCharged)??b},{key:"expiry",header:"Expiry",render:a=>ae(a.expiry)}],se=50;function re(a,r){return a==="query_too_short"?`Searches need at least ${h} characters.`:a==="query_too_long"?"That search term is too long â shorten it and try again.":r===429||a==="rate_limited"?"Too many requests in a minute â this list is rate-limited. Wait a moment and try again.":a==="invalid_status"||a==="invalid_method"||a==="invalid_expiry"?"That filter value is not one this screen can use. Clear the filters and try again.":"Could not load users. Please try again in a moment."}const h=3;function ne(){const[a,r]=l.useState(1),[d,p]=l.useState(""),[t,n]=l.useState(""),[x,_]=l.useState(""),[R,E]=l.useState(""),[g,w]=l.useState(""),[C,c]=l.useState(null),u=new URLSearchParams({page:String(a),pageSize:String(se)});d&&u.set("status",d),t&&u.set("method",t),x&&u.set("expiry",x),g&&u.set("q",g);const{data:s,state:y,errorCode:D,errorStatus:L}=O(`/admin/users?${u.toString()}`),k=i=>o=>{i(o),r(1),E(g),c(null)},F=i=>{i.preventDefault();const o=R.trim();if(o&&o.length<h){c(`Searches need at least ${h} characters.`);return}c(null),r(1),w(o)},T=(i,o,I,$)=>e.jsx("select",{value:o,"aria-label":i,onChange:f=>I(f.target.value),children:$.map(([f,q])=>e.jsx("option",{value:f,children:q},f))},i),U=!!(d||t||x||g),m=y==="loading",M=!!s&&y!=="forbidden";return e.jsxs("section",{className:"admin-section",children:[e.jsxs("div",{className:"admin-head-row",children:[e.jsx("h2",{children:"Users"}),e.jsxs("div",{className:"admin-filter",children:[T("Filter by plan status",d,k(p),V),T("Filter by payment method",t,k(n),G),T("Filter by expiry",x,k(_),J),e.jsxs("form",{className:"admin-filter",onSubmit:F,children:[e.jsx("input",{type:"search",value:R,minLength:h,"aria-label":"Search by email","aria-invalid":C?!0:void 0,placeholder:`Email contains (${h}+ characters)`,onChange:i=>{E(i.target.value),c(null)}}),e.jsx("button",{type:"submit",className:"btn",children:"Search"})]}),U&&e.jsx("button",{type:"button",className:"btn",onClick:()=>{p(""),n(""),_(""),E(""),w(""),c(null),r(1)},children:"Clear filters"})]})]}),C&&e.jsx("div",{className:"admin-error",children:C}),y==="forbidden"&&e.jsx("div",{className:"admin-state",children:"Not authorized."}),y==="error"&&e.jsx("div",{className:"admin-error",children:re(D,L)}),m&&!s&&e.jsx("div",{className:"admin-state",children:"Loadingâ¦"}),M&&s&&e.jsxs("div",{className:"admin-loading-wrap","aria-busy":m,"data-loading":m||void 0,children:[e.jsx(Z,{columns:te,rows:s.users,empty:U?"No users match those filters.":"No users yet."}),e.jsxs("div",{className:"admin-pager",children:[e.jsx("button",{type:"button",className:"btn",disabled:m||s.page<=1,onClick:()=>r(s.page-1),children:"Previous"}),e.jsxs("span",{children:["Page ",s.page," of ",s.totalPages," · ",v(s.total)," users"]}),e.jsx("button",{type:"button",className:"btn",disabled:m||s.page>=s.totalPages,onClick:()=>r(s.page+1),children:"Next"})]})]})]})}function he(){const a=B(),{data:r,loading:d,error:p}=H("users",a);return e.jsxs(e.Fragment,{children:[e.jsx(Y,{loading:d,error:p,data:r,children:t=>e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"kpi-grid",children:[e.jsx(j,{label:"Total users",value:v(t.totalUsers)}),e.jsx(j,{label:`New signups (${a}d)`,value:v(t.newSignups),tone:"info"}),e.jsx(j,{label:"Email-verified",value:z(t.verifiedRate),tone:"good"}),e.jsx(j,{label:"Soft-deleted",value:v(t.softDeleted)})]}),e.jsxs("div",{className:"admin-charts",children:[e.jsx(S,{title:"Signups per day",subtitle:"UTC",children:e.jsx(P,{data:t.signupsSeries,kind:"area",series:[{key:"n",name:"Signups",color:A.teal}]})}),e.jsx(S,{title:"Cumulative users",subtitle:"excludes legacy rows with
1no join date",children:e.jsx(P,{data:t.cumulativeSeries,series:[{key:"n",name:"Users",color:A.info}]})}),e.jsx(S,{title:"Role mix",children:e.jsx(W,{data:t.roleBreakdown.map(n=>({name:n.role,value:n.count}))})}),e.jsx(S,{title:"Top countries",children:e.jsx(X,{horizontal:!0,data:t.topCountries.map(n=>({name:n.country,value:n.count}))})})]})]})}),e.jsx(ne,{})]})}export{he 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.