PageSourceSearch

https://matters.group/assets/UserRolesAdmin-CtdHmZez.js

js matters.group collected 2026-10-09 22:42:14 UTC 8,271 bytes, 16 lines download raw bytes

1import{c as N,K as H,O as Y,M as O,q as P,r as i,s as u,j as e,S as z,N as Q,B as A,P as V,Q as $,T as G,V as K,Y as W,Z,_ as J,$ as X,a0 as ee,F as se}from"./index-CISjGKDG.js";import{I as _}from"./input-DGwrk3E_.js";import{B as b}from"./badge-CYkC30cE.js";import{T as re,a as ae,b as L,c as f,d as te,e as g}from"./table-DqBp5wl9.js";import{S as ie}from"./search-D6dewDhK.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 ne=N("ShieldOff",[["path",{d:"m2 2 20 20",key:"1ooewy"}],["path",{d:"M5 5a1 1 0 0 0-1 1v7c0 5 3.5 7.5 7.67 8.94a1 1 0 0 0 .67.01c2.35-.82 4.48-1.97 5.9-3.71",key:"1jlk70"}],["path",{d:"M9.309 3.652A12.252 12.252 0 0 0 11.24 2.28a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1v7a9.784 9.784 0 0 1-.08 1.264",key:"18rp1v"}]]);/**
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 T=N("Shield",[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}]]);/**
12 * @license lucide-react v0.462.0 - ISC
13 *
14 * This source code is licensed under the ISC license.
15 * See the LICENSE file in the root directory of this source tree.
16 */const oe=N("UserPlus",[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}],["line",{x1:"19",x2:"19",y1:"8",y2:"14",key:"1bvyxn"}],["line",{x1:"22",x2:"16",y1:"11",y2:"11",key:"1shjgl"}]]),he=()=>{const{user:a,loading:v}=H(),{isAdmin:c,loading:j}=Y(),h=O(),{toast:t}=P(),[w,D]=i.useState([]),[R,E]=i.useState(!0),[m,M]=i.useState(""),[p,C]=i.useState(""),[S,k]=i.useState(!1);i.useEffect(()=>{!v&&!a&&h("/auth")},[a,v,h]),i.useEffect(()=>{!j&&!c&&a&&(t({title:"Access Denied",description:"You don't have permission to access this page.",variant:"destructive"}),h("/"))},[c,j,a,h,t]),i.useEffect(()=>{c&&x()},[c]);const x=async()=>{try{E(!0);const{data:s,error:r}=await u.functions.invoke("admin-list-users");if(r)throw r;const o=(s==null?void 0:s.users)??[],{data:n,error:l}=await u.from("user_roles").select("user_id").eq("role","admin");if(l)throw l;const y=new Set((n==null?void 0:n.map(d=>
16d.user_id))||[]),B=o.map(d=>({id:d.id,email:d.email??"",full_name:d.full_name,isAdmin:y.has(d.id)}));D(B)}catch(s){console.error("Error fetching users:",s),t({title:"Error",description:"Failed to load users.",variant:"destructive"})}finally{E(!1)}},I=async()=>{if(!p.trim()){t({title:"Error",description:"Please enter an email address.",variant:"destructive"});return}try{k(!0);const s=p.trim(),r=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;let o;if(r.test(s))o=s;else{const l=w.find(y=>y.email.toLowerCase()===s.toLowerCase());o=l==null?void 0:l.id}if(!o){t({title:"Error",description:"User not found. Make sure the email matches a registered account.",variant:"destructive"});return}const{error:n}=await u.from("user_roles").insert({user_id:o,role:"admin"});if(n)if(n.code==="23505")t({title:"Info",description:"This user is already an admin."});else throw n;else t({title:"Success",description:"Admin role assigned successfully."}),C(""),x()}catch(s){console.error("Error adding admin:",s),t({title:"Error",description:"Failed to assign admin role.",variant:"destructive"})}finally{k(!1)}},F=async s=>{if(s===(a==null?void 0:a.id)){t({title:"Error",description:"You cannot remove your own admin role.",variant:"destructive"});return}try{const{error:r}=await u.from("user_roles").delete().eq("user_id",s).eq("role","admin");if(r)throw r;t({title:"Success",description:"Admin role removed successfully."}),x()}catch(r){console.error("Error removing admin:",r),t({title:"Error",description:"Failed to remove admin role.",variant:"destructive"})}},q=async s=>{try{const{error:r}=await u.from("user_roles").insert({user_id:s,role:"admin"});if(r)throw r;t({title:"Success",description:"Admin role granted successfully."}),x()}catch(r){console.error("Error granting admin:",r),t({title:"Error",description:"Failed to grant admin role.",variant:"destructive"})}},U=w.filter(s=>{var r;return((r=s.full_name)==null?void 0:r.toLowerCase().includes(m.toLowerCase()))||s.email.toLowerCase().includes(m.toLowerCase())||s.id.toLowerCase().includes(m.toLowerCase())});return v||j?e.jsx("div",{className:"min-h-screen flex items-center justify-center bg-background",children:e.jsx("div",{className:"animate-pulse text-muted-foreground",children:"Loading..."})}):!a||!c?null:e.jsxs("div",{className:"min-h-screen flex flex-col bg-background",children:[e.jsx(z,{title:"User Roles Management | Hexline",description:"Manage user roles and admin permissions"}),e.jsx(Q,{}),e.jsx("main",{className:"flex-grow container mx-auto px-4 py-8 mt-20",children:e.jsxs("div",{className:"max-w-4xl mx-auto",children:[e.jsx("div",{className:"flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 mb-8",children:e.jsxs("div",{children:[e.jsx("h1",{className:"text-3xl font-bold text-foreground",children:"User Roles"}),e.jsx("p",{className:"text-muted-foreground mt-1",children:"Manage admin permissions for users"})]})}),e.jsxs("div",{className:"bg-card border border-border rounded-lg p-6 mb-6",children:[e.jsxs("h2",{className:"text-lg font-semibold mb-4 flex items-center gap-2",children:[e.jsx(oe,{className:"h-5 w-5"}),"Add Admin by Email"]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(_,{placeholder:"Enter user email address",value:p,onChange:s=>C(s.target.value),className:"flex-grow"}),e.jsx(A,{onClick:I,disabled:S,children:S?"Adding...":"Add Admin"})]}),e.jsx("p",{className:"text-sm text-muted-foreground mt-2",children:"Enter the email of a registered user. You can also paste a user UUID."})]}),e.jsxs("div",{className:"relative mb-6",children:[e.jsx(ie,{className:"absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(_,{placeholder:"Search by name, email, or ID...",value:m,onChange:s=>M(s.target.value),className:"pl-10"})]}),R?e.jsx("div",{className:"text-center py-12 text-muted-foreground",children:"Loading users..."}):U.length===0?e.jsx("div",{className:"text-center py-12 text-muted-foreground",children:m?"No users found matching your search.":"No users found."}):e.jsx("div",{className:"bg-card border border-border rounded-lg overflow-hidden",children:e.jsxs(re,{children:[e.jsx(ae,{children:e.jsxs(L,{children:[e.jsx(f,{children:"User"}),e.jsx(f,{children:"Email"}),e.jsx(f,{children:"Role"}),e.jsx(f,{className:"text-right",children:"Actions"})]})}),e.jsx(te,{children:U.map(s=>e.jsxs(L,{children:[e.jsxs(g,{className:"font-medium",children:[s.full_name||"Anonymous",s.id===(a==null?void 0:a.id)&&e.jsx(b,{variant:"outline",className:"ml-2",children:"You"})]}),e.jsx(g,{className:"text-sm text-muted-foreground",children:s.email||e.jsxs("span",{className:"font-mono text-xs",children:[s.id.slice(0,8),"…"]})}),e.jsx(g,{children:s.isAdmin?e.jsxs(b,{className:"bg-primary/10 text-primary border-primary/20",children:[e.jsx(T,{className:"h-3 w-3 mr-1"}),"Admin"]}):e.jsx(b,{variant:"secondary",children:"User"})}),e.jsx(g,{className:"text-right",children:s.isAdmin?e.jsxs(V,{children:[e.jsx($,{asChild:!0,children:e.jsxs(A,{variant:"ghost",size:"sm",disabled:s.id===(a==null?void 0:a.id),className:"text-destructive hover:text-destructive",children:[e.jsx(ne,{className:"h-4 w-4 mr-1"}),"Remove Admin"]})}),e.jsxs(G,{children:[e.jsxs(K,{children:[e.jsx(W,{children:"Remove Admin Role"}),e.jsxs(Z,{children:["Are you sure you want to remove admin privileges from ",s.full_name||"this user","? They will no longer be able to manage blog posts or user roles."]})]}),e.jsxs(J,{children:[e.jsx(X,{children:"Cancel"}),e.jsx(ee,{onClick:()=>F(s.id),className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"Remove Admin"})]})]})]}):e.jsxs(A,{variant:"ghost",size:"sm",onClick:()=>q(s.id),className:"text-primary hover:text-primary",children:[e.jsx(T,{className:"h-4 w-4 mr-1"}),"Make Admin"]})})]},s.id))})]})})]})}),e.jsx(se,{})]})};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.