1import{c as se,d as B,u as L,r as j,e as te,f as _,g as F,j as e,bX as ae,B as v,P as K,G as R,M as q,d4 as A,H as ie,J as re,E as z,Y as ne,h as le,i as G,k as H,m as X,n as Y,p as E,I as Q,au as de,S as oe,N as ce,O as xe,Q as ue,U as he,am as me,d7 as pe,a_ as ge,q as J,aG as je,X as ve,fG as be}from"./index-C8KwbIXq.js";import{u as fe,a as V,b as ye,D as Ne,c as we,S as Ce,v as Se,s as Te,K as Pe,P as ke,d as Ee,C as De}from"./sortable.esm-DPZCvMmw.js";import{C as Fe}from"./CommonPageContainer-Ch04DT1k.js";import{u as Me}from"./usePinchZoom-DuT0XA_c.js";import{T as Oe,a as Re,b as W,c as S,d as qe,e as T}from"./table-ChmO8q6G.js";import{E as ze}from"./eye-BZ3jfAvx.js";import{E as Ae}from"./eye-off-ChEEL-hY.js";import{G as Ie}from"./grip-vertical-aZfiN9IU.js";import{P as Ue}from"./play-CBaE0zNO.js";import{P as Be}from"./pencil-AUqnmRye.js";import"./vendor-offline-DCjJAT_B.js";/** 2 * @license lucide-react v0.562.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 Le=[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",key:"1oefj6"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5",key:"wfsgrz"}],["path",{d:"M15.033 13.44a.647.647 0 0 1 0 1.12l-4.065 2.352a.645.645 0 0 1-.968-.56v-4.704a.645.645 0 0 1 .967-.56z",key:"1tzo1f"}]],Z=se("file-play",Le),ee=[{value:"getting-started",label:"Getting Started"},{value:"clients",label:"Clients"},{value:"jobs",label:"Jobs"},{value:"team",label:"Team"},{value:"billing",label:"Billing & Payments"},{value:"advanced",label:"Advanced"}],Ge=Object.fromEntries(ee.map(s=>[s.value,s.label]));function He(s){const o=Math.floor(s/60),t=s%60;return`${o}:${t.toString().padStart(2,"0")}`}function Ke(s){return s<1024*1024?`${(s/1024).toFixed(1)} KB`:`${(s/(1024*1024)).toFixed(1)} MB`}const Qe={title:"",description:"",category:"getting-started",sortOrder:"0",durationSeconds:"",isPublished:!1};function $(s){return s?{title:s.title,description:s.description||"",category:s.category,sortOrder:String(s.sortOrder),durationSeconds:s.durationSeconds?String(s.durationSeconds):"",isPublished:s.isPublished}:{...Qe}}function Ve({open:s,onClose:o,tutorial:t}){const m=B(),{toast:p}=L(),x=j.useRef(null),[i,u]=j.useState(()=>$(t)),[d,f]=j.useState(null),[c,P]=j.useState(!1),[r,N]=j.useState(null),b=j.useRef(null),D=j.useRef((t==null?void 0:t.id)??null);((t==null?void 0:t.id)??null)!==D.current&&(D.current=(t==null?void 0:t.id)??null,u($(t)),f(null),N(null));const I=a=>{var g;const l=(g=a.target.files)==null?void 0:g[0];if(!l)return;const n=200*1024*1024;if(l.size>n){p({title:"File too large",description:"Maximum file size is 200MB",variant:"destructive"});return}if(!["video/mp4","video/quicktime","video/webm"].includes(l.type)){p({title:"Invalid file type",description:"Please upload an MP4, MOV, or WebM video",variant:"destructive"});return}f(l)},U=async()=>{if(!i.title.trim()){p({title:"Title required",description:"Please enter a tutorial title",variant:"destructive"});return}P(!0),N(d?0:null);try{let a;if(d){const g=await F("POST","/api/tutorials/upload-url",{fileName:d.name,contentType:d.type,sizeBytes:d.size});let C=null;if(g.sameOrigin&&(C=await be(),!C))throw new Error("Security token unavailable â please refresh and try again.");await new Promise((O,k)=>{const h=new XMLHttpRequest;b.current=h,h.upload.addEventListener("progress",y=>{y.lengthComputable&&N(Math.round(y.loaded/y.total*100))}),h.addEventListener("load",()=>{h.status>=200&&h.status<300?O():k(new Error(`Upload failed with status ${h.status}`))}),h.addEventListener("error",()=>{k(new Error("Network error during upload"))}),h.addEventListener("abort",()=>{k(new Error("Upload cancelled"))}),h.open(g.method,g.uploadUrl),h.withCredentials=g.sameOrigin,h.setRequestHeader("Content-Type",g.contentType),g.sameOrigin&&C&&h.setRequestHeader("X-CSRF-Token",C),h.send(d)}),a=g.uploadHandle,N(100)}const l=t?`/api/tutorials/${t.id}`:"/api/tutorials",n=t?"PUT":"POST",w={title:i.title.trim(),description:i.description.trim(),category:i.category,sortOrder:i.sortOrder?Number(i.sortOrder):0,isPublished:i.isPublished};i.durationSeconds&&(w.durationSeconds=Number(i.durationSeconds)),a&&(w.uploadHandle=a),await F(n,l,w),p({title:t?"Tutorial updated":"Tutorial created",description:`"${i.title}" has been ${t?"updated":"created"} successfully.`}
6),m.invalidateQueries({queryKey:["/api/tutorials/admin"]}),m.invalidateQueries({queryKey:["/api/tutorials"]}),o()}catch(a){p({title:"Error",description:a instanceof Error?a.message:"Something went wrong",variant:"destructive"})}finally{P(!1),N(null),b.current=null}},M=()=>{b.current&&b.current.abort(),o()};return e.jsx(G,{open:s,onOpenChange:a=>{a||M()},children:e.jsxs(H,{className:"max-w-lg",children:[e.jsx(X,{children:e.jsx(Y,{children:t?"Edit Tutorial":"Add Tutorial"})}),e.jsxs("div",{className:"space-y-4 py-2",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(E,{htmlFor:"title",children:"Title"}),e.jsx(Q,{id:"title",value:i.title,onChange:a=>{u(l=>({...l,title:a.target.value}))},placeholder:"e.g., Getting Started After Registration",disabled:c})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(E,{htmlFor:"description",children:"Description"}),e.jsx(de,{id:"description",value:i.description,onChange:a=>{u(l=>({...l,description:a.target.value}))},placeholder:"Brief description of what this tutorial covers...",rows:3,disabled:c})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(E,{children:"Category"}),e.jsxs(oe,{value:i.category,onValueChange:a=>{u(l=>({...l,category:a}))},disabled:c,children:[e.jsx(ce,{children:e.jsx(xe,{})}),e.jsx(ue,{children:ee.map(a=>e.jsx(he,{value:a.value,children:a.label},a.value))})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(E,{htmlFor:"duration",children:"Duration (auto-detected)"}),e.jsx(Q,{id:"duration",type:"number",min:"0",value:i.durationSeconds,onChange:a=>{u(l=>({...l,durationSeconds:a.target.value}))},placeholder:"Auto-detected on upload",disabled:c})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(E,{children:"Video File"}),e.jsxs("div",{className:`border-2 border-dashed rounded-lg p-4 text-center transition-colors ${c?"opacity-50 cursor-not-allowed":"cursor-pointer hover:border-blue-400 hover:bg-blue-50/50 dark:hover:bg-blue-950/20"}`,onClick:()=>{var a;c||(a=x.current)==null||a.click()},children:[d?e.jsxs("div",{className:"flex items-center gap-3 justify-center",children:[e.jsx(Z,{className:"h-5 w-5 text-blue-600"}),e.jsxs("div",{className:"text-left",children:[e.jsx("p",{className:"text-sm font-medium text-gray-900 dark:text-gray-100",children:d.name}),e.jsx("p",{className:"text-xs text-gray-500",children:Ke(d.size)})]}),!c&&e.jsx(v,{variant:"ghost",size:"sm",onClick:a=>{a.stopPropagation(),f(null)},children:"Remove"})]}):t!=null&&t.videoFilePath?e.jsxs("div",{className:"flex items-center gap-2 justify-center text-sm text-gray-500",children:[e.jsx(A,{className:"h-4 w-4"}),e.jsx("span",{children:"Video already uploaded. Click to replace."})]}):e.jsxs("div",{className:"flex flex-col items-center gap-1",children:[e.jsx(me,{className:"h-6 w-6 text-gray-400"}),e.jsx("p",{className:"text-sm text-gray-500",children:"Click to upload a video"}),e.jsx("p",{className:"text-xs text-gray-400",children:"MP4, MOV, or WebM (max 200MB)"})]}),e.jsx("input",{ref:x,type:"file",accept:"video/mp4,video/quicktime,video/webm",className:"hidden",onChange:I,disabled:c})]})]}),r!==null&&e.jsxs("div",{className:"space-y-1.5",children:[e.jsxs("div",{className:"flex items-center justify-between text-xs text-gray-500",children:[e.jsx("span",{children:r<100?"Uploading video...":"Processing video..."}),e.jsxs("span",{children:[r,"%"]})]}),e.jsx(pe,{value:r,className:"h-2"}),r>=100&&e.jsx("p",{className:"text-xs text-blue-600",children:"Generating thumbnail and detecting duration..."})]}),e.jsxs("div",{className:"flex items-center justify-between rounded-lg border p-3",children:[e.jsxs("div",{children:[e.jsx(E,{htmlFor:"publish-toggle",className:"text-sm font-medium",children:"Published"}),e.jsx("p",{className:"text-xs text-gray-500",children:"Only published tutorials are visible to users"})]}),e.jsx(ge,{id:"publish-toggle",checked:i.isPublished,onCheckedChange:a=>{u(l=>({...l,isPublished:a}))},disabled:c})]})]}),e.jsxs(J,{children:[e.jsx(v,{variant:"outline",onClick:M,disabled:c&&r!==null&&r<100,children:"Cancel"}
6),e.jsx(v,{onClick:U,disabled:c,children:c?r!==null&&r<100?"Uploading...":"Processing...":t?"Save Changes":"Create Tutorial"})]})]})})}function $e({open:s,onClose:o,tutorial:t}){const m=B(),{toast:p}=L(),x=_({mutationFn:async()=>{await F("DELETE",`/api/tutorials/${t.id}`)},onSuccess:()=>{p({title:"Tutorial deleted",description:`"${t.title}" has been deleted.`}),m.invalidateQueries({queryKey:["/api/tutorials/admin"]}),m.invalidateQueries({queryKey:["/api/tutorials"]}),o()},onError:i=>{p({title:"Error",description:i.message,variant:"destructive"})}});return e.jsx(G,{open:s,onOpenChange:i=>{i||o()},children:e.jsxs(H,{className:"max-w-sm",children:[e.jsx(X,{children:e.jsx(Y,{children:"Delete Tutorial"})}),e.jsxs("p",{className:"text-sm text-gray-600 dark:text-gray-400",children:["Are you sure you want to delete â",e.jsx("strong",{children:t.title}),"â? This will also remove the video file and cannot be undone."]}),e.jsxs(J,{children:[e.jsx(v,{variant:"outline",onClick:o,disabled:x.isPending,children:"Cancel"}),e.jsx(v,{variant:"destructive",onClick:()=>{x.mutate()},disabled:x.isPending,children:x.isPending?"Deleting...":"Delete"})]})]})})}function _e({open:s,onClose:o,tutorial:t}){const m=je(),{mediaRef:p,isZoomed:x,transformStyle:i,handlers:u}=Me({active:s,resetKey:t.id,controlBandPx:48});return e.jsx(G,{open:s,onOpenChange:d=>{d||o()},children:e.jsxs(H,{className:"max-w-4xl p-0 gap-0 overflow-hidden [&>button]:hidden",children:[e.jsxs("div",{className:"flex items-center justify-between bg-gray-900 px-4 py-3",children:[e.jsx("h2",{className:"text-sm font-medium text-white truncate pr-4",children:t.title}),e.jsx(v,{variant:"ghost",size:"icon",onClick:o,className:"shrink-0 text-gray-400 hover:text-white hover:bg-gray-800",children:e.jsx(ve,{className:"h-4 w-4"})})]}),e.jsxs("div",{className:"relative aspect-video overflow-hidden bg-black",style:{touchAction:x?"none":"pan-x pan-y"},onTouchStart:u.onTouchStart,onTouchMove:u.onTouchMove,onTouchEnd:u.onTouchEnd,children:[t.videoUrl?e.jsx("video",{ref:p,src:t.videoUrl,controls:!0,autoPlay:!0,playsInline:!0,className:"h-full w-full",style:i,children:"Your browser does not support video playback."}):e.jsxs("div",{className:"flex h-full w-full flex-col items-center justify-center gap-2 text-gray-400",children:[e.jsx(A,{className:"h-12 w-12"}),e.jsx("p",{className:"text-sm",children:"No video uploaded"})]}),m&&t.videoUrl&&e.jsx("div",{className:"pointer-events-none absolute left-2 top-2 rounded bg-black/60 px-2 py-1 text-[11px] font-medium text-white/90",children:"Pinch to zoom ⢠Drag to pan ⢠Double-tap to reset"})]})]})})}function Xe({tutorial:s,onEdit:o,onDelete:t,onPreview:m}){const{attributes:p,listeners:x,setNodeRef:i,transform:u,transition:d,isDragging:f}=Ee({id:s.id}),c={transform:De.Transform.toString(u),transition:d,opacity:f?.5:1};return e.jsxs(W,{ref:i,style:c,className:f?"bg-blue-50 dark:bg-blue-950/30":"",children:[e.jsx(T,{className:"text-gray-400 text-xs w-12",children:e.jsx("button",{className:"flex items-center gap-1 cursor-grab active:cursor-grabbing touch-none",...p,...x,children:e.jsx(Ie,{className:"h-4 w-4 text-gray-400 hover:text-gray-600"})})}),e.jsx(T,{children:e.jsxs("div",{children:[e.jsx("p",{className:"font-medium text-sm",children:s.title}),s.description&&e.jsx("p",{className:"text-xs text-gray-500 truncate max-w-[200px] sm:max-w-[300px]",children:s.description})]})}),e.jsx(T,{className:"hidden sm:table-cell",children:e.jsx(z,{variant:"outline",className:"text-xs",children:Ge[s.category]||s.category})}),e.jsx(T,{className:"hidden md:table-cell",children:s.durationSeconds?e.jsxs("span",{className:"flex items-center gap-1 text-xs text-gray-500",children:[e.jsx(ne,{className:"h-3 w-3"}),He(s.durationSeconds)]}):e.jsx("span",{className:"text-xs text-gray-400",children:"--"})}),e.jsx(T,{className:"hidden md:table-cell",children:s.videoFilePath?e.jsxs(z,{variant:"secondary",className:"text-xs",children:[e.jsx(Z,{className:"h-3 w-3 mr-1"}),"Uploaded"]}):e.jsx("span",{className:"text-xs text-gray-400",children:"No video"})}),e.jsx(T,{children:s.isPublished?e.jsx(z,{className:"bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200 text-xs",children:"Published"}):e.jsx(z,{variant:"outline",className:"text-xs text-amber-600 border-amber-300",children:"Draft"})}),e.jsx(T,{className:"text-right",children:e.jsxs("div",{className:"flex items-center justify-end gap-1",children:[s.videoUrl&&e.jsx(v,{variant:"ghost",size:"icon",className:"h-8 w-8 text-blue-500 hover:text-blue-700 hover:bg-blue-50 dark:hover:bg-blue-950",onClick:()=>{m(s)},title:"Preview video",children:e.jsx(Ue,{className:"h-3.5 w-3.5"})}),e.jsx(v,{variant:"ghost",size:"icon",className:"h-8 w-8",onClick:()=>{o(s)},children:e.jsx(Be,{className:"h-3.5 w-3.5"})}),e.jsx(v,{variant:"ghost",size:"icon",className:"h-8 w-8 text-red-500 hover:text-red-700 hover:bg-red-50 dark:hover:bg-red-950",onClick:()=>{t(s)},children:e.jsx(le,{className:"h-3.5 w-3.5"})})]})})]})}function ls(){const s=B(),{toast:o}=L(),[t,m]=j.useState(!1),[p,x]=j.useState(null),[i,u]=j.useState(null),[d,f]=j.useState(null),{data:c,isLoading:P}=te({queryKey:["/api/tutorials/admin"],queryFn:()=>F("GET","/api/tutorials/admin")}),r=c||[],N=fe(V(ke,{activationConstraint:{distance:8}}),V(Pe,{coordinateGetter:Te})),b=j.useRef(null),D=_({mutationFn:async n=>F("PATCH","/api/tutorials/reorder",{orderedIds:n}),onSuccess:()=>{b.current=null,s.invalidateQueries({queryKey:["/api/tutorials/admin"]}),s.invalidateQueries({queryKey:["/api/tutorials"]}),o({title:"Order saved",description:"Tutorial order has been updated."})},onError:n=>{b.current&&(s.setQueryData(["/api/tutorials/admin"],()=>b.current),b.current=null),o({title:"Error",description:n.message,variant:"destructive"})}}),I=j.useCallback(n=>{const{active:w,over:g}=n;if(!g||w.id===g.id)return;const C=r.findIndex(y=>y.id===w.id),O=r.findIndex(y=>y.id===g.id);if(C===-1||O===-1)return;b.current=[...r];const k=ye(r,C,O),h=k.map(y=>y.id);s.setQueryData(["/api/tutorials/admin"],()=>k),D.mutate(h)},[r,s,D]),U=n=>{x(n),m(!0)},M=()=>{m(!1),x(null)},a=r.filter(n=>n.isPublished).length,l=r.filter(n=>!n.isPublished).length;return e.jsxs(Fe,{children:[e.jsxs("div",{className:"mb-6",children:[e.jsxs("div",{className:"flex items-center gap-3 mb-1",children:[e.jsx(ae,{className:"h-6 w-6 text-blue-600"}),e.jsx("h1",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Manage Tutorials"})]}),e.jsxs("div",{className:"flex items-start justify-between gap-4 mt-1",children:[e.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400 ml-9",children:"Upload and manage tutorial videos for your users. Drag rows to reorder."}),e.jsxs(v,{className:"shrink-0",onClick:()=>{x(null),m(!0)},children:[e.jsx(K,{className:"h-4 w-4 mr-2"}),"Add Tutorial"]})]})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-4 mb-6",children:[e.jsx(R,{children:e.jsx(q,{className:"pt-4 pb-4",children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-2xl font-bold",children:r.length}),e.jsx("p",{className:"text-xs text-gray-500",children:"Total Tutorials"})]}
6),e.jsx(A,{className:"h-8 w-8 text-blue-100 dark:text-blue-900"})]})})}),e.jsx(R,{children:e.jsx(q,{className:"pt-4 pb-4",children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-2xl font-bold text-green-600",children:a}),e.jsx("p",{className:"text-xs text-gray-500",children:"Published"})]}),e.jsx(ze,{className:"h-8 w-8 text-green-100 dark:text-green-900"})]})})}),e.jsx(R,{children:e.jsx(q,{className:"pt-4 pb-4",children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-2xl font-bold text-amber-600",children:l}),e.jsx("p",{className:"text-xs text-gray-500",children:"Drafts"})]}),e.jsx(Ae,{className:"h-8 w-8 text-amber-100 dark:text-amber-900"})]})})})]}),e.jsxs(R,{children:[e.jsx(ie,{children:e.jsx(re,{className:"text-base",children:"All Tutorials"})}),e.jsxs(q,{children:[P&&e.jsx("div",{className:"space-y-3",children:[1,2,3].map(n=>e.jsx("div",{className:"h-12 bg-gray-100 dark:bg-gray-800 rounded animate-pulse"},n))}),!P&&r.length===0&&e.jsxs("div",{className:"text-center py-12",children:[e.jsx(A,{className:"h-12 w-12 text-gray-300 dark:text-gray-600 mx-auto mb-3"}),e.jsx("p",{className:"text-sm text-gray-500 mb-4",children:"No tutorials yet. Create your first one!"}),e.jsxs(v,{onClick:()=>{m(!0)},children:[e.jsx(K,{className:"h-4 w-4 mr-2"}),"Add Tutorial"]})]}),!P&&r.length>0&&e.jsx("div",{className:"overflow-x-auto",children:e.jsx(Ne,{sensors:N,collisionDetection:we,onDragEnd:I,children:e.jsxs(Oe,{children:[e.jsx(Re,{children:e.jsxs(W,{children:[e.jsx(S,{className:"w-12"}),e.jsx(S,{children:"Title"}),e.jsx(S,{className:"hidden sm:table-cell",children:"Category"}),e.jsx(S,{className:"hidden md:table-cell",children:"Duration"}),e.jsx(S,{className:"hidden md:table-cell",children:"Video"}),e.jsx(S,{children:"Status"}),e.jsx(S,{className:"text-right",children:"Actions"})]})}),e.jsx(Ce,{items:r.map(n=>n.id),strategy:Se,children:e.jsx(qe,{children:r.map(n=>e.jsx(Xe,{tutorial:n,onEdit:U,onDelete:u,onPreview:f},n.id))})})]})})})]})]}),t&&e.jsx(Ve,{open:t,onClose:M,tutorial:p}),i&&e.jsx($e,{open:!!i,onClose:()=>{u(null)},tutorial:i}),d&&e.jsx(_e,{open:!!d,onClose:()=>{f(null)},tutorial:d})]})}export{ls 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.