PageSourceSearch

https://goneat.co.uk/assets/gallery-DtIWKaXT.js

js goneat.co.uk collected 2026-10-02 02:09:34 UTC 16,335 bytes, 1 lines download raw bytes

1import{j as e}from"./vendor-query-D1Mshrk-.js";import{r as t}from"./vendor-react-BfQMi0FG.js";import{I as W,c as ae}from"./image-compression-BLM619nq.js";import{P as te}from"./page-header-C7x1KRLA.js";import{B as o,U as B,S as le,I as U,e as H,j as K,f as G,t as f,X as ie,P as X,L as D,r as $}from"./index-BrXTQpUj.js";import{S as F,a as _,b as z,c as A,d as T}from"./select-CxlFVGv9.js";import{D as O,a as R,b as V,c as q,e as J}from"./dialog-OAqv1hEh.js";import{C as Q}from"./confirm-dialog-NWiIykoS.js";import{u as re,a as Y,b as ne,c as ce,d as de,e as oe,f as me,g as ue}from"./use-gallery-C9eBKXiP.js";import{u as Z}from"./use-clients-BGII2zas.js";import{T as pe}from"./tags-BsmeIwS0.js";import{F as ee}from"./film-BuHzBznR.js";import{P as se}from"./pencil-DXFkiqC-.js";import"./vendor-ui-87y9m6y2.js";import"./check-DjZQULyt.js";import"./alert-dialog-ktYZjlA1.js";function _e(){const[l,S]=t.useState(""),[w,i]=t.useState(""),[m,N]=t.useState("all"),[y,j]=t.useState(""),[d,h]=t.useState(""),[r,b]=t.useState(""),[x,I]=t.useState(1),[n,g]=t.useState(!1),[k,c]=t.useState(null),[E,M]=t.useState(!1);t.useEffect(()=>{const s=setTimeout(()=>i(l),300);return()=>clearTimeout(s)},[l]),t.useEffect(()=>{I(1)},[w,d,m,r,y]),t.useEffect(()=>{m==="public"&&b("")},[m]);const{data:C,isLoading:L}=re({page:x,limit:24,scope:m,tagId:d||void 0,search:w||void 0,adminView:!0,clientId:r||void 0,mediaType:y||void 0}),{data:P}=Y(),{data:a}=Z({limit:100}),p=ne(),u=async s=>{try{await p.mutateAsync(s),f.success("Image deleted")}catch{f.error("Failed to delete image")}};return e.jsxs("div",{className:"space-y-6",children:[e.jsx(te,{title:"Gallery",description:"Manage all gallery media across clients",action:e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(o,{variant:"outline",onClick:()=>M(!0),children:[e.jsx(pe,{className:"mr-2 h-4 w-4"}),"Tags"]}),e.jsxs(o,{onClick:()=>g(!0),children:[e.jsx(B,{className:"mr-2 h-4 w-4"}),"Upload"]})]})}),e.jsxs("div",{className:"flex flex-col gap-3 sm:flex-row sm:items-center",children:[e.jsxs("div",{className:"relative flex-1",children:[e.jsx(le,{className:"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground"}),e.jsx(U,{placeholder:"Search...",value:l,onChange:s=>S(s.target.value),className:"pl-9"})]}),e.jsx("div",{className:"flex gap-1 rounded-lg border p-1",children:["all","public","private"].map(s=>e.jsx(o,{variant:m===s?"default":"ghost",size:"sm",onClick:()=>N(s),className:"capitalize",children:s},s))}),e.jsx("div",{className:"flex gap-1 rounded-lg border p-1",children:[["","All"],["image","Images"],["video","Videos"]].map(([s,v])=>e.jsx(o,{variant:y===s?"default":"ghost",size:"sm",onClick:()=>j(s),children:v},s))}),e.jsxs(F,{value:d||"_all",onValueChange:s=>h(s==="_all"?"":s),children:[e.jsx(_,{className:"w-[180px]",children:e.jsx(z,{placeholder:"All tags"})}),e.jsxs(A,{children:[e.jsx(T,{value:"_all",children:"All tags"}),P?.map(s=>e.jsxs(T,{value:s.id,children:[s.name," (",s._count?.images??0,")"]},s.id))]})]}),m!=="public"&&e.jsxs(F,{value:r||"_all",onValueChange:s=>b(s==="_all"?"":s),children:[e.jsx(_,{className:"w-[180px]",children:e.jsx(z,{placeholder:"All clients"})}),e.jsxs(A,{children:[e.jsx(T,{value:"_all",children:"All clients"}),a?.clients.map(s=>e.jsx(T,{value:s.id,children:s.name},s.id))]})]})]}),C&&e.jsxs("p",{className:"text-sm text-muted-foreground",children:[C.meta.total," item",C.meta.total!==1?"s":"",m!=="all"&&` (${m})`,r&&a?.clients.find(s=>s.id===r)&&` - ${a.clients.find(s=>s.id===r).name}`]}),L?e.jsx("div",{className:"grid grid-cols-2 gap-4 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6",children:Array.from({length:12}).map((s,v)=>e.jsx(H,{className:"aspect-square rounded-lg"},v))}):C?.images.length?e.jsx("div",{className:"grid grid-cols-2 gap-4 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6",children:C.images.map(s=>e.jsxs("div",{className:"group relative overflow-hidden rounded-lg border bg-muted",children:[e.jsx("div",{className:"aspect-square",children:s.mediaType==="video"?e.jsxs("div",{className:"relative h-full w-full bg-black",children:[e.jsx("video",{src:s.url,className:"h-full w-full object-cover",muted:!0,loop:!0,playsInl
1ine:!0,preload:"metadata",onMouseEnter:v=>v.currentTarget.play(),onMouseLeave:v=>{v.currentTarget.pause(),v.currentTarget.currentTime=0}}),e.jsx("div",{className:"pointer-events-none absolute inset-0 flex items-center justify-center transition-opacity group-hover:opacity-0",children:e.jsx(ee,{className:"h-8 w-8 text-white/80"})})]}):e.jsx("img",{src:s.url,alt:s.name,className:"h-full w-full object-cover",loading:"lazy"})}),e.jsxs("div",{className:"absolute right-1.5 top-1.5 flex gap-1 opacity-0 transition-opacity group-hover:opacity-100",children:[e.jsx(o,{variant:"secondary",size:"icon",className:"h-7 w-7",onClick:()=>c(s),children:e.jsx(se,{className:"h-3.5 w-3.5"})}),e.jsx(Q,{trigger:e.jsx(o,{variant:"destructive",size:"icon",className:"h-7 w-7",children:e.jsx(K,{className:"h-3.5 w-3.5"})}),title:"Delete Image",description:`Delete "${s.name}"? This will also remove it from Cloudinary.`,onConfirm:()=>u(s.id)})]}),e.jsxs("div",{className:"absolute left-1.5 top-1.5 flex flex-col gap-0.5",children:[e.jsx(G,{variant:s.clientId===null?"default":"secondary",className:"text-[10px] px-1.5 py-0",children:s.clientId===null?"Public":"Private"}),s.client&&e.jsx(G,{variant:"outline",className:"text-[10px] px-1.5 py-0 bg-background/80",children:s.client.name})]}),e.jsxs("div",{className:"p-2",children:[e.jsx("p",{className:"truncate text-xs font-medium",children:s.name}),s.tag&&e.jsx("p",{className:"truncate text-[10px] text-muted-foreground",children:s.tag.name})]})]},s.id))}):e.jsxs("div",{className:"flex flex-col items-center justify-center py-16 text-muted-foreground",children:[e.jsx(W,{className:"mb-3 h-12 w-12"}),e.jsx("p",{className:"text-lg font-medium",children:"No media found"}),e.jsx("p",{className:"text-sm",children:w||d||r?"Try adjusting your filters":"Upload images or videos to get started"}),!w&&!d&&!r&&e.jsxs(o,{className:"mt-4",onClick:()=>g(!0),children:[e.jsx(B,{className:"mr-2 h-4 w-4"}),"Upload"]})]}),C&&C.meta.totalPages>1&&e.jsxs("div",{className:"flex items-center justify-center gap-2",children:[e.jsx(o,{variant:"outline",size:"sm",disabled:x<=1,onClick:()=>I(x-1),children:"Previous"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:["Page ",x," of ",C.meta.totalPages]}),e.jsx(o,{variant:"outline",size:"sm",disabled:x>=C.meta.totalPages,onClick:()=>I(x+1),children:"Next"})]}),e.jsx(he,{open:n,onOpenChange:g,tags:P??[]}),k&&e.jsx(xe,{image:k,tags:P??[],open:!!k,onOpenChange:s=>{s||c(null)}}),e.jsx(ge,{open:E,onOpenChange:M})]})}function he({open:l,onOpenChange:S,tags:w}){const[i,m]=t.useState([]),[N,y]=t.useState(""),[j,d]=t.useState(""),[h,r]=t.useState(!1),[b,x]=t.useState(!1),[I,n]=t.useState(!1),g=t.useRef(null),k=ce(),c=i.length===1,E=async a=>{const p=a.filter(u=>u.type.startsWith("image/")||u.type.startsWith("video/"));if(p.length===0){f.error("Please select image or video files");return}r(!0);try{const u=[];for(const s of p){let v;if(s.type.startsWith("video/"))v=s;else try{v=await ae(s)}catch{v=s}u.push({file:v,preview:URL.createObjectURL(v),name:s.name.replace(/\.[^.]+$/,"")})}m(s=>[...s,...u]),i.length===0&&u.length===1&&!N&&y(u[0].name)}finally{r(!1)}},M=a=>{m(p=>{const u=[...p];return URL.revokeObjectURL(u[a].preview),u.splice(a,1),u})},C=async()=>{if(i.length===0||c&&!N.trim())return;x(!0);let a=0;try{for(const p of i){const u=new FormData;u.append("file",p.file),u.append("name",c?N.trim():p.name),u.append("scope","public"),j&&u.append("tagId",j),await k.mutateAsync(u),a++}f.success(a===1?"Image uploaded":`${a} images uploaded`),L(),S(!1)}catch{a>0?f.error(`Uploaded ${a}/${i.length} — some failed`):f.error("Failed to upload images")}finally{x(!1)}},L=()=>{y(""),d("");for(const a of i)URL.revokeObjectURL(a.preview);m([])};t.useEffect(()=>{l||L()},[l]);const P=a=>{a.preventDefault(),n(!1);const p=Array.from(a.dataTransfer.files);p.length&&E(p)};return e.jsx(O,{open:l,onOpenChange:S,children:e.jsxs(R,{children:[e.jsx(V,{children:e.jsx(q,{children:"Upload Public Media"})}),e.jsxs("div",{className:"space-y-4",children:[i.length>0?e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"grid grid-cols-3 gap-2 max-h-48 overflow-y-auto",children:[i.map((a,p)=>e.jsxs("div",{className:"relative group",children:[a.file.type.startsWith("video/")?e.jsxs("div",{className:"relative aspect-square w-full rounded-lg border bg-black overflow-hidden",children:[e.jsx("video",{src:a.preview,className:"h-full w-full object-cover",muted:!0,preload:"metadata"}),e.jsx("div",{className:"absolute inset-0 flex items-center justify-center",children:e.jsx(ee,{className:"h-6 w-6 text-white/80"})})]}):e.jsx("img",{src:a.preview,alt:a.name,className:"aspect-square w-full rounded-lg border object-cover"}),e.jsx(o,{type:"button",variant:"destructive",size:"icon",className:"absolute -right-1 -top-1 h-5 w-5 opacity-0 group-hover:opacity-100 transition-opacity",onClick:()=>M(p),children:e.jsx(ie,{className:"h-3 w-3"})})]},p)),e.jsx("button",{type:"button",className:"aspect-square flex items-center justify-center rounded-lg border-2 border-dashed border-muted-foreground
1/25 hover:border-muted-foreground/50 text-muted-foreground",onClick:()=>g.current?.click(),children:e.jsx(X,{className:"h-5 w-5"})})]}),i.length>1&&e.jsxs("p",{className:"text-xs text-muted-foreground",children:[i.length," images selected"]})]}):e.jsx("button",{type:"button",className:`flex h-40 w-full items-center justify-center rounded-lg border-2 border-dashed transition-colors ${I?"border-primary bg-primary/5":"border-muted-foreground/25 hover:border-muted-foreground/50"}`,onClick:()=>g.current?.click(),onDragOver:a=>{a.preventDefault(),n(!0)},onDragLeave:()=>n(!1),onDrop:P,children:e.jsxs("div",{className:"text-center text-muted-foreground",children:[e.jsx(W,{className:"mx-auto mb-2 h-8 w-8"}),e.jsx("p",{className:"text-sm",children:"Click or drag & drop images/videos"}),e.jsx("p",{className:"text-xs mt-1",children:"Images (5MB) and videos (50MB) supported"})]})}),c&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(D,{children:"Name"}),e.jsx(U,{value:N,onChange:a=>y(a.target.value),placeholder:"Image name"})]}),i.length>0&&e.jsxs("div",{className:"space-y-2",children:[e.jsxs(D,{children:["Tag",i.length>1?" (applied to all)":""," ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsxs(F,{value:j||"_none",onValueChange:a=>d(a==="_none"?"":a),children:[e.jsx(_,{children:e.jsx(z,{placeholder:"Select a tag"})}),e.jsx(A,{children:w.map(a=>e.jsx(T,{value:a.id,children:a.name},a.id))})]}),!j&&e.jsx("p",{className:"text-xs text-muted-foreground",children:"Please select a tag before uploading"})]})]}),e.jsxs(J,{children:[e.jsx(o,{variant:"outline",onClick:()=>S(!1),children:"Cancel"}),e.jsxs(o,{disabled:i.length===0||c&&!N.trim()||!j||h||b,onClick:C,children:[(h||b)&&e.jsx($,{className:"mr-2 h-4 w-4 animate-spin"}),h?"Compressing...":b?"Uploading...":i.length>1?`Upload ${i.length}`:"Upload"]})]}),e.jsx("input",{ref:g,type:"file",accept:"image/jpeg,image/png,image/webp,image/gif,video/mp4,video/webm,video/quicktime",multiple:!0,className:"hidden",onChange:a=>{const p=Array.from(a.target.files??[]);p.length&&E(p),a.target.value=""}})]})})}function xe({image:l,tags:S,open:w,onOpenChange:i}){const[m,N]=t.useState(l.name),[y,j]=t.useState(l.tagId??""),[d,h]=t.useState(l.clientId===null?"public":"private"),[r,b]=t.useState(l.clientId??""),x=de(),{data:I}=Z({limit:100});t.useEffect(()=>{N(l.name),j(l.tagId??""),h(l.clientId===null?"public":"private"),b(l.clientId??"")},[l]);const n=l.clientId===null?"public":"private",g=d!==n||d==="private"&&r!==l.clientId,k=async()=>{if(d==="private"&&!r){f.error("Please select a client for private images");return}try{await x.mutateAsync({id:l.id,data:{name:m.trim(),tagId:y||null,...g&&{scope:d,...d==="private"&&{clientId:r}}}}),f.success("Image updated"),i(!1)}catch{f.error("Failed to update image")}};return e.jsx(O,{open:w,onOpenChange:i,children:e.jsxs(R,{children:[e.jsx(V,{children:e.jsx(q,{children:"Edit Image"})}),e.jsxs("div",{className:"space-y-4",children:[e.jsx("div",{className:"flex justify-center",children:l.mediaType==="video"?e.jsx("video",{src:l.url,className:"max-h-48 rounded-lg border object-contain",controls:!0,muted:!0}):e.jsx("img",{src:l.url,alt:l.name,className:"max-h-48 rounded-lg border object-contain"})}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(D,{children:"Name"}),e.jsx(U,{value:m,onChange:c=>N(c.target.value),placeholder:"Image name"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(D,{children:"Tag"}),e.jsxs(F,{value:y||"_none",onValueChange:c=>j(c==="_none"?"":c),children:[e.jsx(_,{children:e.jsx(z,{placeholder:"No tag"})}),e.jsxs(A,{children:[e.jsx(T,{value:"_none",children:"No tag"}),S.map(c=>e.jsx(T,{value:c.id,children:c.name},c.id))]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(D,{children:"Visibility"}),e.jsxs("div",{className:"flex gap-1 rounded-lg border p-1",children:[e.jsx(o,{type:"button",variant:d==="public"?"default":"ghost",size:"sm",className:"flex-1",onClick:()=>h("public"),children:"Public"}),e.jsx(o,{type:"button",variant:d==="private"?"default":"ghost",size:"sm",className:"flex-1",onClick:()=>h("private"),children:"Private"})]})]}),d==="private"&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(D,{children:"Client"}),e.jsxs(F,{value:r||"_none",onValueChange:c=>b(c==="_none"?"":c),children:[e.jsx(_,{children:e.jsx(z,{placeholder:"Select a client"})}),e.jsxs(A,{children:[e.jsx(T,{value:"_none",disabled:!0,children:"Select a client"}),I?.clients.map(c=>e.jsx(T,{value:c.id,children:c.name},c.id))]})]})]})]}),e.jsxs(J,{children:[e.jsx(o,{variant:"outline",onClick:()=>i(!1),children:"Cancel"}),e.jsxs(o,{disabled:!m.trim()||d==="private"&&!r||x.isPending,onClick:k,children:[x.isPending&&e.jsx($,{className:"mr-2 h-4 w-4 animate-spin"}),"Save"]})]})]})})}function ge({open:l,onOpenChange:S}){const{data:w,isLoading:i}=Y(),m=oe(),N=me(),y=ue(),[j,d]=t.useState(""),[h,r]=t.useState(null),b=async()=>
1{if(j.trim())try{await m.mutateAsync({name:j.trim()}),d(""),f.success("Tag created")}catch{f.error("Failed to create tag")}},x=async()=>{if(!(!h||!h.name.trim()))try{await N.mutateAsync({id:h.id,data:{name:h.name.trim()}}),r(null),f.success("Tag updated")}catch{f.error("Failed to update tag")}},I=async n=>{try{await y.mutateAsync(n),f.success("Tag deleted")}catch{f.error("Failed to delete tag")}};return e.jsx(O,{open:l,onOpenChange:S,children:e.jsxs(R,{children:[e.jsx(V,{children:e.jsx(q,{children:"Manage Public Tags"})}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex gap-2",children:[e.jsx(U,{value:j,onChange:n=>d(n.target.value),placeholder:"New tag name",onKeyDown:n=>{n.key==="Enter"&&b()}}),e.jsx(o,{size:"sm",disabled:!j.trim()||m.isPending,onClick:b,children:m.isPending?e.jsx($,{className:"h-4 w-4 animate-spin"}):e.jsx(X,{className:"h-4 w-4"})})]}),e.jsx("div",{className:"max-h-64 space-y-2 overflow-y-auto",children:i?Array.from({length:3}).map((n,g)=>e.jsx(H,{className:"h-10 rounded-lg"},g)):w?.length?w.map(n=>e.jsx("div",{className:"flex items-center gap-2 rounded-lg border p-2",children:h?.id===n.id?e.jsxs(e.Fragment,{children:[e.jsx(U,{value:h.name,onChange:g=>r({...h,name:g.target.value}),className:"h-8",onKeyDown:g=>{g.key==="Enter"&&x(),g.key==="Escape"&&r(null)},autoFocus:!0}),e.jsx(o,{size:"sm",variant:"ghost",onClick:x,children:"Save"}),e.jsx(o,{size:"sm",variant:"ghost",onClick:()=>r(null),children:"Cancel"})]}):e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"flex-1 text-sm",children:n.name}),e.jsx(G,{variant:"secondary",className:"text-xs",children:n._count?.images??0}),e.jsx(o,{size:"icon",variant:"ghost",className:"h-7 w-7",onClick:()=>r({id:n.id,name:n.name}),children:e.jsx(se,{className:"h-3.5 w-3.5"})}),e.jsx(Q,{trigger:e.jsx(o,{size:"icon",variant:"ghost",className:"h-7 w-7 text-destructive",children:e.jsx(K,{className:"h-3.5 w-3.5"})}),title:"Delete Tag",description:`Delete "${n.name}"? Images with this tag will be untagged.`,onConfirm:()=>I(n.id)})]})},n.id)):e.jsx("p",{className:"py-4 text-center text-sm text-muted-foreground",children:"No tags yet"})})]})]})})}export{_e as SuperAdminGalleryPage};

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.