PageSourceSearch

https://nicholasalifa.lovable.app/assets/AdminTeam-BNY-XUIG.js

js nicholasalifa.lovable.app collected 2026-10-03 03:35:17 UTC 11,862 bytes, 6 lines download raw bytes

1var W=Object.defineProperty;var Z=(n,i,t)=>i in n?W(n,i,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[i]=t;var q=(n,i,t)=>Z(n,typeof i!="symbol"?i+"":i,t);import{c as ee,Q as $,$ as b,a0 as k,O as p,a1 as se,r as d,a3 as u,j as e,M as te,I as ne,B as h,b0 as ie,V as D,av as P,a$ as U}from"./index-DVnvwKss.js";import{A as ae,C as re}from"./AdminLayout-C50e_CCB.js";import{C as S}from"./card-CyDJmAKF.js";import{A as ce,T as oe,a as le,b as de}from"./alert-Da7Z02jc.js";import{L as me}from"./label-Bnts9xf-.js";import{R as ue}from"./refresh-cw-BskMRNIY.js";import{C as xe}from"./copy-BOvaw5G9.js";import{S as fe}from"./shield-DtdZXWBG.js";import"./lock-D_WmPVvn.js";import"./chart-column-4glrh6i_.js";import"./graduation-cap-B6HRXtd7.js";import"./package-CWCtnPMe.js";import"./star-DgJGUcrD.js";import"./tag-BsS18FKR.js";import"./users-Slprv71S.js";import"./send-DbAweDjN.js";import"./code-DeKqVZ0y.js";import"./link-2-FU3pAgyk.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 he=ee("Ban",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m4.9 4.9 14.2 14.2",key:"1m5liu"}]]);function pe(){return $({queryKey:["admin-invites"],queryFn:async()=>{const{data:n,error:i}=await p.from("admin_invites").select("*").order("created_at",{ascending:!1});if(i)throw i;return n??[]}})}function ge(){return $({queryKey:["admin-users"],queryFn:async()=>{const{data:n,error:i}=await p.from("user_roles").select("user_id, role").in("role",["admin","super_admin"]);if(i)throw i;if(!(n!=null&&n.length))return[];const t=n.map(r=>r.user_id),{data:c}=await p.from("profiles").select("id, email, full_name, created_at").in("id",t),v=new Map((c??[]).map(r=>[r.id,r]));return n.map(r=>{const o=v.get(r.user_id);return{user_id:r.user_id,role:r.role,email:(o==null?void 0:o.email)??null,full_name:(o==null?void 0:o.full_name)??null,joined_at:(o==null?void 0:o.created_at)??""}})}})}class C extends Error{constructor(t,c){super(t);q(this,"code");this.code=c}}function ve(){const n=b();return k({mutationFn:async i=>{const{data:t,error:c}=await p.functions.invoke("send-admin-invite",{body:{email:i}});if(c)throw new C(c.message);if(t!=null&&t.error)throw new C(t.error,t.code);return t},onSuccess:()=>n.invalidateQueries({queryKey:["admin-invites"]})})}function je(){const n=b();return k({mutationFn:async i=>{const{error:t}=await p.from("admin_invites").update({revoked_at:new Date().toISOString()}).eq("id",i);if(t)throw t},onSuccess:()=>n.invalidateQueries({queryKey:["admin-invites"]})})}function ye(){const n=b();return k({mutationFn:async i=>{const{error:t}=await p.from("admin_invites").delete().eq("id",i);if(t)throw t},onSuccess:()=>n.invalidateQueries({queryKey:["admin-invites"]})})}function we(){const n=b();return k({mutationFn:async i=>{const{error:t}=await p.from("user_roles").delete().eq("user_id",i).eq("role","admin");if(t)throw t},onSuccess:()=>n.invalidateQueries({queryKey:["admin-users"]})})}function Be(){const{user:n}=se(),[i,t]=d.useState(""),[c,v]=d.useState(null),[r,o]=d.useState(!1),[j,y]=d.useState(0),[N,w]=d.useState(!1),[g,_]=d.useState(null),[F,B]=d.useState(()=>Date.now()),x=d.useRef(null),z=5e3,Q=6e4,f=6,L=Math.min(z*2**j,Q),K=r&&g?Math.max(0,Math.ceil((g-F)/1e3)):0,T=Math.max(0,f-j),{data:E=[],isLoading:O}=pe(),{data:M=[],isLoading:Y}=ge(),m=ve(),G=je(),V=ye(),X=we(),I=async(s,a)=>{try{const l=await m.mutateAsync(s);return a!=null&&a.clearInputOnSuccess&&t(""),v(null),o(!1),y(0),w(!1),_(null),l.email_sent?u.success(`Invite emailed to ${s}`):u.success("Invite created — copy the link below to share"),{ok:!0}}catch(l){return l instanceof C&&l.code==="INVALID_PUBLIC_SITE_URL"?(v({code:l.code,message:l.message,email:s}),a!=null&&a.silent||u.error("Site URL not configured"),{ok:!1,configError:!0}):(a!=null&&a.silent||u.error(l instanceof Error?l.message:"Failed to send invite"),{ok:!1,configError:!1})}};d.useEffect(()=>{if(!r||!c){x.current&&(window.clearTimeout(x.current),x.current=null),_(null);return}if(j>=f){o(!1),w(!0),_(null),u.error(`Auto-retry stopped after ${f} attempts`,{description:"PUBLIC_SITE_URL still appears invalid. Update it and try again manually.",duration:8e3});return}const s=c.email,a=Date.now()+L;return _(a),x.current=window.setTimeout(async()=>{y(l=>l+1),await I(s,{silent:!0})},L),()=>{x.current&&(window.clearTimeout(x.current),x.current=null)}},[r,c,j]),d.useEffect(()=>{if(!r||!g)return;const s=window.setInterval(()=>B(Date.now()),1e3);return()=>window.clearInterval(s)},[r,g]);const H=async s=>{s.preventDefault();const a=i.trim().toLowerCase();a&&await I(a,{clearInputOnSuccess:!0})},J=s=>{const a=`${window.location.origin}/admin/accept-invite?token=${s}`;navigator.clipboard.writeText(a),u.success("Invite link copied")},A=E.filter(s=>!s.accepted_at&&!s.revoked_at&&new Date(s.expires_at)>new Date),R=E.filter(s=>s.accepted_at||s.revoked_at||new Date(s.expires_at)<=new Date);return e.jsx(ae,{title:"Team",children:e.jsxs("div",{className:"max-w-5xl mx-auto 
6space-y-8",children:[e.jsx("p",{className:"text-muted-foreground -mt-2",children:"Manage admins and invite new ones."}),e.jsxs(S,{className:"p-6",children:[e.jsxs("h2",{className:"text-lg font-semibold mb-4 flex items-center gap-2",children:[e.jsx(te,{className:"h-5 w-5"})," Invite an admin"]}),e.jsxs("form",{onSubmit:H,className:"flex gap-2",children:[e.jsx(ne,{type:"email",placeholder:"[email protected]",value:i,onChange:s=>t(s.target.value),required:!0,maxLength:255}),e.jsx(h,{type:"submit",disabled:m.isPending,children:m.isPending?"Sending...":"Send invite"})]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-2",children:"They'll receive an email with a link to sign up and join as admin. Link expires in 7 days."}),c&&e.jsxs(ce,{variant:"destructive",className:"mt-4",children:[e.jsx(oe,{className:"h-4 w-4"}),e.jsxs(le,{className:"flex items-center gap-2",children:["Invite link domain misconfigured",e.jsx("code",{className:"text-xs font-mono px-1.5 py-0.5 rounded bg-destructive/10 text-destructive",children:c.code})]}),e.jsxs(de,{className:"space-y-2 mt-2",children:[e.jsx("p",{children:c.message}),e.jsx("p",{className:"font-medium",children:"To fix this:"}),e.jsxs("ol",{className:"list-decimal list-inside space-y-1 text-sm",children:[e.jsx("li",{children:"Open the backend secrets manager."}),e.jsxs("li",{children:["Add or update the ",e.jsx("code",{className:"font-mono px-1 rounded bg-muted",children:"PUBLIC_SITE_URL"})," secret."]}),e.jsxs("li",{children:["Set its value to your live https domain — e.g."," ",e.jsx("code",{className:"font-mono px-1 rounded bg-muted",children:"https://nicholasalifa.com"})," ","(no trailing slash, no path)."]}),e.jsx("li",{children:"Save, then resend the invite using the button below."})]}),r&&g&&!N&&e.jsxs("div",{className:"rounded-md border border-destructive/30 bg-destructive/5 p-3 text-sm space-y-1",children:[e.jsxs("p",{className:"font-medium",children:[m.isPending?"Retrying now…":`Next retry in ${K}s`,!m.isPending&&e.jsxs("span",{className:"text-muted-foreground font-normal ml-1",children:["(at ",new Date(g).toLocaleTimeString(),")"]})]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Attempt ",Math.min(j+1,f)," of ",f," ·"," ",T," ",T===1?"try":"tries"," remaining"]})]}),N&&e.jsxs("div",{className:"rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm",children:[e.jsxs("p",{className:"font-medium",children:["Auto-retry stopped after ",f," attempts."]}),e.jsxs("p",{className:"text-destructive/80 mt-1",children:["The server is still rejecting the request with"," ",e.jsx("code",{className:"font-mono",children:c.code}),". Double-check that"," ",e.jsx("code",{className:"font-mono",children:"PUBLIC_SITE_URL"})," is set to a valid https domain and try again manually."]})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2 pt-2",children:[e.jsxs(h,{size:"sm",variant:"outline",onClick:()=>{w(!1),y(0),I(c.email)},disabled:m.isPending,children:[e.jsx(ue,{className:`h-3.5 w-3.5 mr-1.5 ${m.isPending?"animate-spin":""}`}),m.isPending?"Resending...":`Resend invite to ${c.email}`]}),e.jsx(h,{size:"sm",variant:"ghost",onClick:()=>{o(!1),y(0),w(!1),v(null)},disabled:m.isPending,children:"Dismiss"}),e.jsxs("div",{className:"flex items-center gap-2 ml-auto",children:[e.jsx(ie,{id:"auto-retry-invite",checked:r,disabled:N,onCheckedChange:s=>{o(s),s&&(w(!1),y(0))}}),e.jsxs(me,{htmlFor:"auto-retry-invite",className:"text-xs cursor-pointer",children:["Auto-retry with backoff",e.jsx("span",{className:"ml-1 text-muted-foreground",children:N?"(stopped)":r?"(on)":`(5s → 10s → 20s, max ${f} tries)`})]})]})]})]})]})]}),e.jsxs(S,{className:"p-6",children:[e.jsxs("h2",{className:"text-lg font-semibold mb-4",children:["Pending invites (",A.length,")"]}),O?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading..."}):A.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No pending invites."}):e.jsx("div",{className:"space-y-3",children:A.map(s=>e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-3 p-3 border rounded-md",children:[e.jsxs("div",{children:[e.jsx("p",{className:"font-medium",children:s.email}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Sent ",D(new Date(s.created_at),"MMM d, yyyy")," · Expires"," ",D(new Date(s.expires_at),"MMM d, yyyy")]})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(h,{size:"sm",variant:"outline",onClick:()=>J(s.token),children:[e.jsx(xe,{className:"h-3.5 w-3.5 mr-1"})," Copy link"]}),e.jsx(h,{size:"sm",variant:"ghost",onClick:()=>{confirm(`Revoke invite for ${s.email}?`)&&G.mutate(s.id,{onSuccess:()=>u.success("Invite revoked")})},children:e.jsx(he,{className:"h-3.5 w-3.5"})})]})]},s.id))})]}),e.jsxs(S,{className:"p-6",children:[e.jsxs("h2",{className:"text-lg font-semibold mb-4",children:["Active admins (",M.length,")"]}),Y?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading..."}):e.jsx("div",{className:"space-y-3",children:M.map(s=>{const a=s.role==="super_admin",l=s.user_id===(n==null?void 0:n.id);return e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-3 p-3 border rounded-md",children:[e.jsx("div",{className:"flex items-center gap-3",children:e.jsxs("div",{children:[e.jsxs("p",{className:"font-medium flex items-center gap-2",children:[s.email??s.user_id,l&&e.jsx("span",{className:"text-xs text-muted-foreground",children:"(you)"})]}),s.full_name&&e.jsx("p",{className:"text-xs text-muted-foreground",children:s.full_name})]})}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(P,{variant:a?"default":"secondary",className:"gap-1",children:a?e.jsxs(e.Fragment,{children:[e.jsx(re,{className:"h-3 w-3"})," Super admin"]}):e.jsxs(e.Fragment,{children:[e.jsx(fe,{className:"h-3 w-3"})," Admin"]})}),!a&&!l&&e.jsx(h,{size:"sm",variant:"ghost",onClick:()=>{confirm(`Revoke admin access for ${s.email}?`)&&X.mutate(s.user_id,{onSuccess:()=>u.success("Admin access revoked")})},children:e.jsx(U,{className:"h-3.5 w-3.5"})})]})]}
6,s.user_id)})})]}),R.length>0&&e.jsxs(S,{className:"p-6",children:[e.jsxs("h2",{className:"text-lg font-semibold mb-4",children:["Past invites (",R.length,")"]}),e.jsx("div",{className:"space-y-2",children:R.map(s=>{const a=s.accepted_at?"accepted":s.revoked_at?"revoked":"expired";return e.jsxs("div",{className:"flex items-center justify-between gap-3 p-2 text-sm",children:[e.jsxs("div",{children:[e.jsx("span",{className:"font-medium",children:s.email}),e.jsx(P,{variant:"outline",className:"ml-2 text-xs capitalize",children:a})]}),e.jsx(h,{size:"sm",variant:"ghost",onClick:()=>V.mutate(s.id),children:e.jsx(U,{className:"h-3.5 w-3.5"})})]},s.id)})})]})]})})}export{Be 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.