@anker-in/campaign-ui 0.3.4 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/cjs/components/LiveChatWidget/LiveChatWidget.js +1 -1
  2. package/dist/cjs/components/LiveChatWidget/LiveChatWidget.js.map +3 -3
  3. package/dist/cjs/components/LiveChatWidget/components/MessageContent/PromotionList.js.map +2 -2
  4. package/dist/cjs/components/LiveChatWidget/components/MessageList.js +3 -3
  5. package/dist/cjs/components/LiveChatWidget/components/MessageList.js.map +3 -3
  6. package/dist/cjs/components/LiveChatWidget/hooks/useChatState.d.ts +2 -1
  7. package/dist/cjs/components/LiveChatWidget/hooks/useChatState.js +1 -1
  8. package/dist/cjs/components/LiveChatWidget/hooks/useChatState.js.map +2 -2
  9. package/dist/cjs/components/LiveChatWidget/types.d.ts +2 -1
  10. package/dist/cjs/components/LiveChatWidget/types.js.map +1 -1
  11. package/dist/cjs/components/credits/creditsBanner/index.js +2 -2
  12. package/dist/cjs/components/credits/creditsBanner/index.js.map +2 -2
  13. package/dist/cjs/stories/LiveChatWidget.stories.js +2 -9
  14. package/dist/cjs/stories/LiveChatWidget.stories.js.map +2 -2
  15. package/dist/esm/components/LiveChatWidget/LiveChatWidget.js +1 -1
  16. package/dist/esm/components/LiveChatWidget/LiveChatWidget.js.map +3 -3
  17. package/dist/esm/components/LiveChatWidget/components/MessageContent/PromotionList.js.map +2 -2
  18. package/dist/esm/components/LiveChatWidget/components/MessageList.js +3 -3
  19. package/dist/esm/components/LiveChatWidget/components/MessageList.js.map +3 -3
  20. package/dist/esm/components/LiveChatWidget/hooks/useChatState.d.ts +2 -1
  21. package/dist/esm/components/LiveChatWidget/hooks/useChatState.js +1 -1
  22. package/dist/esm/components/LiveChatWidget/hooks/useChatState.js.map +2 -2
  23. package/dist/esm/components/LiveChatWidget/types.d.ts +2 -1
  24. package/dist/esm/components/credits/creditsBanner/index.js +2 -2
  25. package/dist/esm/components/credits/creditsBanner/index.js.map +2 -2
  26. package/dist/esm/stories/LiveChatWidget.stories.js +1 -8
  27. package/dist/esm/stories/LiveChatWidget.stories.js.map +2 -2
  28. package/package.json +2 -2
  29. package/src/components/LiveChatWidget/LiveChatWidget.tsx +20 -0
  30. package/src/components/LiveChatWidget/components/MessageContent/PromotionList.tsx +1 -1
  31. package/src/components/LiveChatWidget/components/MessageList.tsx +39 -44
  32. package/src/components/LiveChatWidget/hooks/useChatState.ts +4 -3
  33. package/src/components/LiveChatWidget/types.ts +2 -1
  34. package/src/components/credits/creditsBanner/index.tsx +5 -5
  35. package/src/stories/LiveChatWidget.stories.tsx +7 -12
  36. package/src/styles/livechat.css +29 -0
@@ -1,2 +1,2 @@
1
- "use strict";var Qe=Object.create;var N=Object.defineProperty;var ze=Object.getOwnPropertyDescriptor;var He=Object.getOwnPropertyNames;var Ye=Object.getPrototypeOf,Ge=Object.prototype.hasOwnProperty;var Ve=(i,d)=>{for(var l in d)N(i,l,{get:d[l],enumerable:!0})},ce=(i,d,l,q)=>{if(d&&typeof d=="object"||typeof d=="function")for(let n of He(d))!Ge.call(i,n)&&n!==l&&N(i,n,{get:()=>d[n],enumerable:!(q=ze(d,n))||q.enumerable});return i};var K=(i,d,l)=>(l=i!=null?Qe(Ye(i)):{},ce(d||!i||!i.__esModule?N(l,"default",{value:i,enumerable:!0}):l,i)),Xe=i=>ce(N({},"__esModule",{value:!0}),i);var Je={};Ve(Je,{LiveChatWidget:()=>Ke});module.exports=Xe(Je);var h=require("react/jsx-runtime"),o=K(require("react")),J=K(require("@radix-ui/react-dialog")),de=require("./constants"),pe=require("./components/ChatBubble"),le=require("./components/ChatWindow"),ue=require("./components/ComplianceDialog"),me=require("./hooks/useChatState"),ge=require("./hooks/useChatAPI"),he=require("./utils/messageRenderers"),fe=require("./utils/validation"),Z=require("./utils/productTransformers.js"),ye=require("./utils/cartTransformers.js"),j=K(require("js-cookie")),r=require("./components/MessageContent/index.js");const Ke=({apiBaseUrl:i,headers:d,recaptchaSitekey:l,recaptchaAction:q,site:n,channelCode:C,loginUserId:y,cartId:U,accessToken:b,position:_e,welcomeMessage:E,quickReplies:_,customRenderers:$,logoUrl:Ce,title:we,chatBubbleIcon:Re,open:xe,onOpenChange:De,onOpen:Se,onClose:Ee,onMessageSend:k,onError:w,onTextMessage:Me,onProductList:Pe,onPromotionList:Te,onAddToCart:O,onCart:Q,showNewSessionButton:Ae,commonText:ee,productCardRender:ve,bottomTips:qe,complianceConfig:D})=>{const z=D?.cookieName||"livechat_compliance_agreed",[te,H]=o.default.useState(!1),[se,Oe]=o.default.useState(()=>D?j.default.get(z)!==void 0:!0),M=o.default.useMemo(()=>({...de.DEFAULT_COMMON_TEXT,...ee}),[ee]),Fe=(0,me.useChatState)({welcomeMessage:E,site:n,open:xe,onOpenChange:De,onOpen:Se,onClose:Ee,onMessageSend:k,onError:w,onTextMessage:Me,onProductList:Pe,onPromotionList:Te,onAddToCart:O,onCart:Q,productCardRender:ve}),{messages:F,isOpen:B,userId:u,sessionId:Y,inputValue:G,isStreaming:Be,openChat:P,closeChat:ae,setInputValue:V,addMessage:f,setMessages:S,clearMessages:W,handleSSEEvent:re,saveSession:T,clearSession:A}=Fe,{sendMessageStream:ne,createSession:R}=(0,ge.useChatAPI)({apiBaseUrl:i,headers:d,recaptchaConfig:{needRecaptcha:!!l,recaptchaSitekey:l,recaptchaAction:q},onError:w}),oe=o.default.useRef(async t=>{}),We=o.default.useMemo(()=>{const t=new he.MessageRendererRegistry;t.register("text",r.TextBlock),t.register("product_card",r.ProductCard),t.register("product_list",r.ProductList),t.register("product_comparison",r.ProductComparisonRenderer),t.register("policy",r.PolicyBlock),t.register("thinking",r.ThinkingBlock),t.register("error",r.ErrorBlock),t.register("faq_list",r.FAQListRenderer),t.register("promotion_list",r.PromotionListRenderer),t.register("cart",r.CartCard);const s=(0,r.createQuickRepliesRenderer)(c=>{oe.current(c.value)});return t.register("quick_replies",s),$&&t.registerMany($),t},[$]);(0,o.useEffect)(()=>{if(!B||!u)return;const t=Y;t?Ie(t):v()},[B,u]);const ie=(0,o.useCallback)(t=>{if(Array.isArray(t.content))return t;const s=[];typeof t.content=="string"&&t.content.trim()&&s.push({type:"text",text:t.content});const c=t.structuredContent||t.structured_content;return Array.isArray(c)&&c.forEach(e=>{if(e.type==="product_list"&&Array.isArray(e.data))s.push({type:"product_list",data:{products:(0,Z.transformProducts)(e.data,n),title:void 0,commonText:M}});else if(e.type==="quick_replies"&&e.data?.replies)s.push({type:"quick_replies",data:{replies:e.data.replies}});else if(e.type==="policy"&&e.data?.title&&e.data?.content)s.push({type:"policy",data:{title:e.data.title,content:e.data.content}});else if(e.type==="product_comparison"&&e.data?.products&&e.data?.dimensions)s.push({type:"product_comparison",data:{products:(0,Z.transformProducts)(e.data.products,n),dimensions:e.data.dimensions,onAddToCart:O,commonText:M}});else if(e.type==="faq_list"&&e.data?.found!==void 0)s.push({type:"faq_list",data:e.data});else if(e.type==="promotion_list"&&e.data?.found!==void 0)s.push({type:"promotion_list",data:{...e.data,commonText:M}});else if(e.type==="cart"&&e.data?.id!==void 0){const m=(0,ye.transformCartData)(e.data);s.push({type:"cart",data:{...m,onCart:Q,commonText:M}})}else s.push(e)}),s.length===0&&s.push({type:"text",text:""}),{...t,content:s}},[n,Q,O,M]),v=(0,o.useCallback)(async()=>{if(u)try{const t=await R({user_id:u,site:n,channel_code:C,real_user_id:y});if(t.success){T(t.sessionId),W();const s=t.welcomeMessage||E;if(s){const c=[{type:"text",text:s}],e=t.quickQuestions;if(e&&e.length>0){const m=e.map((g,a)=>({id:`quick-${a}`,label:g,value:g}));c.push({type:"quick_replies",data:{replies:m}})}else _&&_.length>0&&c.push({type:"quick_replies",data:{replies:_}});f({id:`welcome-${Date.now()}`,role:"assistant",content:c,timestamp:Date.now()})}}}catch(t){console.error("[LiveChatWidget] Failed to create new session:",t),w?.(t);const s=t?.type==="GoogleRecaptchaError";f({id:`error-${Date.now()}`,role:"system",content:[{type:"error",data:{message:s?"Your session has expired. Please refresh the page and try again.":"Failed to create session. Please refresh the page and try again.",code:s?"RECAPTCHA_ERROR":"SESSION_CREATE_ERROR"}}],timestamp:Date.now()})}},[u,n,C,y,R,T,W,E,_,f,w]),Ie=(0,o.useCallback)(async t=>{try{const s=await R({user_id:u,session_id:t,site:n,channel_code:C,real_user_id:y});if(s.success&&s.resumed){const c=s.welcomeMessage||E,e=c?[{type:"text",text:c}]:[],m=s.quickQuestions;if(m&&m.length>0){const g=m.map((a,L)=>({id:`quick-${L}`,label:a,value:a}));e.push({type:"quick_replies",data:{replies:g}})}else _&&_.length>0&&e.push({type:"quick_replies",data:{replies:_}});if(s.messages&&s.messages.length>0){const g=s.messages.filter(a=>a!=null).map(ie).filter(a=>a.content&&a.content.length>0&&!(a.content.length===1&&a.content[0].type==="text"&&!a.content[0].text));if(e.length>0){const a={id:`welcome-${Date.now()}`,role:"assistant",content:e,timestamp:Date.now()};S([a,...g])}else S(g)}else W(),e.length>0&&f({id:`welcome-${Date.now()}`,role:"assistant",content:e,timestamp:Date.now()})}else s.resumed||(A(),v())}catch(s){console.error("[LiveChatWidget] Failed to resume session:",s),s?.type==="GoogleRecaptchaError"?f({id:`error-${Date.now()}`,role:"system",content:[{type:"error",data:{message:"Your session has expired. Please refresh the page and try again.",code:"RECAPTCHA_ERROR"}}],timestamp:Date.now()}):(f({id:`error-${Date.now()}`,role:"system",content:[{type:"error",data:{message:"Failed to resume session. Creating a new session...",code:"SESSION_RESUME_ERROR"}}],timestamp:Date.now()}),A(),v())}},[u,n,C,y,R,S,A,W,ie,v,E,_,f]),I=(0,o.useCallback)(async(t,s=!1)=>{const c=t||G.trim();if(!c)return;!t&&!s&&V("");const e=(0,fe.sanitizeInput)(c);if(!e){w?.(new Error("Invalid message"));return}if(!s){const a={id:`user-${Date.now()}`,role:"user",content:[{type:"text",text:e}],timestamp:Date.now()};f(a)}const m={id:`thinking-${Date.now()}`,role:"assistant",content:[{type:"thinking",data:{status:"thinking"}}],timestamp:Date.now()};f(m),s||k?.(e);let g=!1;try{let a=Y;if(!a){const p=await R({user_id:u,site:n,channel_code:C,real_user_id:y});if(p.success)a=p.sessionId,T(a);else throw new Error("Failed to create session")}if(await ne({message:e,user_id:u,session_id:a,context:{cartId:U,accessToken:b,real_user_id:y}},p=>{re(p),p.event==="error"&&p.data.type==="validation_error"&&(g=!0,A())}),g&&!s){console.log("[LiveChatWidget] Session expired (validation_error), creating new session and retrying...");const p=F.filter(X=>X.id!==m.id);S(p);const x=await R({user_id:u,site:n,channel_code:C,real_user_id:y});if(x.success)T(x.sessionId),await I(e,!0);else throw new Error("Failed to recreate session after expiration")}}catch(a){console.error("[LiveChatWidget] Failed to send message:",a),w?.(a);const L=a?.type==="GoogleRecaptchaError";let p,x;L?(p="Your session has expired. Please refresh the page and try again.",x="RECAPTCHA_ERROR"):g?(p="Your session has expired. We tried to reconnect but failed. Please try again.",x="SESSION_EXPIRED"):(p="Failed to send message. Please check your network connection and try again.",x="NETWORK_ERROR");const X=F.filter(ke=>ke.id!==m.id);S([...X,{id:`error-${Date.now()}`,role:"system",content:[{type:"error",data:{message:p,code:x}}],timestamp:Date.now()}])}},[G,u,Y,n,C,y,U,b,F,V,f,S,R,ne,re,T,A,k,w]);o.default.useEffect(()=>{oe.current=I},[I]);const Le=(0,o.useCallback)(()=>{D&&!se?H(!0):P()},[D,se,P]),Ne=(0,o.useCallback)(()=>{Oe(!0),H(!1),j.default.set(z,"true",{expires:365}),P()},[P,z]),$e=(0,o.useCallback)(()=>{H(!1)},[]);return(0,h.jsxs)(h.Fragment,{children:[D&&(0,h.jsx)(ue.ComplianceDialog,{open:te,config:D,onAgree:Ne,onClose:$e}),(0,h.jsx)(pe.ChatBubble,{position:_e,onClick:Le,visible:!B&&!te,iconImageUrl:Re}),(0,h.jsx)(J.Root,{open:B,onOpenChange:t=>t?P():ae(),children:(0,h.jsx)(J.Portal,{children:(0,h.jsx)(J.Content,{className:"livechat-window-enter",style:{position:"fixed",zIndex:9998},children:(0,h.jsx)(le.ChatWindow,{messages:F,inputValue:G,onInputChange:V,onSend:()=>I(),onClose:ae,onNewSession:v,title:we,logoUrl:Ce,isSending:Be,rendererRegistry:We,inputPlaceholder:"",onAddToCart:O,showNewSessionButton:Ae,bottomTips:qe})})})})]})};
1
+ "use strict";var He=Object.create;var $=Object.defineProperty;var Ye=Object.getOwnPropertyDescriptor;var Ge=Object.getOwnPropertyNames;var Ve=Object.getPrototypeOf,Xe=Object.prototype.hasOwnProperty;var Ke=(o,d)=>{for(var l in d)$(o,l,{get:d[l],enumerable:!0})},de=(o,d,l,q)=>{if(d&&typeof d=="object"||typeof d=="function")for(let i of Ge(d))!Xe.call(o,i)&&i!==l&&$(o,i,{get:()=>d[i],enumerable:!(q=Ye(d,i))||q.enumerable});return o};var J=(o,d,l)=>(l=o!=null?He(Ve(o)):{},de(d||!o||!o.__esModule?$(l,"default",{value:o,enumerable:!0}):l,o)),Je=o=>de($({},"__esModule",{value:!0}),o);var je={};Ke(je,{LiveChatWidget:()=>Ze});module.exports=Je(je);var f=require("react/jsx-runtime"),n=J(require("react")),Z=J(require("@radix-ui/react-dialog")),pe=require("./constants"),le=require("./components/ChatBubble"),ue=require("./components/ChatWindow"),me=require("./components/ComplianceDialog"),ge=require("./hooks/useChatState"),fe=require("./hooks/useChatAPI"),he=require("./utils/messageRenderers"),ye=require("./utils/validation"),j=require("./utils/productTransformers.js"),_e=require("./utils/cartTransformers.js"),U=J(require("js-cookie")),r=require("./components/MessageContent/index.js");const Ze=({apiBaseUrl:o,headers:d,recaptchaSitekey:l,recaptchaAction:q,site:i,channelCode:C,loginUserId:y,cartId:b,accessToken:ee,position:Ce,welcomeMessage:R,quickReplies:_,customRenderers:k,logoUrl:Re,title:we,chatBubbleIcon:xe,open:Se,onOpenChange:De,onOpen:Ee,onClose:Pe,onMessageSend:z,onError:w,onTextMessage:Me,onProductList:Te,onPromotionList:Ae,onAddToCart:I,onCart:Q,showNewSessionButton:ve,commonText:te,productCardRender:qe,bottomTips:Ie,complianceConfig:D})=>{const H=D?.cookieName||"livechat_compliance_agreed",[se,Y]=n.default.useState(!1),[ae,Oe]=n.default.useState(()=>D?U.default.get(H)!==void 0:!0),P=n.default.useMemo(()=>({...pe.DEFAULT_COMMON_TEXT,...te}),[te]),Fe=(0,ge.useChatState)({welcomeMessage:R,site:i,open:Se,onOpenChange:De,onOpen:Ee,onClose:Pe,onMessageSend:z,onError:w,onTextMessage:Me,onProductList:Te,onPromotionList:Ae,onAddToCart:I,onCart:Q,productCardRender:qe}),{messages:O,isOpen:F,userId:u,sessionId:G,inputValue:V,isStreaming:Be,openChat:M,closeChat:re,setInputValue:X,addMessage:h,setMessages:E,clearMessages:B,handleSSEEvent:ne,saveSession:T,clearSession:A}=Fe,[Le,L]=n.default.useState(!1),{sendMessageStream:ie,createSession:x}=(0,fe.useChatAPI)({apiBaseUrl:o,headers:d,recaptchaConfig:{needRecaptcha:!!l,recaptchaSitekey:l,recaptchaAction:q},onError:w}),oe=n.default.useRef(async t=>{}),We=n.default.useMemo(()=>{const t=new he.MessageRendererRegistry;t.register("text",r.TextBlock),t.register("product_card",r.ProductCard),t.register("product_list",r.ProductList),t.register("product_comparison",r.ProductComparisonRenderer),t.register("policy",r.PolicyBlock),t.register("thinking",r.ThinkingBlock),t.register("error",r.ErrorBlock),t.register("faq_list",r.FAQListRenderer),t.register("promotion_list",r.PromotionListRenderer),t.register("cart",r.CartCard);const s=(0,r.createQuickRepliesRenderer)(c=>{oe.current(c.value)});return t.register("quick_replies",s),k&&t.registerMany(k),t},[k]);(0,n.useEffect)(()=>{if(!F||!u)return;const t=G;t?Ne(t):v()},[F,u]);const ce=(0,n.useCallback)(t=>{if(Array.isArray(t.content))return t;const s=[];typeof t.content=="string"&&t.content.trim()&&s.push({type:"text",text:t.content});const c=t.structuredContent||t.structured_content;return Array.isArray(c)&&c.forEach(e=>{if(e.type==="product_list"&&Array.isArray(e.data))s.push({type:"product_list",data:{products:(0,j.transformProducts)(e.data,i),title:void 0,commonText:P}});else if(e.type==="quick_replies"&&e.data?.replies)s.push({type:"quick_replies",data:{replies:e.data.replies}});else if(e.type==="policy"&&e.data?.title&&e.data?.content)s.push({type:"policy",data:{title:e.data.title,content:e.data.content}});else if(e.type==="product_comparison"&&e.data?.products&&e.data?.dimensions)s.push({type:"product_comparison",data:{products:(0,j.transformProducts)(e.data.products,i),dimensions:e.data.dimensions,onAddToCart:I,commonText:P}});else if(e.type==="faq_list"&&e.data?.found!==void 0)s.push({type:"faq_list",data:e.data});else if(e.type==="promotion_list"&&e.data?.found!==void 0)s.push({type:"promotion_list",data:{...e.data,commonText:P}});else if(e.type==="cart"&&e.data?.id!==void 0){const m=(0,_e.transformCartData)(e.data);s.push({type:"cart",data:{...m,onCart:Q,commonText:P}})}else s.push(e)}),s.length===0&&s.push({type:"text",text:""}),{...t,content:s}},[i,Q,I,P]),v=(0,n.useCallback)(async()=>{if(u){R||L(!0);try{const t=await x({user_id:u,site:i,channel_code:C,real_user_id:y});if(t.success){T(t.sessionId),B();const s=t.welcomeMessage||R;if(s){const c=[{type:"text",text:s}],e=t.quickQuestions;if(e&&e.length>0){const m=e.map((g,a)=>({id:`quick-${a}`,label:g,value:g}));c.push({type:"quick_replies",data:{replies:m}})}else _&&_.length>0&&c.push({type:"quick_replies",data:{replies:_}});h({id:`welcome-${Date.now()}`,role:"assistant",content:c,timestamp:Date.now()})}}}catch(t){console.error("[LiveChatWidget] Failed to create new session:",t),w?.(t);const s=t?.type==="GoogleRecaptchaError";h({id:`error-${Date.now()}`,role:"system",content:[{type:"error",data:{message:s?"Your session has expired. Please refresh the page and try again.":"Failed to create session. Please refresh the page and try again.",code:s?"RECAPTCHA_ERROR":"SESSION_CREATE_ERROR"}}],timestamp:Date.now()})}finally{L(!1)}}},[u,i,C,y,x,T,B,R,_,h,w]),Ne=(0,n.useCallback)(async t=>{R||L(!0);try{const s=await x({user_id:u,session_id:t,site:i,channel_code:C,real_user_id:y});if(s.success&&s.resumed){const c=s.welcomeMessage||R,e=c?[{type:"text",text:c}]:[],m=s.quickQuestions;if(m&&m.length>0){const g=m.map((a,N)=>({id:`quick-${N}`,label:a,value:a}));e.push({type:"quick_replies",data:{replies:g}})}else _&&_.length>0&&e.push({type:"quick_replies",data:{replies:_}});if(s.messages&&s.messages.length>0){const g=s.messages.filter(a=>a!=null).map(ce).filter(a=>a.content&&a.content.length>0&&!(a.content.length===1&&a.content[0].type==="text"&&!a.content[0].text));if(e.length>0){const a={id:`welcome-${Date.now()}`,role:"assistant",content:e,timestamp:Date.now()};E([a,...g])}else E(g)}else B(),e.length>0&&h({id:`welcome-${Date.now()}`,role:"assistant",content:e,timestamp:Date.now()})}else s.resumed||(A(),v())}catch(s){console.error("[LiveChatWidget] Failed to resume session:",s),s?.type==="GoogleRecaptchaError"?h({id:`error-${Date.now()}`,role:"system",content:[{type:"error",data:{message:"Your session has expired. Please refresh the page and try again.",code:"RECAPTCHA_ERROR"}}],timestamp:Date.now()}):(h({id:`error-${Date.now()}`,role:"system",content:[{type:"error",data:{message:"Failed to resume session. Creating a new session...",code:"SESSION_RESUME_ERROR"}}],timestamp:Date.now()}),A(),v())}finally{L(!1)}},[u,i,C,y,x,E,A,B,ce,v,R,_,h]),W=(0,n.useCallback)(async(t,s=!1)=>{const c=t||V.trim();if(!c)return;!t&&!s&&X("");const e=(0,ye.sanitizeInput)(c);if(!e){w?.(new Error("Invalid message"));return}if(!s){const a={id:`user-${Date.now()}`,role:"user",content:[{type:"text",text:e}],timestamp:Date.now()};h(a)}const m={id:`thinking-${Date.now()}`,role:"assistant",content:[{type:"thinking",data:{status:"thinking"}}],timestamp:Date.now()};h(m),s||z?.(e);let g=!1;try{let a=G;if(!a){const p=await x({user_id:u,site:i,channel_code:C,real_user_id:y});if(p.success)a=p.sessionId,T(a);else throw new Error("Failed to create session")}if(await ie({message:e,user_id:u,session_id:a,context:{cartId:b,accessToken:ee,real_user_id:y}},p=>{ne(p),p.event==="error"&&p.data.type==="validation_error"&&(g=!0,A())}),g&&!s){console.log("[LiveChatWidget] Session expired (validation_error), creating new session and retrying...");const p=O.filter(K=>K.id!==m.id);E(p);const S=await x({user_id:u,site:i,channel_code:C,real_user_id:y});if(S.success)T(S.sessionId),await W(e,!0);else throw new Error("Failed to recreate session after expiration")}}catch(a){console.error("[LiveChatWidget] Failed to send message:",a),w?.(a);const N=a?.type==="GoogleRecaptchaError";let p,S;N?(p="Your session has expired. Please refresh the page and try again.",S="RECAPTCHA_ERROR"):g?(p="Your session has expired. We tried to reconnect but failed. Please try again.",S="SESSION_EXPIRED"):(p="Failed to send message. Please check your network connection and try again.",S="NETWORK_ERROR");const K=O.filter(Qe=>Qe.id!==m.id);E([...K,{id:`error-${Date.now()}`,role:"system",content:[{type:"error",data:{message:p,code:S}}],timestamp:Date.now()}])}},[V,u,G,i,C,y,b,ee,O,X,h,E,x,ie,ne,T,A,z,w]);n.default.useEffect(()=>{oe.current=W},[W]);const $e=(0,n.useCallback)(()=>{D&&!ae?Y(!0):M()},[D,ae,M]),ke=(0,n.useCallback)(()=>{Oe(!0),Y(!1),U.default.set(H,"true",{expires:365}),M()},[M,H]),ze=(0,n.useCallback)(()=>{Y(!1)},[]);return(0,f.jsxs)(f.Fragment,{children:[D&&(0,f.jsx)(me.ComplianceDialog,{open:se,config:D,onAgree:ke,onClose:ze}),(0,f.jsx)(le.ChatBubble,{position:Ce,onClick:$e,visible:!F&&!se,iconImageUrl:xe}),(0,f.jsx)(Z.Root,{open:F,onOpenChange:t=>t?M():re(),children:(0,f.jsx)(Z.Portal,{children:(0,f.jsx)(Z.Content,{className:"livechat-window-enter",style:{position:"fixed",zIndex:9998},children:(0,f.jsx)(ue.ChatWindow,{messages:O,inputValue:V,onInputChange:X,onSend:()=>W(),onClose:re,onNewSession:v,title:we,logoUrl:Re,isSending:Be,isLoadingHistory:Le,rendererRegistry:We,inputPlaceholder:"",onAddToCart:I,showNewSessionButton:ve,bottomTips:Ie})})})})]})};
2
2
  //# sourceMappingURL=LiveChatWidget.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/components/LiveChatWidget/LiveChatWidget.tsx"],
4
- "sourcesContent": ["/**\n * LiveChat \u4E3B\u7EC4\u4EF6\n * \u96C6\u6210\u6240\u6709\u5B50\u7EC4\u4EF6\uFF0C\u63D0\u4F9B\u5B8C\u6574\u7684\u804A\u5929\u529F\u80FD\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u4E09\u5C42\u67B6\u6784\u8BBE\u8BA1\n */\n\nimport React, { useEffect, useCallback } from 'react'\nimport * as Dialog from '@radix-ui/react-dialog'\nimport type {\n LiveChatWidgetProps,\n QuickReply,\n Message,\n MessageContent,\n ChatStreamRequest,\n BackendCartData,\n CommonText,\n} from './types'\nimport { DEFAULT_COMMON_TEXT } from './constants'\nimport { ChatBubble } from './components/ChatBubble'\nimport { ChatWindow } from './components/ChatWindow'\nimport { ComplianceDialog } from './components/ComplianceDialog'\nimport { useChatState } from './hooks/useChatState'\nimport { useChatAPI } from './hooks/useChatAPI'\nimport { MessageRendererRegistry } from './utils/messageRenderers'\nimport { sanitizeInput } from './utils/validation'\nimport { transformProducts } from './utils/productTransformers.js'\nimport { transformCartData } from './utils/cartTransformers.js'\nimport Cookies from 'js-cookie'\nimport {\n TextBlock,\n ProductCard,\n ProductList,\n ProductComparisonRenderer,\n PolicyBlock,\n createQuickRepliesRenderer,\n ThinkingBlock,\n ErrorBlock,\n FAQListRenderer,\n PromotionListRenderer,\n CartCard,\n} from './components/MessageContent/index.js'\n\n/**\n * LiveChat \u804A\u5929\u7EC4\u4EF6\n *\n * \u529F\u80FD\uFF1A\n * - \u6C14\u6CE1\u5F39\u7A97\u804A\u5929\u754C\u9762\n * - SSE \u6D41\u5F0F\u6D88\u606F\u63A5\u6536\n * - \u4F1A\u8BDD\u7BA1\u7406\uFF08userId, sessionId\uFF09\n * - \u5386\u53F2\u6D88\u606F\u52A0\u8F7D\n * - \u591A\u79CD\u6D88\u606F\u7C7B\u578B\u6E32\u67D3\n * - \u81EA\u5B9A\u4E49\u6269\u5C55\u673A\u5236\n * - reCAPTCHA v3 \u5B89\u5168\u9632\u62A4\n *\n * \u67B6\u6784\uFF1A\n * - UI Layer: ChatBubble, ChatWindow, MessageList, etc.\n * - Logic Layer: useChatState, useChatAPI, useSession\n * - Core Layer: MessageRendererRegistry, \u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\n *\n * @example\n * ```tsx\n * // \u57FA\u7840\u4F7F\u7528\uFF08\u4F7F\u7528\u9ED8\u8BA4\u4F4D\u7F6E\uFF09\n * <LiveChatWidget\n * apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n * site=\"www.eufy.com\"\n * welcomeMessage=\"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\"\n * onMessageSend={(msg) => console.log('Sent:', msg)}\n * />\n *\n * // \u4F7F\u7528\u81EA\u5B9A\u4E49\u4F4D\u7F6E\n * <LiveChatWidget\n * apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n * site=\"www.eufy.com\"\n * position={{ bottom: \"20px\", right: \"30px\" }}\n * onMessageSend={(msg) => console.log('Sent:', msg)}\n * />\n *\n * // \u542F\u7528 reCAPTCHA v3 \u5B89\u5168\u9632\u62A4\uFF08\u63D0\u4F9B sitekey \u5373\u81EA\u52A8\u542F\u7528\uFF09\n * <LiveChatWidget\n * apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n * site=\"www.eufy.com\"\n * recaptchaSitekey=\"6LfS4J4pAAAAACX1e_WrxutmxxzCK7FU4WzVqL14\"\n * recaptchaAction=\"livechat\"\n * />\n *\n * // \u4F7F\u7528\u81EA\u5B9A\u4E49 headers \u548C reCAPTCHA\n * <LiveChatWidget\n * apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n * site=\"www.eufy.com\"\n * headers={{\n * \"Authorization\": \"Bearer your-token\",\n * \"X-Custom-Header\": \"value\"\n * }}\n * recaptchaSitekey=\"your-site-key\"\n * />\n * ```\n */\nexport const LiveChatWidget: React.FC<LiveChatWidgetProps> = ({\n apiBaseUrl,\n headers,\n recaptchaSitekey,\n recaptchaAction,\n site,\n channelCode,\n loginUserId,\n cartId,\n accessToken,\n position,\n welcomeMessage,\n quickReplies,\n customRenderers,\n logoUrl,\n title,\n chatBubbleIcon,\n open,\n onOpenChange,\n onOpen,\n onClose,\n onMessageSend,\n onError,\n onTextMessage,\n onProductList,\n onPromotionList,\n onAddToCart,\n onCart,\n showNewSessionButton,\n commonText,\n productCardRender,\n bottomTips,\n complianceConfig,\n}) => {\n // \u6CD5\u89C4\u534F\u8BAE\u5F39\u7A97\u72B6\u6001\n // \u4ECE Cookie \u8BFB\u53D6\u7528\u6237\u662F\u5426\u5DF2\u540C\u610F\uFF08\u6709\u6548\u671F 365 \u5929\uFF09\n const cookieName = complianceConfig?.cookieName || 'livechat_compliance_agreed'\n const [showComplianceDialog, setShowComplianceDialog] = React.useState(false)\n const [hasAgreedCompliance, setHasAgreedCompliance] = React.useState(() => {\n // \u521D\u59CB\u5316\u65F6\u68C0\u67E5 Cookie\n return complianceConfig ? Cookies.get(cookieName) !== undefined : true\n })\n\n // \u5408\u5E76\u9ED8\u8BA4\u6587\u6848\u548C\u81EA\u5B9A\u4E49\u6587\u6848\n const mergedText: Required<CommonText> = React.useMemo(\n () => ({\n ...DEFAULT_COMMON_TEXT,\n ...commonText,\n }),\n [commonText]\n )\n\n // \u72B6\u6001\u7BA1\u7406\n const chatState = useChatState({\n welcomeMessage,\n site,\n open,\n onOpenChange,\n onOpen,\n onClose,\n onMessageSend,\n onError,\n onTextMessage,\n onProductList,\n onPromotionList,\n onAddToCart,\n onCart,\n productCardRender,\n })\n\n const {\n messages,\n isOpen,\n userId,\n sessionId,\n inputValue,\n isStreaming,\n openChat,\n closeChat,\n setInputValue,\n addMessage,\n setMessages,\n clearMessages,\n handleSSEEvent,\n saveSession,\n clearSession,\n } = chatState\n\n // API \u8C03\u7528\n const { sendMessageStream, createSession } = useChatAPI({\n apiBaseUrl,\n headers,\n recaptchaConfig: {\n needRecaptcha: !!recaptchaSitekey, // \u6839\u636E sitekey \u81EA\u52A8\u5224\u65AD\u662F\u5426\u542F\u7528\n recaptchaSitekey,\n recaptchaAction,\n },\n onError,\n })\n\n // \u4F7F\u7528 ref \u5B58\u50A8\u6700\u65B0\u7684 handleSendMessage\uFF0C\u907F\u514D\u5FAA\u73AF\u4F9D\u8D56\n const handleSendMessageRef = React.useRef<(_message?: string) => Promise<void>>(async (_message?: string) => {})\n\n // \u6D88\u606F\u6E32\u67D3\u5668\u6CE8\u518C\u8868\n const rendererRegistry = React.useMemo(() => {\n const registry = new MessageRendererRegistry()\n\n // \u6CE8\u518C\u9ED8\u8BA4\u6E32\u67D3\u5668\n registry.register('text', TextBlock)\n registry.register('product_card', ProductCard)\n registry.register('product_list', ProductList)\n registry.register('product_comparison', ProductComparisonRenderer)\n registry.register('policy', PolicyBlock)\n registry.register('thinking', ThinkingBlock)\n registry.register('error', ErrorBlock)\n registry.register('faq_list', FAQListRenderer)\n registry.register('promotion_list', PromotionListRenderer)\n registry.register('cart', CartCard)\n\n // \u6CE8\u518C\u5FEB\u6377\u56DE\u590D\u6E32\u67D3\u5668\uFF08\u5E26\u56DE\u8C03\uFF09\n const quickRepliesRenderer = createQuickRepliesRenderer((reply: QuickReply) => {\n // \u4F7F\u7528 ref \u8C03\u7528\u6700\u65B0\u7684 handleSendMessage\n handleSendMessageRef.current(reply.value)\n })\n registry.register('quick_replies', quickRepliesRenderer)\n\n // \u6CE8\u518C\u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\n if (customRenderers) {\n registry.registerMany(customRenderers)\n }\n\n return registry\n }, [customRenderers])\n\n /**\n * T043: \u6253\u5F00\u804A\u5929\u7A97\u53E3\u65F6\u521D\u59CB\u5316\u4F1A\u8BDD\n * \u4F7F\u7528 API v2.0.0 \u7684\u7EDF\u4E00\u63A5\u53E3\uFF1A\n * - \u5982\u679C\u6CA1\u6709 sessionId\uFF0C\u521B\u5EFA\u65B0\u4F1A\u8BDD\n * - \u5982\u679C\u6709 sessionId\uFF0C\u6062\u590D\u4F1A\u8BDD\u5E76\u52A0\u8F7D\u5386\u53F2\u6D88\u606F\n */\n useEffect(() => {\n if (!isOpen || !userId) return\n\n const currentSessionId = sessionId\n\n if (!currentSessionId) {\n // \u6CA1\u6709\u4F1A\u8BDD\uFF0C\u521B\u5EFA\u65B0\u4F1A\u8BDD\n handleCreateNewSession()\n } else {\n // \u6709\u4F1A\u8BDD\uFF0C\u5C1D\u8BD5\u6062\u590D\u4F1A\u8BDD\u548C\u5386\u53F2\u6D88\u606F\n handleResumeSession(currentSessionId)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen, userId])\n\n /**\n * \u89C4\u8303\u5316\u6D88\u606F\u683C\u5F0F\uFF08\u786E\u4FDD content \u662F\u6570\u7EC4\uFF09\n * \u540E\u7AEF\u8FD4\u56DE\u683C\u5F0F\uFF1A\n * - content: \u5B57\u7B26\u4E32\uFF08\u6587\u672C\u5185\u5BB9\uFF09\n * - structuredContent: \u6570\u7EC4\uFF08\u7ED3\u6784\u5316\u5185\u5BB9\uFF0C\u5982\u4EA7\u54C1\u5217\u8868\u3001\u653F\u7B56\u7B49\uFF09\n * \u9700\u8981\u5408\u5E76\u4E3A\u7EDF\u4E00\u7684 content \u6570\u7EC4\u683C\u5F0F\n */\n const normalizeMessage = useCallback(\n (message: any): Message => {\n // \u5982\u679C content \u5DF2\u7ECF\u662F\u6570\u7EC4\uFF0C\u76F4\u63A5\u8FD4\u56DE\n if (Array.isArray(message.content)) {\n return message as Message\n }\n\n const contentBlocks: MessageContent[] = []\n\n // \u5904\u7406\u6587\u672C\u5185\u5BB9\n if (typeof message.content === 'string' && message.content.trim()) {\n contentBlocks.push({\n type: 'text',\n text: message.content,\n })\n }\n\n // \u5904\u7406\u7ED3\u6784\u5316\u5185\u5BB9\n // \u5386\u53F2\u6D88\u606F\u683C\u5F0F: structured_content: [{type, data}]\n const structuredData = message.structuredContent || message.structured_content\n\n if (Array.isArray(structuredData)) {\n structuredData.forEach((block: any) => {\n if (block.type === 'product_list' && Array.isArray(block.data)) {\n // \u8F6C\u6362\u4EA7\u54C1\u5217\u8868\u6570\u636E\u7ED3\u6784 - data \u76F4\u63A5\u662F\u4EA7\u54C1\u6570\u7EC4\n contentBlocks.push({\n type: 'product_list',\n data: {\n products: transformProducts(block.data, site),\n title: undefined, // \u5386\u53F2\u6D88\u606F\u4E0D\u5305\u542B title\n commonText: mergedText,\n },\n })\n } else if (block.type === 'quick_replies' && block.data?.replies) {\n contentBlocks.push({\n type: 'quick_replies',\n data: {\n replies: block.data.replies,\n },\n })\n } else if (block.type === 'policy' && block.data?.title && block.data?.content) {\n contentBlocks.push({\n type: 'policy',\n data: {\n title: block.data.title,\n content: block.data.content,\n },\n })\n } else if (block.type === 'product_comparison' && block.data?.products && block.data?.dimensions) {\n // \u8F6C\u6362\u4EA7\u54C1\u5BF9\u6BD4\u6570\u636E\u7ED3\u6784\u5E76\u6CE8\u5165 onAddToCart \u56DE\u8C03\n contentBlocks.push({\n type: 'product_comparison',\n data: {\n products: transformProducts(block.data.products, site),\n dimensions: block.data.dimensions,\n onAddToCart: onAddToCart,\n commonText: mergedText,\n },\n })\n } else if (block.type === 'faq_list' && block.data?.found !== undefined) {\n // FAQ \u5217\u8868\u5361\u7247 - \u76F4\u63A5\u4F7F\u7528\u540E\u7AEF\u6570\u636E\n contentBlocks.push({\n type: 'faq_list',\n data: block.data,\n })\n } else if (block.type === 'promotion_list' && block.data?.found !== undefined) {\n // \u4FC3\u9500\u6D3B\u52A8\u5217\u8868\u5361\u7247 - \u76F4\u63A5\u4F7F\u7528\u540E\u7AEF\u6570\u636E\n contentBlocks.push({\n type: 'promotion_list',\n data: {\n ...block.data,\n commonText: mergedText,\n },\n })\n } else if (block.type === 'cart' && block.data?.id !== undefined) {\n // \u8D2D\u7269\u8F66\u5361\u7247 - \u8F6C\u6362\u540E\u7AEF\u6570\u636E\u683C\u5F0F\u5E76\u6CE8\u5165 onCart \u56DE\u8C03\n const transformedData = transformCartData(block.data as BackendCartData)\n contentBlocks.push({\n type: 'cart',\n data: {\n ...transformedData,\n onCart: onCart,\n commonText: mergedText,\n },\n })\n } else {\n // \u5176\u4ED6\u7C7B\u578B\u76F4\u63A5\u6DFB\u52A0\n contentBlocks.push(block)\n }\n })\n }\n\n // \u5982\u679C\u6CA1\u6709\u4EFB\u4F55\u5185\u5BB9\u5757\uFF0C\u8FD4\u56DE\u7A7A\u6587\u672C\u5757\n if (contentBlocks.length === 0) {\n contentBlocks.push({\n type: 'text',\n text: '',\n })\n }\n\n return {\n ...message,\n content: contentBlocks,\n } as Message\n },\n [site, onCart, onAddToCart, mergedText]\n )\n\n /**\n * \u521B\u5EFA\u65B0\u4F1A\u8BDD\n */\n const handleCreateNewSession = useCallback(async () => {\n if (!userId) return\n\n try {\n const response = await createSession({\n user_id: userId,\n site: site,\n channel_code: channelCode,\n real_user_id: loginUserId,\n })\n\n if (response.success) {\n // \u4FDD\u5B58\u65B0\u4F1A\u8BDD ID\n saveSession(response.sessionId)\n\n // \u6E05\u7A7A\u6D88\u606F\u5217\u8868\n clearMessages()\n\n // \u4F7F\u7528\u540E\u7AEF\u8FD4\u56DE\u7684\u6B22\u8FCE\u6D88\u606F\uFF0C\u5982\u679C\u6CA1\u6709\u5219\u4F7F\u7528 props \u4E2D\u7684\u9ED8\u8BA4\u503C\n const messageText = response.welcomeMessage || welcomeMessage\n\n if (messageText) {\n const welcomeContent: MessageContent[] = [{ type: 'text', text: messageText }]\n\n // \u4F7F\u7528\u540E\u7AEF\u8FD4\u56DE\u7684\u5FEB\u6377\u95EE\u9898\uFF0C\u5982\u679C\u6CA1\u6709\u5219\u4F7F\u7528 props \u4E2D\u7684\u5FEB\u6377\u56DE\u590D\n const questions = response.quickQuestions\n if (questions && questions.length > 0) {\n // \u5C06\u540E\u7AEF\u7684 quickQuestions (\u5B57\u7B26\u4E32\u6570\u7EC4) \u8F6C\u6362\u4E3A QuickReply \u683C\u5F0F\n const quickRepliesFromBackend = questions.map((question, index) => ({\n id: `quick-${index}`,\n label: question,\n value: question,\n }))\n\n welcomeContent.push({\n type: 'quick_replies',\n data: {\n replies: quickRepliesFromBackend,\n },\n })\n } else if (quickReplies && quickReplies.length > 0) {\n // \u5982\u679C\u540E\u7AEF\u6CA1\u6709\u8FD4\u56DE\uFF0C\u4F7F\u7528 props \u4E2D\u7684\u5FEB\u6377\u56DE\u590D\n welcomeContent.push({\n type: 'quick_replies',\n data: {\n replies: quickReplies,\n },\n })\n }\n\n addMessage({\n id: `welcome-${Date.now()}`,\n role: 'assistant',\n content: welcomeContent,\n timestamp: Date.now(),\n })\n }\n }\n } catch (error) {\n console.error('[LiveChatWidget] Failed to create new session:', error)\n onError?.(error as Error)\n\n // Check if it's a reCAPTCHA error\n const isRecaptcha = (error as any)?.type === 'GoogleRecaptchaError'\n\n // \u6DFB\u52A0\u9519\u8BEF\u6D88\u606F\u5230\u754C\u9762\n addMessage({\n id: `error-${Date.now()}`,\n role: 'system',\n content: [\n {\n type: 'error',\n data: {\n message: isRecaptcha\n ? 'Your session has expired. Please refresh the page and try again.'\n : 'Failed to create session. Please refresh the page and try again.',\n code: isRecaptcha ? 'RECAPTCHA_ERROR' : 'SESSION_CREATE_ERROR',\n },\n },\n ],\n timestamp: Date.now(),\n })\n }\n }, [\n userId,\n site,\n channelCode,\n loginUserId,\n createSession,\n saveSession,\n clearMessages,\n welcomeMessage,\n quickReplies,\n addMessage,\n onError,\n ])\n\n /**\n * \u6062\u590D\u4F1A\u8BDD\u548C\u5386\u53F2\u6D88\u606F\uFF08\u4F7F\u7528\u65B0\u7684 API v2.0.0\uFF09\n */\n const handleResumeSession = useCallback(\n async (existingSessionId: string) => {\n try {\n const response = await createSession({\n user_id: userId,\n session_id: existingSessionId,\n site: site,\n channel_code: channelCode,\n real_user_id: loginUserId,\n })\n\n if (response.success && response.resumed) {\n // \u4F1A\u8BDD\u6062\u590D\u6210\u529F\n\n // \u51C6\u5907\u6B22\u8FCE\u6D88\u606F\uFF08\u65E0\u8BBA\u662F\u5426\u6709\u5386\u53F2\u6D88\u606F\u90FD\u9700\u8981\uFF09\n const messageText = response.welcomeMessage || welcomeMessage\n const welcomeContent: MessageContent[] = messageText ? [{ type: 'text', text: messageText }] : []\n\n // \u6DFB\u52A0\u5FEB\u6377\u56DE\u590D\u5230\u6B22\u8FCE\u6D88\u606F\n const questions = response.quickQuestions\n if (questions && questions.length > 0) {\n const quickRepliesFromBackend = questions.map((question, index) => ({\n id: `quick-${index}`,\n label: question,\n value: question,\n }))\n\n welcomeContent.push({\n type: 'quick_replies',\n data: {\n replies: quickRepliesFromBackend,\n },\n })\n } else if (quickReplies && quickReplies.length > 0) {\n welcomeContent.push({\n type: 'quick_replies',\n data: {\n replies: quickReplies,\n },\n })\n }\n\n if (response.messages && response.messages.length > 0) {\n // \u6709\u5386\u53F2\u6D88\u606F\uFF0C\u89C4\u8303\u5316\u5E76\u52A0\u8F7D\uFF08\u8FC7\u6EE4\u6389 null/undefined \u503C\u548C\u7A7A\u5185\u5BB9\u6D88\u606F\uFF09\n const normalizedMessages = response.messages\n .filter((msg: any) => msg != null)\n .map(normalizeMessage)\n .filter((msg: Message) => msg.content && msg.content.length > 0 && !(msg.content.length === 1 && msg.content[0].type === 'text' && !msg.content[0].text))\n\n // \u5982\u679C\u6709\u6B22\u8FCE\u6D88\u606F\uFF0C\u5C06\u5176\u6DFB\u52A0\u5230\u5386\u53F2\u6D88\u606F\u7684\u5F00\u5934\n if (welcomeContent.length > 0) {\n const welcomeMsg: Message = {\n id: `welcome-${Date.now()}`,\n role: 'assistant',\n content: welcomeContent,\n timestamp: Date.now(),\n }\n setMessages([welcomeMsg, ...normalizedMessages])\n } else {\n setMessages(normalizedMessages)\n }\n } else {\n // \u6CA1\u6709\u5386\u53F2\u6D88\u606F\uFF0C\u4EC5\u663E\u793A\u6B22\u8FCE\u6D88\u606F\n clearMessages()\n\n if (welcomeContent.length > 0) {\n addMessage({\n id: `welcome-${Date.now()}`,\n role: 'assistant',\n content: welcomeContent,\n timestamp: Date.now(),\n })\n }\n }\n } else if (!response.resumed) {\n // \u4F1A\u8BDD\u65E0\u6548\u6216\u8FC7\u671F\uFF0C\u521B\u5EFA\u65B0\u4F1A\u8BDD\n clearSession()\n handleCreateNewSession()\n }\n } catch (error) {\n console.error('[LiveChatWidget] Failed to resume session:', error)\n\n // Check if it's a reCAPTCHA error\n const isRecaptcha = (error as any)?.type === 'GoogleRecaptchaError'\n\n if (isRecaptcha) {\n // reCAPTCHA error - show refresh page message, don't retry\n addMessage({\n id: `error-${Date.now()}`,\n role: 'system',\n content: [\n {\n type: 'error',\n data: {\n message: 'Your session has expired. Please refresh the page and try again.',\n code: 'RECAPTCHA_ERROR',\n },\n },\n ],\n timestamp: Date.now(),\n })\n } else {\n // Other errors - show message and try to create new session\n addMessage({\n id: `error-${Date.now()}`,\n role: 'system',\n content: [\n {\n type: 'error',\n data: {\n message: 'Failed to resume session. Creating a new session...',\n code: 'SESSION_RESUME_ERROR',\n },\n },\n ],\n timestamp: Date.now(),\n })\n\n // \u6062\u590D\u5931\u8D25\uFF0C\u6E05\u7A7A\u4F1A\u8BDD\u5E76\u521B\u5EFA\u65B0\u7684\n clearSession()\n handleCreateNewSession()\n }\n }\n },\n [\n userId,\n site,\n channelCode,\n loginUserId,\n createSession,\n setMessages,\n clearSession,\n clearMessages,\n normalizeMessage,\n handleCreateNewSession,\n welcomeMessage,\n quickReplies,\n addMessage,\n ]\n )\n\n /**\n * \u53D1\u9001\u6D88\u606F\n */\n const handleSendMessage = useCallback(\n async (message?: string, isRetry: boolean = false) => {\n const textToSend = message || inputValue.trim()\n\n if (!textToSend) return\n\n // \u6E05\u7A7A\u8F93\u5165\u6846\uFF08\u4EC5\u5728\u975E\u91CD\u8BD5\u65F6\uFF09\n if (!message && !isRetry) {\n setInputValue('')\n }\n\n // \u8F93\u5165\u9A8C\u8BC1\n const sanitized = sanitizeInput(textToSend)\n if (!sanitized) {\n onError?.(new Error('Invalid message'))\n return\n }\n\n // \u6DFB\u52A0\u7528\u6237\u6D88\u606F\u5230\u754C\u9762\uFF08\u4EC5\u5728\u975E\u91CD\u8BD5\u65F6\uFF09\n if (!isRetry) {\n const userMessage = {\n id: `user-${Date.now()}`,\n role: 'user' as const,\n content: [{ type: 'text' as const, text: sanitized }],\n timestamp: Date.now(),\n }\n addMessage(userMessage)\n }\n\n // \u7ACB\u5373\u6DFB\u52A0\u601D\u8003\u72B6\u6001\u6D88\u606F\uFF0C\u63D0\u5347\u7528\u6237\u4F53\u9A8C\n const thinkingMessage = {\n id: `thinking-${Date.now()}`,\n role: 'assistant' as const,\n content: [{ type: 'thinking' as const, data: { status: 'thinking' } }],\n timestamp: Date.now(),\n }\n addMessage(thinkingMessage)\n\n // \u89E6\u53D1\u6D88\u606F\u53D1\u9001\u56DE\u8C03\uFF08\u4EC5\u5728\u975E\u91CD\u8BD5\u65F6\uFF09\n if (!isRetry) {\n onMessageSend?.(sanitized)\n }\n\n // \u6807\u8BB0\u662F\u5426\u68C0\u6D4B\u5230\u4F1A\u8BDD\u8FC7\u671F\n let sessionExpiredDetected = false\n\n try {\n // \u786E\u4FDD\u6709 sessionId\uFF0C\u5982\u679C\u6CA1\u6709\u5219\u5148\u521B\u5EFA\u4F1A\u8BDD\n let currentSessionId = sessionId\n if (!currentSessionId) {\n // \u6CA1\u6709\u4F1A\u8BDD\uFF0C\u521B\u5EFA\u65B0\u4F1A\u8BDD\n const response = await createSession({\n user_id: userId,\n site: site,\n channel_code: channelCode,\n real_user_id: loginUserId,\n })\n if (response.success) {\n currentSessionId = response.sessionId\n saveSession(currentSessionId)\n } else {\n throw new Error('Failed to create session')\n }\n }\n\n // \u6784\u5EFA\u8BF7\u6C42\u53C2\u6570\uFF08session_id \u73B0\u5728\u662F\u5FC5\u586B\u7684\uFF09\n const requestPayload: ChatStreamRequest = {\n message: sanitized,\n user_id: userId,\n session_id: currentSessionId,\n context: {\n cartId: cartId,\n accessToken: accessToken,\n real_user_id: loginUserId,\n },\n }\n\n // \u53D1\u9001\u6D88\u606F\u5230\u540E\u7AEF\n await sendMessageStream(requestPayload, event => {\n // \u5904\u7406 SSE \u4E8B\u4EF6\n handleSSEEvent(event)\n\n // \u7279\u6B8A\u5904\u7406\uFF1A\u4F1A\u8BDD\u8FC7\u671F\uFF08error \u4E8B\u4EF6\u4E14 type \u4E3A validation_error\uFF09\n if (event.event === 'error' && event.data.type === 'validation_error') {\n sessionExpiredDetected = true\n clearSession()\n }\n })\n\n // \u5982\u679C\u68C0\u6D4B\u5230\u4F1A\u8BDD\u8FC7\u671F\u4E14\u4E0D\u662F\u91CD\u8BD5\uFF0C\u81EA\u52A8\u521B\u5EFA\u65B0\u4F1A\u8BDD\u5E76\u91CD\u8BD5\n if (sessionExpiredDetected && !isRetry) {\n console.log('[LiveChatWidget] Session expired (validation_error), creating new session and retrying...')\n\n // \u79FB\u9664 thinking \u6D88\u606F\n const messagesWithoutThinking = messages.filter(msg => msg.id !== thinkingMessage.id)\n setMessages(messagesWithoutThinking)\n\n // \u521B\u5EFA\u65B0\u4F1A\u8BDD\n const response = await createSession({\n user_id: userId,\n site: site,\n channel_code: channelCode,\n real_user_id: loginUserId,\n })\n\n if (response.success) {\n saveSession(response.sessionId)\n // \u91CD\u8BD5\u53D1\u9001\u6D88\u606F\n await handleSendMessage(sanitized, true)\n } else {\n throw new Error('Failed to recreate session after expiration')\n }\n }\n } catch (error) {\n console.error('[LiveChatWidget] Failed to send message:', error)\n onError?.(error as Error)\n\n // Check if it's a reCAPTCHA error\n const isRecaptcha = (error as any)?.type === 'GoogleRecaptchaError'\n\n // Determine error message based on error type\n let errorMessage: string\n let errorCode: string\n\n if (isRecaptcha) {\n errorMessage = 'Your session has expired. Please refresh the page and try again.'\n errorCode = 'RECAPTCHA_ERROR'\n } else if (sessionExpiredDetected) {\n errorMessage = 'Your session has expired. We tried to reconnect but failed. Please try again.'\n errorCode = 'SESSION_EXPIRED'\n } else {\n errorMessage = 'Failed to send message. Please check your network connection and try again.'\n errorCode = 'NETWORK_ERROR'\n }\n\n // \u79FB\u9664\u521A\u624D\u6DFB\u52A0\u7684 thinking \u6D88\u606F\uFF0C\u5E76\u6DFB\u52A0\u9519\u8BEF\u6D88\u606F\n const messagesWithoutThinking = messages.filter(msg => msg.id !== thinkingMessage.id)\n setMessages([\n ...messagesWithoutThinking,\n {\n id: `error-${Date.now()}`,\n role: 'system',\n content: [\n {\n type: 'error',\n data: {\n message: errorMessage,\n code: errorCode,\n },\n },\n ],\n timestamp: Date.now(),\n },\n ])\n }\n },\n [\n inputValue,\n userId,\n sessionId,\n site,\n channelCode,\n loginUserId,\n cartId,\n accessToken,\n messages,\n setInputValue,\n addMessage,\n setMessages,\n createSession,\n sendMessageStream,\n handleSSEEvent,\n saveSession,\n clearSession,\n onMessageSend,\n onError,\n ]\n )\n\n // \u66F4\u65B0 ref \u4EE5\u4FDD\u6301\u6700\u65B0\u7684 handleSendMessage\n React.useEffect(() => {\n handleSendMessageRef.current = handleSendMessage\n }, [handleSendMessage])\n\n /**\n * \u5904\u7406\u6C14\u6CE1\u6309\u94AE\u70B9\u51FB\n * \u5982\u679C\u914D\u7F6E\u4E86\u6CD5\u89C4\u534F\u8BAE\u4E14\u7528\u6237\u672A\u540C\u610F\uFF0C\u5148\u663E\u793A\u6CD5\u89C4\u5F39\u7A97\n * \u5426\u5219\u76F4\u63A5\u6253\u5F00\u804A\u5929\u7A97\u53E3\n */\n const handleBubbleClick = useCallback(() => {\n if (complianceConfig && !hasAgreedCompliance) {\n // \u663E\u793A\u6CD5\u89C4\u534F\u8BAE\u5F39\u7A97\n setShowComplianceDialog(true)\n } else {\n // \u76F4\u63A5\u6253\u5F00\u804A\u5929\u7A97\u53E3\n openChat()\n }\n }, [complianceConfig, hasAgreedCompliance, openChat])\n\n /**\n * \u5904\u7406\u7528\u6237\u540C\u610F\u6CD5\u89C4\u534F\u8BAE\n */\n const handleComplianceAgree = useCallback(() => {\n // \u8BBE\u7F6E\u540C\u610F\u72B6\u6001\n setHasAgreedCompliance(true)\n setShowComplianceDialog(false)\n\n // \u4FDD\u5B58\u5230 Cookie\uFF08\u6709\u6548\u671F 365 \u5929\uFF09\n Cookies.set(cookieName, 'true', { expires: 365 })\n\n // \u540C\u610F\u540E\u7ACB\u5373\u6253\u5F00\u804A\u5929\u7A97\u53E3\n openChat()\n }, [openChat, cookieName])\n\n /**\n * \u5904\u7406\u6CD5\u89C4\u5F39\u7A97\u5173\u95ED\n */\n const handleComplianceClose = useCallback(() => {\n setShowComplianceDialog(false)\n }, [])\n\n return (\n <>\n {/* \u6CD5\u89C4\u534F\u8BAE\u5F39\u7A97 */}\n {complianceConfig && (\n <ComplianceDialog\n open={showComplianceDialog}\n config={complianceConfig}\n onAgree={handleComplianceAgree}\n onClose={handleComplianceClose}\n />\n )}\n\n {/* \u6C14\u6CE1\u6309\u94AE */}\n <ChatBubble\n position={position}\n onClick={handleBubbleClick}\n visible={!isOpen && !showComplianceDialog}\n iconImageUrl={chatBubbleIcon}\n />\n\n {/* \u804A\u5929\u7A97\u53E3\uFF08\u4F7F\u7528 Radix UI Dialog\uFF09 */}\n <Dialog.Root open={isOpen} onOpenChange={open => (open ? openChat() : closeChat())}>\n <Dialog.Portal>\n <Dialog.Content\n className=\"livechat-window-enter\"\n style={{\n position: 'fixed',\n zIndex: 9998,\n }}\n >\n <ChatWindow\n messages={messages}\n inputValue={inputValue}\n onInputChange={setInputValue}\n onSend={() => handleSendMessage()}\n onClose={closeChat}\n onNewSession={handleCreateNewSession}\n title={title}\n logoUrl={logoUrl}\n isSending={isStreaming}\n rendererRegistry={rendererRegistry}\n inputPlaceholder=\"\"\n onAddToCart={onAddToCart}\n showNewSessionButton={showNewSessionButton}\n bottomTips={bottomTips}\n />\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n </>\n )\n}\n"],
5
- "mappings": "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",
6
- "names": ["LiveChatWidget_exports", "__export", "LiveChatWidget", "__toCommonJS", "import_jsx_runtime", "import_react", "Dialog", "import_constants", "import_ChatBubble", "import_ChatWindow", "import_ComplianceDialog", "import_useChatState", "import_useChatAPI", "import_messageRenderers", "import_validation", "import_productTransformers", "import_cartTransformers", "import_js_cookie", "import_MessageContent", "apiBaseUrl", "headers", "recaptchaSitekey", "recaptchaAction", "site", "channelCode", "loginUserId", "cartId", "accessToken", "position", "welcomeMessage", "quickReplies", "customRenderers", "logoUrl", "title", "chatBubbleIcon", "open", "onOpenChange", "onOpen", "onClose", "onMessageSend", "onError", "onTextMessage", "onProductList", "onPromotionList", "onAddToCart", "onCart", "showNewSessionButton", "commonText", "productCardRender", "bottomTips", "complianceConfig", "cookieName", "showComplianceDialog", "setShowComplianceDialog", "React", "hasAgreedCompliance", "setHasAgreedCompliance", "Cookies", "mergedText", "chatState", "messages", "isOpen", "userId", "sessionId", "inputValue", "isStreaming", "openChat", "closeChat", "setInputValue", "addMessage", "setMessages", "clearMessages", "handleSSEEvent", "saveSession", "clearSession", "sendMessageStream", "createSession", "handleSendMessageRef", "_message", "rendererRegistry", "registry", "quickRepliesRenderer", "reply", "currentSessionId", "handleResumeSession", "handleCreateNewSession", "normalizeMessage", "message", "contentBlocks", "structuredData", "block", "transformedData", "response", "messageText", "welcomeContent", "questions", "quickRepliesFromBackend", "question", "index", "error", "isRecaptcha", "existingSessionId", "normalizedMessages", "msg", "welcomeMsg", "handleSendMessage", "isRetry", "textToSend", "sanitized", "userMessage", "thinkingMessage", "sessionExpiredDetected", "event", "messagesWithoutThinking", "errorMessage", "errorCode", "handleBubbleClick", "handleComplianceAgree", "handleComplianceClose"]
4
+ "sourcesContent": ["/**\n * LiveChat \u4E3B\u7EC4\u4EF6\n * \u96C6\u6210\u6240\u6709\u5B50\u7EC4\u4EF6\uFF0C\u63D0\u4F9B\u5B8C\u6574\u7684\u804A\u5929\u529F\u80FD\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u4E09\u5C42\u67B6\u6784\u8BBE\u8BA1\n */\n\nimport React, { useEffect, useCallback } from 'react'\nimport * as Dialog from '@radix-ui/react-dialog'\nimport type {\n LiveChatWidgetProps,\n QuickReply,\n Message,\n MessageContent,\n ChatStreamRequest,\n BackendCartData,\n CommonText,\n} from './types'\nimport { DEFAULT_COMMON_TEXT } from './constants'\nimport { ChatBubble } from './components/ChatBubble'\nimport { ChatWindow } from './components/ChatWindow'\nimport { ComplianceDialog } from './components/ComplianceDialog'\nimport { useChatState } from './hooks/useChatState'\nimport { useChatAPI } from './hooks/useChatAPI'\nimport { MessageRendererRegistry } from './utils/messageRenderers'\nimport { sanitizeInput } from './utils/validation'\nimport { transformProducts } from './utils/productTransformers.js'\nimport { transformCartData } from './utils/cartTransformers.js'\nimport Cookies from 'js-cookie'\nimport {\n TextBlock,\n ProductCard,\n ProductList,\n ProductComparisonRenderer,\n PolicyBlock,\n createQuickRepliesRenderer,\n ThinkingBlock,\n ErrorBlock,\n FAQListRenderer,\n PromotionListRenderer,\n CartCard,\n} from './components/MessageContent/index.js'\n\n/**\n * LiveChat \u804A\u5929\u7EC4\u4EF6\n *\n * \u529F\u80FD\uFF1A\n * - \u6C14\u6CE1\u5F39\u7A97\u804A\u5929\u754C\u9762\n * - SSE \u6D41\u5F0F\u6D88\u606F\u63A5\u6536\n * - \u4F1A\u8BDD\u7BA1\u7406\uFF08userId, sessionId\uFF09\n * - \u5386\u53F2\u6D88\u606F\u52A0\u8F7D\n * - \u591A\u79CD\u6D88\u606F\u7C7B\u578B\u6E32\u67D3\n * - \u81EA\u5B9A\u4E49\u6269\u5C55\u673A\u5236\n * - reCAPTCHA v3 \u5B89\u5168\u9632\u62A4\n *\n * \u67B6\u6784\uFF1A\n * - UI Layer: ChatBubble, ChatWindow, MessageList, etc.\n * - Logic Layer: useChatState, useChatAPI, useSession\n * - Core Layer: MessageRendererRegistry, \u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\n *\n * @example\n * ```tsx\n * // \u57FA\u7840\u4F7F\u7528\uFF08\u4F7F\u7528\u9ED8\u8BA4\u4F4D\u7F6E\uFF09\n * <LiveChatWidget\n * apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n * site=\"www.eufy.com\"\n * welcomeMessage=\"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\"\n * onMessageSend={(msg) => console.log('Sent:', msg)}\n * />\n *\n * // \u4F7F\u7528\u81EA\u5B9A\u4E49\u4F4D\u7F6E\n * <LiveChatWidget\n * apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n * site=\"www.eufy.com\"\n * position={{ bottom: \"20px\", right: \"30px\" }}\n * onMessageSend={(msg) => console.log('Sent:', msg)}\n * />\n *\n * // \u542F\u7528 reCAPTCHA v3 \u5B89\u5168\u9632\u62A4\uFF08\u63D0\u4F9B sitekey \u5373\u81EA\u52A8\u542F\u7528\uFF09\n * <LiveChatWidget\n * apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n * site=\"www.eufy.com\"\n * recaptchaSitekey=\"6LfS4J4pAAAAACX1e_WrxutmxxzCK7FU4WzVqL14\"\n * recaptchaAction=\"livechat\"\n * />\n *\n * // \u4F7F\u7528\u81EA\u5B9A\u4E49 headers \u548C reCAPTCHA\n * <LiveChatWidget\n * apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n * site=\"www.eufy.com\"\n * headers={{\n * \"Authorization\": \"Bearer your-token\",\n * \"X-Custom-Header\": \"value\"\n * }}\n * recaptchaSitekey=\"your-site-key\"\n * />\n * ```\n */\nexport const LiveChatWidget: React.FC<LiveChatWidgetProps> = ({\n apiBaseUrl,\n headers,\n recaptchaSitekey,\n recaptchaAction,\n site,\n channelCode,\n loginUserId,\n cartId,\n accessToken,\n position,\n welcomeMessage,\n quickReplies,\n customRenderers,\n logoUrl,\n title,\n chatBubbleIcon,\n open,\n onOpenChange,\n onOpen,\n onClose,\n onMessageSend,\n onError,\n onTextMessage,\n onProductList,\n onPromotionList,\n onAddToCart,\n onCart,\n showNewSessionButton,\n commonText,\n productCardRender,\n bottomTips,\n complianceConfig,\n}) => {\n // \u6CD5\u89C4\u534F\u8BAE\u5F39\u7A97\u72B6\u6001\n // \u4ECE Cookie \u8BFB\u53D6\u7528\u6237\u662F\u5426\u5DF2\u540C\u610F\uFF08\u6709\u6548\u671F 365 \u5929\uFF09\n const cookieName = complianceConfig?.cookieName || 'livechat_compliance_agreed'\n const [showComplianceDialog, setShowComplianceDialog] = React.useState(false)\n const [hasAgreedCompliance, setHasAgreedCompliance] = React.useState(() => {\n // \u521D\u59CB\u5316\u65F6\u68C0\u67E5 Cookie\n return complianceConfig ? Cookies.get(cookieName) !== undefined : true\n })\n\n // \u5408\u5E76\u9ED8\u8BA4\u6587\u6848\u548C\u81EA\u5B9A\u4E49\u6587\u6848\n const mergedText: Required<CommonText> = React.useMemo(\n () => ({\n ...DEFAULT_COMMON_TEXT,\n ...commonText,\n }),\n [commonText]\n )\n\n // \u72B6\u6001\u7BA1\u7406\n const chatState = useChatState({\n welcomeMessage,\n site,\n open,\n onOpenChange,\n onOpen,\n onClose,\n onMessageSend,\n onError,\n onTextMessage,\n onProductList,\n onPromotionList,\n onAddToCart,\n onCart,\n productCardRender,\n })\n\n const {\n messages,\n isOpen,\n userId,\n sessionId,\n inputValue,\n isStreaming,\n openChat,\n closeChat,\n setInputValue,\n addMessage,\n setMessages,\n clearMessages,\n handleSSEEvent,\n saveSession,\n clearSession,\n } = chatState\n\n // \u521D\u59CB\u5316\u52A0\u8F7D\u72B6\u6001\uFF08\u7528\u6237\u672A\u914D\u7F6E\u6B22\u8FCE\u8BED\u65F6\uFF0C\u663E\u793A loading \u76F4\u5230\u63A5\u53E3\u8FD4\u56DE\uFF09\n const [isInitializing, setIsInitializing] = React.useState(false)\n\n // API \u8C03\u7528\n const { sendMessageStream, createSession } = useChatAPI({\n apiBaseUrl,\n headers,\n recaptchaConfig: {\n needRecaptcha: !!recaptchaSitekey, // \u6839\u636E sitekey \u81EA\u52A8\u5224\u65AD\u662F\u5426\u542F\u7528\n recaptchaSitekey,\n recaptchaAction,\n },\n onError,\n })\n\n // \u4F7F\u7528 ref \u5B58\u50A8\u6700\u65B0\u7684 handleSendMessage\uFF0C\u907F\u514D\u5FAA\u73AF\u4F9D\u8D56\n const handleSendMessageRef = React.useRef<(_message?: string) => Promise<void>>(async (_message?: string) => {})\n\n // \u6D88\u606F\u6E32\u67D3\u5668\u6CE8\u518C\u8868\n const rendererRegistry = React.useMemo(() => {\n const registry = new MessageRendererRegistry()\n\n // \u6CE8\u518C\u9ED8\u8BA4\u6E32\u67D3\u5668\n registry.register('text', TextBlock)\n registry.register('product_card', ProductCard)\n registry.register('product_list', ProductList)\n registry.register('product_comparison', ProductComparisonRenderer)\n registry.register('policy', PolicyBlock)\n registry.register('thinking', ThinkingBlock)\n registry.register('error', ErrorBlock)\n registry.register('faq_list', FAQListRenderer)\n registry.register('promotion_list', PromotionListRenderer)\n registry.register('cart', CartCard)\n\n // \u6CE8\u518C\u5FEB\u6377\u56DE\u590D\u6E32\u67D3\u5668\uFF08\u5E26\u56DE\u8C03\uFF09\n const quickRepliesRenderer = createQuickRepliesRenderer((reply: QuickReply) => {\n // \u4F7F\u7528 ref \u8C03\u7528\u6700\u65B0\u7684 handleSendMessage\n handleSendMessageRef.current(reply.value)\n })\n registry.register('quick_replies', quickRepliesRenderer)\n\n // \u6CE8\u518C\u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\n if (customRenderers) {\n registry.registerMany(customRenderers)\n }\n\n return registry\n }, [customRenderers])\n\n /**\n * T043: \u6253\u5F00\u804A\u5929\u7A97\u53E3\u65F6\u521D\u59CB\u5316\u4F1A\u8BDD\n * \u4F7F\u7528 API v2.0.0 \u7684\u7EDF\u4E00\u63A5\u53E3\uFF1A\n * - \u5982\u679C\u6CA1\u6709 sessionId\uFF0C\u521B\u5EFA\u65B0\u4F1A\u8BDD\n * - \u5982\u679C\u6709 sessionId\uFF0C\u6062\u590D\u4F1A\u8BDD\u5E76\u52A0\u8F7D\u5386\u53F2\u6D88\u606F\n */\n useEffect(() => {\n if (!isOpen || !userId) return\n\n const currentSessionId = sessionId\n\n if (!currentSessionId) {\n // \u6CA1\u6709\u4F1A\u8BDD\uFF0C\u521B\u5EFA\u65B0\u4F1A\u8BDD\n handleCreateNewSession()\n } else {\n // \u6709\u4F1A\u8BDD\uFF0C\u5C1D\u8BD5\u6062\u590D\u4F1A\u8BDD\u548C\u5386\u53F2\u6D88\u606F\n handleResumeSession(currentSessionId)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen, userId])\n\n /**\n * \u89C4\u8303\u5316\u6D88\u606F\u683C\u5F0F\uFF08\u786E\u4FDD content \u662F\u6570\u7EC4\uFF09\n * \u540E\u7AEF\u8FD4\u56DE\u683C\u5F0F\uFF1A\n * - content: \u5B57\u7B26\u4E32\uFF08\u6587\u672C\u5185\u5BB9\uFF09\n * - structuredContent: \u6570\u7EC4\uFF08\u7ED3\u6784\u5316\u5185\u5BB9\uFF0C\u5982\u4EA7\u54C1\u5217\u8868\u3001\u653F\u7B56\u7B49\uFF09\n * \u9700\u8981\u5408\u5E76\u4E3A\u7EDF\u4E00\u7684 content \u6570\u7EC4\u683C\u5F0F\n */\n const normalizeMessage = useCallback(\n (message: any): Message => {\n // \u5982\u679C content \u5DF2\u7ECF\u662F\u6570\u7EC4\uFF0C\u76F4\u63A5\u8FD4\u56DE\n if (Array.isArray(message.content)) {\n return message as Message\n }\n\n const contentBlocks: MessageContent[] = []\n\n // \u5904\u7406\u6587\u672C\u5185\u5BB9\n if (typeof message.content === 'string' && message.content.trim()) {\n contentBlocks.push({\n type: 'text',\n text: message.content,\n })\n }\n\n // \u5904\u7406\u7ED3\u6784\u5316\u5185\u5BB9\n // \u5386\u53F2\u6D88\u606F\u683C\u5F0F: structured_content: [{type, data}]\n const structuredData = message.structuredContent || message.structured_content\n\n if (Array.isArray(structuredData)) {\n structuredData.forEach((block: any) => {\n if (block.type === 'product_list' && Array.isArray(block.data)) {\n // \u8F6C\u6362\u4EA7\u54C1\u5217\u8868\u6570\u636E\u7ED3\u6784 - data \u76F4\u63A5\u662F\u4EA7\u54C1\u6570\u7EC4\n contentBlocks.push({\n type: 'product_list',\n data: {\n products: transformProducts(block.data, site),\n title: undefined, // \u5386\u53F2\u6D88\u606F\u4E0D\u5305\u542B title\n commonText: mergedText,\n },\n })\n } else if (block.type === 'quick_replies' && block.data?.replies) {\n contentBlocks.push({\n type: 'quick_replies',\n data: {\n replies: block.data.replies,\n },\n })\n } else if (block.type === 'policy' && block.data?.title && block.data?.content) {\n contentBlocks.push({\n type: 'policy',\n data: {\n title: block.data.title,\n content: block.data.content,\n },\n })\n } else if (block.type === 'product_comparison' && block.data?.products && block.data?.dimensions) {\n // \u8F6C\u6362\u4EA7\u54C1\u5BF9\u6BD4\u6570\u636E\u7ED3\u6784\u5E76\u6CE8\u5165 onAddToCart \u56DE\u8C03\n contentBlocks.push({\n type: 'product_comparison',\n data: {\n products: transformProducts(block.data.products, site),\n dimensions: block.data.dimensions,\n onAddToCart: onAddToCart,\n commonText: mergedText,\n },\n })\n } else if (block.type === 'faq_list' && block.data?.found !== undefined) {\n // FAQ \u5217\u8868\u5361\u7247 - \u76F4\u63A5\u4F7F\u7528\u540E\u7AEF\u6570\u636E\n contentBlocks.push({\n type: 'faq_list',\n data: block.data,\n })\n } else if (block.type === 'promotion_list' && block.data?.found !== undefined) {\n // \u4FC3\u9500\u6D3B\u52A8\u5217\u8868\u5361\u7247 - \u76F4\u63A5\u4F7F\u7528\u540E\u7AEF\u6570\u636E\n contentBlocks.push({\n type: 'promotion_list',\n data: {\n ...block.data,\n commonText: mergedText,\n },\n })\n } else if (block.type === 'cart' && block.data?.id !== undefined) {\n // \u8D2D\u7269\u8F66\u5361\u7247 - \u8F6C\u6362\u540E\u7AEF\u6570\u636E\u683C\u5F0F\u5E76\u6CE8\u5165 onCart \u56DE\u8C03\n const transformedData = transformCartData(block.data as BackendCartData)\n contentBlocks.push({\n type: 'cart',\n data: {\n ...transformedData,\n onCart: onCart,\n commonText: mergedText,\n },\n })\n } else {\n // \u5176\u4ED6\u7C7B\u578B\u76F4\u63A5\u6DFB\u52A0\n contentBlocks.push(block)\n }\n })\n }\n\n // \u5982\u679C\u6CA1\u6709\u4EFB\u4F55\u5185\u5BB9\u5757\uFF0C\u8FD4\u56DE\u7A7A\u6587\u672C\u5757\n if (contentBlocks.length === 0) {\n contentBlocks.push({\n type: 'text',\n text: '',\n })\n }\n\n return {\n ...message,\n content: contentBlocks,\n } as Message\n },\n [site, onCart, onAddToCart, mergedText]\n )\n\n /**\n * \u521B\u5EFA\u65B0\u4F1A\u8BDD\n */\n const handleCreateNewSession = useCallback(async () => {\n if (!userId) return\n\n // \u5982\u679C\u7528\u6237\u6CA1\u6709\u914D\u7F6E\u6B22\u8FCE\u8BED\uFF0C\u663E\u793A loading \u72B6\u6001\n if (!welcomeMessage) {\n setIsInitializing(true)\n }\n\n try {\n const response = await createSession({\n user_id: userId,\n site: site,\n channel_code: channelCode,\n real_user_id: loginUserId,\n })\n\n if (response.success) {\n // \u4FDD\u5B58\u65B0\u4F1A\u8BDD ID\n saveSession(response.sessionId)\n\n // \u6E05\u7A7A\u6D88\u606F\u5217\u8868\n clearMessages()\n\n // \u4F7F\u7528\u540E\u7AEF\u8FD4\u56DE\u7684\u6B22\u8FCE\u6D88\u606F\uFF0C\u5982\u679C\u6CA1\u6709\u5219\u4F7F\u7528 props \u4E2D\u7684\u9ED8\u8BA4\u503C\n const messageText = response.welcomeMessage || welcomeMessage\n\n if (messageText) {\n const welcomeContent: MessageContent[] = [{ type: 'text', text: messageText }]\n\n // \u4F7F\u7528\u540E\u7AEF\u8FD4\u56DE\u7684\u5FEB\u6377\u95EE\u9898\uFF0C\u5982\u679C\u6CA1\u6709\u5219\u4F7F\u7528 props \u4E2D\u7684\u5FEB\u6377\u56DE\u590D\n const questions = response.quickQuestions\n if (questions && questions.length > 0) {\n // \u5C06\u540E\u7AEF\u7684 quickQuestions (\u5B57\u7B26\u4E32\u6570\u7EC4) \u8F6C\u6362\u4E3A QuickReply \u683C\u5F0F\n const quickRepliesFromBackend = questions.map((question, index) => ({\n id: `quick-${index}`,\n label: question,\n value: question,\n }))\n\n welcomeContent.push({\n type: 'quick_replies',\n data: {\n replies: quickRepliesFromBackend,\n },\n })\n } else if (quickReplies && quickReplies.length > 0) {\n // \u5982\u679C\u540E\u7AEF\u6CA1\u6709\u8FD4\u56DE\uFF0C\u4F7F\u7528 props \u4E2D\u7684\u5FEB\u6377\u56DE\u590D\n welcomeContent.push({\n type: 'quick_replies',\n data: {\n replies: quickReplies,\n },\n })\n }\n\n addMessage({\n id: `welcome-${Date.now()}`,\n role: 'assistant',\n content: welcomeContent,\n timestamp: Date.now(),\n })\n }\n }\n } catch (error) {\n console.error('[LiveChatWidget] Failed to create new session:', error)\n onError?.(error as Error)\n\n // Check if it's a reCAPTCHA error\n const isRecaptcha = (error as any)?.type === 'GoogleRecaptchaError'\n\n // \u6DFB\u52A0\u9519\u8BEF\u6D88\u606F\u5230\u754C\u9762\n addMessage({\n id: `error-${Date.now()}`,\n role: 'system',\n content: [\n {\n type: 'error',\n data: {\n message: isRecaptcha\n ? 'Your session has expired. Please refresh the page and try again.'\n : 'Failed to create session. Please refresh the page and try again.',\n code: isRecaptcha ? 'RECAPTCHA_ERROR' : 'SESSION_CREATE_ERROR',\n },\n },\n ],\n timestamp: Date.now(),\n })\n } finally {\n // \u63A5\u53E3\u8FD4\u56DE\u540E\u5173\u95ED loading \u72B6\u6001\n setIsInitializing(false)\n }\n }, [\n userId,\n site,\n channelCode,\n loginUserId,\n createSession,\n saveSession,\n clearMessages,\n welcomeMessage,\n quickReplies,\n addMessage,\n onError,\n ])\n\n /**\n * \u6062\u590D\u4F1A\u8BDD\u548C\u5386\u53F2\u6D88\u606F\uFF08\u4F7F\u7528\u65B0\u7684 API v2.0.0\uFF09\n */\n const handleResumeSession = useCallback(\n async (existingSessionId: string) => {\n // \u5982\u679C\u7528\u6237\u6CA1\u6709\u914D\u7F6E\u6B22\u8FCE\u8BED\uFF0C\u663E\u793A loading \u72B6\u6001\n if (!welcomeMessage) {\n setIsInitializing(true)\n }\n\n try {\n const response = await createSession({\n user_id: userId,\n session_id: existingSessionId,\n site: site,\n channel_code: channelCode,\n real_user_id: loginUserId,\n })\n\n if (response.success && response.resumed) {\n // \u4F1A\u8BDD\u6062\u590D\u6210\u529F\n\n // \u51C6\u5907\u6B22\u8FCE\u6D88\u606F\uFF08\u65E0\u8BBA\u662F\u5426\u6709\u5386\u53F2\u6D88\u606F\u90FD\u9700\u8981\uFF09\n const messageText = response.welcomeMessage || welcomeMessage\n const welcomeContent: MessageContent[] = messageText ? [{ type: 'text', text: messageText }] : []\n\n // \u6DFB\u52A0\u5FEB\u6377\u56DE\u590D\u5230\u6B22\u8FCE\u6D88\u606F\n const questions = response.quickQuestions\n if (questions && questions.length > 0) {\n const quickRepliesFromBackend = questions.map((question, index) => ({\n id: `quick-${index}`,\n label: question,\n value: question,\n }))\n\n welcomeContent.push({\n type: 'quick_replies',\n data: {\n replies: quickRepliesFromBackend,\n },\n })\n } else if (quickReplies && quickReplies.length > 0) {\n welcomeContent.push({\n type: 'quick_replies',\n data: {\n replies: quickReplies,\n },\n })\n }\n\n if (response.messages && response.messages.length > 0) {\n // \u6709\u5386\u53F2\u6D88\u606F\uFF0C\u89C4\u8303\u5316\u5E76\u52A0\u8F7D\uFF08\u8FC7\u6EE4\u6389 null/undefined \u503C\u548C\u7A7A\u5185\u5BB9\u6D88\u606F\uFF09\n const normalizedMessages = response.messages\n .filter((msg: any) => msg != null)\n .map(normalizeMessage)\n .filter((msg: Message) => msg.content && msg.content.length > 0 && !(msg.content.length === 1 && msg.content[0].type === 'text' && !msg.content[0].text))\n\n // \u5982\u679C\u6709\u6B22\u8FCE\u6D88\u606F\uFF0C\u5C06\u5176\u6DFB\u52A0\u5230\u5386\u53F2\u6D88\u606F\u7684\u5F00\u5934\n if (welcomeContent.length > 0) {\n const welcomeMsg: Message = {\n id: `welcome-${Date.now()}`,\n role: 'assistant',\n content: welcomeContent,\n timestamp: Date.now(),\n }\n setMessages([welcomeMsg, ...normalizedMessages])\n } else {\n setMessages(normalizedMessages)\n }\n } else {\n // \u6CA1\u6709\u5386\u53F2\u6D88\u606F\uFF0C\u4EC5\u663E\u793A\u6B22\u8FCE\u6D88\u606F\n clearMessages()\n\n if (welcomeContent.length > 0) {\n addMessage({\n id: `welcome-${Date.now()}`,\n role: 'assistant',\n content: welcomeContent,\n timestamp: Date.now(),\n })\n }\n }\n } else if (!response.resumed) {\n // \u4F1A\u8BDD\u65E0\u6548\u6216\u8FC7\u671F\uFF0C\u521B\u5EFA\u65B0\u4F1A\u8BDD\n clearSession()\n handleCreateNewSession()\n }\n } catch (error) {\n console.error('[LiveChatWidget] Failed to resume session:', error)\n\n // Check if it's a reCAPTCHA error\n const isRecaptcha = (error as any)?.type === 'GoogleRecaptchaError'\n\n if (isRecaptcha) {\n // reCAPTCHA error - show refresh page message, don't retry\n addMessage({\n id: `error-${Date.now()}`,\n role: 'system',\n content: [\n {\n type: 'error',\n data: {\n message: 'Your session has expired. Please refresh the page and try again.',\n code: 'RECAPTCHA_ERROR',\n },\n },\n ],\n timestamp: Date.now(),\n })\n } else {\n // Other errors - show message and try to create new session\n addMessage({\n id: `error-${Date.now()}`,\n role: 'system',\n content: [\n {\n type: 'error',\n data: {\n message: 'Failed to resume session. Creating a new session...',\n code: 'SESSION_RESUME_ERROR',\n },\n },\n ],\n timestamp: Date.now(),\n })\n\n // \u6062\u590D\u5931\u8D25\uFF0C\u6E05\u7A7A\u4F1A\u8BDD\u5E76\u521B\u5EFA\u65B0\u7684\n clearSession()\n handleCreateNewSession()\n }\n } finally {\n // \u63A5\u53E3\u8FD4\u56DE\u540E\u5173\u95ED loading \u72B6\u6001\n setIsInitializing(false)\n }\n },\n [\n userId,\n site,\n channelCode,\n loginUserId,\n createSession,\n setMessages,\n clearSession,\n clearMessages,\n normalizeMessage,\n handleCreateNewSession,\n welcomeMessage,\n quickReplies,\n addMessage,\n ]\n )\n\n /**\n * \u53D1\u9001\u6D88\u606F\n */\n const handleSendMessage = useCallback(\n async (message?: string, isRetry: boolean = false) => {\n const textToSend = message || inputValue.trim()\n\n if (!textToSend) return\n\n // \u6E05\u7A7A\u8F93\u5165\u6846\uFF08\u4EC5\u5728\u975E\u91CD\u8BD5\u65F6\uFF09\n if (!message && !isRetry) {\n setInputValue('')\n }\n\n // \u8F93\u5165\u9A8C\u8BC1\n const sanitized = sanitizeInput(textToSend)\n if (!sanitized) {\n onError?.(new Error('Invalid message'))\n return\n }\n\n // \u6DFB\u52A0\u7528\u6237\u6D88\u606F\u5230\u754C\u9762\uFF08\u4EC5\u5728\u975E\u91CD\u8BD5\u65F6\uFF09\n if (!isRetry) {\n const userMessage = {\n id: `user-${Date.now()}`,\n role: 'user' as const,\n content: [{ type: 'text' as const, text: sanitized }],\n timestamp: Date.now(),\n }\n addMessage(userMessage)\n }\n\n // \u7ACB\u5373\u6DFB\u52A0\u601D\u8003\u72B6\u6001\u6D88\u606F\uFF0C\u63D0\u5347\u7528\u6237\u4F53\u9A8C\n const thinkingMessage = {\n id: `thinking-${Date.now()}`,\n role: 'assistant' as const,\n content: [{ type: 'thinking' as const, data: { status: 'thinking' } }],\n timestamp: Date.now(),\n }\n addMessage(thinkingMessage)\n\n // \u89E6\u53D1\u6D88\u606F\u53D1\u9001\u56DE\u8C03\uFF08\u4EC5\u5728\u975E\u91CD\u8BD5\u65F6\uFF09\n if (!isRetry) {\n onMessageSend?.(sanitized)\n }\n\n // \u6807\u8BB0\u662F\u5426\u68C0\u6D4B\u5230\u4F1A\u8BDD\u8FC7\u671F\n let sessionExpiredDetected = false\n\n try {\n // \u786E\u4FDD\u6709 sessionId\uFF0C\u5982\u679C\u6CA1\u6709\u5219\u5148\u521B\u5EFA\u4F1A\u8BDD\n let currentSessionId = sessionId\n if (!currentSessionId) {\n // \u6CA1\u6709\u4F1A\u8BDD\uFF0C\u521B\u5EFA\u65B0\u4F1A\u8BDD\n const response = await createSession({\n user_id: userId,\n site: site,\n channel_code: channelCode,\n real_user_id: loginUserId,\n })\n if (response.success) {\n currentSessionId = response.sessionId\n saveSession(currentSessionId)\n } else {\n throw new Error('Failed to create session')\n }\n }\n\n // \u6784\u5EFA\u8BF7\u6C42\u53C2\u6570\uFF08session_id \u73B0\u5728\u662F\u5FC5\u586B\u7684\uFF09\n const requestPayload: ChatStreamRequest = {\n message: sanitized,\n user_id: userId,\n session_id: currentSessionId,\n context: {\n cartId: cartId,\n accessToken: accessToken,\n real_user_id: loginUserId,\n },\n }\n\n // \u53D1\u9001\u6D88\u606F\u5230\u540E\u7AEF\n await sendMessageStream(requestPayload, event => {\n // \u5904\u7406 SSE \u4E8B\u4EF6\n handleSSEEvent(event)\n\n // \u7279\u6B8A\u5904\u7406\uFF1A\u4F1A\u8BDD\u8FC7\u671F\uFF08error \u4E8B\u4EF6\u4E14 type \u4E3A validation_error\uFF09\n if (event.event === 'error' && event.data.type === 'validation_error') {\n sessionExpiredDetected = true\n clearSession()\n }\n })\n\n // \u5982\u679C\u68C0\u6D4B\u5230\u4F1A\u8BDD\u8FC7\u671F\u4E14\u4E0D\u662F\u91CD\u8BD5\uFF0C\u81EA\u52A8\u521B\u5EFA\u65B0\u4F1A\u8BDD\u5E76\u91CD\u8BD5\n if (sessionExpiredDetected && !isRetry) {\n console.log('[LiveChatWidget] Session expired (validation_error), creating new session and retrying...')\n\n // \u79FB\u9664 thinking \u6D88\u606F\n const messagesWithoutThinking = messages.filter(msg => msg.id !== thinkingMessage.id)\n setMessages(messagesWithoutThinking)\n\n // \u521B\u5EFA\u65B0\u4F1A\u8BDD\n const response = await createSession({\n user_id: userId,\n site: site,\n channel_code: channelCode,\n real_user_id: loginUserId,\n })\n\n if (response.success) {\n saveSession(response.sessionId)\n // \u91CD\u8BD5\u53D1\u9001\u6D88\u606F\n await handleSendMessage(sanitized, true)\n } else {\n throw new Error('Failed to recreate session after expiration')\n }\n }\n } catch (error) {\n console.error('[LiveChatWidget] Failed to send message:', error)\n onError?.(error as Error)\n\n // Check if it's a reCAPTCHA error\n const isRecaptcha = (error as any)?.type === 'GoogleRecaptchaError'\n\n // Determine error message based on error type\n let errorMessage: string\n let errorCode: string\n\n if (isRecaptcha) {\n errorMessage = 'Your session has expired. Please refresh the page and try again.'\n errorCode = 'RECAPTCHA_ERROR'\n } else if (sessionExpiredDetected) {\n errorMessage = 'Your session has expired. We tried to reconnect but failed. Please try again.'\n errorCode = 'SESSION_EXPIRED'\n } else {\n errorMessage = 'Failed to send message. Please check your network connection and try again.'\n errorCode = 'NETWORK_ERROR'\n }\n\n // \u79FB\u9664\u521A\u624D\u6DFB\u52A0\u7684 thinking \u6D88\u606F\uFF0C\u5E76\u6DFB\u52A0\u9519\u8BEF\u6D88\u606F\n const messagesWithoutThinking = messages.filter(msg => msg.id !== thinkingMessage.id)\n setMessages([\n ...messagesWithoutThinking,\n {\n id: `error-${Date.now()}`,\n role: 'system',\n content: [\n {\n type: 'error',\n data: {\n message: errorMessage,\n code: errorCode,\n },\n },\n ],\n timestamp: Date.now(),\n },\n ])\n }\n },\n [\n inputValue,\n userId,\n sessionId,\n site,\n channelCode,\n loginUserId,\n cartId,\n accessToken,\n messages,\n setInputValue,\n addMessage,\n setMessages,\n createSession,\n sendMessageStream,\n handleSSEEvent,\n saveSession,\n clearSession,\n onMessageSend,\n onError,\n ]\n )\n\n // \u66F4\u65B0 ref \u4EE5\u4FDD\u6301\u6700\u65B0\u7684 handleSendMessage\n React.useEffect(() => {\n handleSendMessageRef.current = handleSendMessage\n }, [handleSendMessage])\n\n /**\n * \u5904\u7406\u6C14\u6CE1\u6309\u94AE\u70B9\u51FB\n * \u5982\u679C\u914D\u7F6E\u4E86\u6CD5\u89C4\u534F\u8BAE\u4E14\u7528\u6237\u672A\u540C\u610F\uFF0C\u5148\u663E\u793A\u6CD5\u89C4\u5F39\u7A97\n * \u5426\u5219\u76F4\u63A5\u6253\u5F00\u804A\u5929\u7A97\u53E3\n */\n const handleBubbleClick = useCallback(() => {\n if (complianceConfig && !hasAgreedCompliance) {\n // \u663E\u793A\u6CD5\u89C4\u534F\u8BAE\u5F39\u7A97\n setShowComplianceDialog(true)\n } else {\n // \u76F4\u63A5\u6253\u5F00\u804A\u5929\u7A97\u53E3\n openChat()\n }\n }, [complianceConfig, hasAgreedCompliance, openChat])\n\n /**\n * \u5904\u7406\u7528\u6237\u540C\u610F\u6CD5\u89C4\u534F\u8BAE\n */\n const handleComplianceAgree = useCallback(() => {\n // \u8BBE\u7F6E\u540C\u610F\u72B6\u6001\n setHasAgreedCompliance(true)\n setShowComplianceDialog(false)\n\n // \u4FDD\u5B58\u5230 Cookie\uFF08\u6709\u6548\u671F 365 \u5929\uFF09\n Cookies.set(cookieName, 'true', { expires: 365 })\n\n // \u540C\u610F\u540E\u7ACB\u5373\u6253\u5F00\u804A\u5929\u7A97\u53E3\n openChat()\n }, [openChat, cookieName])\n\n /**\n * \u5904\u7406\u6CD5\u89C4\u5F39\u7A97\u5173\u95ED\n */\n const handleComplianceClose = useCallback(() => {\n setShowComplianceDialog(false)\n }, [])\n\n return (\n <>\n {/* \u6CD5\u89C4\u534F\u8BAE\u5F39\u7A97 */}\n {complianceConfig && (\n <ComplianceDialog\n open={showComplianceDialog}\n config={complianceConfig}\n onAgree={handleComplianceAgree}\n onClose={handleComplianceClose}\n />\n )}\n\n {/* \u6C14\u6CE1\u6309\u94AE */}\n <ChatBubble\n position={position}\n onClick={handleBubbleClick}\n visible={!isOpen && !showComplianceDialog}\n iconImageUrl={chatBubbleIcon}\n />\n\n {/* \u804A\u5929\u7A97\u53E3\uFF08\u4F7F\u7528 Radix UI Dialog\uFF09 */}\n <Dialog.Root open={isOpen} onOpenChange={open => (open ? openChat() : closeChat())}>\n <Dialog.Portal>\n <Dialog.Content\n className=\"livechat-window-enter\"\n style={{\n position: 'fixed',\n zIndex: 9998,\n }}\n >\n <ChatWindow\n messages={messages}\n inputValue={inputValue}\n onInputChange={setInputValue}\n onSend={() => handleSendMessage()}\n onClose={closeChat}\n onNewSession={handleCreateNewSession}\n title={title}\n logoUrl={logoUrl}\n isSending={isStreaming}\n isLoadingHistory={isInitializing}\n rendererRegistry={rendererRegistry}\n inputPlaceholder=\"\"\n onAddToCart={onAddToCart}\n showNewSessionButton={showNewSessionButton}\n bottomTips={bottomTips}\n />\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n </>\n )\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["LiveChatWidget_exports", "__export", "LiveChatWidget", "__toCommonJS", "import_jsx_runtime", "import_react", "Dialog", "import_constants", "import_ChatBubble", "import_ChatWindow", "import_ComplianceDialog", "import_useChatState", "import_useChatAPI", "import_messageRenderers", "import_validation", "import_productTransformers", "import_cartTransformers", "import_js_cookie", "import_MessageContent", "apiBaseUrl", "headers", "recaptchaSitekey", "recaptchaAction", "site", "channelCode", "loginUserId", "cartId", "accessToken", "position", "welcomeMessage", "quickReplies", "customRenderers", "logoUrl", "title", "chatBubbleIcon", "open", "onOpenChange", "onOpen", "onClose", "onMessageSend", "onError", "onTextMessage", "onProductList", "onPromotionList", "onAddToCart", "onCart", "showNewSessionButton", "commonText", "productCardRender", "bottomTips", "complianceConfig", "cookieName", "showComplianceDialog", "setShowComplianceDialog", "React", "hasAgreedCompliance", "setHasAgreedCompliance", "Cookies", "mergedText", "chatState", "messages", "isOpen", "userId", "sessionId", "inputValue", "isStreaming", "openChat", "closeChat", "setInputValue", "addMessage", "setMessages", "clearMessages", "handleSSEEvent", "saveSession", "clearSession", "isInitializing", "setIsInitializing", "sendMessageStream", "createSession", "handleSendMessageRef", "_message", "rendererRegistry", "registry", "quickRepliesRenderer", "reply", "currentSessionId", "handleResumeSession", "handleCreateNewSession", "normalizeMessage", "message", "contentBlocks", "structuredData", "block", "transformedData", "response", "messageText", "welcomeContent", "questions", "quickRepliesFromBackend", "question", "index", "error", "isRecaptcha", "existingSessionId", "normalizedMessages", "msg", "welcomeMsg", "handleSendMessage", "isRetry", "textToSend", "sanitized", "userMessage", "thinkingMessage", "sessionExpiredDetected", "event", "messagesWithoutThinking", "errorMessage", "errorCode", "handleBubbleClick", "handleComplianceAgree", "handleComplianceClose"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/components/LiveChatWidget/components/MessageContent/PromotionList.tsx"],
4
- "sourcesContent": ["/**\n * \u4FC3\u9500\u6D3B\u52A8\u5217\u8868\u7EC4\u4EF6\n * \u663E\u793A\u5F53\u524D\u8FDB\u884C\u4E2D\u7684\u4FC3\u9500\u6D3B\u52A8\u4FE1\u606F\n * \u57FA\u4E8E\u540E\u7AEF\u6570\u636E\u7ED3\u6784\u89C4\u8303\uFF1Apromotion_list\n */\n\nimport React from 'react'\nimport type { MessageRenderer, CommonText } from '../../types'\nimport { DEFAULT_COMMON_TEXT } from '../../constants'\n\n/**\n * \u4FC3\u9500\u6D3B\u52A8\u6570\u636E\u7ED3\u6784\n */\nexport interface PromotionItem {\n id: string // \u6D3B\u52A8 ID\n title: string // \u6D3B\u52A8\u6807\u9898\n subtitle?: string // \u526F\u6807\u9898\uFF08\u5982 \"Up to 30% off\"\uFF09\n description?: string // \u6D3B\u52A8\u63CF\u8FF0\n banner_url?: string // Banner \u56FE\u7247 URL\n url?: string // \u6D3B\u52A8\u8BE6\u60C5\u9875 URL\n time_range: {\n start: string // \u5F00\u59CB\u65F6\u95F4 (ISO 8601)\n end?: string | null // \u7ED3\u675F\u65F6\u95F4\uFF0Cnull \u8868\u793A\u65E0\u7ED3\u675F\u65E5\u671F\n is_active: boolean // \u662F\u5426\u5F53\u524D\u6D3B\u8DC3\n }\n priority?: number // \u4F18\u5148\u7EA7\uFF08\u6570\u5B57\u8D8A\u5927\u8D8A\u9760\u524D\uFF09\n product_count?: number // \u53C2\u4E0E\u5546\u54C1\u6570\u91CF\n metadata?: {\n display_order?: number\n target_audience?: string\n highlight_color?: string\n banner_url?:string\n }\n}\n\n/**\n * \u4FC3\u9500\u6D3B\u52A8\u5217\u8868\u6570\u636E\u7ED3\u6784\n */\nexport interface PromotionListData {\n found: boolean // \u662F\u5426\u627E\u5230\u6D3B\u52A8\n count: number // \u8FD4\u56DE\u7684\u6D3B\u52A8\u6570\u91CF\n total?: number // \u603B\u6D3B\u52A8\u6570\u91CF\uFF08\u53EF\u9009\uFF09\n results: PromotionItem[] // \u6D3B\u52A8\u5217\u8868\n commonText?: CommonText // \u901A\u7528\u6587\u6848\u914D\u7F6E\n}\n\nexport interface PromotionListProps {\n /**\n * \u4FC3\u9500\u6D3B\u52A8\u5217\u8868\u6570\u636E\n */\n data: PromotionListData\n\n /**\n * \u662F\u5426\u4E3A\u7528\u6237\u6D88\u606F\n */\n isUser?: boolean\n\n /**\n * \u662F\u5426\u4E3A\u7CFB\u7EDF\u6D88\u606F\n */\n isSystem?: boolean\n}\n\n/**\n * \u683C\u5F0F\u5316\u65E5\u671F\u663E\u793A\n */\nconst formatDate = (dateStr: string): string => {\n const date = new Date(dateStr)\n return date.toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })\n}\n\n/**\n * \u4FC3\u9500\u6D3B\u52A8\u5217\u8868\u7EC4\u4EF6\n *\n * \u529F\u80FD\uFF1A\n * - \u663E\u793A\u5F53\u524D\u8FDB\u884C\u4E2D\u7684\u4FC3\u9500\u6D3B\u52A8\n * - \u652F\u6301\u6D3B\u52A8 Banner \u56FE\u7247\u5C55\u793A\n * - \u663E\u793A\u6D3B\u52A8\u65F6\u95F4\u8303\u56F4\n * - \u663E\u793A\u53C2\u4E0E\u5546\u54C1\u6570\u91CF\n * - \u652F\u6301\u8DF3\u8F6C\u5230\u6D3B\u52A8\u8BE6\u60C5\u9875\n *\n * @example\n * ```tsx\n * <PromotionList\n * data={{\n * found: true,\n * count: 2,\n * results: [...]\n * }}\n * />\n * ```\n */\nexport const PromotionList: React.FC<PromotionListProps> = ({ data, isUser = false, isSystem = false }) => {\n const { found, results, commonText } = data\n\n // \u5408\u5E76\u9ED8\u8BA4\u6587\u6848\u548C\u81EA\u5B9A\u4E49\u6587\u6848\n const mergedText = { ...DEFAULT_COMMON_TEXT, ...commonText }\n\n return (\n <div className=\"space-y-3\">\n {results.map(promotion => {\n const bannerUrl = promotion.banner_url ||promotion?.metadata?.banner_url\n\n // \u6CA1\u6709\u56FE\u7247\u5219\u4E0D\u5C55\u793A\n if (!bannerUrl) {\n return null\n }\n\n return (\n <div key={promotion.id} className=\"relative overflow-hidden rounded-2xl bg-[#F5F6F7]\">\n {/* Banner \u56FE\u7247 */}\n <div className=\"aspect-[16/9] w-full overflow-hidden bg-gray-100\">\n <img\n src={bannerUrl}\n alt={promotion.title}\n className=\"size-full object-cover object-center\"\n loading=\"lazy\"\n />\n </div>\n\n {/* \u6D3B\u52A8\u4FE1\u606F - \u53E0\u52A0\u5728\u56FE\u7247\u4E0A */}\n <div\n className=\"absolute inset-0 flex flex-col justify-end p-4 text-[#080A0F]\"\n style={{ color: promotion?.metadata?.highlight_color }}\n >\n <div className=\"mb-2\">\n <h3 className=\"text-xl font-bold leading-[1.2] tracking-[-0.04em]\">{promotion.title}</h3>\n {promotion.subtitle && (\n <p className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em]\">{promotion.subtitle}</p>\n )}\n </div>\n\n {/* \u67E5\u770B\u8BE6\u60C5\u6309\u94AE */}\n {promotion.url && (\n <a\n href={promotion.url + '?ref=LiveChat'}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1 text-sm font-bold tracking-[-0.04em]\"\n >\n {mergedText.learnMore}\n <svg className=\"size-[18px]\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5l7 7-7 7\" />\n </svg>\n </a>\n )}\n </div>\n </div>\n )\n })}\n </div>\n )\n}\n\n/**\n * \u521B\u5EFA\u4FC3\u9500\u6D3B\u52A8\u5217\u8868\u6E32\u67D3\u5668\n */\nexport const PromotionListRenderer: MessageRenderer = {\n render: (content, isUser, isSystem) => {\n if (content.type !== 'promotion_list' || !content.data) {\n return null\n }\n\n return <PromotionList data={content.data as PromotionListData} isUser={isUser} isSystem={isSystem} />\n },\n}\n"],
5
- "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,mBAAAE,EAAA,0BAAAC,IAAA,eAAAC,EAAAJ,GAoHc,IAAAK,EAAA,6BA5GdC,EAAoC,2BA0DpC,MAAMC,EAAcC,GACL,IAAI,KAAKA,CAAO,EACjB,mBAAmB,QAAS,CACtC,KAAM,UACN,MAAO,QACP,IAAK,SACP,CAAC,EAwBUN,EAA8C,CAAC,CAAE,KAAAO,EAAM,OAAAC,EAAS,GAAO,SAAAC,EAAW,EAAM,IAAM,CACzG,KAAM,CAAE,MAAAC,EAAO,QAAAC,EAAS,WAAAC,CAAW,EAAIL,EAGjCM,EAAa,CAAE,GAAG,sBAAqB,GAAGD,CAAW,EAE3D,SACE,OAAC,OAAI,UAAU,YACZ,SAAAD,EAAQ,IAAIG,GAAa,CACxB,MAAMC,EAAYD,EAAU,YAAaA,GAAW,UAAU,WAG9D,OAAKC,KAKH,QAAC,OAAuB,UAAU,oDAEhC,oBAAC,OAAI,UAAU,mDACb,mBAAC,OACC,IAAKA,EACL,IAAKD,EAAU,MACf,UAAU,uCACV,QAAQ,OACV,EACF,KAGA,QAAC,OACC,UAAU,gEACV,MAAO,CAAE,MAAOA,GAAW,UAAU,eAAgB,EAErD,qBAAC,OAAI,UAAU,OACb,oBAAC,MAAG,UAAU,qDAAsD,SAAAA,EAAU,MAAM,EACnFA,EAAU,aACT,OAAC,KAAE,UAAU,qDAAsD,SAAAA,EAAU,SAAS,GAE1F,EAGCA,EAAU,QACT,QAAC,KACC,KAAMA,EAAU,IAAM,gBACtB,OAAO,SACP,IAAI,sBACJ,UAAU,sEAET,UAAAD,EAAW,aACZ,OAAC,OAAI,UAAU,cAAc,KAAK,OAAO,OAAO,eAAe,QAAQ,YACrE,mBAAC,QAAK,cAAc,QAAQ,eAAe,QAAQ,YAAa,EAAG,EAAE,eAAe,EACtF,GACF,GAEJ,IArCQC,EAAU,EAsCpB,EA1CO,IA4CX,CAAC,EACH,CAEJ,EAKab,EAAyC,CACpD,OAAQ,CAACe,EAASR,EAAQC,IACpBO,EAAQ,OAAS,kBAAoB,CAACA,EAAQ,KACzC,QAGF,OAAChB,EAAA,CAAc,KAAMgB,EAAQ,KAA2B,OAAQR,EAAQ,SAAUC,EAAU,CAEvG",
4
+ "sourcesContent": ["/**\n * \u4FC3\u9500\u6D3B\u52A8\u5217\u8868\u7EC4\u4EF6\n * \u663E\u793A\u5F53\u524D\u8FDB\u884C\u4E2D\u7684\u4FC3\u9500\u6D3B\u52A8\u4FE1\u606F\n * \u57FA\u4E8E\u540E\u7AEF\u6570\u636E\u7ED3\u6784\u89C4\u8303\uFF1Apromotion_list\n */\n\nimport React from 'react'\nimport type { MessageRenderer, CommonText } from '../../types'\nimport { DEFAULT_COMMON_TEXT } from '../../constants'\n\n/**\n * \u4FC3\u9500\u6D3B\u52A8\u6570\u636E\u7ED3\u6784\n */\nexport interface PromotionItem {\n id: string // \u6D3B\u52A8 ID\n title: string // \u6D3B\u52A8\u6807\u9898\n subtitle?: string // \u526F\u6807\u9898\uFF08\u5982 \"Up to 30% off\"\uFF09\n description?: string // \u6D3B\u52A8\u63CF\u8FF0\n banner_url?: string // Banner \u56FE\u7247 URL\n url?: string // \u6D3B\u52A8\u8BE6\u60C5\u9875 URL\n time_range: {\n start: string // \u5F00\u59CB\u65F6\u95F4 (ISO 8601)\n end?: string | null // \u7ED3\u675F\u65F6\u95F4\uFF0Cnull \u8868\u793A\u65E0\u7ED3\u675F\u65E5\u671F\n is_active: boolean // \u662F\u5426\u5F53\u524D\u6D3B\u8DC3\n }\n priority?: number // \u4F18\u5148\u7EA7\uFF08\u6570\u5B57\u8D8A\u5927\u8D8A\u9760\u524D\uFF09\n product_count?: number // \u53C2\u4E0E\u5546\u54C1\u6570\u91CF\n metadata?: {\n display_order?: number\n target_audience?: string\n highlight_color?: string\n banner_url?:string\n }\n}\n\n/**\n * \u4FC3\u9500\u6D3B\u52A8\u5217\u8868\u6570\u636E\u7ED3\u6784\n */\nexport interface PromotionListData {\n found: boolean // \u662F\u5426\u627E\u5230\u6D3B\u52A8\n count: number // \u8FD4\u56DE\u7684\u6D3B\u52A8\u6570\u91CF\n total?: number // \u603B\u6D3B\u52A8\u6570\u91CF\uFF08\u53EF\u9009\uFF09\n results: PromotionItem[] // \u6D3B\u52A8\u5217\u8868\n commonText?: CommonText // \u901A\u7528\u6587\u6848\u914D\u7F6E\n}\n\nexport interface PromotionListProps {\n /**\n * \u4FC3\u9500\u6D3B\u52A8\u5217\u8868\u6570\u636E\n */\n data: PromotionListData\n\n /**\n * \u662F\u5426\u4E3A\u7528\u6237\u6D88\u606F\n */\n isUser?: boolean\n\n /**\n * \u662F\u5426\u4E3A\u7CFB\u7EDF\u6D88\u606F\n */\n isSystem?: boolean\n}\n\n/**\n * \u683C\u5F0F\u5316\u65E5\u671F\u663E\u793A\n */\nconst formatDate = (dateStr: string): string => {\n const date = new Date(dateStr)\n return date.toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })\n}\n\n/**\n * \u4FC3\u9500\u6D3B\u52A8\u5217\u8868\u7EC4\u4EF6\n *\n * \u529F\u80FD\uFF1A\n * - \u663E\u793A\u5F53\u524D\u8FDB\u884C\u4E2D\u7684\u4FC3\u9500\u6D3B\u52A8\n * - \u652F\u6301\u6D3B\u52A8 Banner \u56FE\u7247\u5C55\u793A\n * - \u663E\u793A\u6D3B\u52A8\u65F6\u95F4\u8303\u56F4\n * - \u663E\u793A\u53C2\u4E0E\u5546\u54C1\u6570\u91CF\n * - \u652F\u6301\u8DF3\u8F6C\u5230\u6D3B\u52A8\u8BE6\u60C5\u9875\n *\n * @example\n * ```tsx\n * <PromotionList\n * data={{\n * found: true,\n * count: 2,\n * results: [...]\n * }}\n * />\n * ```\n */\nexport const PromotionList: React.FC<PromotionListProps> = ({ data, isUser = false, isSystem = false }) => {\n const { found, results, commonText } = data\n\n // \u5408\u5E76\u9ED8\u8BA4\u6587\u6848\u548C\u81EA\u5B9A\u4E49\u6587\u6848\n const mergedText = { ...DEFAULT_COMMON_TEXT, ...commonText }\n\n return (\n <div className=\"space-y-3\">\n {results.map(promotion => {\n const bannerUrl = promotion.banner_url || promotion?.metadata?.banner_url\n\n // \u6CA1\u6709\u56FE\u7247\u5219\u4E0D\u5C55\u793A\n if (!bannerUrl) {\n return null\n }\n\n return (\n <div key={promotion.id} className=\"relative overflow-hidden rounded-2xl bg-[#F5F6F7]\">\n {/* Banner \u56FE\u7247 */}\n <div className=\"aspect-[16/9] w-full overflow-hidden bg-gray-100\">\n <img\n src={bannerUrl}\n alt={promotion.title}\n className=\"size-full object-cover object-center\"\n loading=\"lazy\"\n />\n </div>\n\n {/* \u6D3B\u52A8\u4FE1\u606F - \u53E0\u52A0\u5728\u56FE\u7247\u4E0A */}\n <div\n className=\"absolute inset-0 flex flex-col justify-end p-4 text-[#080A0F]\"\n style={{ color: promotion?.metadata?.highlight_color }}\n >\n <div className=\"mb-2\">\n <h3 className=\"text-xl font-bold leading-[1.2] tracking-[-0.04em]\">{promotion.title}</h3>\n {promotion.subtitle && (\n <p className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em]\">{promotion.subtitle}</p>\n )}\n </div>\n\n {/* \u67E5\u770B\u8BE6\u60C5\u6309\u94AE */}\n {promotion.url && (\n <a\n href={promotion.url + '?ref=LiveChat'}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1 text-sm font-bold tracking-[-0.04em]\"\n >\n {mergedText.learnMore}\n <svg className=\"size-[18px]\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5l7 7-7 7\" />\n </svg>\n </a>\n )}\n </div>\n </div>\n )\n })}\n </div>\n )\n}\n\n/**\n * \u521B\u5EFA\u4FC3\u9500\u6D3B\u52A8\u5217\u8868\u6E32\u67D3\u5668\n */\nexport const PromotionListRenderer: MessageRenderer = {\n render: (content, isUser, isSystem) => {\n if (content.type !== 'promotion_list' || !content.data) {\n return null\n }\n\n return <PromotionList data={content.data as PromotionListData} isUser={isUser} isSystem={isSystem} />\n },\n}\n"],
5
+ "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,mBAAAE,EAAA,0BAAAC,IAAA,eAAAC,EAAAJ,GAoHc,IAAAK,EAAA,6BA5GdC,EAAoC,2BA0DpC,MAAMC,EAAcC,GACL,IAAI,KAAKA,CAAO,EACjB,mBAAmB,QAAS,CACtC,KAAM,UACN,MAAO,QACP,IAAK,SACP,CAAC,EAwBUN,EAA8C,CAAC,CAAE,KAAAO,EAAM,OAAAC,EAAS,GAAO,SAAAC,EAAW,EAAM,IAAM,CACzG,KAAM,CAAE,MAAAC,EAAO,QAAAC,EAAS,WAAAC,CAAW,EAAIL,EAGjCM,EAAa,CAAE,GAAG,sBAAqB,GAAGD,CAAW,EAE3D,SACE,OAAC,OAAI,UAAU,YACZ,SAAAD,EAAQ,IAAIG,GAAa,CACxB,MAAMC,EAAYD,EAAU,YAAcA,GAAW,UAAU,WAG/D,OAAKC,KAKH,QAAC,OAAuB,UAAU,oDAEhC,oBAAC,OAAI,UAAU,mDACb,mBAAC,OACC,IAAKA,EACL,IAAKD,EAAU,MACf,UAAU,uCACV,QAAQ,OACV,EACF,KAGA,QAAC,OACC,UAAU,gEACV,MAAO,CAAE,MAAOA,GAAW,UAAU,eAAgB,EAErD,qBAAC,OAAI,UAAU,OACb,oBAAC,MAAG,UAAU,qDAAsD,SAAAA,EAAU,MAAM,EACnFA,EAAU,aACT,OAAC,KAAE,UAAU,qDAAsD,SAAAA,EAAU,SAAS,GAE1F,EAGCA,EAAU,QACT,QAAC,KACC,KAAMA,EAAU,IAAM,gBACtB,OAAO,SACP,IAAI,sBACJ,UAAU,sEAET,UAAAD,EAAW,aACZ,OAAC,OAAI,UAAU,cAAc,KAAK,OAAO,OAAO,eAAe,QAAQ,YACrE,mBAAC,QAAK,cAAc,QAAQ,eAAe,QAAQ,YAAa,EAAG,EAAE,eAAe,EACtF,GACF,GAEJ,IArCQC,EAAU,EAsCpB,EA1CO,IA4CX,CAAC,EACH,CAEJ,EAKab,EAAyC,CACpD,OAAQ,CAACe,EAASR,EAAQC,IACpBO,EAAQ,OAAS,kBAAoB,CAACA,EAAQ,KACzC,QAGF,OAAChB,EAAA,CAAc,KAAMgB,EAAQ,KAA2B,OAAQR,EAAQ,SAAUC,EAAU,CAEvG",
6
6
  "names": ["PromotionList_exports", "__export", "PromotionList", "PromotionListRenderer", "__toCommonJS", "import_jsx_runtime", "import_constants", "formatDate", "dateStr", "data", "isUser", "isSystem", "found", "results", "commonText", "mergedText", "promotion", "bannerUrl", "content"]
7
7
  }
@@ -1,5 +1,5 @@
1
- "use strict";var f=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var M=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var L=(r,o)=>{for(var i in o)f(r,i,{get:o[i],enumerable:!0})},k=(r,o,i,c)=>{if(o&&typeof o=="object"||typeof o=="function")for(let s of M(o))!C.call(r,s)&&s!==i&&f(r,s,{get:()=>o[s],enumerable:!(c=w(o,s))||c.enumerable});return r};var B=r=>k(f({},"__esModule",{value:!0}),r);var z={};L(z,{MessageList:()=>S});module.exports=B(z);var e=require("react/jsx-runtime"),n=require("react"),v=require("./ChatMessage"),h=require("./ScrollAnchor");const E=()=>(0,e.jsx)("div",{className:"flex h-full items-center justify-center text-gray-400",children:(0,e.jsx)("p",{className:"text-sm",children:"No messages yet"})}),H=()=>(0,e.jsx)("div",{className:"flex justify-center py-4",children:(0,e.jsxs)("div",{className:"flex gap-1",children:[(0,e.jsx)("div",{className:"size-2 animate-bounce rounded-full bg-gray-400"}),(0,e.jsx)("div",{className:"size-2 animate-bounce rounded-full bg-gray-400",style:{animationDelay:"0.1s"}}),(0,e.jsx)("div",{className:"size-2 animate-bounce rounded-full bg-gray-400",style:{animationDelay:"0.2s"}})]})}),S=({messages:r,rendererRegistry:o,defaultRenderer:i,showTimestamp:c=!0,autoScroll:s=!0,isLoadingHistory:p=!1,emptyPlaceholder:y,className:g="",onAddToCart:b})=>{const a=(0,n.useRef)(null),[u,m]=(0,n.useState)(!1),d=(0,n.useCallback)((t=100)=>{const l=a.current;if(!l)return!0;const{scrollTop:R,scrollHeight:N,clientHeight:T}=l;return N-R-T<t},[]),x=(0,n.useCallback)(()=>{const t=a.current;t&&t.scrollTo({top:t.scrollHeight,behavior:"smooth"})},[]);return(0,n.useEffect)(()=>{const t=a.current;if(!t)return;const l=()=>{m(!d())};return l(),t.addEventListener("scroll",l,{passive:!0}),()=>t.removeEventListener("scroll",l)},[d]),(0,n.useEffect)(()=>{if(s)return;const t=setTimeout(()=>{m(!d())},150);return()=>clearTimeout(t)},[r,s,d]),(0,n.useEffect)(()=>{if(!s||!a.current)return;const t=setTimeout(()=>{a.current&&(a.current.scrollTop=a.current.scrollHeight,m(!1))},100);return()=>clearTimeout(t)},[r,s]),r.length===0&&!p?(0,e.jsx)("div",{className:`flex-1 overflow-hidden ${g}`,children:y||(0,e.jsx)(E,{})}):(0,e.jsxs)("div",{className:"relative flex-1 overflow-hidden",children:[(0,e.jsxs)("div",{ref:a,className:`
1
+ "use strict";var u=Object.defineProperty;var M=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var E=(o,r)=>{for(var a in r)u(o,a,{get:r[a],enumerable:!0})},k=(o,r,a,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let i of w(r))!C.call(o,i)&&i!==a&&u(o,i,{get:()=>r[i],enumerable:!(n=M(r,i))||n.enumerable});return o};var H=o=>k(u({},"__esModule",{value:!0}),o);var S={};E(S,{MessageList:()=>P});module.exports=H(S);var e=require("react/jsx-runtime"),l=require("react"),v=require("./ChatMessage"),g=require("./ScrollAnchor");const B=()=>(0,e.jsx)("div",{className:"flex h-full items-center justify-center text-gray-400",children:(0,e.jsx)("p",{className:"text-sm",children:"No messages yet"})}),D=()=>(0,e.jsx)("div",{className:"flex justify-center py-4",children:(0,e.jsxs)("div",{className:"flex gap-1",children:[(0,e.jsx)("div",{className:"size-2 animate-bounce rounded-full bg-gray-400"}),(0,e.jsx)("div",{className:"size-2 animate-bounce rounded-full bg-gray-400",style:{animationDelay:"0.1s"}}),(0,e.jsx)("div",{className:"size-2 animate-bounce rounded-full bg-gray-400",style:{animationDelay:"0.2s"}})]})}),P=({messages:o,rendererRegistry:r,defaultRenderer:a,showTimestamp:n=!0,autoScroll:i=!0,isLoadingHistory:p=!1,emptyPlaceholder:h,className:c="",onAddToCart:y})=>{const[t,b]=(0,l.useState)(null),R=(0,l.useCallback)(s=>{b(s)},[]),[f,m]=(0,l.useState)(!1),d=(0,l.useCallback)((s=100)=>{if(!t)return!0;const{scrollTop:x,scrollHeight:T,clientHeight:L}=t;return T-x-L<s},[t]),N=(0,l.useCallback)(()=>{t&&t.scrollTo({top:t.scrollHeight,behavior:"smooth"})},[t]);return(0,l.useEffect)(()=>{if(!t)return;const s=()=>{m(!d())};return s(),t.addEventListener("scroll",s,{passive:!0}),()=>t.removeEventListener("scroll",s)},[t,d]),(0,l.useEffect)(()=>{if(i)return;const s=setTimeout(()=>{m(!d())},150);return()=>clearTimeout(s)},[o,i,d]),(0,l.useEffect)(()=>{if(!i||!t)return;const s=setTimeout(()=>{t&&(t.scrollTop=t.scrollHeight,m(!1))},100);return()=>clearTimeout(s)},[o,i,t]),o.length===0?p?(0,e.jsx)("div",{className:`flex flex-1 items-center justify-center overflow-hidden ${c}`,children:(0,e.jsx)(D,{})}):(0,e.jsx)("div",{className:`flex-1 overflow-hidden ${c}`,children:h||(0,e.jsx)(B,{})}):(0,e.jsxs)("div",{className:"relative flex-1 overflow-hidden",children:[(0,e.jsxs)("div",{ref:R,className:`
2
2
  livechat-message-list absolute inset-0 overflow-y-auto p-4
3
- ${g}
4
- `,children:[p&&(0,e.jsx)(H,{}),(0,e.jsx)("div",{className:"flex flex-col gap-1",children:r.map(t=>(0,e.jsx)(v.ChatMessage,{message:t,rendererRegistry:o,defaultRenderer:i,showTimestamp:c,onAddToCart:b},t.id))}),s&&(0,e.jsx)(h.ScrollAnchor,{dependencies:[r]})]}),(0,e.jsx)("button",{onClick:x,className:`flex -translate-x-1/2 items-center justify-center ${u?"":"pointer-events-none"}`,style:{position:"absolute",bottom:"24px",left:"50%",zIndex:10,width:"40px",height:"40px",borderRadius:"50%",backgroundColor:"rgba(255, 255, 255, 0.95)",boxShadow:"0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",transition:"all 300ms ease-in-out",opacity:u?1:0,cursor:"pointer",border:"none"},"aria-label":"Scroll to bottom","aria-hidden":!u,children:(0,e.jsx)("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"text-gray-700",children:(0,e.jsx)("polyline",{points:"6 9 12 15 18 9"})})})]})};
3
+ ${c}
4
+ `,children:[(0,e.jsx)("div",{className:"flex flex-col gap-1",children:o.map(s=>(0,e.jsx)(v.ChatMessage,{message:s,rendererRegistry:r,defaultRenderer:a,showTimestamp:n,onAddToCart:y},s.id))}),i&&(0,e.jsx)(g.ScrollAnchor,{dependencies:[o]})]}),(0,e.jsx)("button",{onClick:N,className:`livechat-scroll-to-bottom ${f?"visible":"hidden"}`,"aria-label":"Scroll to bottom","aria-hidden":!f,children:(0,e.jsx)("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"text-gray-700",children:(0,e.jsx)("polyline",{points:"6 9 12 15 18 9"})})})]})};
5
5
  //# sourceMappingURL=MessageList.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/components/LiveChatWidget/components/MessageList.tsx"],
4
- "sourcesContent": ["/**\n * \u6D88\u606F\u5217\u8868\u7EC4\u4EF6\n * \u663E\u793A\u6240\u6709\u804A\u5929\u6D88\u606F\uFF0C\u652F\u6301\u6EDA\u52A8\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u6D88\u606F\u5217\u8868\u8BBE\u8BA1\n */\n\nimport React, { useRef, useEffect, useState, useCallback } from 'react'\nimport type { Message, MessageRenderer } from '../types'\nimport { ChatMessage } from './ChatMessage'\nimport { ScrollAnchor } from './ScrollAnchor'\nimport { MessageRendererRegistry } from '../utils/messageRenderers'\n\nexport interface MessageListProps {\n /**\n * \u6D88\u606F\u5217\u8868\n */\n messages: Message[]\n\n /**\n * \u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\u6CE8\u518C\u8868\n */\n rendererRegistry?: MessageRendererRegistry\n\n /**\n * \u9ED8\u8BA4\u6E32\u67D3\u5668\n */\n defaultRenderer?: MessageRenderer\n\n /**\n * \u662F\u5426\u663E\u793A\u65F6\u95F4\u6233\n * @default true\n */\n showTimestamp?: boolean\n\n /**\n * \u662F\u5426\u81EA\u52A8\u6EDA\u52A8\u5230\u5E95\u90E8\n * @default true\n */\n autoScroll?: boolean\n\n /**\n * \u662F\u5426\u6B63\u5728\u52A0\u8F7D\u5386\u53F2\u6D88\u606F\n * @default false\n */\n isLoadingHistory?: boolean\n\n /**\n * \u7A7A\u72B6\u6001\u5360\u4F4D\u5185\u5BB9\n */\n emptyPlaceholder?: React.ReactNode\n\n /**\n * \u81EA\u5B9A\u4E49\u6837\u5F0F\u7C7B\u540D\n */\n className?: string\n\n /**\n * \u5546\u54C1\u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u56DE\u8C03\n */\n onAddToCart?: (product: any) => void\n}\n\n/**\n * \u9ED8\u8BA4\u7A7A\u72B6\u6001\u5360\u4F4D\n */\nconst DefaultEmptyPlaceholder: React.FC = () => (\n <div className=\"flex h-full items-center justify-center text-gray-400\">\n <p className=\"text-sm\">No messages yet</p>\n </div>\n)\n\n/**\n * \u52A0\u8F7D\u6307\u793A\u5668\n */\nconst LoadingIndicator: React.FC = () => (\n <div className=\"flex justify-center py-4\">\n <div className=\"flex gap-1\">\n <div className=\"size-2 animate-bounce rounded-full bg-gray-400\" />\n <div className=\"size-2 animate-bounce rounded-full bg-gray-400\" style={{ animationDelay: '0.1s' }} />\n <div className=\"size-2 animate-bounce rounded-full bg-gray-400\" style={{ animationDelay: '0.2s' }} />\n </div>\n </div>\n)\n\n/**\n * \u6D88\u606F\u5217\u8868\u7EC4\u4EF6\n *\n * \u529F\u80FD\uFF1A\n * - \u663E\u793A\u6240\u6709\u6D88\u606F\uFF08\u7528\u6237\u3001\u52A9\u624B\u3001\u7CFB\u7EDF\uFF09\n * - \u81EA\u52A8\u6EDA\u52A8\u5230\u6700\u65B0\u6D88\u606F\n * - \u52A0\u8F7D\u5386\u53F2\u6D88\u606F\u65F6\u663E\u793A\u6307\u793A\u5668\n * - \u7A7A\u72B6\u6001\u5360\u4F4D\n *\n * \u6837\u5F0F\uFF1A\n * - \u4F7F\u7528\u81EA\u5B9A\u4E49\u6EDA\u52A8\u6761\u6837\u5F0F\uFF08livechat.css\uFF09\n * - \u5185\u5BB9\u95F4\u8DDD\u5408\u7406\n * - \u652F\u6301\u54CD\u5E94\u5F0F\u5E03\u5C40\n *\n * @example\n * ```tsx\n * <MessageList\n * messages={messages}\n * rendererRegistry={customRegistry}\n * autoScroll={true}\n * isLoadingHistory={isLoading}\n * />\n * ```\n */\nexport const MessageList: React.FC<MessageListProps> = ({\n messages,\n rendererRegistry,\n defaultRenderer,\n showTimestamp = true,\n autoScroll = true,\n isLoadingHistory = false,\n emptyPlaceholder,\n className = '',\n onAddToCart,\n}) => {\n const listRef = useRef<HTMLDivElement>(null)\n const [showScrollButton, setShowScrollButton] = useState(false)\n\n // \u68C0\u67E5\u662F\u5426\u63A5\u8FD1\u5E95\u90E8\n const isNearBottom = useCallback((threshold = 100) => {\n const container = listRef.current\n if (!container) return true\n\n const { scrollTop, scrollHeight, clientHeight } = container\n return scrollHeight - scrollTop - clientHeight < threshold\n }, [])\n\n // \u5E73\u6ED1\u6EDA\u52A8\u5230\u5E95\u90E8\n const scrollToBottom = useCallback(() => {\n const container = listRef.current\n if (!container) return\n\n container.scrollTo({\n top: container.scrollHeight,\n behavior: 'smooth',\n })\n }, [])\n\n // \u76D1\u542C\u6EDA\u52A8\u4E8B\u4EF6\uFF0C\u63A7\u5236\u6309\u94AE\u663E\u793A\n useEffect(() => {\n const container = listRef.current\n if (!container) return\n\n const handleScroll = () => {\n setShowScrollButton(!isNearBottom())\n }\n\n // \u521D\u59CB\u68C0\u67E5\n handleScroll()\n\n container.addEventListener('scroll', handleScroll, { passive: true })\n return () => container.removeEventListener('scroll', handleScroll)\n }, [isNearBottom])\n\n // \u5F53\u6D88\u606F\u5217\u8868\u53D8\u5316\u65F6\uFF0C\u91CD\u65B0\u68C0\u67E5\u6309\u94AE\u72B6\u6001\uFF08\u4F46\u4E0D\u5728\u81EA\u52A8\u6EDA\u52A8\u65F6\uFF09\n useEffect(() => {\n if (autoScroll) return // \u81EA\u52A8\u6EDA\u52A8\u4F1A\u5728\u53E6\u4E00\u4E2A effect \u4E2D\u5904\u7406\n\n const timeoutId = setTimeout(() => {\n setShowScrollButton(!isNearBottom())\n }, 150)\n\n return () => clearTimeout(timeoutId)\n }, [messages, autoScroll, isNearBottom])\n\n // \u76D1\u542C\u6D88\u606F\u5217\u8868\u53D8\u5316\uFF0C\u81EA\u52A8\u6EDA\u52A8\n useEffect(() => {\n if (!autoScroll || !listRef.current) return\n\n // \u5EF6\u8FDF\u6EDA\u52A8\u4EE5\u786E\u4FDD DOM \u5DF2\u66F4\u65B0\n const timeoutId = setTimeout(() => {\n if (listRef.current) {\n listRef.current.scrollTop = listRef.current.scrollHeight\n // \u81EA\u52A8\u6EDA\u52A8\u5230\u5E95\u90E8\u540E\uFF0C\u9690\u85CF\u6309\u94AE\n setShowScrollButton(false)\n }\n }, 100)\n\n return () => clearTimeout(timeoutId)\n }, [messages, autoScroll])\n\n // \u7A7A\u72B6\u6001\n if (messages.length === 0 && !isLoadingHistory) {\n return (\n <div className={`flex-1 overflow-hidden ${className}`}>{emptyPlaceholder || <DefaultEmptyPlaceholder />}</div>\n )\n }\n\n return (\n <div className=\"relative flex-1 overflow-hidden\">\n <div\n ref={listRef}\n className={`\n livechat-message-list absolute inset-0 overflow-y-auto p-4\n ${className}\n `}\n >\n {/* \u52A0\u8F7D\u5386\u53F2\u6D88\u606F\u6307\u793A\u5668 */}\n {isLoadingHistory && <LoadingIndicator />}\n\n {/* \u6D88\u606F\u5217\u8868 */}\n <div className=\"flex flex-col gap-1\">\n {messages.map(message => (\n <ChatMessage\n key={message.id}\n message={message}\n rendererRegistry={rendererRegistry}\n defaultRenderer={defaultRenderer}\n showTimestamp={showTimestamp}\n onAddToCart={onAddToCart}\n />\n ))}\n </div>\n\n {/* \u6EDA\u52A8\u951A\u70B9 */}\n {autoScroll && <ScrollAnchor dependencies={[messages]} />}\n </div>\n\n {/* \u56DE\u5230\u5E95\u90E8\u6309\u94AE */}\n <button\n onClick={scrollToBottom}\n className={`flex -translate-x-1/2 items-center justify-center ${showScrollButton ? '' : 'pointer-events-none'}`}\n style={{\n position: 'absolute',\n bottom: '24px',\n left: '50%',\n zIndex: 10,\n width: '40px',\n height: '40px',\n borderRadius: '50%',\n backgroundColor: 'rgba(255, 255, 255, 0.95)',\n boxShadow: '0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)',\n transition: 'all 300ms ease-in-out',\n opacity: showScrollButton ? 1 : 0,\n cursor: 'pointer',\n border: 'none',\n }}\n aria-label=\"Scroll to bottom\"\n aria-hidden={!showScrollButton}\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"text-gray-700\"\n >\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </button>\n </div>\n )\n}\n"],
5
- "mappings": "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",
6
- "names": ["MessageList_exports", "__export", "MessageList", "__toCommonJS", "import_jsx_runtime", "import_react", "import_ChatMessage", "import_ScrollAnchor", "DefaultEmptyPlaceholder", "LoadingIndicator", "messages", "rendererRegistry", "defaultRenderer", "showTimestamp", "autoScroll", "isLoadingHistory", "emptyPlaceholder", "className", "onAddToCart", "listRef", "showScrollButton", "setShowScrollButton", "isNearBottom", "threshold", "container", "scrollTop", "scrollHeight", "clientHeight", "scrollToBottom", "handleScroll", "timeoutId", "message"]
4
+ "sourcesContent": ["/**\n * \u6D88\u606F\u5217\u8868\u7EC4\u4EF6\n * \u663E\u793A\u6240\u6709\u804A\u5929\u6D88\u606F\uFF0C\u652F\u6301\u6EDA\u52A8\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u6D88\u606F\u5217\u8868\u8BBE\u8BA1\n */\n\nimport React, { useRef, useEffect, useState, useCallback } from 'react'\nimport type { Message, MessageRenderer } from '../types'\nimport { ChatMessage } from './ChatMessage'\nimport { ScrollAnchor } from './ScrollAnchor'\nimport { MessageRendererRegistry } from '../utils/messageRenderers'\n\nexport interface MessageListProps {\n /**\n * \u6D88\u606F\u5217\u8868\n */\n messages: Message[]\n\n /**\n * \u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\u6CE8\u518C\u8868\n */\n rendererRegistry?: MessageRendererRegistry\n\n /**\n * \u9ED8\u8BA4\u6E32\u67D3\u5668\n */\n defaultRenderer?: MessageRenderer\n\n /**\n * \u662F\u5426\u663E\u793A\u65F6\u95F4\u6233\n * @default true\n */\n showTimestamp?: boolean\n\n /**\n * \u662F\u5426\u81EA\u52A8\u6EDA\u52A8\u5230\u5E95\u90E8\n * @default true\n */\n autoScroll?: boolean\n\n /**\n * \u662F\u5426\u6B63\u5728\u52A0\u8F7D\u5386\u53F2\u6D88\u606F\n * @default false\n */\n isLoadingHistory?: boolean\n\n /**\n * \u7A7A\u72B6\u6001\u5360\u4F4D\u5185\u5BB9\n */\n emptyPlaceholder?: React.ReactNode\n\n /**\n * \u81EA\u5B9A\u4E49\u6837\u5F0F\u7C7B\u540D\n */\n className?: string\n\n /**\n * \u5546\u54C1\u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u56DE\u8C03\n */\n onAddToCart?: (product: any) => void\n}\n\n/**\n * \u9ED8\u8BA4\u7A7A\u72B6\u6001\u5360\u4F4D\n */\nconst DefaultEmptyPlaceholder: React.FC = () => (\n <div className=\"flex h-full items-center justify-center text-gray-400\">\n <p className=\"text-sm\">No messages yet</p>\n </div>\n)\n\n/**\n * \u52A0\u8F7D\u6307\u793A\u5668\n */\nconst LoadingIndicator: React.FC = () => (\n <div className=\"flex justify-center py-4\">\n <div className=\"flex gap-1\">\n <div className=\"size-2 animate-bounce rounded-full bg-gray-400\" />\n <div className=\"size-2 animate-bounce rounded-full bg-gray-400\" style={{ animationDelay: '0.1s' }} />\n <div className=\"size-2 animate-bounce rounded-full bg-gray-400\" style={{ animationDelay: '0.2s' }} />\n </div>\n </div>\n)\n\n/**\n * \u6D88\u606F\u5217\u8868\u7EC4\u4EF6\n *\n * \u529F\u80FD\uFF1A\n * - \u663E\u793A\u6240\u6709\u6D88\u606F\uFF08\u7528\u6237\u3001\u52A9\u624B\u3001\u7CFB\u7EDF\uFF09\n * - \u81EA\u52A8\u6EDA\u52A8\u5230\u6700\u65B0\u6D88\u606F\n * - \u52A0\u8F7D\u5386\u53F2\u6D88\u606F\u65F6\u663E\u793A\u6307\u793A\u5668\n * - \u7A7A\u72B6\u6001\u5360\u4F4D\n *\n * \u6837\u5F0F\uFF1A\n * - \u4F7F\u7528\u81EA\u5B9A\u4E49\u6EDA\u52A8\u6761\u6837\u5F0F\uFF08livechat.css\uFF09\n * - \u5185\u5BB9\u95F4\u8DDD\u5408\u7406\n * - \u652F\u6301\u54CD\u5E94\u5F0F\u5E03\u5C40\n *\n * @example\n * ```tsx\n * <MessageList\n * messages={messages}\n * rendererRegistry={customRegistry}\n * autoScroll={true}\n * isLoadingHistory={isLoading}\n * />\n * ```\n */\nexport const MessageList: React.FC<MessageListProps> = ({\n messages,\n rendererRegistry,\n defaultRenderer,\n showTimestamp = true,\n autoScroll = true,\n isLoadingHistory = false,\n emptyPlaceholder,\n className = '',\n onAddToCart,\n}) => {\n // \u4F7F\u7528 callback ref + state \u786E\u4FDD DOM \u6302\u8F7D\u540E\u89E6\u53D1\u91CD\u65B0\u6E32\u67D3\n const [listElement, setListElement] = useState<HTMLDivElement | null>(null)\n const listRef = useCallback((node: HTMLDivElement | null) => {\n setListElement(node)\n }, [])\n const [showScrollButton, setShowScrollButton] = useState(false)\n\n // \u68C0\u67E5\u662F\u5426\u63A5\u8FD1\u5E95\u90E8\n const isNearBottom = useCallback(\n (threshold = 100) => {\n if (!listElement) return true\n\n const { scrollTop, scrollHeight, clientHeight } = listElement\n return scrollHeight - scrollTop - clientHeight < threshold\n },\n [listElement]\n )\n\n // \u5E73\u6ED1\u6EDA\u52A8\u5230\u5E95\u90E8\n const scrollToBottom = useCallback(() => {\n if (!listElement) return\n\n listElement.scrollTo({\n top: listElement.scrollHeight,\n behavior: 'smooth',\n })\n }, [listElement])\n\n // \u76D1\u542C\u6EDA\u52A8\u4E8B\u4EF6\uFF0C\u63A7\u5236\u6309\u94AE\u663E\u793A\n useEffect(() => {\n if (!listElement) return\n\n const handleScroll = () => {\n setShowScrollButton(!isNearBottom())\n }\n\n // \u521D\u59CB\u68C0\u67E5\n handleScroll()\n\n listElement.addEventListener('scroll', handleScroll, { passive: true })\n return () => listElement.removeEventListener('scroll', handleScroll)\n }, [listElement, isNearBottom])\n\n // \u5F53\u6D88\u606F\u5217\u8868\u53D8\u5316\u65F6\uFF0C\u91CD\u65B0\u68C0\u67E5\u6309\u94AE\u72B6\u6001\uFF08\u4F46\u4E0D\u5728\u81EA\u52A8\u6EDA\u52A8\u65F6\uFF09\n useEffect(() => {\n if (autoScroll) return // \u81EA\u52A8\u6EDA\u52A8\u4F1A\u5728\u53E6\u4E00\u4E2A effect \u4E2D\u5904\u7406\n\n const timeoutId = setTimeout(() => {\n setShowScrollButton(!isNearBottom())\n }, 150)\n\n return () => clearTimeout(timeoutId)\n }, [messages, autoScroll, isNearBottom])\n\n // \u76D1\u542C\u6D88\u606F\u5217\u8868\u53D8\u5316\uFF0C\u81EA\u52A8\u6EDA\u52A8\n useEffect(() => {\n if (!autoScroll || !listElement) return\n\n // \u5EF6\u8FDF\u6EDA\u52A8\u4EE5\u786E\u4FDD DOM \u5DF2\u66F4\u65B0\n const timeoutId = setTimeout(() => {\n if (listElement) {\n listElement.scrollTop = listElement.scrollHeight\n // \u81EA\u52A8\u6EDA\u52A8\u5230\u5E95\u90E8\u540E\uFF0C\u9690\u85CF\u6309\u94AE\n setShowScrollButton(false)\n }\n }, 100)\n\n return () => clearTimeout(timeoutId)\n }, [messages, autoScroll, listElement])\n\n // \u7A7A\u72B6\u6001 + \u52A0\u8F7D\u4E2D\n if (messages.length === 0) {\n if (isLoadingHistory) {\n // \u52A0\u8F7D\u4E2D\uFF0C\u663E\u793A loading\n return (\n <div className={`flex flex-1 items-center justify-center overflow-hidden ${className}`}>\n <LoadingIndicator />\n </div>\n )\n }\n // \u7A7A\u72B6\u6001\n return (\n <div className={`flex-1 overflow-hidden ${className}`}>{emptyPlaceholder || <DefaultEmptyPlaceholder />}</div>\n )\n }\n\n return (\n <div className=\"relative flex-1 overflow-hidden\">\n <div\n ref={listRef}\n className={`\n livechat-message-list absolute inset-0 overflow-y-auto p-4\n ${className}\n `}\n >\n {/* \u6D88\u606F\u5217\u8868 */}\n <div className=\"flex flex-col gap-1\">\n {messages.map(message => (\n <ChatMessage\n key={message.id}\n message={message}\n rendererRegistry={rendererRegistry}\n defaultRenderer={defaultRenderer}\n showTimestamp={showTimestamp}\n onAddToCart={onAddToCart}\n />\n ))}\n </div>\n\n {/* \u6EDA\u52A8\u951A\u70B9 */}\n {autoScroll && <ScrollAnchor dependencies={[messages]} />}\n </div>\n\n {/* \u56DE\u5230\u5E95\u90E8\u6309\u94AE */}\n <button\n onClick={scrollToBottom}\n className={`livechat-scroll-to-bottom ${showScrollButton ? 'visible' : 'hidden'}`}\n aria-label=\"Scroll to bottom\"\n aria-hidden={!showScrollButton}\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"text-gray-700\"\n >\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </button>\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["MessageList_exports", "__export", "MessageList", "__toCommonJS", "import_jsx_runtime", "import_react", "import_ChatMessage", "import_ScrollAnchor", "DefaultEmptyPlaceholder", "LoadingIndicator", "messages", "rendererRegistry", "defaultRenderer", "showTimestamp", "autoScroll", "isLoadingHistory", "emptyPlaceholder", "className", "onAddToCart", "listElement", "setListElement", "listRef", "node", "showScrollButton", "setShowScrollButton", "isNearBottom", "threshold", "scrollTop", "scrollHeight", "clientHeight", "scrollToBottom", "handleScroll", "timeoutId", "message"]
7
7
  }
@@ -54,8 +54,9 @@ export interface UseChatStateOptions {
54
54
  onProductList?: () => void;
55
55
  /**
56
56
  * AI 回复促销卡片时触发
57
+ * @param promotions 促销活动数组数据
57
58
  */
58
- onPromotionList?: () => void;
59
+ onPromotionList?: (promotions: any[]) => void;
59
60
  /**
60
61
  * 商品添加到购物车回调
61
62
  */
@@ -1,2 +1,2 @@
1
- "use strict";var z=Object.defineProperty;var ct=Object.getOwnPropertyDescriptor;var it=Object.getOwnPropertyNames;var dt=Object.prototype.hasOwnProperty;var ut=(e,r)=>{for(var f in r)z(e,f,{get:r[f],enumerable:!0})},lt=(e,r,f,M)=>{if(r&&typeof r=="object"||typeof r=="function")for(let d of it(r))!dt.call(e,d)&&d!==f&&z(e,d,{get:()=>r[d],enumerable:!(M=ct(r,d))||M.enumerable});return e};var gt=e=>lt(z({},"__esModule",{value:!0}),e);var xt={};ut(xt,{useChatState:()=>mt});module.exports=gt(xt);var i=require("react"),j=require("../utils/userId"),G=require("./useSession"),V=require("../utils/productTransformers"),J=require("../utils/cartTransformers");function pt(e,r,f,M,d){const o=[],g=/\{\{(?:product:)?([^}]+)\}\}/g;let u=0,l,m=!1;for(;(l=g.exec(e))!==null;){m=!0;const C=e.slice(u,l.index);C&&o.push({type:"text",text:C});const p=l[1].trim(),y=r.get(p),I=f.get(p);y?console.log("[useChatState] \u{1F3AF} \u5B9E\u65F6\u68C0\u6D4B\u5230\u4EA7\u54C1:",p,"\u2192",y.title):console.log("[useChatState] \u{1F4E6} \u5B9E\u65F6\u68C0\u6D4B\u5230\u4EA7\u54C1\u5360\u4F4D\u7B26\uFF0C\u4EA7\u54C1\u6570\u636E\u5F85\u5E94\u7528\u5C42\u67E5\u8BE2:",p),o.push({type:"product_card",data:{product:y,rawProduct:I,productHandle:p,onAddToCart:M,productCardRender:d}}),u=g.lastIndex}if(m){const C=e.slice(u);return{contents:o,remainingBuffer:C}}else{const C=e.match(/\{\{[^}]*$/);if(C){const p=e.slice(0,C.index);return p&&o.push({type:"text",text:p}),{contents:o,remainingBuffer:C[0]}}else return e&&o.push({type:"text",text:e}),{contents:o,remainingBuffer:""}}}function ft(e,r,f,M,d){const o=[],g=/\{\{(?:product:)?([^}]+)\}\}/g;let u=0,l;for(;(l=g.exec(e))!==null;){const C=e.slice(u,l.index).trim(),p=l[1].trim();C&&o.push({type:"text",text:C});const y=r.get(p),I=f.get(p);console.log(y?`[useChatState] \u2705 \u627E\u5230\u4EA7\u54C1\u5339\u914D: ${p} \u2192 ${y.title}`:`[useChatState] \u{1F4E6} \u4EA7\u54C1\u5360\u4F4D\u7B26\uFF0C\u4EA7\u54C1\u6570\u636E\u5F85\u5E94\u7528\u5C42\u67E5\u8BE2: ${p}`),o.push({type:"product_card",data:{product:y,rawProduct:I,productHandle:p,onAddToCart:M,productCardRender:d}}),u=g.lastIndex}const m=e.slice(u).trim();return m&&o.push({type:"text",text:m}),o}function ht(e,r,f,M,d){const o=[];for(const g of e)if(g.type==="text"){const l=ft(g.text,r,f,M,d);o.push(...l)}else{if(g.type==="product_list")continue;o.push(g)}return o}function Ct(e,r,f){if(!e.content.some(u=>u.type==="text"&&/\{\{(?:product:)?[^}]+\}\}/.test(u.text)))return e;console.log("[useChatState] \u68C0\u6D4B\u5230\u5386\u53F2\u6D88\u606F\u9700\u8981\u91CD\u7EC4, \u6D88\u606FID:",e.id);const d=new Map,o=new Map;e.structured_content&&e.structured_content.forEach(u=>{u.type==="product_list"&&Array.isArray(u.data)&&u.data.forEach(l=>{l&&l.handle&&(o.set(l.handle,l),console.log("[useChatState] \u4ECE structured_content \u63D0\u53D6\u539F\u59CB\u4EA7\u54C1\u6570\u636E, handle:",l.handle))})}),e.content.forEach(u=>{u.type==="product_list"&&u.data.products.forEach(m=>{m&&m.handle&&d.set(m.handle,m)})});const g=ht(e.content,d,o,r,f);return{...e,content:g}}function mt(e={}){const{welcomeMessage:r,site:f,open:M,onOpenChange:d,onOpen:o,onClose:g,onMessageSend:u,onError:l,onTextMessage:m,onProductList:C,onPromotionList:p,onAddToCart:y,onCart:I,productCardRender:O}=e,{sessionId:B,saveSession:H,clearSession:L}=(0,G.useSession)(),[K,Q]=(0,i.useState)("");(0,i.useEffect)(()=>{(0,j.getUserId)().then(x=>Q(x))},[]);const[X,D]=(0,i.useState)(()=>r?[{id:`welcome-${Date.now()}`,role:"assistant",content:[{type:"text",text:r}],timestamp:Date.now()}]:[]),[Y,$]=(0,i.useState)(!1),T=M!==void 0,U=T?M:Y,[Z,tt]=(0,i.useState)(""),[et,b]=(0,i.useState)(!1),t=(0,i.useRef)(null),N=(0,i.useRef)(!1),P=(0,i.useRef)(new Map),w=(0,i.useRef)(new Map),S=(0,i.useRef)(""),k=(0,i.useRef)([]),nt=(0,i.useCallback)(()=>{T||$(!0),d?.(!0),o?.()},[T,d,o]),st=(0,i.useCallback)(()=>{T||$(!1),d?.(!1),g?.()},[T,d,g]),at=(0,i.useCallback)(()=>{const x=!U;T||$(x),d?.(x),x?o?.():g?.()},[T,U,d,o,g]),A=(0,i.useCallback)(x=>{if(!x){console.warn("[useChatState] Attempted to add null/undefined message");return}D(R=>[...R,x])},[]),ot=(0,i.useCallback)(x=>{const R=x.filter(s=>s!=null);R.length!==x.length&&console.warn("[useChatState] Filtered out null/undefined messages from batch set");const E=R.map(s=>Ct(s,y,O));D(E)},[y,O]),q=(0,i.useCallback)(()=>{D([])},[]),rt=(0,i.useCallback)(x=>{const{event:R,data:E}=x;switch(R){case"message_start":{b(!0),N.current=!1,S.current="",k.current=[];const s=E;s.sessionId&&s.sessionId!==B&&H(s.sessionId),D(a=>{const n=a[a.length-1];if(n&&n.role==="assistant"&&n.content.length===1&&n.content[0].type==="thinking")return t.current=n,a;{const _=`msg-${Date.now()}`;return t.current={id:_,role:"assistant",content:[{type:"thinking",data:{status:"thinking"}}],timestamp:Date.now()},[...a,t.current]}});break}case"content_delta":{const s=E,a=s.delta||s.text||"";if(t.current&&a){N.current||(N.current=!0,m?.()),t.current.content.some(c=>c.type==="thinking")&&(t.current.content=t.current.content.filter(c=>c.type!=="thinking")),S.current+=a;const{contents:h,remainingBuffer:_}=pt(S.current,P.current,w.current,y,O);S.current=_,h.length>0&&(h.forEach(c=>{const v=t.current.content[t.current.content.length-1];c.type==="text"&&v&&v.type==="text"?v.text+=c.text:t.current.content.push(c)}),D(c=>{if(!t.current)return c;const v=[...c],F=v.findIndex(W=>W&&W.id===t.current.id);return F>=0?v[F]={...t.current}:v.push({...t.current}),v}))}break}case"content_block":{const s=E;if(t.current){const a=s.type||s.data?.type,n=s.data;if(!a||!n){console.warn("[useChatState] Invalid content_block:",s);break}let h;if(a==="product_list"&&Array.isArray(n)){C?.(),n.forEach(c=>{c&&c.handle&&(w.current.set(c.handle,c),console.log("[useChatState] \u7F13\u5B58\u539F\u59CB\u4EA7\u54C1\u6570\u636E, handle:",c.handle))}),(0,V.transformProducts)(n,f).forEach(c=>{c&&c.handle&&(P.current.set(c.handle,c),console.log("[useChatState] \u5EFA\u7ACB\u4EA7\u54C1\u6620\u5C04:",{handle:c.handle,title:c.title}))}),console.log("[useChatState] \u2705 \u4EA7\u54C1\u5217\u8868\u5DF2\u7F13\u5B58\uFF0C\u4E0D\u6DFB\u52A0\u5230\u6D88\u606F\u4E2D\uFF08\u907F\u514D\u95EA\u70C1\uFF09");break}else a==="product_comparison"&&n.products?h={type:"product_comparison",data:{products:(0,V.transformProducts)(n.products,f),dimensions:n.dimensions||{}}}:a==="faq_list"&&n.found!==void 0?h={type:"faq_list",data:n}:a==="quick_replies"&&n.replies?h={type:"quick_replies",data:{replies:n.replies}}:a==="policy"&&n.title&&n.content?h={type:"policy",data:{title:n.title,content:n.content}}:a==="promotion_list"&&n.found!==void 0?(p?.(),h={type:"promotion_list",data:n}):a==="cart"&&n.id!==void 0?h={type:"cart",data:{...(0,J.transformCartData)(n),onCart:I}}:h={type:a,data:n};console.log("[useChatState] \u2705 \u5361\u7247\u5DF2\u7F13\u5B58\uFF0C\u7B49\u5F85\u6587\u672C\u5B8C\u6210\u540E\u663E\u793A:",a),k.current.push(h)}break}case"tool_start":case"tool_end":break;case"message_end":{if(b(!1),t.current&&S.current){console.log("[useChatState] \u5904\u7406\u5269\u4F59\u7F13\u51B2\u533A:",S.current);const s=t.current.content[t.current.content.length-1];s&&s.type==="text"?s.text+=S.current:t.current.content.push({type:"text",text:S.current})}t.current&&k.current.length>0&&(console.log("[useChatState] \u{1F4CB} \u6587\u672C\u5DF2\u5B8C\u6210\uFF0C\u73B0\u5728\u6DFB\u52A0",k.current.length,"\u4E2A\u7F13\u5B58\u7684\u5361\u7247"),t.current.content.push(...k.current)),t.current&&t.current.content.some(a=>a.type==="thinking")&&(console.log("[useChatState] \u26A0\uFE0F message_end \u65F6\u4ECD\u5B58\u5728 thinking block\uFF0C\u7ACB\u5373\u79FB\u9664\uFF08\u89C6\u4E3A\u8D85\u65F6\uFF09"),t.current.content=t.current.content.filter(a=>a.type!=="thinking"),t.current.content.length===0&&t.current.content.push({type:"text",text:"Response timed out, please try again."})),t.current&&D(s=>{if(!t.current)return s;const a=[...s],n=a.findIndex(h=>h&&h.id===t.current.id);return n>=0&&(a[n]={...t.current}),a}),S.current="",k.current=[],P.current.clear(),w.current.clear(),t.current=null;break}case"status":{E.type==="session_expired"&&(q(),L(),r&&A({id:`welcome-${Date.now()}`,role:"assistant",content:[{type:"text",text:r}],timestamp:Date.now()}));break}case"error":{const s=E;b(!1),S.current="",k.current=[],P.current.clear(),w.current.clear(),t.current=null,A({id:`error-${Date.now()}`,role:"system",content:[{type:"error",data:{message:s.message,code:s.code}}],timestamp:Date.now()}),l?.(new Error(s.message));break}case"done":{b(!1),S.current="",k.current=[],P.current.clear(),w.current.clear(),t.current=null;break}default:break}},[r,f,A,q,L,H,B,l,m,C,p,y,I]);return{messages:X,isOpen:U,userId:K,sessionId:B,inputValue:Z,isStreaming:et,openChat:nt,closeChat:st,toggleChat:at,setInputValue:tt,addMessage:A,setMessages:ot,clearMessages:q,handleSSEEvent:rt,saveSession:H,clearSession:L}}
1
+ "use strict";var z=Object.defineProperty;var ct=Object.getOwnPropertyDescriptor;var it=Object.getOwnPropertyNames;var dt=Object.prototype.hasOwnProperty;var ut=(e,r)=>{for(var f in r)z(e,f,{get:r[f],enumerable:!0})},lt=(e,r,f,M)=>{if(r&&typeof r=="object"||typeof r=="function")for(let d of it(r))!dt.call(e,d)&&d!==f&&z(e,d,{get:()=>r[d],enumerable:!(M=ct(r,d))||M.enumerable});return e};var gt=e=>lt(z({},"__esModule",{value:!0}),e);var xt={};ut(xt,{useChatState:()=>mt});module.exports=gt(xt);var i=require("react"),j=require("../utils/userId"),G=require("./useSession"),V=require("../utils/productTransformers"),J=require("../utils/cartTransformers");function pt(e,r,f,M,d){const a=[],g=/\{\{(?:product:)?([^}]+)\}\}/g;let u=0,l,m=!1;for(;(l=g.exec(e))!==null;){m=!0;const C=e.slice(u,l.index);C&&a.push({type:"text",text:C});const p=l[1].trim(),y=r.get(p),I=f.get(p);y?console.log("[useChatState] \u{1F3AF} \u5B9E\u65F6\u68C0\u6D4B\u5230\u4EA7\u54C1:",p,"\u2192",y.title):console.log("[useChatState] \u{1F4E6} \u5B9E\u65F6\u68C0\u6D4B\u5230\u4EA7\u54C1\u5360\u4F4D\u7B26\uFF0C\u4EA7\u54C1\u6570\u636E\u5F85\u5E94\u7528\u5C42\u67E5\u8BE2:",p),a.push({type:"product_card",data:{product:y,rawProduct:I,productHandle:p,onAddToCart:M,productCardRender:d}}),u=g.lastIndex}if(m){const C=e.slice(u);return{contents:a,remainingBuffer:C}}else{const C=e.match(/\{\{[^}]*$/);if(C){const p=e.slice(0,C.index);return p&&a.push({type:"text",text:p}),{contents:a,remainingBuffer:C[0]}}else return e&&a.push({type:"text",text:e}),{contents:a,remainingBuffer:""}}}function ft(e,r,f,M,d){const a=[],g=/\{\{(?:product:)?([^}]+)\}\}/g;let u=0,l;for(;(l=g.exec(e))!==null;){const C=e.slice(u,l.index).trim(),p=l[1].trim();C&&a.push({type:"text",text:C});const y=r.get(p),I=f.get(p);console.log(y?`[useChatState] \u2705 \u627E\u5230\u4EA7\u54C1\u5339\u914D: ${p} \u2192 ${y.title}`:`[useChatState] \u{1F4E6} \u4EA7\u54C1\u5360\u4F4D\u7B26\uFF0C\u4EA7\u54C1\u6570\u636E\u5F85\u5E94\u7528\u5C42\u67E5\u8BE2: ${p}`),a.push({type:"product_card",data:{product:y,rawProduct:I,productHandle:p,onAddToCart:M,productCardRender:d}}),u=g.lastIndex}const m=e.slice(u).trim();return m&&a.push({type:"text",text:m}),a}function ht(e,r,f,M,d){const a=[];for(const g of e)if(g.type==="text"){const l=ft(g.text,r,f,M,d);a.push(...l)}else{if(g.type==="product_list")continue;a.push(g)}return a}function Ct(e,r,f){if(!e.content.some(u=>u.type==="text"&&/\{\{(?:product:)?[^}]+\}\}/.test(u.text)))return e;console.log("[useChatState] \u68C0\u6D4B\u5230\u5386\u53F2\u6D88\u606F\u9700\u8981\u91CD\u7EC4, \u6D88\u606FID:",e.id);const d=new Map,a=new Map;e.structured_content&&e.structured_content.forEach(u=>{u.type==="product_list"&&Array.isArray(u.data)&&u.data.forEach(l=>{l&&l.handle&&(a.set(l.handle,l),console.log("[useChatState] \u4ECE structured_content \u63D0\u53D6\u539F\u59CB\u4EA7\u54C1\u6570\u636E, handle:",l.handle))})}),e.content.forEach(u=>{u.type==="product_list"&&u.data.products.forEach(m=>{m&&m.handle&&d.set(m.handle,m)})});const g=ht(e.content,d,a,r,f);return{...e,content:g}}function mt(e={}){const{welcomeMessage:r,site:f,open:M,onOpenChange:d,onOpen:a,onClose:g,onMessageSend:u,onError:l,onTextMessage:m,onProductList:C,onPromotionList:p,onAddToCart:y,onCart:I,productCardRender:O}=e,{sessionId:B,saveSession:H,clearSession:L}=(0,G.useSession)(),[K,Q]=(0,i.useState)("");(0,i.useEffect)(()=>{(0,j.getUserId)().then(x=>Q(x))},[]);const[X,D]=(0,i.useState)(()=>r?[{id:`welcome-${Date.now()}`,role:"assistant",content:[{type:"text",text:r}],timestamp:Date.now()}]:[]),[Y,$]=(0,i.useState)(!1),T=M!==void 0,U=T?M:Y,[Z,tt]=(0,i.useState)(""),[et,b]=(0,i.useState)(!1),t=(0,i.useRef)(null),N=(0,i.useRef)(!1),P=(0,i.useRef)(new Map),w=(0,i.useRef)(new Map),S=(0,i.useRef)(""),k=(0,i.useRef)([]),nt=(0,i.useCallback)(()=>{T||$(!0),d?.(!0),a?.()},[T,d,a]),st=(0,i.useCallback)(()=>{T||$(!1),d?.(!1),g?.()},[T,d,g]),ot=(0,i.useCallback)(()=>{const x=!U;T||$(x),d?.(x),x?a?.():g?.()},[T,U,d,a,g]),A=(0,i.useCallback)(x=>{if(!x){console.warn("[useChatState] Attempted to add null/undefined message");return}D(R=>[...R,x])},[]),at=(0,i.useCallback)(x=>{const R=x.filter(s=>s!=null);R.length!==x.length&&console.warn("[useChatState] Filtered out null/undefined messages from batch set");const E=R.map(s=>Ct(s,y,O));D(E)},[y,O]),q=(0,i.useCallback)(()=>{D([])},[]),rt=(0,i.useCallback)(x=>{const{event:R,data:E}=x;switch(R){case"message_start":{b(!0),N.current=!1,S.current="",k.current=[];const s=E;s.sessionId&&s.sessionId!==B&&H(s.sessionId),D(o=>{const n=o[o.length-1];if(n&&n.role==="assistant"&&n.content.length===1&&n.content[0].type==="thinking")return t.current=n,o;{const _=`msg-${Date.now()}`;return t.current={id:_,role:"assistant",content:[{type:"thinking",data:{status:"thinking"}}],timestamp:Date.now()},[...o,t.current]}});break}case"content_delta":{const s=E,o=s.delta||s.text||"";if(t.current&&o){N.current||(N.current=!0,m?.()),t.current.content.some(c=>c.type==="thinking")&&(t.current.content=t.current.content.filter(c=>c.type!=="thinking")),S.current+=o;const{contents:h,remainingBuffer:_}=pt(S.current,P.current,w.current,y,O);S.current=_,h.length>0&&(h.forEach(c=>{const v=t.current.content[t.current.content.length-1];c.type==="text"&&v&&v.type==="text"?v.text+=c.text:t.current.content.push(c)}),D(c=>{if(!t.current)return c;const v=[...c],F=v.findIndex(W=>W&&W.id===t.current.id);return F>=0?v[F]={...t.current}:v.push({...t.current}),v}))}break}case"content_block":{const s=E;if(t.current){const o=s.type||s.data?.type,n=s.data;if(!o||!n){console.warn("[useChatState] Invalid content_block:",s);break}let h;if(o==="product_list"&&Array.isArray(n)){C?.(),n.forEach(c=>{c&&c.handle&&(w.current.set(c.handle,c),console.log("[useChatState] \u7F13\u5B58\u539F\u59CB\u4EA7\u54C1\u6570\u636E, handle:",c.handle))}),(0,V.transformProducts)(n,f).forEach(c=>{c&&c.handle&&(P.current.set(c.handle,c),console.log("[useChatState] \u5EFA\u7ACB\u4EA7\u54C1\u6620\u5C04:",{handle:c.handle,title:c.title}))}),console.log("[useChatState] \u2705 \u4EA7\u54C1\u5217\u8868\u5DF2\u7F13\u5B58\uFF0C\u4E0D\u6DFB\u52A0\u5230\u6D88\u606F\u4E2D\uFF08\u907F\u514D\u95EA\u70C1\uFF09");break}else o==="product_comparison"&&n.products?h={type:"product_comparison",data:{products:(0,V.transformProducts)(n.products,f),dimensions:n.dimensions||{}}}:o==="faq_list"&&n.found!==void 0?h={type:"faq_list",data:n}:o==="quick_replies"&&n.replies?h={type:"quick_replies",data:{replies:n.replies}}:o==="policy"&&n.title&&n.content?h={type:"policy",data:{title:n.title,content:n.content}}:o==="promotion_list"&&n.found!==void 0?(p?.(n.results||[]),h={type:"promotion_list",data:n}):o==="cart"&&n.id!==void 0?h={type:"cart",data:{...(0,J.transformCartData)(n),onCart:I}}:h={type:o,data:n};console.log("[useChatState] \u2705 \u5361\u7247\u5DF2\u7F13\u5B58\uFF0C\u7B49\u5F85\u6587\u672C\u5B8C\u6210\u540E\u663E\u793A:",o),k.current.push(h)}break}case"tool_start":case"tool_end":break;case"message_end":{if(b(!1),t.current&&S.current){console.log("[useChatState] \u5904\u7406\u5269\u4F59\u7F13\u51B2\u533A:",S.current);const s=t.current.content[t.current.content.length-1];s&&s.type==="text"?s.text+=S.current:t.current.content.push({type:"text",text:S.current})}t.current&&k.current.length>0&&(console.log("[useChatState] \u{1F4CB} \u6587\u672C\u5DF2\u5B8C\u6210\uFF0C\u73B0\u5728\u6DFB\u52A0",k.current.length,"\u4E2A\u7F13\u5B58\u7684\u5361\u7247"),t.current.content.push(...k.current)),t.current&&t.current.content.some(o=>o.type==="thinking")&&(console.log("[useChatState] \u26A0\uFE0F message_end \u65F6\u4ECD\u5B58\u5728 thinking block\uFF0C\u7ACB\u5373\u79FB\u9664\uFF08\u89C6\u4E3A\u8D85\u65F6\uFF09"),t.current.content=t.current.content.filter(o=>o.type!=="thinking"),t.current.content.length===0&&t.current.content.push({type:"text",text:"Response timed out, please try again."})),t.current&&D(s=>{if(!t.current)return s;const o=[...s],n=o.findIndex(h=>h&&h.id===t.current.id);return n>=0&&(o[n]={...t.current}),o}),S.current="",k.current=[],P.current.clear(),w.current.clear(),t.current=null;break}case"status":{E.type==="session_expired"&&(q(),L(),r&&A({id:`welcome-${Date.now()}`,role:"assistant",content:[{type:"text",text:r}],timestamp:Date.now()}));break}case"error":{const s=E;b(!1),S.current="",k.current=[],P.current.clear(),w.current.clear(),t.current=null,A({id:`error-${Date.now()}`,role:"system",content:[{type:"error",data:{message:s.message,code:s.code}}],timestamp:Date.now()}),l?.(new Error(s.message));break}case"done":{b(!1),S.current="",k.current=[],P.current.clear(),w.current.clear(),t.current=null;break}default:break}},[r,f,A,q,L,H,B,l,m,C,p,y,I]);return{messages:X,isOpen:U,userId:K,sessionId:B,inputValue:Z,isStreaming:et,openChat:nt,closeChat:st,toggleChat:ot,setInputValue:tt,addMessage:A,setMessages:at,clearMessages:q,handleSSEEvent:rt,saveSession:H,clearSession:L}}
2
2
  //# sourceMappingURL=useChatState.js.map