1import{j as e}from"./vendor-framer-e_lHCn70.js";import{r as a,L as N}from"./vendor-react-KJNI7MOv.js";import{s as m,u as t,B as c,S as k,X as w}from"./index-fBnR0sxX.js";import{u as R}from"./useAdminAuthGuard-BPvi08JJ.js";import{I as C}from"./input-u-di5Od2.js";import{C as b}from"./card-Cvhc0jcH.js";import{B as S}from"./badge-B__t_d23.js";import{u as _}from"./usePageSEO-CxtTPGmV.js";import{A as G}from"./arrow-left-Cjser2SV.js";import{U as E}from"./user-plus-86kienB1.js";import{R as A}from"./refresh-cw-DamgBDd0.js";import"./vendor-radix-core-Dl2pI1uY.js";import"./vendor-utils-MBSoW7Mz.js";import"./vendor-query-B0dKBn0F.js";import"./vendor-supabase-DEDxcdm9.js";import"./vendor-radix-extended-hypInIJy.js";const H=()=>{_({title:"Privacy Officer Roles. Vetano Admin",description:"Grant or revoke the privacy_officer role for Data Subject Request access.",canonical:"https://vetano.com/admin/privacy-roles"}),R();const[l,g]=a.useState([]),[i,d]=a.useState(!0),[f,u]=a.useState(""),[x,h]=a.useState(!1),[j,p]=a.useState(null),o=a.useCallback(async()=>{d(!0);const{data:r,error:s}=await m.functions.invoke("admin-privacy-roles",{body:{action:"list"}});if(d(!1),s||!r?.ok){t.error(r?.error||s?.message||"Failed to load members");return}g(r.members)},[]);a.useEffect(()=>{o()},[o]);const v=async()=>{const r=f.trim().toLowerCase();if(!r){t.error("Enter an email");return}h(!0);try{const{data:s,error:n}=await m.functions.invoke("admin-privacy-roles",{body:{action:"grant",email:r}});n||!s?.ok?t.error(s?.error||n?.message||"Grant failed"):(t.success(`${s.email} granted privacy_officer`),u(""),await o())}finally{h(!1)}},y=async r=>{if(r.email&&confirm(`Revoke privacy_officer for ${r.email}?`)){p(r.user_id);try{const{data:s,error:n}=await m.functions.invoke("admin-privacy-roles",{body:{action:"revoke",email:r.email}});n||!s?.ok?t.error(s?.error||n?.message||"Revoke failed"):(t.success(`Revoked from ${r.email}`),await o())}finally{p(null)}}};return e.jsx("div",{className:"min-h-screen bg-background",children:e.jsxs("main",{className:"max-w-3xl mx-auto px-4 sm:px-6 py-10",children:[e.jsx(N,{to:"/admin/dashboard",children:e.jsxs(c,{variant:"ghost",className:"mb-4 -ml-2 text-muted-foreground",children:[e.jsx(G,{className:"w-4 h-4 mr-2"})," Back to dashboard"]})}),e.jsxs("div",{className:"flex items-center gap-3 mb-6",children:[e.jsx("div",{className:"w-12 h-12 rounded-xl bg-primary/10 flex items-center justify-center",children:e.jsx(k,{className:"w-6 h-6 text-primary"})}),e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Privacy Officer Roles"}),e.jsxs("p",{className:"text-sm text-muted-foreground",children:["Members with the ",e.jsx("code",{children:"privacy_officer"})," role can view and manage Data Subject Requests, audit logs, and the email pipeline."]})]})]}),e.jsxs(b,{className:"p-5 mb-6 bg-card/50 border-border/50",children:[e.jsxs("h2",{className:"font-semibold mb-3 flex items-center gap-2",children:[e.jsx(E,{className:"w-4 h-4 text-primary"})," Grant role"]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(C,{type:"email",placeholder:"[email protected]",value:f,onChange:r=>u(r.target.value),onKeyDown:r=>{r.key==="Enter"&&v()}}),e.jsx(c,{onClick:v,disabled:x,children:x?"Grantingâ¦":"Grant"})]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-2",children:"The person must have signed in at least once before they can be granted a role."})]}),e.jsxs(b,{className:"bg-card/50 border-border/50 overflow-hidden",children:[e.jsxs("div",{className:"px-5 py-3 border-b border-border/50 flex items-center justify-between",children:[e.jsxs("h2",{className:"font-semibold",children:["Current members (",l.length,")"]}),e.jsx(c,{variant:"outline",size:"sm",onClick:o,disabled:i,children:e.jsx(A,{className:`w-3.5 h-3.5 ${i?"animate-spin":""}`})})]}),i&&e.jsx("div",{className:"p-6 text-center text-sm text-muted-foreground",children:"Loadingâ¦"}),!i&&l.length===0&&e.jsx("div",{className:"p-6 text-center text-sm text-muted-foreground",children:"No privacy officers yet. Grant the role above."}),!i&&l.length>0&&e.jsx("ul",{className:"divide-y divide-border/40",children:l.map(r=>e.jsxs("li",{className:"px-5 py-3 flex items-center justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"font-medium truncate",children:r.email??"(unknown email)"}),e.jsx("div",{className:"text-xs text-muted-foreground font-mono truncate",children:r.user_id})]}),e.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[e.jsx(S,{variant:"outline",className:"text-amber-400 border-amber-500/30",children:"privacy_officer"}),e.jsxs(c,{size:"sm",variant:"outline",onClick:()=>y(r),disabled:j===r.user_id,children:[e.jsx(w,{className:"w-3.5 h-3.5 mr-1"})," Revoke"]})]})]},r.user_id))})]})]})})};export{H 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.