PageSourceSearch

https://printroom.co/cdn/shop/t/59/assets/ai-chatbot.bundle.js?v=114215721854634402901788472409

js printroom.co collected 2026-10-04 08:38:32 UTC 17,968 bytes, 2 lines download raw bytes

1import deferrableData from"deferrable-data";import{createClient}from"@supabase/supabase-js";console.log("[AI Chatbot] Module loading...");const SUPABASE_URL="https://bthsxgmcnbvwwgvdveek.supabase.co",SUPABASE_PUBLISHABLE_KEY="sb_publishable_GAaqy-dbfmxvEsbpfDfhYg_LChZxtUA";let supabaseClientSingleton=null;function getSupabaseClient(){return supabaseClientSingleton||(supabaseClientSingleton=createClient(SUPABASE_URL,SUPABASE_PUBLISHABLE_KEY)),supabaseClientSingleton}const DEFAULT_API_ENDPOINT="https://print-room-chatbot-api.vercel.app/api/chat",DEFAULT_QUESTIONS_API="https://print-room-chatbot-api.vercel.app/api/questions",DEFAULT_PROMPTS=["What printing methods do you offer?","What are your minimum order quantities?","How do I request a quote?","What's your turnaround time?"],CONVERSATION_STORAGE_KEY="pr_chat_conversation_id",HEARTBEAT_INTERVAL_MS=25e3,ECHO_DEDUPE_WINDOW_MS=2e4,DEFAULT_CHAT_UNAVAILABLE_MESSAGE="Chat is temporarily unavailable. Please request a quote or contact us directly.";function deriveRespondEndpoint(chatEndpoint){const base=(chatEndpoint||DEFAULT_API_ENDPOINT).replace(/\/+$/,"");return/\/api\/chat$/i.test(base)?base.replace(/\/api\/chat\/?$/,"/api/respond"):/\/api\/respond$/i.test(base)?base:`${base}/api/respond`}function getInitials(name){return name?name.trim().split(/\s+/).slice(0,2).map(part=>part[0]?part[0].toUpperCase():"").join(""):""}var ai_chatbot_default=({apiEndpoint="",welcomeMessage="Hi! How can I help you today?",suggestedPrompts=[],questionsApiUrl="",unavailableMessage=DEFAULT_CHAT_UNAVAILABLE_MESSAGE})=>({isOpen:!1,isMinimized:!1,messages:[],inputText:"",isLoading:!1,error:null,unavailableMessage,dynamicQuestions:[],questionsLoading:!1,questionsLoaded:!1,leadData:{companyName:null,projectType:null,quantity:null,quantityRange:null,decorationMethod:null,timeline:null,deliveryLocation:null,artworkStatus:null,additionalNotes:null},ctaButton:null,mondayItemId:null,quoteData:null,pendingOptionsIndex:null,conversationId:null,conversationStatus:null,contactName:null,contactEmail:null,showContactAsk:!1,contactAskMode:null,contactNameInput:"",contactEmailInput:"",contactSubmitting:!1,apiEndpoint:apiEndpoint||DEFAULT_API_ENDPOINT,questionsApiUrl:questionsApiUrl||DEFAULT_QUESTIONS_API,welcomeMessage,suggestedPrompts:suggestedPrompts.length>0?suggestedPrompts:DEFAULT_PROMPTS,getActivePrompts(){return this.dynamicQuestions.length>0?this.dynamicQuestions.map(q=>q.text):this.suggestedPrompts},init(){console.log("[AI Chatbot] Alpine init() called"),console.log("[AI Chatbot] Config:",{apiEndpoint:this.apiEndpoint,questionsApiUrl:this.questionsApiUrl,welcomeMessage:this.welcomeMessage}),console.log("[AI Chatbot] Suggested prompts:",this.suggestedPrompts),this._realtimeChannel=null,this._heartbeatIntervalId=null,this._sessionInitPromise=null,this._historyLoaded=!1,this._renderedAssistantIds=new Set,this._lastStreamedAssistant=null,this._visibilityHandler=()=>{document.visibilityState==="visible"?this.isOpen&&this.startHeartbeat():this.stopHeartbeatTimer()},document.addEventListener("visibilitychange",this._visibilityHandler);try{new URLSearchParams(window.location.search).get("chat")==="open"&&this.$nextTick(()=>this.open())}catch(e){console.warn("[AI Chatbot] Could not read ?chat=open deep link:",e)}},destroy(){this.stopHeartbeatTimer(),this.unsubscribeRealtime(),this._visibilityHandler&&document.removeEventListener("visibilitychange",this._visibilityHandler)},handleEscape(e){e.key==="Escape"&&this.isOpen&&this.close()},toggle(){console.log("[AI Chatbot] toggle() called, isOpen:",this.isOpen),this.isOpen=!this.isOpen,this.isOpen?(this.isMinimized=!1,this.fetchDynamicQuestions(),this.$nextTick(()=>{const input=this.$refs.chatInput;input&&input.focus()}),this.initChatSession(),this.startHeartbeat()):this.stopHeartbeatTimer()},open(){this.isOpen=!0,this.isMinimized=!1,this.fetchDynamicQuestions(),this.$nextTick(()=>{const input=this.$refs.chatInput;input&&input.focus()}),this.initChatSession(),this.startHeartbeat()},close(){this.isOpen=!1,this.stopHeartbeatTimer()},async ensureSession(){const client=getSupabaseClient(),{data:{session}}=await client.auth.getSession();if(session)return session;const{data,error}=await client.auth.signInAnonymously();if(error)throw error;return data.session},applyConversationRow(row){this.conversationId=row.id,this.conversationStatus=row.status,this.contactName=row.contact_name,this.contactEmail=row.contact_email},async ensureConversation(){const client=getSupabaseClient(),ownerId=(await this.ensureSession()).user.id,storedId=localStorage.getItem(CONVERSATION_STORAGE_KEY);if(storedId){const{data,error}=await client.from("chat_conversations").select("id, status, contact_name, contact_email").eq("id",storedId).maybeSingle();if(!error&&data)return this.applyConversationRow(data),{id:data.id,isNew:!1}}const{data:created,error:createErr}=await client.from("chat_conversations").insert({status:"bot",owner_id:ownerId}).select("id, status, contact_name, contact_email").single();if(createErr)throw createErr;return localStorage.setItem(CONVERSATION_STORAGE_KEY,created.id),this.applyConversationRow(created),{id:created.id,isNew:!0}},async loadHistory(conversationId){const client=getSupabaseClient(),{data,error}=await client.from("chat_messages").select("id, role, content, sender_name, meta, created_at").eq("conversation_id",conversationId).order("created_at",{ascending:!0});if(error){console.error("[AI Chatbot] Failed to load history",error);return}this.messages=(data||[]).map(row=>({id:row.id,role:row.role,content:row.content,senderName:row.sender_name||null,initials:row.sender_name?getInitials(row.sender_name):null,timestamp:new Date(row.
1created_at),isStreaming:!1,options:null,selectedOptions:[],optionsSubmitted:!1})),this.messages.filter(m=>m.role==="assistant").forEach(m=>this._renderedAssistantIds.add(m.id)),this.scrollToBottom()},initChatSession(){return this._sessionInitPromise?this._sessionInitPromise:(this._sessionInitPromise=(async()=>{try{const{id,isNew}=await this.ensureConversation();!isNew&&!this._historyLoaded&&(await this.loadHistory(id),this._historyLoaded=!0),this.subscribeRealtime()}catch(err){console.error("[AI Chatbot] Failed to initialize chat session",err),this.error="Unable to connect to chat. Please refresh and try again.",this._sessionInitPromise=null}})(),this._sessionInitPromise)},subscribeRealtime(){if(this._realtimeChannel||!this.conversationId)return;const channel=getSupabaseClient().channel(`conv:${this.conversationId}`).on("postgres_changes",{event:"INSERT",schema:"public",table:"chat_messages",filter:`conversation_id=eq.${this.conversationId}`},payload=>this.handleRealtimeMessageInsert(payload.new)).on("postgres_changes",{event:"UPDATE",schema:"public",table:"chat_conversations",filter:`id=eq.${this.conversationId}`},payload=>this.handleConversationUpdate(payload.new)).subscribe();this._realtimeChannel=channel},unsubscribeRealtime(){this._realtimeChannel&&(getSupabaseClient().removeChannel(this._realtimeChannel),this._realtimeChannel=null)},handleRealtimeMessageInsert(row){if(row.role==="assistant"){if(this._renderedAssistantIds.has(row.id))return;if(this._renderedAssistantIds.add(row.id),this._lastStreamedAssistant&&this._lastStreamedAssistant.conversationId===this.conversationId&&this._lastStreamedAssistant.content===row.content&&Date.now()-this._lastStreamedAssistant.ts<ECHO_DEDUPE_WINDOW_MS){for(let i=this.messages.length-1;i>=0;i--)if(this.messages[i].role==="assistant"&&this.messages[i].content===row.content){this.messages[i].id=row.id;break}return}this.addMessage("assistant",row.content,{id:row.id}),row.meta&&row.meta.quoteData&&this.applyQuoteData(row.meta.quoteData),this.scrollToBottom();return}if(row.role==="staff"){this.addMessage("staff",row.content,{id:row.id,senderName:row.sender_name}),this.scrollToBottom();return}if(row.role==="system"){this.addMessage("system",row.content,{id:row.id}),this.scrollToBottom();return}},handleConversationUpdate(row){const previousStatus=this.conversationStatus;this.conversationStatus=row.status,this.contactName=row.contact_name,this.contactEmail=row.contact_email,row.status==="needs_human"&&!row.contact_email?(this.showContactAsk=!0,this.contactAskMode="email_chip"):this.contactAskMode==="email_chip"&&row.status!=="needs_human"&&(this.showContactAsk=!1,this.contactAskMode=null),previousStatus!==row.status&&console.log("[AI Chatbot] Conversation status:",previousStatus,"->",row.status)},startHeartbeat(){this.stopHeartbeatTimer(),!(!this.isOpen||document.visibilityState!=="visible")&&(this.sendHeartbeat(),this._heartbeatIntervalId=setInterval(()=>this.sendHeartbeat(),HEARTBEAT_INTERVAL_MS))},stopHeartbeatTimer(){this._heartbeatIntervalId&&(clearInterval(this._heartbeatIntervalId),this._heartbeatIntervalId=null)},async sendHeartbeat(){if(!this.isOpen||document.visibilityState!=="visible"||!this.conversationId)return;const client=getSupabaseClient(),{error}=await client.from("chat_conversations").update({last_seen_at:new Date().toISOString()}).eq("id",this.conversationId);error&&console.warn("[AI Chatbot] Heartbeat update failed",error)},async submitContact(){const name=this.contactNameInput.trim(),email=this.contactEmailInput.trim();if(!name&&!email)return;this.contactSubmitting=!0;const patch={};name&&(patch.contact_name=name),email&&(patch.contact_email=email);try{const client=getSupabaseClient(),{error}=await client.from("chat_conversations").update(patch).eq("id",this.conversationId);if(error)throw error;name&&(this.contactName=name),email&&(this.contactEmail=email),this.showContactAsk=!1,this.contactAskMode=null,this.contactNameInput="",this.contactEmailInput=""}catch(err){console.error("[AI Chatbot] Failed to save contact info",err),this.error="Could not save your details. Please try again."}finally{this.contactSubmitting=!1}},dismissContactAsk(){this.showContactAsk=!1,this.contactAskMode=null},applyQuoteData(quoteData){this.quoteData=quoteData,console.log("[AI Chatbot] Quote data received:",quoteData);try{var chatQuoteStore=Alpine.store("chatQuote");chatQuoteStore&&chatQuoteStore.setFromChatData(quoteData,this.conversationId)}catch(e){console.error("[AI Chatbot] Error setting chat quote data:",e)}},async fetchDynamicQuestions(){if(!(this.questionsLoaded||this.questionsLoading||!this.questionsApiUrl)){this.questionsLoading=!0,console.log("[AI Chatbot] Fetching dynamic questions from:",this.questionsApiUrl);try{const response=await fetch(this.questionsApiUrl);if(!response.ok)throw new Error(`Failed to fetch questions: ${response.status}`);const data=await response.json();data.questions&&Array.isArray(data.questions)&&(this.dynamicQuestions=data.questions,console.log("[AI Chatbot] Loaded",data.questions.length,"dynamic questions"))}catch(err){console.warn("[AI Chatbot] Failed to load dynamic questions, using fallback:",err.message)}finally{this.questionsLoading=!1,this.questionsLoaded=!0}}},minimize(){this.isMinimized=!this.isMinimized},async clearHistory(){this.unsubscribeRealtime(),localStorage.removeItem(CONVERSATION_STORAGE_KEY),this.conversationId=null,this.conversationStatus=null,this.contactName=null,this.contactEmail=null,this.contactNameInput="",this.contactEmailInput="",this.showContactAsk=!1,this.contactAskMode=null,this._sessionInitPromise=null,this._historyLoaded=!1,this._renderedAssistantIds.clear(),this._lastStreamedAssistant=null,this.messages=[],this.error=null,this.ctaButton=null,this.mondayItemId=null,this.quoteData=null,this.pendingOptionsIndex=null,this.leadData={companyName:null,projectType:null,quantity:null,quantityRange:null,decorationMethod:null,timeline:null,deliveryLocation:null,artworkStatus:null,additionalNotes:null};try{var chatQuoteStore=Alpine.store("chatQuote");chatQuoteStore&&chatQuoteStore.clear()}catch{}await this.initChatSession(),this.startHeartbeat()},dismissCTA(){this.ctaButton=null},openQuoteRequest(){this.isOpen=!1,setTimeout(function(){try{Alpine.store("modals").open("quoteRequest")}catch(e){console.error("[AI Chatbot] Error opening quote modal:",e)}},300)},handleCTAClick(){this.ctaButton&&this.ctaButton.action==="openQuoteModal"?this.openQuoteRequest():this.ctaButton&&this.ctaButton.url&&window.open(this.ctaButton.url,"_blank")},selectOption(messageIndex,choiceValue){var msg=this.messages[messageIndex];if(!(!msg||!msg.options||msg.optionsSubmitted))if(msg.options.multiSelect){var idx=msg.selectedOptions.indexOf(choiceValue);idx===-1?msg.selectedOptions.push(choiceValue):msg.selectedOptions.splice(idx,1)}else msg.selectedOptions=[choiceValue],this.submitOptions(messageIndex)},submitOptions(messageIndex){var msg=this.messages[messageIndex];if(!(!msg||!msg.options||msg.optionsSubmitted||msg.selectedOptions.length===0)){msg.optionsSubmitted=!0,this.pendingOptionsIndex=null;var selectedLabels=msg.selectedOptions.map(function(val){var choice=msg.options.choices.find(function(c){return c.value===val});return choice?choice.label:val}),userText=selectedLabels.join(", ");this.inputText=userText,this.sendMessage()}},clearError(){this.error=null},addMessage(role,content,extra){extra=extra||{},this.messages.push({id:extra.id||`${role}-${Date.now()}-${Math.random().toString(36).slice(2)}`,role,content,senderName:extra.senderName||null,initials:extra.senderName?getInitials(extra.senderName):null,timestamp:new Date,isStreaming:role==="assistant"&&content==="",options:null,selectedOptions:[],optionsSubmitted:!1})},scrollToBottom(){this.$nextTick(()=>{const container=this.$refs.messagesContainer;container&&(container.scrollTop=container.scrollHeight)})},useSuggestedPrompt(prompt){this.inputText=prompt,this.sendMessage()},handleKeyDown(e){e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),this.sendMessage())},async sendMessage(){const userMessage=this.inputText.trim();if(!userMessage||this.isLoading)return;if(this.pendingOptionsIndex!==null){var pendingMsg=this.messages[this.pendingOptionsIndex];pendingMsg&&!pendingMsg.optionsSubmitted&&(pendingMsg.optionsSubmitted=!0),this.pendingOptionsIndex=null}this.error=null,this.inputText="";try{await this.initChatSession()}catch{}if(!this.conversationId){this.error=this.error||"Unable to start chat session. Please try again.";return}
1this.addMessage("user",userMessage),this.scrollToBottom(),this.addMessage("assistant","");const assistantIndex=this.messages.length-1;this.isLoading=!0;try{const client=getSupabaseClient(),{data:{session}}=await client.auth.getSession(),accessToken=session&&session.access_token;if(!accessToken)throw new Error("No active chat session");const apiMessages=this.messages.slice(0,-1).filter(m=>m.role==="user"||m.role==="assistant").map(m=>({role:m.role,content:m.content})),insertPromise=client.from("chat_messages").insert({conversation_id:this.conversationId,role:"user",content:userMessage}),respondPromise=fetch(deriveRespondEndpoint(this.apiEndpoint),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${accessToken}`},body:JSON.stringify({conversation_id:this.conversationId,messages:apiMessages,message:userMessage})}),[insertResult,response]=await Promise.all([insertPromise,respondPromise]);if(insertResult&&insertResult.error&&console.error("[AI Chatbot] Failed to persist user message",insertResult.error),response.status===204){this.messages=this.messages.filter((_,i)=>i!==assistantIndex);return}if(!response.ok){const errorData=await response.json().catch(()=>({}));throw new Error(errorData.error||"Failed to send message")}const reader=response.body?.getReader();if(!reader)throw new Error("No response body");const decoder=new TextDecoder;let accumulatedContent="",sseBuffer="";for(;;){const{done,value}=await reader.read();value&&(sseBuffer+=decoder.decode(value,{stream:!0})),done&&(sseBuffer+=decoder.decode());const lines=sseBuffer.split(/\r?\n/);sseBuffer=done?"":lines.pop()||"";for(const line of lines)if(line.startsWith("data: ")){const data=line.slice(6);if(data==="[DONE]")continue;let parsed;try{parsed=JSON.parse(data)}catch{continue}if(parsed.error)throw new Error(this.unavailableMessage);parsed.text&&(accumulatedContent+=parsed.text,this.messages[assistantIndex].content=accumulatedContent,this.messages[assistantIndex].isStreaming=!0,this.scrollToBottom()),parsed.type==="message"&&typeof parsed.id=="string"&&(this.messages[assistantIndex].id=parsed.id,this._renderedAssistantIds.add(parsed.id)),parsed.type==="metadata"&&(console.log("[AI Chatbot] Received metadata:",parsed),parsed.leadData&&(this.leadData={...this.leadData,...parsed.leadData},console.log("[AI Chatbot] Updated lead data:",this.leadData)),parsed.cta&&parsed.cta.show&&(this.ctaButton=parsed.cta,console.log("[AI Chatbot] CTA triggered:",parsed.cta)),parsed.mondayItemId&&(this.mondayItemId=parsed.mondayItemId),parsed.quoteData&&this.applyQuoteData(parsed.quoteData),parsed.status&&this.handleConversationUpdate({status:parsed.status,contact_name:this.contactName,contact_email:this.contactEmail}),parsed.askContact&&(this.showContactAsk=!0,this.contactAskMode="progressive")),parsed.type==="options"&&(console.log("[AI Chatbot] Options received:",parsed),this.messages[assistantIndex].options={id:parsed.id||"options-"+Date.now(),prompt:parsed.prompt||"",multiSelect:parsed.multiSelect||!1,choices:parsed.choices||[]},this.messages[assistantIndex].selectedOptions=[],this.messages[assistantIndex].optionsSubmitted=!1,this.pendingOptionsIndex=assistantIndex,this.scrollToBottom())}if(done)break}this.messages[assistantIndex].isStreaming=!1,this._lastStreamedAssistant={conversationId:this.conversationId,content:accumulatedContent,ts:Date.now()}}catch(err){this.messages=this.messages.filter((_,i)=>i!==assistantIndex),console.error("[AI Chatbot] Message failed:",err),this.error=this.unavailableMessage}finally{this.isLoading=!1,this.scrollToBottom()}}});deferrableData("AIChatbot",ai_chatbot_default),console.log("[AI Chatbot] Module registered");
2//# sourceMappingURL=/cdn/shop/t/59/assets/ai-chatbot.bundle.js.map?v=114215721854634402901788472409

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.