PageSourceSearch

https://convolyze.io/assets/TenantAdminPage-C0VXpMyK.js

js convolyze.io collected 2026-10-02 01:57:22 UTC 7,399 bytes, 11 lines download raw bytes

1import{c as b,m as S,a6 as C,r as o,s as l,j as e,N as m,S as R}from"./index-Bbgev6vg.js";import{u as E}from"./TenantContext-CIrAByQW.js";import{R as M}from"./rotate-ccw-C8WgNk9A.js";/**
2 * @license lucide-react v0.462.0 - ISC
3 *
4 * This source code is licensed under the ISC license.
5 * See the LICENSE file in the root directory of this source tree.
6 */const T=b("Archive",[["rect",{width:"20",height:"5",x:"2",y:"3",rx:"1",key:"1wp1u1"}],["path",{d:"M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8",key:"1s80jp"}],["path",{d:"M10 12h4",key:"a56b0p"}]]);/**
7 * @license lucide-react v0.462.0 - ISC
8 *
9 * This source code is licensed under the ISC license.
10 * See the LICENSE file in the root directory of this source tree.
11 */const L=b("FastForward",[["polygon",{points:"13 19 22 12 13 5 13 19",key:"587y9g"}],["polygon",{points:"2 19 11 12 2 5 2 19",key:"3pweh0"}]]),O=[{value:"feed_user",label:"Feed user"},{value:"feed_admin",label:"Feed admin"},{value:"subdomain_admin",label:"Subdomain admin"}],I=()=>{const{user:a,loading:f}=S(),{tenant:r,isTenantAdmin:v,isSubdomainAdmin:c,notFound:_}=E(),{toast:i}=C(),[x,j]=o.useState([]),[y,u]=o.useState(!0),d=o.useCallback(async()=>{if(!r)return;u(!0);const{data:t,error:s}=await l.rpc("tenant_members_with_email",{_tenant_id:r.id});s&&i({title:"Failed to load",description:s.message,variant:"destructive"}),j((t??[]).map(n=>({user_id:n.user_id,email:n.email,role:n.role,attempts:Number(n.attempts??0),best_score:n.best_score,archived_at:n.archived_at,archived_by_email:n.archived_by_email}))),u(!1)},[r,i]);if(o.useEffect(()=>{d()},[d]),f)return e.jsx("div",{className:"p-8 text-muted-foreground",children:"Loading…"});if(_)return e.jsx(m,{to:"/not-found",replace:!0});if(!a)return e.jsx(m,{to:"/auth",replace:!0});if(!v)return e.jsx(m,{to:"/",replace:!0});const N=async(t,s)=>{const{error:n}=await l.rpc("set_tenant_member_role",{_tenant_id:r.id,_user_id:t,_role:s});if(n){i({title:"Failed",description:n.message,variant:"destructive"});return}i({title:"Role updated"}),d()},g=async t=>{if(!confirm(`Archive ${t.email??"this member"}? They will lose access to the feed.`))return;const{error:s}=await l.rpc("archive_tenant_member",{_tenant_id:r.id,_user_id:t.user_id});if(s){i({title:"Failed",description:s.message,variant:"destructive"});return}i({title:"Member archived"}),d()},w=async t=>{const{error:s}=await l.rpc("unarchive_tenant_member",{_tenant_id:r.id,_user_id:t.user_id});if(s){i({title:"Failed",description:s.message,variant:"destructive"});return}i({title:"Member restored"}),d()},k=async t=>{const{error:s}=await l.rpc("advance_member_level",{_tenant_id:r.id,_user_id:t.user_id});if(s){i({title:"Could not advance",description:s.message,variant:"destructive"});return}i({title:"Next level unlocked",description:`${t.email??"Member"} can continue.`})},h=x.filter(t=>!t.archived_at),p=x.filter(t=>!!t.archived_at),A=t=>t.archived_at?e.jsx("span",{className:"text-muted-foreground",children:t.role}):c?e.jsx("select",{value:t.role,onChange:s=>N(t.user_id,s.target.value),className:"px-2 py-1 rounded-md border border-input bg-background text-xs",disabled:t.user_id===(a==null?void 0:a.id),children:O.map(s=>e.jsx("option",{value:s.value,children:s.label},s.value))}):e.jsx("span",{children:t.role}),F=t=>!(t.user_id===(a==null?void 0:a.id)||!c&&(t.role==="subdomain_admin"||t.role==="feed_admin"));return e.jsxs("div",{className:"max-w-5xl mx-auto px-4 md:px-6 py-6 md:py-8 space-y-8",children:[e.jsx(R,{title:`Members — ${r==null?void 0:r.name}`,description:"Tenant administration.",path:"/admin",noindex:!0}),e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold",style:{fontFamily:"'Space Grotesk', sans-serif"},children:"Members & scores"}),e.jsxs("p",{className:"text-sm text-muted-foreground",children:["Everyone in ",r==null?void 0:r.name,"."," ",c?"You can change roles and archive members.":"You can archive members. Only subdomain admins can change roles."]})]}),e.jsxs("section",{className:"space-y-2",children:[e.jsx("h2",{className:"text-sm font-semibold text-muted-foreground uppercase tracking-wide",children:"Active"}),e.jsx("div",{className:"rounded-xl border border-border bg-card overflow-hidden",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-muted/50",children:e.jsxs("tr",{children:[e.jsx("th",{className:"text-left px-4 py-2 font-medium",children:"Email"}),e.jsx("th",{className:"text-left px-4 py-2 font-medium",children:"Role"}),e.jsx("th",{className:"text-right px-4 py-2 font-medium",children:"Completed"}),e.jsx("th",{className:"text-right px-4 py-2 font-medium",children:"Best score"}),e.jsx("th",{className:"px-4 py-2"})]})}),e.jsx("tbody",{children:y?e.jsx("tr",{children:e.jsx("td",{colSpan:5,className:"px-4 py-6 text-center text-muted-foreground",children:"Loading…"})}):h.length===0?e.jsx("tr",{children:e.jsx("td",{colSpan:5,className:"px-4 py-6 text-center text-muted-foreground",children:"No members yet."})}):h.map(t=>e.jsxs("tr",{className:"border-t border-border",children:[e.jsxs("td",{className:"px-4 py-2",title:t.user_id,children:[t.email??"—",t.user_id===(a==null?void 0:a.id)&&e.jsx("span",{className:"ml-2 text-xs text-muted-foreground",children:"(you)"})]}),e.jsx("td",{className:"px-4 py-2",children:A(t)}),e.jsx("td",{className:"px-4 py-2 text-right",children:t.attempts}),e.jsx("td",{className:"px-4 py-2 text-right",children:t.best_score??"—"}),e.jsxs("td",{className:"px-4 py-2 text-right whitespace-nowrap space-x-3",children:[e.jsxs("button",{onClick:()=>k(t),className:"inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-primary",title:"Unlock this member's next difficulty level",children:[e.jsx(L,{className:"w-3.5 h-3.5"})," Advance level"]}),F(t)&&e.jsxs("button",{onClick:()=>g(t),className:"inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-destructive",children:[e.jsx(T,{className:"w-3.5 h-3.5"})," Archive"]})]})]},t.user_id))})]})})]}),c&&p.length>0&&e.jsxs("section",{className:"space-y-2",children:[e.jsx("h2",{className:"text-sm font-semibold text-muted-foreground uppercase tracking-wide",children:"Archived"}),e.jsx("div",{className:"rounded-xl border border-border bg-card/50 overflow-hidden",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-muted/50",children:e.jsxs("tr",{children:[e.jsx("th",{className:"text-left px-4 py-2 font-medium",children:"Email"}),e.jsx("th",{className:"text-left px-4 py-2 font-medium",children:"Role"}),e.jsx("th",{className:"text-left px-4 py-2 font-medium",children:"Archived"}),e.jsx("th",{className:"px-4 py-2"})]})}),e.jsx("tbody",{children:p.map(t=>e.jsxs("tr",{className:"border-t border-border text-muted-foreground line-through",children:[e.jsx("td",{className:"px-4 py-2",title:t.user_id,children:t.email??"—"}),e.jsx("td",{className:"px-4 py-2",children:t.role}),e.jsx("td",{className:"px-4 py-2 no-underline",children:e.jsxs("span",{className:"text-xs",children:[t.archived_at?new Date(t.archived_at).toLocaleDateString():"",t.archived_by_email?` · by ${t.archived_by_email}`:""]})}),e.jsx("td",{className:"px-4 py-2 text-right no-underline",children:e.jsxs("button",{onClick:()=>w(t),className:"inline-flex items-center gap-1 text-xs text-primary hover:underline",children:[e.jsx(M,{className:"w-3.5 h-3.5"})," Unarchive"]})})]},t.user_id))})]})})]})]})};export{I 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.