PageSourceSearch

https://frimurer.no/assets/SupportRequests-DGPRFcwe.js

js frimurer.no collected 2026-09-25 00:00:57 UTC 18,579 bytes, 7 lines download raw bytes

1import{g as et,r as l,j as e}from"./vendor-react-GnwsTJfO.js";import{u as tt,a as te,b as Le}from"./vendor-query-Dp4tHR6-.js";import{f as w,N as st,B as c,a1 as Ee,aB as se,R as at,C as Fe,g as Oe,i as K,j as P,k as U,l as M,m as x,E as rt,G as nt,n as R,a8 as ae,a9 as re,aa as ne,ab as ie,ac as le,ad as oe,U as o,I as it,a4 as ce,ak as Be,aA as lt}from"./index-Bj2Y77AF.js";import{u as ot}from"./useAdminAuth-BXhWp9H6.js";import{e as ct,L as dt}from"./AdminNavigation-DYLQ05kD.js";import{L as T}from"./label-9b9pu6HH.js";import{T as de}from"./textarea-B-AJzF_c.js";import{logActivity as ue}from"./activityLog-Hv6ME3gy.js";import{o as ut,s as $e,e as pt}from"./types-gK4KrKiz.js";import{I as mt}from"./image-plus-Da47C4bS.js";import{T as ht}from"./trash-2-D673yTlG.js";import"./vendor-cjs-BcELrC9x.js";import"./vendor-supabase-BWPZKnGU.js";import"./vendor-ui-C1xCQL2z.js";import"./vendor-utils-B2rm_Apj.js";import"./MasonicCross-CB_Vslf8.js";import"./users-CHiFHZvy.js";import"./image-l440pP5V.js";const A={bug:"Feil",adjustment:"Justering",feature:"Ny funksjonalitet"},C={new:{label:"Ny",variant:"secondary"},approved:{label:"Sendt til Lovable",variant:"default"},in_progress:{label:"Under arbeid",variant:"outline"},resolved:{label:"Løst",variant:"default"},rejected:{label:"Avvist",variant:"destructive"}},q="support-attachments",pe=5,xt=10*1024*1024,Ke=["image/jpeg","image/png","image/webp","image/heic","image/heif"],gt=ut({title:$e().trim().min(3,{message:"Tittel må være minst 3 tegn"}).max(150,{message:"Tittel må være under 150 tegn"}),body:$e().trim().min(10,{message:"Beskrivelsen må være minst 10 tegn"}).max(5e3,{message:"Beskrivelsen må være under 5000 tegn"}),request_type:pt(["bug","adjustment","feature"])});function Pe(i,D=[]){const j=[`## ${i.title}`,"",`**Type:** ${A[i.request_type]}`,`**Registrert:** ${new Date(i.created_at).toLocaleString("nb-NO",{timeZone:"Europe/Oslo"})}`,"",i.body];return D.length>0&&(j.push("","**Skjermdumper:**"),D.forEach((f,v)=>j.push(`${v+1}. ${f}`))),j.join(`
2`)}const h=w;function me(i){return new Date(i).toLocaleString("nb-NO",{timeZone:"Europe/Oslo",day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit"})}function Bt(){var Ce,qe;const{user:i,role:D,loading:j,isWebmaster:f}=ot({requiredRoles:["webmaster","editor_dnfo","editor_region"]}),v=tt(),[L,Ue]=et(),[Me,y]=l.useState(!1),[he,k]=l.useState(null),[E,xe]=l.useState(""),[N,Re]=l.useState("active"),[F,De]=l.useState("all"),[I,Ie]=l.useState("desc"),[ge,H]=l.useState(""),[je,G]=l.useState(""),[fe,Q]=l.useState("bug"),[V,O]=l.useState([]),[g,ve]=l.useState(null),[B,z]=l.useState([]),[ye,be]=l.useState(!1),[He,_e]=l.useState(!1),{data:d=[],isLoading:we}=te({queryKey:["support-requests"],enabled:!j&&!!i,queryFn:async()=>{const{data:t,error:s}=await h.from("support_requests").select("*, attachments:support_request_attachments(*)").order("created_at",{ascending:!0});if(s)throw s;return t||[]}}),{data:Ge=[]}=te({queryKey:["support-request-profiles",d.length],enabled:d.length>0,queryFn:async()=>{const t=[...new Set(d.flatMap(r=>[r.created_by,r.approved_by].filter(Boolean)))];if(t.length===0)return[];const{data:s}=await h.from("profiles").select("id, user_id, display_name, first_name, last_name").in("user_id",t);return s||[]}}),W=t=>{if(!t)return"–";const s=Ge.find(r=>r.user_id===t||r.id===t);return s&&(s.display_name||[s.first_name,s.last_name].filter(Boolean).join(" "))||"Ukjent"},a=d.find(t=>t.id===he)||null;l.useEffect(()=>{xe((a==null?void 0:a.resolution_note)??"")},[he,a==null?void 0:a.resolution_note]),l.useEffect(()=>{const t=L.get("request");t&&d.some(s=>s.id===t)&&k(t)},[d,L]);const X=l.useMemo(()=>{const t=d.filter(r=>(N==="all"?!0:N==="active"?r.status!=="resolved"&&r.status!=="rejected":r.status===N)&&(F==="all"||r.request_type===F)),s=I==="desc"?-1:1;return t.sort((r,n)=>s*(new Date(r.created_at).getTime()-new Date(n.created_at).getTime()))},[d,N,F,I]),S=l.useMemo(()=>d.filter(t=>t.status==="approved"),[d]),[ke,Ne]=l.useState(!1),[Y,J]=l.useState(null),Qe=async()=>{if(S.length!==0){Ne(!0);try{const t=[];for(const r of S){const n=(r.attachments||[]).map(u=>u.storage_path);let m=[];
2if(n.length>0){const{data:u}=await w.storage.from(q).createSignedUrls(n,3600);m=(u||[]).map(p=>p.signedUrl).filter(Boolean)}t.push(Pe(r,m))}const s=[`# Godkjente supporthenvendelser (${S.length})`,"",t.join(`
3
4---
5
6`)].join(`
7`);J(s);try{await navigator.clipboard.writeText(s),o.success("Alle godkjente saker er kopiert")}catch{o.message("Kopier teksten manuelt fra vinduet")}}catch(t){console.error(t),o.error("Kunne ikke hente sakene")}finally{Ne(!1)}}},Se=d.filter(t=>t.status==="new").length,{data:Z=[]}=te({queryKey:["support-attachment-urls",a==null?void 0:a.id,(Ce=a==null?void 0:a.attachments)==null?void 0:Ce.length],enabled:!!a&&(((qe=a.attachments)==null?void 0:qe.length)??0)>0,queryFn:async()=>{const t=((a==null?void 0:a.attachments)||[]).map(r=>r.storage_path),{data:s}=await w.storage.from(q).createSignedUrls(t,60*60);return(s||[]).map(r=>r.signedUrl).filter(Boolean)}}),$=()=>{H(""),G(""),Q("bug"),O([]),ve(null),z([])},Ve=t=>{ve(t.id),H(t.title),G(t.body),Q(t.request_type),O([]),z([]),k(null),y(!0)},b=d.find(t=>t.id===g)||null,ee=((b==null?void 0:b.attachments)||[]).filter(t=>!B.includes(t.id)),ze=pe-ee.length-V.length,We=t=>f||t.created_by===(i==null?void 0:i.id)&&t.status==="new",Xe=t=>{if(!t)return;const s=Array.from(t),r=[];for(const n of s){if(!Ke.includes(n.type)){o.error(`${n.name}: kun JPG, PNG, WEBP eller HEIC`);continue}if(n.size>xt){o.error(`${n.name}: maks 10 MB`);continue}r.push(n)}O(n=>[...n,...r].slice(0,Math.max(0,pe-ee.length)))},Te=async(t,s)=>{var r;for(const n of V){const m=((r=n.name.split(".").pop())==null?void 0:r.toLowerCase())||"jpg",u=`${t}/${crypto.randomUUID()}.${m}`,{error:p}=await w.storage.from(q).upload(u,n,{contentType:n.type});if(p){o.error(`Kunne ikke laste opp ${n.name}`);continue}await h.from("support_request_attachments").insert({request_id:t,storage_path:u,file_name:n.name,mime_type:n.type,created_by:s})}},Ye=async()=>{const t=gt.safeParse({title:ge,body:je,request_type:fe});if(!t.success){o.error(t.error.issues[0].message);return}if(i){be(!0);try{if(g){const{error:n}=await h.from("support_requests").update({title:t.data.title,body:t.data.body,request_type:t.data.request_type}).eq("id",g);if(n)throw n;if(B.length>0){const u=((b==null?void 0:b.attachments)||[]).filter(p=>B.includes(p.id)).map(p=>p.storage_path);u.length>0&&await w.storage.from(q).remove(u),await h.from("support_request_attachments").delete().in("id",B)}await Te(g,i.id),await ue(i.id,"support_request_updated","support_request",g,{title:t.data.title}),o.success("Henvendelsen er oppdatert"),$(),y(!1),v.invalidateQueries({queryKey:["support-requests"]});return}const{data:s,error:r}=await h.from("support_requests").insert({title:t.data.title,body:t.data.body,request_type:t.data.request_type,created_by:i.id}).select().single();if(r)throw r;await Te(s.id,i.id),await ue(i.id,"support_request_created","support_request",s.id,{title:t.data.title,request_type:t.data.request_type}),o.success("Henvendelsen er registrert"),$(),y(!1),v.invalidateQueries({queryKey:["support-requests"]})}catch(s){console.error(s),o.error("Kunne ikke lagre henvendelsen")}finally{be(!1)}}},_=Le({mutationFn:async({request:t,status:s,note:r})=>{const n={status:s};s==="approved"&&(n.approved_by=(i==null?void 0:i.id)??null,n.approved_at=new Date().toISOString()),r!==void 0&&(n.resolution_note=r);const{error:m}=await h.from("support_requests").update(n).eq("id",t.id);if(m)throw m;const u=s==="approved"?"support_request_approved":s==="rejected"?"support_request_rejected":"support_request_status_changed";if(await ue(i==null?void 0:i.id,u,"support_request",t.id,{title:t.title,status:s}),(s==="resolved"||s==="rejected")&&t.created_by&&t.created_by!==(i==null?void 0:i.id)){const p=s==="resolved",{error:Ae}=await h.rpc("create_admin_notification",{_user_id:t.created_by,_type:p?"success":"error",_title:p?`Supporthenvendelse løst: ${t.title}`:`Supporthenvendelse avvist: ${t.title}`,_message:p?r?`Svar: ${r.slice(0,300)}`:"Henvendelsen din er markert som løst.":r?`Begrunnelse: ${r}`:"Henvendelsen din ble avvist.",_link:`/admin/support?request=${t.id}`});Ae&&console.error("Kunne ikke sende varsel:",Ae)}},onSuccess:()=>
7{o.success("Status oppdatert"),v.invalidateQueries({queryKey:["support-requests"]})},onError:()=>o.error("Kunne ikke oppdatere status")}),Je=Le({mutationFn:async t=>{const s=(t.attachments||[]).map(n=>n.storage_path);s.length>0&&await w.storage.from(q).remove(s);const{error:r}=await h.from("support_requests").delete().eq("id",t.id);if(r)throw r},onSuccess:()=>{o.success("Henvendelsen er slettet"),k(null),v.invalidateQueries({queryKey:["support-requests"]})},onError:()=>o.error("Kunne ikke slette henvendelsen")}),Ze=async()=>{a&&(await navigator.clipboard.writeText(Pe(a,Z)),_e(!0),o.success("Kopiert til utklippstavlen"),setTimeout(()=>_e(!1),2e3))};return j?null:e.jsxs("div",{className:"min-h-screen bg-background",children:[e.jsx(st,{}),e.jsx(ct,{}),e.jsxs("main",{className:"container mx-auto px-4 py-8",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-4 mb-6",children:[e.jsxs("div",{children:[e.jsxs("h1",{className:"text-3xl font-bold flex items-center gap-2",children:[e.jsx(dt,{className:"h-7 w-7 text-primary"}),"Support"]}),e.jsxs("p",{className:"text-muted-foreground mt-1",children:["Meld inn feil, justeringer og ønsker om ny funksjonalitet.",f&&Se>0&&e.jsxs(e.Fragment,{children:[" ",Se," venter på godkjenning."]})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[S.length>0&&e.jsxs(c,{variant:"outline",onClick:Qe,disabled:ke,children:[ke?e.jsx(Ee,{className:"h-4 w-4 mr-2 animate-spin"}):e.jsx(se,{className:"h-4 w-4 mr-2"}),"Send alle godkjente til Lovable (",S.length,")"]}),e.jsxs(c,{onClick:()=>{$(),y(!0)},children:[e.jsx(at,{className:"h-4 w-4 mr-2"}),"Ny henvendelse"]})]})]}),e.jsx(Fe,{className:"bg-muted/50 mb-6",children:e.jsxs(Oe,{className:"flex flex-wrap gap-3 pt-6",children:[e.jsxs(K,{value:N,onValueChange:Re,children:[e.jsx(P,{className:"w-[200px]",children:e.jsx(U,{placeholder:"Status"})}),e.jsxs(M,{children:[e.jsx(x,{value:"active",children:"Aktive saker"}),e.jsx(x,{value:"all",children:"Alle statuser"}),Object.entries(C).map(([t,s])=>e.jsx(x,{value:t,children:s.label},t))]})]}),e.jsxs(K,{value:F,onValueChange:De,children:[e.jsx(P,{className:"w-[200px]",children:e.jsx(U,{placeholder:"Type"})}),e.jsxs(M,{children:[e.jsx(x,{value:"all",children:"Alle typer"}),Object.entries(A).map(([t,s])=>e.jsx(x,{value:t,children:s},t))]})]}),e.jsxs(K,{value:I,onValueChange:t=>Ie(t),children:[e.jsx(P,{className:"w-[200px]",children:e.jsx(U,{placeholder:"Sortering"})}),e.jsxs(M,{children:[e.jsx(x,{value:"desc",children:"Nyeste først"}),e.jsx(x,{value:"asc",children:"Eldste først"})]})]})]})}),e.jsxs(Fe,{children:[e.jsx(rt,{children:e.jsxs(nt,{children:["Henvendelser (",X.length,")"]})}),e.jsxs(Oe,{className:"space-y-3",children:[we&&e.jsx("p",{className:"text-muted-foreground",children:"Laster …"}),!we&&X.length===0&&e.jsx("p",{className:"text-muted-foreground",children:"Ingen henvendelser ennå."}),X.map(t=>{var s;return e.jsxs("button",{onClick:()=>k(t.id),className:"w-full text-left rounded-lg border p-4 hover:bg-muted/50 transition-colors",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("span",{className:"font-medium",children:t.title}),e.jsx(R,{variant:"outline",className:"whitespace-nowrap",children:A[t.request_type]}),e.jsx(R,{variant:C[t.status].variant,className:"whitespace-nowrap",children:C[t.status].label}),(((s=t.attachments)==null?void 0:s.length)??0)>0&&e.jsxs(R,{variant:"secondary",className:"whitespace-nowrap",children:[t.attachments.length," bilde",t.attachments.length>1?"r":""]})]}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1 line-clamp-2",children:t.body}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-2",children:[W(t.created_by)," · ",me(t.created_at)]})]},t.id)})]})]})]}),e.jsx(ae,{open:!!Y,onOpenChange:t=>!t&&J(null),children:e.jsxs(re,{className:"max-w-3xl",children:[e.jsxs(ne,{children:[e.jsx(ie,{children:"Godkjente saker til Lovable"}),e.jsx(le,{children:"Teksten er forsøkt kopiert automatisk. Marker og kopier herfra hvis utklippstavlen er blokkert, og lim den inn i Lovable-chatten."})]}),e.jsx(de,{readOnly:!0,rows:16,value:Y??"",onFocus:t=>t.currentTarget.select(),className:"font-mono text-xs"}),e.jsxs(oe,{children:[e.jsxs(c,{variant:"outline",onClick:async()=>{try{await navigator.clipboard.writeText(Y??""),o.success("Kopiert")}catch{o.error("Utklippstavlen er blokkert – kopier manuelt")}},children:[e.jsx(se,{className:"h-4 w-4 mr-2"}),"Kopier"]}),e.jsx(c,{onClick:()=>J(null),children:"Lukk"})]})]})}),e.jsx(ae,{open:Me,onOpenChange:t=>{y(t),t||$()},children:e.jsxs(re,{className:"max-w-2xl",children:[e.jsxs(ne,{children:[e.jsx(ie,{children:g?"Rediger henvendelse":"Ny henvendelse"}),e.jsx(le,{children:"Beskriv feilen eller ønsket så konkret som mulig. Legg gjerne ved skjermdumper."})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx(T,{htmlFor:"support-title",children:"Tittel"}),e.jsx(it,{id:"support-title",value:ge,maxLength:150,onChange:t=>H(t.target.value),placeholder:"Kort oppsummering"})]}),e.jsxs("div",{children:[e.jsx(T,{htmlFor:"support-type",children:"Type"}),e.jsxs(K,{value:fe,onValueChange:t=>Q(t),children:[e.jsx(P,{id:"support-type",children:e.jsx(U,{})}),e.jsx(M,{children:Object.entries(A).map(([t,s])=>e.jsx(x,{value:t,children:s},t))})]})]}),e.jsxs("div",{children:[e.jsx(T,{htmlFor:"support-body",children:"Beskrivelse"}),e.jsx(de,{id:"support-body",value:je,maxLength:5e3,rows:8,onChange:t=>G(t.target.value),placeholder:"Hva skjer, hvor skjer det, og hva forventet du?"})]}),e.jsxs("div",{children:[e.jsxs(T,{htmlFor:"support-files",children:["Skjermdumper (maks ",pe,")"]}),e.jsxs("div",{className:"mt-2 flex flex-wrap gap-3",children:[ee.map(t=>e.jsxs("div",{className:"relative h-24 w-24 rounded-md overflow-hidden border bg-muted flex items-center justify-center",children:[e.jsx("span",{className:"px-2 text-[10px] text-center text-muted-foreground line-clamp-3",children:t.file_name}),e.jsx("button",{type:"button",onClick:()=>z(s=>[...s,t.id]),className:"absolute top-1 right-1 rounded-full bg-background/90 p-1","aria-label":`Fjern ${t.file_name}`,children:e.jsx(ce,{className:"h-3 w-3"})})]},t.id)),V.map((t,s)=>e.jsxs("div",{className:"relative h-24 w-24 rounded-md overflow-hidden border",children:[e.jsx("img",{loading:"lazy",decoding:"async",src:URL.createObjectURL(t),alt:t.name,className:"h-full w-full object-cover"}),e.jsx("button",{type:"button",onClick:()=>O(r=>r.filter((n,m)=>m!==s)),className:"absolute top-1 right-1 rounded-full bg-background/90 p-1","aria-label":`Fjern ${t.name}`,children:e.jsx(ce,{className:"h-3 w-3"})})]},`${t.name}-${s}`)),ze>0&&e.jsxs("label",{className:"h-24 w-24 rounded-md border border-dashed flex flex-col items-center justify-center cursor-pointer text-muted-foreground hover:bg-muted/50",children:[e.jsx(mt,{className:"h-5 w-5"}),e.jsx("span",{className:"text-xs mt-1",children:"Legg til"}),e.jsx("input",{id:"support-files",type:"file",accept:Ke.join(","),multiple:!0,className:"hidden",onChange:t=>{Xe(t.target.files),t.target.value=""}})]})]})]})]}),e.jsxs(oe,{children:[e.jsx(c,{variant:"outline",onClick:()=>y(!1),children:"Avbryt"}),e.jsxs(c,{onClick:Ye,disabled:ye,children:[ye&&e.jsx(Ee,{className:"h-4 w-4 mr-2 animate-spin"}),g?"Lagre endringer":"Send inn"]})]})]})}),e.jsx(ae,{open:!!a,onOpenChange:t=>{if(!t&&(k(null),L.has("request"))){const s=new URLSearchParams(L);s.delete("request"),Ue(s,{replace:!0})}},children:e.jsx(re,{className:"max-w-3xl max-h-[85vh] overflow-y-auto",children:a&&e.jsxs(e.Fragment,{children:[e.jsxs(ne,{children:[e.jsx(ie,{children:a.title}),e.jsxs(le,{children:[A[a.request_type]," ·"," ",W(a.created_by)," ·"," ",me(a.created_at)]})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsx(R,{variant:C[a.status].variant,children:C[a.status].label}),e.jsx("p",{className:"whitespace-pre-wrap text-sm",children:a.body}),Z.length>0&&e.jsx("div",{className:"grid grid-cols-2 sm:grid-cols-3 gap-3",children:Z.map((t,s)=>e.jsx("a",{href:t,target:"_blank",rel:"noreferrer",className:"block rounded-md overflow-hidden border",children:e.jsx("img",{src:t,alt:`Skjermdump ${s+1}`,loading:"lazy",className:"w-full h-32 object-cover"})},t))}),a.approved_at&&e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Godkjent av ",W(a.approved_by)," ",me(a.approved_at)]}),f?e.jsxs("div",{className:"space-y-2",children:[e.jsx(T,{htmlFor:"support-reply",children:"Svar til innsender"}),e.jsx(de,{id:"support-reply",rows:5,value:E,onChange:t=>xe(t.target.value),placeholder:"Beskriv hva som ble gjort …"}),e.jsx(c,{size:"sm",variant:"outline",disabled:_.isPending,onClick:()=>_.mutate({request:a,status:a.status,note:E.trim()}),children:"Lagre svar"})]}):a.resolution_note&&e.jsxs("div",{className:"rounded-md bg-muted/50 p-3 text-sm",children:[e.jsx("p",{className:"font-medium mb-1",children:"Svar fra Webmaster"}),e.jsx("p",{className:"whitespace-pre-wrap",children:a.resolution_note})]})]}),e.jsxs(oe,{className:"flex-wrap gap-2",children:[e.jsxs(c,{variant:"outline",onClick:Ze,children:[He?e.jsx(Be,{className:"h-4 w-4 mr-2"}):e.jsx(se,{className:"h-4 w-4 mr-2"}),"Kopier som tekst"]}),We(a)&&e.jsxs(c,{variant:"outline",onClick:()=>Ve(a),children:[e.jsx(lt,{className:"h-4 w-4 mr-2"}),"Rediger"]}),f&&e.jsxs(e.Fragment,{children:[a.status==="new"&&e.jsxs(e.Fragment,{children:[e.jsxs(c,{variant:"destructive",onClick:()=>{const t=window.prompt("Kort begrunnelse for avvisning");t!==null&&_.mutate({request:a,status:"rejected",note:t})},children:[e.jsx(ce,{className:"h-4 w-4 mr-2"}),"Avvis"]}),e.jsxs(c,{onClick:()=>_.mutate({request:a,status:"approved"}),children:[e.jsx(Be,{className:"h-4 w-4 mr-2"}),"Godkjenn og send til Lovable"]})]}),a.status==="approved"&&e.jsx(c,{variant:"outline",onClick:()=>_.mutate({request:a,status:"in_progress"}),children:"Marker som under arbeid"}),a.status!=="resolved"&&a.status!=="rejected"&&e.jsx(c,{onClick:()=>_.mutate({request:a,status:"resolved",note:E.trim()}),children:E.trim()?"Lagre svar og marker som løst":"Marker som løst"}),e.jsxs(c,{variant:"ghost",onClick:()=>{window.confirm("Slette henvendelsen permanent?")&&Je.mutate(a)},children:[e.jsx(ht,{className:"h-4 w-4 mr-2"}),"Slett"]})]})]})]})})})]})}export{Bt 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.