1import{j as e,a as M,c as z,u as E,e as C}from"./chunk-Cl_8PWDN.js";import{r as o}from"./chunk-Bzo9Tunx.js";import{k as F,A as R}from"./chunk-DUErHPP3.js";import{A as P}from"./chunk-C9hHCnAK.js";import{C as O}from"./chunk-hdszkXAW.js";import{B as m,c as q,j as b}from"./index-5yA9CUzc.js";import{o as G,H as I,L as N,W as w,be as U,g as B,s as Q}from"./chunk-mAyixyGg.js";import{I as D}from"./chunk-BIJpGMWs.js";import{L as A}from"./chunk-Cswqrut6.js";import{C as K,a as W,b as V,c as X,d as S}from"./chunk-D0e1vpx_.js";import{T as Y,a as Z,b as L,c as p,d as J,e as h}from"./chunk-BLT6yKBQ.js";import"./chunk-DHVgiofg.js";import"./chunk-DaCLkmJg.js";import"./chunk-BNWfZVZZ.js";import"./chunk-DOYwYJoF.js";import"./chunk-Cpk34r19.js";import"./chunk-sOoSo9Bm.js";import"./chunk-C7gcEKhI.js";import"./chunk-Dwamq1GJ.js";import"./chunk-ClMkenV-.js";import"./chunk-me0vpg0v.js";import"./chunk-CD0_quAU.js";import"./chunk-YrvLZ4fv.js";import"./chunk-DBTYFX8p.js";import"./chunk-x6H3mB14.js";import"./chunk-CbG3gslG.js";import"./chunk-BeHpvERE.js";import"./chunk-PeZDclay.js";function H(t,i){const a=new Date(t.expires_at).toLocaleString(void 0,{weekday:"short",month:"short",day:"numeric",year:"numeric",hour:"numeric",minute:"2-digit",timeZoneName:"short"});return`Hi [Name], 2 3Here's your CruisePirate Advisor Portal demo login: 4 5 URL: ${i} 6 Email: ${t.email} 7 Password: ${t.password_plaintext} 8 9This demo expires on ${a}. 10Your demo account is pre-loaded with sample clients, trips, and bookings
11so you can explore the workflow end-to-end. 12 13Let me know if you have any questions!`}function y({label:t,value:i}){const[a,s]=o.useState(!1);return e.jsxs("div",{className:"flex items-center justify-between gap-3 rounded-lg border bg-slate-50 px-3 py-2",children:[e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("p",{className:"text-xs font-medium text-muted-foreground",children:t}),e.jsx("p",{className:"truncate font-mono text-sm",children:i})]}),e.jsx(m,{size:"sm",variant:"ghost",onClick:async()=>{await navigator.clipboard.writeText(i),s(!0),setTimeout(()=>s(!1),1500)},children:a?e.jsx(G,{className:"size-3.5"}):e.jsx(I,{className:"size-3.5"})})]})}function ee({credential:t,loginUrl:i,onClose:a}){const[s,r]=o.useState(!1);return e.jsx(F,{isOpen:!0,onClose:a,title:"Demo Generated",subtitle:"Copy these credentials into an email to your prospect",maxWidth:520,children:e.jsxs("div",{className:"space-y-3",children:[e.jsx(y,{label:"Email",value:t.email}),e.jsx(y,{label:"Password",value:t.password_plaintext}),e.jsx(y,{label:"Login URL",value:i}),e.jsx(m,{className:"w-full",onClick:async()=>{await navigator.clipboard.writeText(H(t,i)),r(!0),setTimeout(()=>r(!1),1500)},children:s?"Copied!":"Copy as Email"}),e.jsxs("p",{className:"pt-1 text-xs text-muted-foreground",children:["This demo expires"," ",new Date(t.expires_at).toLocaleString(),". After that the account auto-deletes on the next login attempt."]})]})})}const T=1,k=168,_=168;function se({open:t,onClose:i,onSubmit:a,isPending:s}){const[r,l]=o.useState(""),[n,u]=o.useState(_),x=r.trim().length>0,v=Number.isFinite(n)&&n>=T&&n<=k,f=x&&v&&!s;function g(c){c.preventDefault(),f&&a({prefix:r.trim(),duration_hours:n})}function d(){s||(l(""),u(_),i())}return e.jsx(F,{isOpen:t,onClose:d,title:"Generate Demo Advisor",subtitle:"Creates a short-lived advisor portal login with seeded sample data",maxWidth:480,children:e.jsxs("form",{onSubmit:g,className:"space-y-4",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(A,{htmlFor:"prefix",children:"Prefix (prospect's name or company)"}),e.jsx(D,{id:"prefix",placeholder:"e.g. kyle",value:r,onChange:c=>l(c.target.value),disabled:s,autoFocus:!0}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Becomes the email:"," ",e.jsxs("code",{children:[r.trim()||"<prefix>","@demo.cruisepirate.ai"]})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(A,{htmlFor:"hours",children:"Duration (hours, max 168 = 7 days)"}),e.jsx(D,{id:"hours",type:"number",min:T,max:k,value:n,onChange:c=>u(Number(c.target.value)),disabled:s})]}),e.jsxs("div",{className:"flex justify-end gap-2 pt-2",children:[e.jsx(m,{type:"button",variant:"outline",onClick:d,disabled:s,children:"Cancel"}),e.jsxs(m,{type:"submit",disabled:!f,children:[s&&e.jsx(N,{className:"mr-2 size-4 animate-spin"}),"Generate"]})]})]})})}function te(t){const i=new Date(t).getTime()-Date.now();if(i<=0)return"expired";const a=Math.floor(i/(1e3*60));if(a<60)return`in ${a}m`;const s=Math.floor(a/60);if(s<24)return`in ${s}h`;const r=Math.floor(s/24),l=s-r*24;return l>0?`in ${r}d ${l}h`:`in ${r}d`}function ae(t){const i=Date.now()-new Date(t).getTime();if(i<6e4)return"just now";const a=Math.floor(i/6e4);if(a<60)return`${a}m ago`;const s=Math.floor(a/60);return s<24?`${s}h ago`:`${Math.floor(s/24)}d ago`}const ie=o.memo(function({credentials:i,actions:a}){return e.jsxs(K,{children:[e.jsx(W,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx(V,{className:"text-xl",children:"Demo Advisors"}),e.jsx(X,{children:"Short-lived advisor portal logins for prospects. Auto-expires."})]}),a?.onCreate&&e.jsxs(m,{size:"sm",onClick:a.onCreate,children:[e.jsx(w,{className:"mr-1.5 size-3.5"}),"Generate Demo"]})]})}),i.length===0?e.jsx(S,{children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-12 text-center",children:[e.jsx("div",{className:"mb-4 rounded-full bg-slate-100 p-4",children:e.jsx(U,{className:"size-8 text-slate-400"})}),e.jsx("h3",{className:"text-lg font-medium",children:"No active demos"}),e.jsx("p",{className:"mt-1 max-w-sm text-sm text-muted-foreground",children:"Generate a demo login to send a prospect a 7-day window into the advisor portal with seeded sample data."}),a?.onCreate&&e.jsxs(m,{className:"mt-4",size:"sm",onClick:a.onCreate,children:[e.jsx(w,{className:"mr-1.5 size-3.5"}),"Generate First Demo"]})]})}):e.jsx(S,{className:"px-0 pb-0",children:e.jsxs(Y,{children:[e.jsx(Z,{children:e.jsxs(L,{className:"bg-muted/30",children:[e.jsx(p,{className:"pl-6",children:"Email"}),e.jsx(p,{children:"Password"}),e.jsx(p,{children:"Expires"}),e.jsx(p,{children:"Created"}),e.jsx(p,{className:"text-right pr-6",children:"Actions"})]})}),e.jsx(J,{children:i.map(s=>{const r=a?.deletingId===s.id;return e.jsxs(L,{children:[e.jsx(h,{className:"pl-6 font-medium",children:s.email}),e.jsx(h,{className:"font-mono text-sm",children:s.password_plaintext}),e.jsx(h,{children:e.jsx("span",{title:new Date(s.expires_at).toLocaleStr
13ing(),children:te(s.expires_at)})}),e.jsx(h,{children:e.jsxs("div",{className:"flex flex-col",children:[e.jsx("span",{className:"text-sm",title:new Date(s.created_at).toLocaleString(),children:ae(s.created_at)}),s.created_by_name&&e.jsxs("span",{className:"text-xs text-muted-foreground",children:["by ",s.created_by_name]})]})}),e.jsx(h,{className:"text-right pr-6",children:e.jsxs("div",{className:"flex items-center justify-end gap-1.5",children:[a?.onCopyEmail&&e.jsxs(m,{variant:"ghost",size:"sm",onClick:()=>a.onCopyEmail(s),title:"Copy a pre-formatted email message to the clipboard",children:[e.jsx(B,{className:"mr-1 size-3.5"}),"Copy as Email"]}),a?.onDelete&&e.jsxs(m,{variant:"ghost",size:"sm",className:q("text-red-500 hover:text-red-700 hover:bg-red-50"),onClick:()=>a.onDelete(s.id),disabled:r,title:"Revoke this demo (deletes the account and all seeded data)",children:[r?e.jsx(N,{className:"mr-1 size-3.5 animate-spin"}):e.jsx(Q,{className:"mr-1 size-3.5"}),"Delete"]})]})})]},s.id)})})]})})]})}),j={all:["admin","demo-advisors"],list:()=>[...j.all,"list"]};function re(){return M({queryKey:j.list(),queryFn:async()=>(await C.get(`${b()}/api/admin/demo-advisors/`)).data})}function oe(){const t=z();return E({mutationFn:async i=>(await C.post(`${b()}/api/admin/demo-advisors/`,i)).data,onSuccess:()=>{t.invalidateQueries({queryKey:j.all})}})}function ne(){const t=z();return E({mutationFn:async i=>{await C.delete(`${b()}/api/admin/demo-advisors/${i}/`)},onSuccess:()=>{t.invalidateQueries({queryKey:j.all})}})}const $="https://advisor.cruisepirate.ai/login";function He(){const[t,i]=o.useState(null),[a,s]=o.useState(!1),[r,l]=o.useState(null),n=re(),u=oe(),x=ne(),v=o.useCallback(d=>{navigator.clipboard.writeText(H(d,$))},[]),f={onCreate:o.useCallback(()=>s(!0),[]),onDelete:o.useCallback(d=>i(d),[]),onCopyEmail:v,deletingId:x.isPending?t:null},g=o.useCallback(()=>{t&&x.mutate(t,{onSuccess:()=>i(null)})},[t,x]);return e.jsxs(R,{children:[e.jsx(P,{title:"Demo Advisors",subtitle:"Provision short-lived advisor portal logins for prospects",children:n.isLoading?e.jsxs("div",{className:"flex items-center gap-2 py-12 justify-center text-muted-foreground",children:[e.jsx(N,{className:"size-5 animate-spin"}),"Loading demos..."]}):n.error?e.jsxs("p",{className:"text-sm text-red-600",children:["Failed to load demos: ",n.error.message]}):e.jsx(ie,{credentials:n.data??[],actions:f})}),e.jsx(se,{open:a,onClose:()=>s(!1),onSubmit:d=>{u.mutate(d,{onSuccess:c=>{s(!1),l(c)}})},isPending:u.isPending}),r&&e.jsx(ee,{credential:r,loginUrl:$,onClose:()=>l(null)}),e.jsx(O,{open:t!==null,onCancel:()=>i(null),onConfirm:g,title:"Revoke this demo?",description:"The demo account and all its seeded sample data will be permanently deleted.",confirmLabel:"Delete",variant:"destructive"})]})}export{He 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.