PageSourceSearch

https://savera.se/assets/AdminUsers-B-9Q5vrf.js

js savera.se collected 2026-10-09 22:04:14 UTC 8,891 bytes, 6 lines download raw bytes

1import{c as ae,l as ne,n as re,r as n,s as $,j as e,a as B,w as S,f as i,G as H,J as K,L as k,I as N}from"./index-Bds7fSVR.js";import{B as M}from"./badge-CzCPep76.js";import{A as ie,a as le,b as oe,c as ce,d as de,e as me,f as ue,g as he}from"./alert-dialog-CtwNVVkw.js";import{D as xe,a as pe,b as fe,c as ge,d as je,e as ve}from"./dialog-BeYhuTnV.js";import{U as V}from"./user-plus-nUOyjTA6.js";import{T as we}from"./trash-2-Dmz7KMw1.js";import{S as ye}from"./shield-check-DxBMj_Md.js";import"./index-_uSYU7jz.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 q=ae("KeyRound",[["path",{d:"M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z",key:"1s6t7t"}],["circle",{cx:"16.5",cy:"7.5",r:".5",fill:"currentColor",key:"w0ekpg"}]]),J={superadmin:{label:"Superadmin",variant:"default",icon:ye},admin:{label:"Admin",variant:"secondary",icon:S},user:{label:"Användare",variant:"outline",icon:S}},_e=()=>{const b=ne(),{toast:r}=re(),[C,G]=n.useState([]),[W,A]=n.useState(!0),[D,x]=n.useState(null),[m,L]=n.useState(null),[p,f]=n.useState(null),[Q,E]=n.useState(!1),[_,T]=n.useState(!1),[u,P]=n.useState(""),[g,R]=n.useState(""),[I,F]=n.useState(!1),[l,h]=n.useState(null),[j,v]=n.useState(""),[U,O]=n.useState(!1),w="https://vmtnjkvdsvxtedlmbpdv.supabase.co/functions/v1/admin-users",y=n.useCallback(async()=>{const{data:{session:s}}=await $.auth.getSession();return s?{Authorization:`Bearer ${s.access_token}`,"Content-Type":"application/json"}:null},[]),o=n.useCallback(async()=>{const s=await y();if(!s){x("Ej inloggad"),A(!1);return}try{const t=await fetch(w,{headers:s}),a=await t.json();if(!t.ok){if(t.status===403)x("Endast superadmins har Ã¥tkomst."),E(!1);else throw new Error(a.error||"Kunde inte hämta användare");return}E(!0),G(a.users||[])}catch(t){x(t instanceof Error?t.message:"Okänt fel")}finally{A(!1)}},[w,y]);n.useEffect(()=>{const{data:{subscription:s}}=$.auth.onAuthStateChange((t,a)=>{a||b("/admin")});return o(),()=>s.unsubscribe()},[o,b]);const c=async s=>{const t=await y();if(t){L(s.user_id||s.email||"action");try{const a=await fetch(w,{method:"POST",headers:t,body:JSON.stringify(s)}),d=await a.json();if(!a.ok)throw new Error(d.error||"Åtgärden misslyckades");return d}catch(a){return r({title:"Fel",description:a instanceof Error?a.message:"Okänt fel",variant:"destructive"}),null}finally{L(null)}}},X=async s=>{const t=await c({action:"reset_password",email:s});t!=null&&t.success&&r({title:"Skickat",description:`Återställningslänk skickad till ${s}`})},Y=async()=>{if(!l)return;if(j.length<6){r({title:"Fel",description:"Lösenordet mÃ¥ste vara minst 6 tecken.",variant:"destructive"});return}O(!0);const s=await c({action:"update_password",email:l.email,password:j});O(!1),s!=null&&s.success&&(r({title:"Lösenord uppdaterat",description:`Nytt lösenord satt för ${l.email}`}),h(null),v(""))},Z=async(s,t)=>{const a=await c({action:"add_role",user_id:s,role:t});a!=null&&a.success&&(r({title:"Roll tillagd",description:`Rollen "${t}" har tilldelats.`}),o())},ee=async(s,t)=>{const a=await c({action:"remove_role",user_id:s,role:t});a!=null&&a.success&&(r({title:"Roll borttagen"}),o())},se=async s=>{const t=await c({action:"delete_user",user_id:s});t!=null&&t.success&&(r({title:"Användare borttagen"}),f(null),o())},te=async s=>{if(s.preventDefault(),!u.toLowerCase().endsWith("@savera.se")){r({title:"Fel",description:"Endast @savera.se-adresser tillÃ¥ts.",variant:"destructive"});return}if(g.length<6){r({title:"Fel",description:"Lösenordet mÃ¥ste vara minst 6 tecken.",variant:"destructive"});return}F(!0);const t=await c({action:"create_user",email:u,password:g});t!=null&&t.success&&(r({title:"Användare skapad",description:`${u} har lagts till.`}),P(""),R(""),T(!1),o()),F(!1)},z=s=>s?new Date(s).toLocaleDateString("sv-SE",{year:"numeric",month:"short",day:"numeric"}):"–";return W?e.jsx("div",{className:"flex items-center justify-center py-20",children:e.jsx(B,{className:"h-8 w-8 animate-spin text-primary"})}):D||!Q?e.jsx("div",{className:"flex items-center justify-center py-20 px-4",children:e.jsxs("div",{className:"text-center space-y-3",children:[e.jsx(S,{className:"h-12 w-12 text-destructive mx-auto"}),e.jsx("p",{className:"text-lg font-semibold text-foreground",children:D||"Åtkomst nekad"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Denna sida kräver superadmin-behörighet."})]})}):e.jsxs("div",{className:"max-w-5xl mx-auto px-4 py-8 sm:px-6",children:[e.jsxs("div",{className:"flex items-center justify-between mb-8",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("h1",{className:"text-2xl font-bold text-foreground",children:"Användare"}),e.jsx(M,{variant:"outline",children:C.length})]}),e.jsxs(i,{onClick:()=>T(!_),children:[e.jsx(V,{className:"h-4 w-4 mr-2"}),"Skapa användare"]})]}),_&&e.jsx(H,{className:"mb-6",children:e.jsx(K,{className:"p-5",children:e.jsxs("form",{onSubmit:te,className:"flex flex-col sm:flex-row gap-3 items-end",children:[e.jsxs("div",{className:"flex-1 w-full space-y-1.5",children:[e.jsx(k,{children:"E-post"}),e.jsx(N,{type:"email",value:u,onChange:s=>P(s.target.value),placeholder:"[email protected]",required:!0})]}),e.jsxs("div",{className:"flex-1 w-full space-y-1.5",children:[e.jsx(k,{children:"Lösenord"}),e.jsx(N,{type:"password",value:g,onChange:s=>R(s.target.value),placeholder:"Minst 6 tecken",required:!0,minLength:6})]}),e.jsx(i,{type:"submit",disabled:I,className:"whitespace-nowrap",children:I?"Skapar…":"Skapa"})]})})}),e.jsx("div",{className:"space-y-3",children:C.sort((s,t)=>{const a=s.roles.includes("superadmin")?0:1,d=t.roles.includes("superadmin")?0:1;return a-d||s.email.localeCompare(t.email)}).map(s=>e.jsx(H,{children:e.jsxs(K,{className:"p-5 flex flex-col md:flex-row md:items-center gap-4",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"text-sm font-semibold text-foreground truncate",children:s.email}),e.jsxs("div",{className:"flex items-center gap-3 mt-1 text-xs text-muted-foreground",children:[e.jsxs("span",{children:["Skapad ",z(s.created_at)]}),e.jsx("span",{children:"·"}),e.jsxs("span",{children:["Senast inloggad ",z(s.last_sign_in_at)]})]}),e.jsxs("div",{className:"flex flex-wrap gap-1.5 mt-2",children:[s.roles.length>0?s.roles.map(t=>{const a=J[t]||J.user,d=a.icon;return e.jsxs(M,{variant:a.variant,className:"gap-1",children:[e.jsx(d,{className:"h-3 w-3"}),a.label,e.jsx("button",{onClick:()=>ee(s.id,t),className:"ml-0.5 hover:text-destructive transition",title:"Ta bort roll",children:"×"})]},t)}):e.jsx("span",{className:"text-xs text-muted-foreground italic",children:"Ingen roll"}),!s.roles.includes("superadmin")&&!s.roles.includes("admin")&&e.jsxs(i,{variant:"outline",size:"sm",className:"h-6 text-xs px-2",onClick:()=>Z(s.id,"admin"),disabled:m===s.id,children:[e.jsx(V,{className:"h-3 w-3 mr-1"})," Admin"]})]})]}),e.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[e.jsxs(i,{variant:"outline",size:"sm",onClick:()=>X(s.email),disabled:m===s.email,children:[m===s.email?e.jsx(B,{className:"h-3 w-3 animate-spin mr-1.5"}):e.jsx(q,{className:"h-3 w-3 mr-1.5"}),"Återställ via mejl"]}),e.jsxs(i,{variant:"outline",size:"sm",onClick:()=>{h(s),v("")},children:[e.jsx(q,{className:"h-3 w-3 mr-1.5"}),"Sätt lösenord"]}),e.jsx(i,{variant:"ghost",size:"icon",className:"h-8 w-8 hover:text-destructive",onClick:()=>f(s.id),title:"Ta bort användare",children:e.jsx(we,{className:"h-4 w-4"})})]})]})},s.id))}),e.jsx(ie,{open:!!p,onOpenChange:()=>f(null),children:e.jsxs(le,{children:[e.jsxs(oe,{children:[e.jsx(ce,{children:"Ta bort användare?"}),e.jsx(de,{children:"Denna Ã¥tgärd kan inte Ã¥ngras. Användaren och alla dess roller kommer att tas bort."})]}),e.jsxs(me,{children:[e.jsx(ue,{children:"Avbryt"}),e.jsx(he,{onClick:()=>p&&se(p),disabled:!!m,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:m?"Tar bort…":"Ta bort"})]})]})}),e.jsx(xe,{open:!!l,onOpenChange:s=>!s&&h(null),children:e.jsxs(pe,{children:[e.jsxs(fe,{children:[e.jsx(ge,{children:"Sätt nytt lösenord"}),e.jsxs(je,{children:["Sätter ett nytt lösenord direkt för ",e.jsx("strong",{children:l==null?void 0:l.email}),". Användaren fÃ¥r inget mejl."]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(k,{children:"Nytt lösenord"}),e.jsx(N,{type:"text",value:j,onChange:s=>v(s.target.value),placeholder:"Minst 6 tecken",autoComplete:"new-password"})]}),e.jsxs(ve,{children:[e.jsx(i,{variant:"outline",onClick:()=>h(null),children:"Avbryt"}),e.jsx(i,{onClick:Y,disabled:U,children:U?"Sparar…":"Sätt lösenord"})]})]})})]})};export{_e 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.