1import{a as e,r as t}from"./rolldown-runtime-B0Z9INg1.js";import{$ as n,D as r,O as i,P as a,a as o,c as s,i as c,k as l,n as u,o as d,p as f,r as p,t as m,v as h}from"./uiFramework-gph6sqzH.js";import{t as g}from"./src-BN6admL3.js";import{c as _,i as v,l as y,o as b,u as x}from"./schemas-BCv8FbkB.js";import{n as S,t as C}from"./coerce-opsCHIWb.js";import{t as w}from"./dist-CN1zt2w1.js";import{t as T}from"./twilio-B9gO9xNu.js";var E=e(n(),1),D={IDENTITY_TOKEN:`chat_identity_token`},O=e=>{if(!e||typeof e!=`string`)return!1;let t=e.split(`.`);if(t.length!==3)return!1;try{let e=JSON.parse(atob(t[0]||``)),n=JSON.parse(atob(t[1]||``));return!e.alg||!e.typ||e.typ!==`JWT`||!n.iss||!n.exp?!1:n.exp>=Math.floor(Date.now()/1e3)}catch{return!1}},k=()=>({getItem:e=>typeof window>`u`?null:localStorage.getItem(e),removeItem:e=>{typeof window>`u`||localStorage.removeItem(e)},setItem:(e,t)=>{typeof window>`u`||localStorage.setItem(e,t)}}),ee=T(),A={backoffFactor:2,initialDelay:1e3,maxDelay:1e4,maxRetries:3};async function te(e,t={}){let{backoffFactor:n,initialDelay:r,maxDelay:i,maxRetries:a}={...A,...t},o,s=r;for(let t=0;t<=a;t++)try{return await e()}catch(e){if(o=e,t===a)break;await new Promise(e=>setTimeout(e,s)),s=Math.min(s*n,i)}throw o}var ne={conversationSid:null,error:null,isConnected:!1,isGenerating:!1,isLoading:!1,isSending:!1,messages:[]};function j(e,t){switch(t.type){case`addMessage`:return e.messages.some(e=>e.id===t.message.id)?e:{...e,messages:[...e.messages,t.message]};case`replaceMessages`:return{...e,messages:t.messages};case`setConnected`:return{...e,isConnected:t.value};case`setConversationSid`:return{...e,conversationSid:t.value};case`setError`:return{...e,error:t.value};case`setGenerating`:return{...e,isGenerating:t.value};case`setLoading`:return{...e,isLoading:t.value};case`setSending`:return{...e,isSending:t.value};default:return e}}function M({baseMessageAttributes:e={},clientInitTimeout:t=1e4,createConversation:n,logError:r,maxRetries:i=2,storageKey:a=D.IDENTITY_TOKEN}){let o=(0,E.useMemo)(()=>k(),[]),[s,c]=(0,E.useReducer)(j,ne),l=(0,E.useRef)({client:null,conversation:null,conversationSid:null,isInitializing:!1,messageIds:new Set,removeMessageListener:null}),u=(0,E.useCallback)(()=>void 0,[]),d=r||u,f=(0,E.useCallback)(()=>{let e=l.current;e.removeMessageListener&&=(e.removeMessageListener(),null),e.client&&=(e.client.shutdown(),null),e.conversation=null,e.conversationSid=null,e.isInitializing=!1,e.messageIds.clear(),c({type:`setConnected`,value:!1}),c({type:`setConversationSid`,value:null}),c({type:`setError`,value:null})},[]);(0,E.useEffect)(()=>()=>{f()},[f]);let p=(0,E.useCallback)(async e=>{if(!O(e))throw Error(`Invalid token provided to Twilio client`);let n=new ee.Client(e);return await new Promise((e,r)=>{let i=setTimeout(()=>{r(Error(`Client initialization timeout`))},t),a=()=>{clearTimeout(i),n.off(`initialized`,a),e()};n.on(`initialized`,a)}),n},[t]),m=(0,E.useCallback)(async(e,t)=>e.getConversationBySid(t),[]),h=(0,E.useCallback)(e=>{let t=e=>{let t=l.current;if(t.messageIds.has(e.sid))return;t.messageIds.add(e.sid);let n=e.author===`system`?`INBOUND`:`OUTBOUND`;c({message:{attributes:e.attributes||void 0,author:e.author||void 0,content:e.body||``,direction:n,id:e.sid,timestamp:new Date(e.dateCreated||Date.now())},type:`addMessage`}),n===`INBOUND`&&c({type:`setGenerating`,value:!1})};return e.on(`messageAdded`,t),()=>{e.off(`messageAdded`,t)}},[]),g=(0,E.useCallback)(async e=>(await e.getMessages()).items.map(e=>({attributes:e.attributes||void 0,author:e.author||void 0,content:e.body||``,direction:e.author===`system`?`INBOUND`:`OUTBOUND`,id:e.sid,timestamp:new Date(e.dateCreated||Date.now())})),[]),_=(0,E.useCallback)(e=>{let t=e.message;return t.includes(`TwilsockUpstreamError2`)||t.includes(`Not Found`)||t.includes(`404`)||t.includes(`Forbidden`)||t.includes(`Unauthorized`)},[]),v=(0,E.useCallback)(async(e,t)=>{let n=l.current;n.conversationSid=t,c({type:`setConversationSid`,value:t});let r=await m(e,t);n.conversation=r,n.removeMessageListener&&n.removeMessageListener(),n.removeMessageListener=h(r);let i=await g(r);c({messages:i,type:`replaceMessages`}),c({type:`setConnected`,value:!0})},[g,m,h]),y=(0,E.useCallback)(async(e,t)=>{let r=l.current;if(r.isInitializing||s.isConnected)return r.conversationSid;try{r.isInitializing=!0,c({type:`setLoading`,value:!0}),c({type:`setError`,value:null});let s=null;return await te(async()=>{let i=o.getItem(a)||void 0,c=await n({contact:t||`[email protected]`,...i?{identity:i}:{},userName:e||`Anonymous User`});
1if(!O(c.token))throw Error(`Received invalid token from server`);c.identity&&o.setItem(a,c.identity);let l=await p(c.token);r.client=l,s=c.conversationSid,await v(l,c.conversationSid)},{maxRetries:i??A.maxRetries}),s}catch(e){let t=e instanceof Error?e:Error(String(e)),n=_(t),r=n?`Connection issue detected. Please try refreshing the page or contact support if the problem persists.`:`Sorry, we're having trouble connecting. Please try again later.`;return d(t,`[AI Receptionist] Failed to initialize Twilio chat conversation`,{isTwilioError:n}),c({type:`setError`,value:r}),c({messages:[{author:`system`,content:r,direction:`INBOUND`,id:`error`,timestamp:new Date}],type:`replaceMessages`}),null}finally{c({type:`setLoading`,value:!1}),r.isInitializing=!1}},[n,p,_,d,i,v,s.isConnected,o,a]),b=(0,E.useCallback)(async(t,n)=>{let r=l.current;if(!(!t.trim()||!r.conversation||s.isSending)){c({type:`setSending`,value:!0}),c({type:`setError`,value:null});try{let i={...e,...n},a=Object.fromEntries(Object.entries(i).filter(e=>e[1]!==void 0));await r.conversation.sendMessage(t.trim(),a),c({type:`setGenerating`,value:!0})}catch(e){d(e instanceof Error?e:Error(String(e)),`[AI Receptionist] Failed to send Twilio chat message`),c({message:{author:`system`,content:`Sorry, your message could not be sent. Please try again.`,direction:`INBOUND`,id:`error-${Date.now()}`,timestamp:new Date},type:`addMessage`}),c({type:`setError`,value:`Failed to send message`})}finally{c({type:`setSending`,value:!1})}}},[e,d,s.isSending]);return{conversationSid:s.conversationSid,disconnect:f,error:s.error,initializeConversation:y,isConnected:s.isConnected,isGenerating:s.isGenerating,isLoading:s.isLoading,isSending:s.isSending,messages:s.messages,sendMessage:b}}var N={scrollContainer:`_scrollContainer_1qrdg_1`,hasTopShadow:`_hasTopShadow_1qrdg_13`,hasBottomShadow:`_hasBottomShadow_1qrdg_17`,scrollSentinel:`_scrollSentinel_1qrdg_21`,outboundMessage:`_outboundMessage_1qrdg_26`,inboundMessage:`_inboundMessage_1qrdg_39`,messageContainer:`_messageContainer_1qrdg_52`,outbound:`_outbound_1qrdg_26`,inbound:`_inbound_1qrdg_39`,messageText:`_messageText_1qrdg_70`,timestamp:`_timestamp_1qrdg_74`,spinning:`_spinning_1qrdg_1`},P=a();function F(e){let t=e instanceof Date?e:new Date(e),n=globalThis?.navigator?navigator.language:`en`;return t.toLocaleTimeString(n,{hourCycle:`h12`,minute:`2-digit`,hour:`numeric`})}var I=({content:e,timestamp:t})=>(0,P.jsxs)(`div`,{className:`${N.messageContainer} ${N.outbound}`,children:[(0,P.jsx)(`span`,{className:N.timestamp,children:(0,P.jsx)(r,{size:`small`,variation:`subdued`,children:F(t)})}),(0,P.jsx)(`div`,{"aria-live":`assertive`,className:N.outboundMessage,children:(0,P.jsx)(r,{size:`large`,children:e})})]}),L=({assistantName:e,content:t,timestamp:n})=>(0,P.jsxs)(h,{direction:`column`,gap:`smaller`,children:[(0,P.jsx)(r,{size:`small`,variation:`subdued`,children:e}),(0,P.jsxs)(`div`,{className:`${N.messageContainer} ${N.inbound}`,children:[(0,P.jsx)(`div`,{"aria-live":`assertive`,className:N.inboundMessage,children:(0,P.jsx)(r,{UNSAFE_className:{textStyle:N.messageText},size:`large`,children:t})}),(0,P.jsx)(`span`,{className:N.timestamp,children:(0,P.jsx)(r,{size:`small`,variation:`subdued`,children:F(n)})})]})]}),R=({assistantName:e,content:t,direction:n,timestamp:r})=>n===`OUTBOUND`?(0,P.jsx)(I,{content:t,timestamp:r}):(0,P.jsx)(L,{assistantName:e,content:t,timestamp:r}),z=()=>(0,P.jsxs)(h,{direction:`row`,gap:`small`,children:[(0,P.jsx)(l,{UNSAFE_style:{path:{fill:`var(--color-base-teal--600)`},svg:{flexShrink:0}},name:`sparkles`}),(0,P.jsxs)(h,{direction:`column`,gap:`small`,width:`100%`,children:[(0,P.jsx)(s,{}),(0,P.jsx)(s,{}),(0,P.jsx)(u,{maxWidth:`75%`,children:(0,P.jsx)(s,{})})]})]});function B({assistantName:e=`Receptionist`,isGenerating:t,messages:n,welcomePrompt:r}){let i=(0,E.useRef)(null),a=(0,E.useRef)(null),o=(0,E.useRef)(null),[s,c]=(0,E.useState)(!1),[l,u]=(0,E.useState)(!1);return(0,E.useEffect)(()=>{let e=i.current;e&&(typeof e.scrollTo==`function`?e.scrollTo({behavior:`smooth`,top:e.scrollHeight}):e.scrollTop=e.scrollHeight)},[t,n]),(0,E.useEffect)(()=>{let e=i.current,t=a.current,n=o.current;if(!e||!t||!n||typeof IntersectionObserver>`u`)return;let r=new IntersectionObserver(e=>{for(let r of e)r.target===t?c(!r.isIntersecting):r.target===n&&u(!r.isIntersecting)},{root:e});return r.observe(t),r.observe(n),()=>r.disconnect()},[]),(0,P.jsxs)(`div`,{className:w(N.scrollContainer,s&&N.hasTopShadow,l&&N.hasBottomShadow),ref:i,children:[(0,P.jsx)(`div`,{"aria-hidden":`true`,className:N.scrollSentinel,ref:a}),(0,P.jsxs)(h,{direction:`column`,gap:`base`,padding:`large`,children:[r,n.map(t=>(0,P.jsx)(R,{assistantName:e,content:t.content,direction:t.direction,timestamp:t.timestamp},t.id)),t&&(0,P.jsx)(z,{})]}),(0,P.jsx)(`div`,{"aria-hidden":`true`,className:N.scrollSentinel,ref:o})]})}function V({isGenerating:e=!1,onSend:t,placeholder:n=`Ask a question...`}){let[r,a]=(0,E.useState)(``),s=async n=>{n.preventDefault(),r.length&&!e&&(a(``),await t(r))},l=!r.length||e;return(0,P.jsx)(`form`,{onSubmit:s,children:(0,P.jsxs)(c,{align:`start`,template:[`grow`,`shrink`],children:[(0,P.jsx)(o,{name:`message`,onChange:a,placeholder:n,value:r}),(0,P.jsx)(i,{UNSAFE_style:{container:{backgroundColor:l?`var(--color-disabled--secondary)`:`var(--color-base-teal--600)`}},ariaLabel:`Send`,disabled:l,icon:`longArrowUp`,size:`large`,submit:!0})]})})}async function H(e,t){let n=await fetch(`/api/chat`,{body:JSON.stringify({...t,websiteName:e}),headers:{"Content-Type":`application/json`},method:`POST`});if(!n.ok){let e=await n.text();throw Error(`Failed to create conversation: ${n.status} ${e}`)}let r=await n.json();if(!r.data)throw Error(`No data received from server`);return r.data}var U={chatButton:`_chatButton_1djwy_1`,spinning:`_spinning_1djwy_1`};function W({onPress:e}){return(0,P.jsx)(`button`,{"aria-label":`Open chat`,className:U.chatButton,onClick:e,type:`button`,children:(0,P.jsx)(l,{name:`sms2`,size:`large`})})}var G=()=>(0,P.jsx)(h,{alignSelf:`center`,children:(0,P.jsxs)(r,{size:`small`,children:[`Powered by Jobber AI\xA0\xA0|\xA0\xA0`,(0,P.jsx)(`a`,{href:`https://www.getjobber.com/privacy-policy/`,rel:`noopener noreferrer`,target:`_blank`,children:`Privacy Policy`})]})}),K={questionsContainer:`_questionsContainer_1tqex_1`,spinning:`_spinning_1tqex_1`};function q({disabled:e,onQuestionSelect:t,question:n}){return(0,P.jsx)(i,{disabled:e,fullWidth:!1,onClick:()=>t(n),size:`small`,type:`secondary`,children:(0,P.jsx)(i.Label,{UNSAFE_style:{textStyle:{color:`var(--color-base-teal--600)`}},children:n})})}var J=({isGenerating:e=!1,onQuestionSelect:t})=>(0,P.jsxs)(P.Fragment,{children:[(0,P.jsxs)(h,{alignItems:`center`,direction:`row`,gap:`small`,children:[(0,P.jsx)(l,{UNSAFE_style:{path:{fill:`var(--color-base-teal--600)`},svg:{flexShrink:0}},name:`sparkles`}),(0,P.jsx)(r,{children:(0,P.jsx)(p,{variation:`bold`,children:`Hello! I'm an AI receptionist.`})})]}),(0,P.jsxs)(`div`,{className:K.questionsContainer,children:[(0,P.jsx)(r,{children:`I can book services or answer questions. How can I help you today?`}),(0,P.jsx)(h,{alignItems:`start`,direction:`column`,gap:`base`,children:[`Tell me more about your services`,`Do you serve my area`,`I'd like to book a service`].map(n=>(0,P.jsx)(q,{disabled:e,onQuestionSelect:t,question:n},n))})]})]});_({q:S().optional()});var Y=y(e=>{if(typeof e==`string`){let t=new Date(e);if(!isNaN(t.getTime()))return e}},x().optional()),X=(e,t)=>new Date(e).getTime()>
1new Date(t).getTime();_({from:Y,to:Y}).transform(e=>{let{from:t,to:n}=e;return t&&n&&X(t,n)?{...e,from:void 0}:e}),x().transform(e=>e!==`false`&&e!==`0`),S().or(v()).transform(e=>typeof e==`boolean`?e:e===`true`||e===``),C();var re=b(),ie=x().regex(/^(?=(?:\D*\d){8,15}\D*$).*$/i),Z=e=>{let t=e.trim();return t.length===0?!1:re.safeParse(t).success?!0:ie.safeParse(t).success};function ae(e){if(e.trim().length===0)return`Phone number or email is required`;if(!Z(e))return`Please enter a valid email address or phone number`}var oe=(0,E.forwardRef)(function({onSubmit:e,onValidityChange:t},n){let[r,a]=(0,E.useState)(``),[s,c]=(0,E.useState)(``),[l,u]=(0,E.useState)(!1),[d,p]=(0,E.useState)(!1),m=l&&!r.trim()?`Name is required`:void 0,g=d?ae(s):void 0,_=async()=>{u(!0),p(!0),r.trim()&&Z(s)&&await e({name:r.trim(),phoneOrEmail:s.trim()})};return(0,E.useImperativeHandle)(n,()=>({submit:_})),(0,E.useEffect)(()=>{let e=r.trim().length>0,n=s.trim().length>0;t(e&&n)},[r,s,t]),(0,P.jsxs)(h,{direction:`column`,gap:`large`,padding:`large`,children:[(0,P.jsx)(h,{direction:`column`,gap:`base`,children:(0,P.jsx)(f,{level:3,children:`Get started with chat`})}),(0,P.jsxs)(`form`,{onSubmit:async e=>{e.preventDefault(),await _()},children:[(0,P.jsxs)(h,{direction:`column`,gap:`base`,children:[(0,P.jsx)(o,{error:m,invalid:!!m,name:`name`,onBlur:()=>u(!0),onChange:a,placeholder:`Your name`,value:r}),(0,P.jsx)(o,{error:g,invalid:!!g,name:`phoneOrEmail`,onBlur:()=>p(!0),onChange:c,placeholder:`Phone number or email`,value:s})]}),(0,P.jsx)(`div`,{className:`hidden`,children:(0,P.jsx)(i,{submit:!0,children:`Submit`})})]})]})}),se=({disabled:e,onSubmit:t})=>(0,P.jsx)(i,{disabled:e,fullWidth:!0,onClick:t,size:`large`,type:`primary`,variation:`learning`,children:`Chat Now`}),Q={title:`_title_g0p4p_2`,chatDrawerContainer:`_chatDrawerContainer_g0p4p_6`,spinning:`_spinning_g0p4p_1`},ce=t({ChatDrawer:()=>$});function $({businessName:e,websiteName:t}){let[n,r]=(0,E.useState)(!1),[i,a]=(0,E.useState)(null),[o,s]=(0,E.useState)(!1),[c,l]=(0,E.useState)(!1),u=(0,E.useRef)(null),{logError:p}=g(),_=(0,E.useCallback)(async e=>H(t,e),[t]),v=(0,E.useCallback)((e,n,r)=>{p(e,n,{...r,websiteName:t})},[p,t]),{initializeConversation:y,isConnected:b,isGenerating:x,isLoading:S,messages:C,sendMessage:w}=M({baseMessageAttributes:{website:t},createConversation:_,logError:v,storageKey:D.IDENTITY_TOKEN});return(0,P.jsxs)(P.Fragment,{children:[(0,P.jsxs)(m,{UNSAFE_className:{container:Q.chatDrawerContainer},onRequestClose:()=>{r(!1)},open:n,children:[(0,P.jsx)(m.Title,{children:(0,P.jsx)(f,{UNSAFE_className:{textStyle:Q.title},level:3,children:`${e} chat`})}),o?(0,P.jsxs)(P.Fragment,{children:[S?(0,P.jsx)(h,{alignItems:`center`,height:`100%`,justifyContent:`center`,children:(0,P.jsx)(d,{})}):(0,P.jsx)(B,{isGenerating:x,messages:C,welcomePrompt:(0,P.jsx)(J,{isGenerating:x,onQuestionSelect:w})}),(0,P.jsx)(m.Footer,{children:(0,P.jsxs)(h,{direction:`column`,gap:`base`,children:[(0,P.jsx)(V,{isGenerating:x,onSend:async e=>{await w(e,{name:i?.name,email_or_phone:i?.phoneOrEmail})}}),(0,P.jsx)(G,{})]})})]}):(0,P.jsxs)(P.Fragment,{children:[(0,P.jsx)(oe,{onSubmit:async e=>{a(e),s(!0),b||await y(e.name,e.phoneOrEmail)},onValidityChange:e=>{l(e)},ref:u}),(0,P.jsx)(m.Footer,{children:(0,P.jsxs)(h,{direction:`column`,gap:`base`,children:[(0,P.jsx)(se,{disabled:!c,onSubmit:async()=>{u.current&&await u.current.submit()}}),(0,P.jsx)(G,{})]})})]})]}),(0,P.jsx)(W,{onPress:()=>{r(!0)}})]})}export{ce as n,$ as t};
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.