@anker-in/campaign-ui 0.4.0-beta.7 → 0.4.0
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.
- package/dist/cjs/components/LiveChatWidget/LiveChatWidget.js +1 -1
- package/dist/cjs/components/LiveChatWidget/LiveChatWidget.js.map +3 -3
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductComparison.d.ts +1 -0
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductComparison.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductComparison.js.map +3 -3
- package/dist/cjs/components/LiveChatWidget/hooks/useChatState.d.ts +11 -2
- package/dist/cjs/components/LiveChatWidget/hooks/useChatState.js +1 -1
- package/dist/cjs/components/LiveChatWidget/hooks/useChatState.js.map +3 -3
- package/dist/cjs/components/LiveChatWidget/index.d.ts +1 -1
- package/dist/cjs/components/LiveChatWidget/index.js +1 -1
- package/dist/cjs/components/LiveChatWidget/index.js.map +2 -2
- package/dist/cjs/components/LiveChatWidget/types.d.ts +14 -0
- package/dist/cjs/components/LiveChatWidget/types.js.map +1 -1
- package/dist/cjs/components/LiveChatWidget/utils/userId.d.ts +7 -2
- package/dist/cjs/components/LiveChatWidget/utils/userId.js +1 -1
- package/dist/cjs/components/LiveChatWidget/utils/userId.js.map +3 -3
- package/dist/cjs/stories/LiveChatWidget.stories.js +1 -1
- package/dist/cjs/stories/LiveChatWidget.stories.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/LiveChatWidget.js +1 -1
- package/dist/esm/components/LiveChatWidget/LiveChatWidget.js.map +3 -3
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductComparison.d.ts +1 -0
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductComparison.js +1 -1
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductComparison.js.map +3 -3
- package/dist/esm/components/LiveChatWidget/hooks/useChatState.d.ts +11 -2
- package/dist/esm/components/LiveChatWidget/hooks/useChatState.js +1 -1
- package/dist/esm/components/LiveChatWidget/hooks/useChatState.js.map +3 -3
- package/dist/esm/components/LiveChatWidget/index.d.ts +1 -1
- package/dist/esm/components/LiveChatWidget/index.js +1 -1
- package/dist/esm/components/LiveChatWidget/index.js.map +3 -3
- package/dist/esm/components/LiveChatWidget/types.d.ts +14 -0
- package/dist/esm/components/LiveChatWidget/utils/userId.d.ts +7 -2
- package/dist/esm/components/LiveChatWidget/utils/userId.js +1 -1
- package/dist/esm/components/LiveChatWidget/utils/userId.js.map +3 -3
- package/dist/esm/stories/LiveChatWidget.stories.js +1 -1
- package/dist/esm/stories/LiveChatWidget.stories.js.map +2 -2
- package/package.json +1 -1
- package/src/components/LiveChatWidget/LiveChatWidget.tsx +44 -8
- package/src/components/LiveChatWidget/components/MessageContent/ProductComparison.tsx +6 -13
- package/src/components/LiveChatWidget/hooks/useChatState.ts +26 -7
- package/src/components/LiveChatWidget/index.tsx +1 -1
- package/src/components/LiveChatWidget/types.ts +15 -0
- package/src/components/LiveChatWidget/utils/userId.ts +13 -62
- package/src/stories/LiveChatWidget.stories.tsx +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/components/LiveChatWidget/utils/userId.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * userId \u751F\u6210\u548C\u7BA1\u7406\u5DE5\u5177\n * \u57FA\u4E8E specs/livechat-widget/research.md \u7684\u51B3\u7B56\n *\n * \u7B56\u7565\uFF1A\n * 1. \u4F18\u5148\u4ECE localStorage \u8BFB\u53D6\n * 2. \u5C1D\u8BD5\u83B7\u53D6 Google Analytics ID (GAID)\n * 3. \
|
|
5
|
-
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,iBAAAE,EAAA,cAAAC,IAAA,eAAAC,
|
|
6
|
-
"names": ["userId_exports", "__export", "clearUserId", "getUserId", "__toCommonJS", "STORAGE_KEY", "stored", "gaid", "getGAID", "
|
|
4
|
+
"sourcesContent": ["/**\n * userId \u751F\u6210\u548C\u7BA1\u7406\u5DE5\u5177\n * \u57FA\u4E8E specs/livechat-widget/research.md \u7684\u51B3\u7B56\n *\n * \u7B56\u7565\uFF1A\n * 1. \u4F18\u5148\u4ECE localStorage \u8BFB\u53D6\n * 2. \u5C1D\u8BD5\u83B7\u53D6 Google Analytics ID (GAID)\n * 3. \u8FD4\u56DE\u7A7A\u5B57\u7B26\u4E32\uFF0C\u7531\u540E\u7AEF\u751F\u6210\n */\n\nconst STORAGE_KEY = 'livechat_user_id'\n\n/**\n * \u83B7\u53D6\u7528\u6237\u552F\u4E00\u6807\u8BC6\u7B26\uFF08\u5F02\u6B65\u7248\u672C\uFF09\n * @returns userId (GAID \u6216\u7A7A\u5B57\u7B26\u4E32\uFF0C\u7A7A\u5B57\u7B26\u4E32\u7531\u540E\u7AEF\u751F\u6210)\n */\nexport async function getUserId(): Promise<string> {\n // 1. \u5C1D\u8BD5\u4ECE localStorage \u8BFB\u53D6\n if (typeof window !== 'undefined') {\n const stored = localStorage.getItem(STORAGE_KEY)\n if (stored) return stored\n }\n\n // 2. \u5C1D\u8BD5\u83B7\u53D6 GAID\n const gaid = getGAID()\n if (gaid) {\n if (typeof window !== 'undefined') {\n localStorage.setItem(STORAGE_KEY, gaid)\n }\n return gaid\n }\n\n // 3. \u8FD4\u56DE\u7A7A\u5B57\u7B26\u4E32\uFF0C\u7531\u540E\u7AEF\u751F\u6210\n return ''\n}\n\n/**\n * \u4FDD\u5B58\u540E\u7AEF\u8FD4\u56DE\u7684 userId \u5230 localStorage\n * @param id \u540E\u7AEF\u751F\u6210\u7684 userId\n */\nexport function saveUserId(id: string): void {\n if (id && typeof window !== 'undefined') {\n localStorage.setItem(STORAGE_KEY, id)\n }\n}\n\n/**\n * \u4ECE Google Analytics \u83B7\u53D6 Client ID (GAID)\n * @returns GAID \u6216 null\n */\nfunction getGAID(): string | null {\n if (typeof window === 'undefined') return null\n\n // \u68C0\u67E5 gtag \u662F\u5426\u53EF\u7528\n if (typeof (window as any).gtag !== 'function') {\n console.warn('[LiveChat userId] Google Analytics gtag is not available')\n return null\n }\n\n try {\n // Google Analytics 4 \u65B9\u6CD5\n // \u6CE8\u610F\uFF1Agtag \u7684 'get' \u547D\u4EE4\u662F\u5F02\u6B65\u7684\uFF0C\u8FD9\u91CC\u4F7F\u7528\u540C\u6B65 fallback\n // \u5728\u5B9E\u9645\u9879\u76EE\u4E2D\uFF0C\u5982\u679C GA \u5DF2\u521D\u59CB\u5316\uFF0C\u53EF\u4EE5\u4ECE dataLayer \u8BFB\u53D6\n const dataLayer = (window as any).dataLayer || []\n\n // \u5C1D\u8BD5\u4ECE dataLayer \u4E2D\u67E5\u627E\u5DF2\u5B58\u5728\u7684 client_id\n for (const item of dataLayer) {\n if (item && item[1] && typeof item[1] === 'object') {\n const clientId = item[1].client_id || item[1].clientId\n if (clientId && typeof clientId === 'string') {\n return `G-${clientId}`\n }\n }\n }\n\n // \u5982\u679C\u6CA1\u6709\u627E\u5230\uFF0C\u8FD4\u56DE null\uFF0C\u4F7F\u7528\u515C\u5E95\u65B9\u6848\n return null\n } catch (error) {\n console.error('[LiveChat userId] Failed to get GAID:', error)\n return null\n }\n}\n\n/**\n * \u6E05\u9664\u4FDD\u5B58\u7684 userId\uFF08\u7528\u4E8E\u6D4B\u8BD5\u6216\u91CD\u7F6E\uFF09\n */\nexport function clearUserId(): void {\n if (typeof window !== 'undefined') {\n localStorage.removeItem(STORAGE_KEY)\n }\n}\n"],
|
|
5
|
+
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,iBAAAE,EAAA,cAAAC,EAAA,eAAAC,IAAA,eAAAC,EAAAL,GAUA,MAAMM,EAAc,mBAMpB,eAAsBH,GAA6B,CAEjD,GAAI,OAAO,OAAW,IAAa,CACjC,MAAMI,EAAS,aAAa,QAAQD,CAAW,EAC/C,GAAIC,EAAQ,OAAOA,CACrB,CAGA,MAAMC,EAAOC,EAAQ,EACrB,OAAID,GACE,OAAO,OAAW,KACpB,aAAa,QAAQF,EAAaE,CAAI,EAEjCA,GAIF,EACT,CAMO,SAASJ,EAAWM,EAAkB,CACvCA,GAAM,OAAO,OAAW,KAC1B,aAAa,QAAQJ,EAAaI,CAAE,CAExC,CAMA,SAASD,GAAyB,CAChC,GAAI,OAAO,OAAW,IAAa,OAAO,KAG1C,GAAI,OAAQ,OAAe,MAAS,WAClC,eAAQ,KAAK,0DAA0D,EAChE,KAGT,GAAI,CAIF,MAAME,EAAa,OAAe,WAAa,CAAC,EAGhD,UAAWC,KAAQD,EACjB,GAAIC,GAAQA,EAAK,CAAC,GAAK,OAAOA,EAAK,CAAC,GAAM,SAAU,CAClD,MAAMC,EAAWD,EAAK,CAAC,EAAE,WAAaA,EAAK,CAAC,EAAE,SAC9C,GAAIC,GAAY,OAAOA,GAAa,SAClC,MAAO,KAAKA,CAAQ,EAExB,CAIF,OAAO,IACT,OAASC,EAAO,CACd,eAAQ,MAAM,wCAAyCA,CAAK,EACrD,IACT,CACF,CAKO,SAASZ,GAAoB,CAC9B,OAAO,OAAW,KACpB,aAAa,WAAWI,CAAW,CAEvC",
|
|
6
|
+
"names": ["userId_exports", "__export", "clearUserId", "getUserId", "saveUserId", "__toCommonJS", "STORAGE_KEY", "stored", "gaid", "getGAID", "id", "dataLayer", "item", "clientId", "error"]
|
|
7
7
|
}
|
|
@@ -48,5 +48,5 @@ const customRenderers = {
|
|
|
48
48
|
customRenderers={customRenderers}
|
|
49
49
|
/>
|
|
50
50
|
\`\`\`
|
|
51
|
-
`}}},tags:["autodocs"],argTypes:{apiBaseUrl:{control:"text",description:"API \u57FA\u7840 URL"},headers:{control:"object",description:"\u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\uFF0C\u5C06\u5728\u6240\u6709 API \u8BF7\u6C42\u4E2D\u6DFB\u52A0",table:{defaultValue:{summary:"undefined"}}},recaptchaSitekey:{control:"text",description:"Google reCAPTCHA v3 site key\uFF0C\u63D0\u4F9B\u6B64\u53C2\u6570\u5C06\u81EA\u52A8\u542F\u7528 reCAPTCHA v3 \u9A8C\u8BC1",table:{defaultValue:{summary:"undefined"}}},recaptchaAction:{control:"text",description:"reCAPTCHA action \u540D\u79F0\uFF0C\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7684\u9A8C\u8BC1\u573A\u666F",table:{defaultValue:{summary:'"activity"'}}},site:{control:"text",description:"Shopify \u5E97\u94FA URL"},channelCode:{control:"text",description:"\u6E20\u9053\u7F16\u7801\uFF0C\u7528\u4E8E\u6807\u8BC6\u6765\u6E90\u6E20\u9053",table:{defaultValue:{summary:"undefined"}}},welcomeMessage:{control:"text",description:"\u6B22\u8FCE\u6D88\u606F",table:{defaultValue:{summary:"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F"}}},logoUrl:{control:"text",description:"Logo URL"},position:{control:"object",description:"\u6C14\u6CE1\u6309\u94AE\u4F4D\u7F6E\u5BF9\u8C61",table:{defaultValue:{summary:'{ bottom: "1.5rem", right: "1.5rem" }'}}}},args:{apiBaseUrl:"http://172.16.38.183:3003",site:"www.eufy.com",loginUserId:"test_test",welcomeMessage:"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F"}};var h=v;const y={args:{loginUserId:"test_test1",apiBaseUrl:"
|
|
51
|
+
`}}},tags:["autodocs"],argTypes:{apiBaseUrl:{control:"text",description:"API \u57FA\u7840 URL"},headers:{control:"object",description:"\u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\uFF0C\u5C06\u5728\u6240\u6709 API \u8BF7\u6C42\u4E2D\u6DFB\u52A0",table:{defaultValue:{summary:"undefined"}}},recaptchaSitekey:{control:"text",description:"Google reCAPTCHA v3 site key\uFF0C\u63D0\u4F9B\u6B64\u53C2\u6570\u5C06\u81EA\u52A8\u542F\u7528 reCAPTCHA v3 \u9A8C\u8BC1",table:{defaultValue:{summary:"undefined"}}},recaptchaAction:{control:"text",description:"reCAPTCHA action \u540D\u79F0\uFF0C\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7684\u9A8C\u8BC1\u573A\u666F",table:{defaultValue:{summary:'"activity"'}}},site:{control:"text",description:"Shopify \u5E97\u94FA URL"},channelCode:{control:"text",description:"\u6E20\u9053\u7F16\u7801\uFF0C\u7528\u4E8E\u6807\u8BC6\u6765\u6E90\u6E20\u9053",table:{defaultValue:{summary:"undefined"}}},welcomeMessage:{control:"text",description:"\u6B22\u8FCE\u6D88\u606F",table:{defaultValue:{summary:"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F"}}},logoUrl:{control:"text",description:"Logo URL"},position:{control:"object",description:"\u6C14\u6CE1\u6309\u94AE\u4F4D\u7F6E\u5BF9\u8C61",table:{defaultValue:{summary:'{ bottom: "1.5rem", right: "1.5rem" }'}}}},args:{apiBaseUrl:"http://172.16.38.183:3003",site:"www.eufy.com",loginUserId:"test_test",welcomeMessage:"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F"}};var h=v;const y={args:{loginUserId:"test_test1",apiBaseUrl:"https://beta-api-v2-livechat.anker.com",site:"beta.eufy.com",channelCode:"dtc",title:"eufy AI Assistant",cartId:"gid://shopify/Cart/hWN7wB3Pa12gh78d8hPOAUBI?key=0e73db1d3fb5ac21da19099c45033253",accessToken:"47b1aa2c0797043f9baba39388029d70",position:{bottom:"24px",right:"30px"},welcomeMessage:"",quickReplies:[{id:"1",label:"Product Info",value:"Tell me about your products",icon:"\u{1F4E6}"},{id:"2",label:"Track Order",value:"I want to track my order",icon:"\u{1F69A}"},{id:"3",label:"Support",value:"I need help with my device",icon:"\u{1F527}"},{id:"4",label:"Recommendations",value:"Recommend products for me",icon:"\u2B50"}],complianceConfig:{title:"Hi! I'm your eufy AI assistant.",content:"AI-generated responses can be inaccurate. Please verify important info. Do not input sensitive personal data.",checkboxText:`By starting to use "Live Chat", you agree to Anker's <a href="https://www.anker.com/pages/privacy-policy" target="_blank" rel="noopener noreferrer" style="text-decoration: underline;">LIVE CHAT PRIVACY NOTICE</a>.`,agreeButtonText:"Agree"},recaptchaAction:"livechat",showNewSessionButton:!0,commonText:{learnMore:"Learn More",total:"Total"},customRenderers:{video:{render:t=>{const e=t;return(0,o.jsxs)("div",{className:"w-full",children:[(0,o.jsx)("video",{src:e.url,controls:!0,className:"w-full rounded-lg",poster:e.poster,children:"Your browser does not support video playback"}),e.title&&(0,o.jsx)("p",{className:"mt-2 text-sm text-gray-600",children:e.title})]})}},image_gallery:{render:t=>{const a=t.images||[];return(0,o.jsx)("div",{className:"grid grid-cols-2 gap-2",children:a.map((i,r)=>(0,o.jsx)("div",{className:"relative aspect-square",children:(0,o.jsx)("img",{src:i.url,alt:i.alt||`Image ${r+1}`,className:"size-full rounded-lg object-cover"})},r))})}}},productCardRender:(t,e)=>{if(!t)return(0,o.jsx)("div",{style:{padding:"16px",border:"1px dashed #ccc",borderRadius:"8px",textAlign:"center"},children:(0,o.jsxs)("p",{children:["Product loading... (handle: ",e,")"]})});const a=t?.featured_image||"",i=t?.title||"",r=t?.description||"",l=t?.average_rating;return(0,o.jsx)("div",{style:{border:"2px solid #4CAF50",borderRadius:"16px",padding:"16px",margin:"12px 0",backgroundColor:"#f0f9ff",boxShadow:"0 4px 12px rgba(76, 175, 80, 0.15)"},children:(0,o.jsxs)("div",{style:{display:"flex",gap:"12px",alignItems:"center"},children:[a&&(0,o.jsx)("img",{src:a,alt:i,style:{width:"60px",height:"60px",borderRadius:"8px",objectFit:"cover"}}),(0,o.jsxs)("div",{style:{flex:1},children:[(0,o.jsx)("h4",{style:{margin:"0 0 4px 0",fontSize:"16px",fontWeight:"bold"},children:i}),r&&(0,o.jsxs)("p",{style:{margin:0,fontSize:"12px",color:"#666",lineHeight:1.4},children:[r.slice(0,80),"..."]}),l&&(0,o.jsxs)("span",{style:{fontSize:"12px",color:"#FFB800"},children:["Rating: ",l.toFixed(1)]})]}),(0,o.jsx)("button",{style:{padding:"8px 16px",backgroundColor:"#4CAF50",color:"white",borderRadius:"8px",border:"none",cursor:"pointer"},onClick:()=>console.log("View product:",e,t),children:"View"})]})})}},render:t=>(0,o.jsx)(s.LiveChatWidget,{...t,onOpen:()=>console.log("[LiveChat] Chat opened"),onClose:()=>console.log("[LiveChat] Chat closed"),onMessageSend:e=>console.log("[LiveChat] Message sent:",e),onError:e=>console.error("[LiveChat] Error:",e),onTextMessage:()=>console.log("[LiveChat] AI text message received"),onProductList:()=>console.log("[LiveChat] Product list received"),onPromotionList:()=>console.log("[LiveChat] Promotion list received"),onAddToCart:e=>{console.log("[LiveChat] Add to cart:",e),alert(`Added "${e.title}" to cart!`)},onCart:(e,a)=>{console.log("[LiveChat] Cart clicked:",{cartId:e,checkoutUrl:a}),alert(`Cart ID: ${e}`)}})};
|
|
52
52
|
//# sourceMappingURL=LiveChatWidget.stories.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/stories/LiveChatWidget.stories.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * LiveChatWidget Storybook Stories\n * \u5C55\u793A LiveChat \u7EC4\u4EF6\u7684\u5404\u79CD\u4F7F\u7528\u573A\u666F\u548C\u914D\u7F6E\n */\n\nimport type { Meta, StoryObj } from '@storybook/react'\nimport { LiveChatWidget } from '../components/LiveChatWidget'\nimport type { MessageRenderer, MessageContent } from '../components/LiveChatWidget'\nimport '../styles/livechat.css'\n\nconst meta: Meta<typeof LiveChatWidget> = {\n title: 'Campaign/LiveChatWidget',\n component: LiveChatWidget,\n parameters: {\n layout: 'fullscreen',\n docs: {\n story: {\n inline: false,\n iframeHeight: 500,\n },\n description: {\n component: `\n# LiveChat \u804A\u5929\u7EC4\u4EF6\n\n\u53EF\u590D\u7528\u7684\u6C14\u6CE1\u5F39\u7A97\u804A\u5929\u7EC4\u4EF6\uFF0C\u652F\u6301 SSE \u6D41\u5F0F\u6D88\u606F\u3001\u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\u548C\u591A\u79CD\u6D88\u606F\u7C7B\u578B\u3002\n\n## \u529F\u80FD\u7279\u6027\n\n- \uD83C\uDF88 **\u6C14\u6CE1\u5F39\u7A97**: \u53EF\u81EA\u5B9A\u4E49\u4F4D\u7F6E\u7684\u60AC\u6D6E\u6C14\u6CE1\u6309\u94AE\n- \uD83D\uDCAC **\u6D41\u5F0F\u6D88\u606F**: \u57FA\u4E8E SSE \u7684\u5B9E\u65F6\u6D41\u5F0F\u54CD\u5E94\n- \uD83D\uDCE6 **\u591A\u79CD\u6D88\u606F\u7C7B\u578B**: \u6587\u672C\u3001\u5546\u54C1\u5361\u7247\u3001\u5546\u54C1\u5217\u8868\u3001\u653F\u7B56\u3001\u5FEB\u6377\u56DE\u590D\u7B49\n- \uD83C\uDFA8 **\u53EF\u5B9A\u5236**: \u652F\u6301\u81EA\u5B9A\u4E49\u54C1\u724C\u989C\u8272\u3001Logo\u3001\u6E32\u67D3\u5668\n- \uD83D\uDCF1 **\u54CD\u5E94\u5F0F**: \u79FB\u52A8\u7AEF\u5168\u5C4F\uFF0C\u684C\u9762\u7AEF\u56FA\u5B9A\u5C3A\u5BF8\n- \uD83D\uDCBE **\u4F1A\u8BDD\u7BA1\u7406**: \u81EA\u52A8\u7BA1\u7406 userId \u548C sessionId\n- \uD83D\uDD12 **\u5B89\u5168\u9632\u62A4**: \u5185\u7F6E XSS \u9632\u62A4\u548C\u8F93\u5165\u9A8C\u8BC1\n\n## \u57FA\u7840\u7528\u6CD5\n\n\\`\\`\\`tsx\nimport { LiveChatWidget } from '@anker-in/campaign-ui'\nimport '@anker-in/campaign-ui/livechat.css'\n\nfunction App() {\n return (\n <LiveChatWidget\n apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n site=\"www.eufy.com\"\n channel_code=\"web_homepage\"\n welcomeMessage=\"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\"\n />\n )\n}\n\\`\\`\\`\n\n## \u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\n\n\\`\\`\\`tsx\nconst customRenderers = {\n video: {\n render: (content) => (\n <video src={content.url} controls className=\"w-full rounded\" />\n )\n }\n}\n\n<LiveChatWidget\n apiBaseUrl=\"...\"\n site=\"...\"\n customRenderers={customRenderers}\n/>\n\\`\\`\\`\n `,\n },\n },\n },\n tags: ['autodocs'],\n argTypes: {\n apiBaseUrl: {\n control: 'text',\n description: 'API \u57FA\u7840 URL',\n },\n headers: {\n control: 'object',\n description: '\u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\uFF0C\u5C06\u5728\u6240\u6709 API \u8BF7\u6C42\u4E2D\u6DFB\u52A0',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n recaptchaSitekey: {\n control: 'text',\n description: 'Google reCAPTCHA v3 site key\uFF0C\u63D0\u4F9B\u6B64\u53C2\u6570\u5C06\u81EA\u52A8\u542F\u7528 reCAPTCHA v3 \u9A8C\u8BC1',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n recaptchaAction: {\n control: 'text',\n description: 'reCAPTCHA action \u540D\u79F0\uFF0C\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7684\u9A8C\u8BC1\u573A\u666F',\n table: {\n defaultValue: { summary: '\"activity\"' },\n },\n },\n site: {\n control: 'text',\n description: 'Shopify \u5E97\u94FA URL',\n },\n channelCode: {\n control: 'text',\n description: '\u6E20\u9053\u7F16\u7801\uFF0C\u7528\u4E8E\u6807\u8BC6\u6765\u6E90\u6E20\u9053',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n welcomeMessage: {\n control: 'text',\n description: '\u6B22\u8FCE\u6D88\u606F',\n table: {\n defaultValue: { summary: '\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F' },\n },\n },\n logoUrl: {\n control: 'text',\n description: 'Logo URL',\n },\n position: {\n control: 'object',\n description: '\u6C14\u6CE1\u6309\u94AE\u4F4D\u7F6E\u5BF9\u8C61',\n table: {\n defaultValue: { summary: '{ bottom: \"1.5rem\", right: \"1.5rem\" }' },\n },\n },\n },\n args: {\n apiBaseUrl: 'http://172.16.38.183:3003',\n site: 'www.eufy.com',\n loginUserId: 'test_test',\n welcomeMessage: '\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F',\n },\n}\n\nexport default meta\ntype Story = StoryObj<typeof LiveChatWidget>\n\n/**\n * \u9ED8\u8BA4\u914D\u7F6E - \u5C55\u793A\u6240\u6709\u529F\u80FD\n */\nexport const Default: Story = {\n args: {\n // \u57FA\u7840\u914D\u7F6E\n loginUserId: 'test_test1',\n apiBaseUrl: 'http://172.16.38.183:3003',\n site: 'beta.eufy.com',\n channelCode: 'dtc',\n title: 'eufy AI Assistant',\n cartId: 'gid://shopify/Cart/hWN7wB3Pa12gh78d8hPOAUBI?key=0e73db1d3fb5ac21da19099c45033253',\n accessToken: '47b1aa2c0797043f9baba39388029d70',\n\n // \u81EA\u5B9A\u4E49\u4F4D\u7F6E\n position: { bottom: '24px', right: '30px' },\n\n // \u6B22\u8FCE\u6D88\u606F\n welcomeMessage: '',\n\n // \u5FEB\u6377\u56DE\u590D\n quickReplies: [\n { id: '1', label: 'Product Info', value: 'Tell me about your products', icon: '\uD83D\uDCE6' },\n { id: '2', label: 'Track Order', value: 'I want to track my order', icon: '\uD83D\uDE9A' },\n { id: '3', label: 'Support', value: 'I need help with my device', icon: '\uD83D\uDD27' },\n { id: '4', label: 'Recommendations', value: 'Recommend products for me', icon: '\u2B50' },\n ],\n\n // \u6CD5\u89C4\u534F\u8BAE\u5F39\u7A97\n complianceConfig: {\n title: \"Hi! I'm your eufy AI assistant.\",\n content:\n 'AI-generated responses can be inaccurate. Please verify important info. Do not input sensitive personal data.',\n checkboxText:\n 'By starting to use \"Live Chat\", you agree to Anker\\'s <a href=\"https://www.anker.com/pages/privacy-policy\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"text-decoration: underline;\">LIVE CHAT PRIVACY NOTICE</a>.',\n agreeButtonText: 'Agree',\n },\n\n // reCAPTCHA \u914D\u7F6E\uFF08\u53D6\u6D88\u6CE8\u91CA\u4EE5\u542F\u7528\uFF09\n // recaptchaSitekey: '6LfS4J4pAAAAACX1e_WrxutmxxzCK7FU4WzVqL14',\n recaptchaAction: 'livechat',\n\n // \u663E\u793A\u65B0\u4F1A\u8BDD\u6309\u94AE\n showNewSessionButton: true,\n\n // \u81EA\u5B9A\u4E49\u6587\u6848\n commonText: {\n learnMore: 'Learn More',\n total: 'Total',\n },\n\n // \u81EA\u5B9A\u4E49\u6D88\u606F\u6E32\u67D3\u5668\n customRenderers: {\n video: {\n render: (content: MessageContent) => {\n const videoContent = content as any\n return (\n <div className=\"w-full\">\n <video src={videoContent.url} controls className=\"w-full rounded-lg\" poster={videoContent.poster}>\n Your browser does not support video playback\n </video>\n {videoContent.title && <p className=\"mt-2 text-sm text-gray-600\">{videoContent.title}</p>}\n </div>\n )\n },\n } as MessageRenderer,\n image_gallery: {\n render: (content: MessageContent) => {\n const galleryContent = content as any\n const images = galleryContent.images || []\n return (\n <div className=\"grid grid-cols-2 gap-2\">\n {images.map((image: any, index: number) => (\n <div key={index} className=\"relative aspect-square\">\n <img\n src={image.url}\n alt={image.alt || `Image ${index + 1}`}\n className=\"size-full rounded-lg object-cover\"\n />\n </div>\n ))}\n </div>\n )\n },\n } as MessageRenderer,\n },\n\n // \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5361\u7247\u6E32\u67D3\n productCardRender: (product, productHandle) => {\n // product \u53EF\u80FD\u4E3A undefined\uFF0C\u6B64\u65F6\u53EF\u7528 productHandle \u67E5\u8BE2\n if (!product) {\n return (\n <div style={{ padding: '16px', border: '1px dashed #ccc', borderRadius: '8px', textAlign: 'center' }}>\n <p>Product loading... (handle: {productHandle})</p>\n </div>\n )\n }\n\n const imageUrl = product?.featured_image || ''\n const title = product?.title || ''\n const description = product?.description || ''\n const averageRating = product?.average_rating\n\n return (\n <div\n style={{\n border: '2px solid #4CAF50',\n borderRadius: '16px',\n padding: '16px',\n margin: '12px 0',\n backgroundColor: '#f0f9ff',\n boxShadow: '0 4px 12px rgba(76, 175, 80, 0.15)',\n }}\n >\n <div style={{ display: 'flex', gap: '12px', alignItems: 'center' }}>\n {imageUrl && (\n <img\n src={imageUrl}\n alt={title}\n style={{ width: '60px', height: '60px', borderRadius: '8px', objectFit: 'cover' }}\n />\n )}\n <div style={{ flex: 1 }}>\n <h4 style={{ margin: '0 0 4px 0', fontSize: '16px', fontWeight: 'bold' }}>{title}</h4>\n {description && (\n <p style={{ margin: 0, fontSize: '12px', color: '#666', lineHeight: 1.4 }}>\n {description.slice(0, 80)}...\n </p>\n )}\n {averageRating && (\n <span style={{ fontSize: '12px', color: '#FFB800' }}>Rating: {averageRating.toFixed(1)}</span>\n )}\n </div>\n <button\n style={{\n padding: '8px 16px',\n backgroundColor: '#4CAF50',\n color: 'white',\n borderRadius: '8px',\n border: 'none',\n cursor: 'pointer',\n }}\n onClick={() => console.log('View product:', productHandle, product)}\n >\n View\n </button>\n </div>\n </div>\n )\n },\n },\n\n render: args => (\n <LiveChatWidget\n {...args}\n // \u6240\u6709\u4E8B\u4EF6\u56DE\u8C03\n onOpen={() => console.log('[LiveChat] Chat opened')}\n onClose={() => console.log('[LiveChat] Chat closed')}\n onMessageSend={(message: string) => console.log('[LiveChat] Message sent:', message)}\n onError={(error: Error) => console.error('[LiveChat] Error:', error)}\n onTextMessage={() => console.log('[LiveChat] AI text message received')}\n onProductList={() => console.log('[LiveChat] Product list received')}\n onPromotionList={() => console.log('[LiveChat] Promotion list received')}\n onAddToCart={(product: any) => {\n console.log('[LiveChat] Add to cart:', product)\n alert(`Added \"${product.title}\" to cart!`)\n }}\n onCart={(cartId: string, checkoutUrl?: string) => {\n console.log('[LiveChat] Cart clicked:', { cartId, checkoutUrl })\n alert(`Cart ID: ${cartId}`)\n }}\n />\n ),\n}\n"],
|
|
5
|
-
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,EAAA,YAAAC,IAAA,eAAAC,EAAAJ,GAwMY,IAAAK,EAAA,6BAlMZC,EAA+B,wCAE/BC,EAAO,kCAEP,MAAMC,EAAoC,CACxC,MAAO,0BACP,UAAW,iBACX,WAAY,CACV,OAAQ,aACR,KAAM,CACJ,MAAO,CACL,OAAQ,GACR,aAAc,GAChB,EACA,YAAa,CACX,UAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAmDb,CACF,CACF,EACA,KAAM,CAAC,UAAU,EACjB,SAAU,CACR,WAAY,CACV,QAAS,OACT,YAAa,sBACf,EACA,QAAS,CACP,QAAS,SACT,YAAa,wGACb,MAAO,CACL,aAAc,CAAE,QAAS,WAAY,CACvC,CACF,EACA,iBAAkB,CAChB,QAAS,OACT,YAAa,2HACb,MAAO,CACL,aAAc,CAAE,QAAS,WAAY,CACvC,CACF,EACA,gBAAiB,CACf,QAAS,OACT,YAAa,wGACb,MAAO,CACL,aAAc,CAAE,QAAS,YAAa,CACxC,CACF,EACA,KAAM,CACJ,QAAS,OACT,YAAa,0BACf,EACA,YAAa,CACX,QAAS,OACT,YAAa,iFACb,MAAO,CACL,aAAc,CAAE,QAAS,WAAY,CACvC,CACF,EACA,eAAgB,CACd,QAAS,OACT,YAAa,2BACb,MAAO,CACL,aAAc,CAAE,QAAS,wHAA0B,CACrD,CACF,EACA,QAAS,CACP,QAAS,OACT,YAAa,UACf,EACA,SAAU,CACR,QAAS,SACT,YAAa,mDACb,MAAO,CACL,aAAc,CAAE,QAAS,uCAAwC,CACnE,CACF,CACF,EACA,KAAM,CACJ,WAAY,4BACZ,KAAM,eACN,YAAa,YACb,eAAgB,wHAClB,CACF,EAEA,IAAOL,EAAQK,EAMR,MAAMN,EAAiB,CAC5B,KAAM,CAEJ,YAAa,aACb,WAAY,
|
|
4
|
+
"sourcesContent": ["/**\n * LiveChatWidget Storybook Stories\n * \u5C55\u793A LiveChat \u7EC4\u4EF6\u7684\u5404\u79CD\u4F7F\u7528\u573A\u666F\u548C\u914D\u7F6E\n */\n\nimport type { Meta, StoryObj } from '@storybook/react'\nimport { LiveChatWidget } from '../components/LiveChatWidget'\nimport type { MessageRenderer, MessageContent } from '../components/LiveChatWidget'\nimport '../styles/livechat.css'\n\nconst meta: Meta<typeof LiveChatWidget> = {\n title: 'Campaign/LiveChatWidget',\n component: LiveChatWidget,\n parameters: {\n layout: 'fullscreen',\n docs: {\n story: {\n inline: false,\n iframeHeight: 500,\n },\n description: {\n component: `\n# LiveChat \u804A\u5929\u7EC4\u4EF6\n\n\u53EF\u590D\u7528\u7684\u6C14\u6CE1\u5F39\u7A97\u804A\u5929\u7EC4\u4EF6\uFF0C\u652F\u6301 SSE \u6D41\u5F0F\u6D88\u606F\u3001\u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\u548C\u591A\u79CD\u6D88\u606F\u7C7B\u578B\u3002\n\n## \u529F\u80FD\u7279\u6027\n\n- \uD83C\uDF88 **\u6C14\u6CE1\u5F39\u7A97**: \u53EF\u81EA\u5B9A\u4E49\u4F4D\u7F6E\u7684\u60AC\u6D6E\u6C14\u6CE1\u6309\u94AE\n- \uD83D\uDCAC **\u6D41\u5F0F\u6D88\u606F**: \u57FA\u4E8E SSE \u7684\u5B9E\u65F6\u6D41\u5F0F\u54CD\u5E94\n- \uD83D\uDCE6 **\u591A\u79CD\u6D88\u606F\u7C7B\u578B**: \u6587\u672C\u3001\u5546\u54C1\u5361\u7247\u3001\u5546\u54C1\u5217\u8868\u3001\u653F\u7B56\u3001\u5FEB\u6377\u56DE\u590D\u7B49\n- \uD83C\uDFA8 **\u53EF\u5B9A\u5236**: \u652F\u6301\u81EA\u5B9A\u4E49\u54C1\u724C\u989C\u8272\u3001Logo\u3001\u6E32\u67D3\u5668\n- \uD83D\uDCF1 **\u54CD\u5E94\u5F0F**: \u79FB\u52A8\u7AEF\u5168\u5C4F\uFF0C\u684C\u9762\u7AEF\u56FA\u5B9A\u5C3A\u5BF8\n- \uD83D\uDCBE **\u4F1A\u8BDD\u7BA1\u7406**: \u81EA\u52A8\u7BA1\u7406 userId \u548C sessionId\n- \uD83D\uDD12 **\u5B89\u5168\u9632\u62A4**: \u5185\u7F6E XSS \u9632\u62A4\u548C\u8F93\u5165\u9A8C\u8BC1\n\n## \u57FA\u7840\u7528\u6CD5\n\n\\`\\`\\`tsx\nimport { LiveChatWidget } from '@anker-in/campaign-ui'\nimport '@anker-in/campaign-ui/livechat.css'\n\nfunction App() {\n return (\n <LiveChatWidget\n apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n site=\"www.eufy.com\"\n channel_code=\"web_homepage\"\n welcomeMessage=\"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\"\n />\n )\n}\n\\`\\`\\`\n\n## \u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\n\n\\`\\`\\`tsx\nconst customRenderers = {\n video: {\n render: (content) => (\n <video src={content.url} controls className=\"w-full rounded\" />\n )\n }\n}\n\n<LiveChatWidget\n apiBaseUrl=\"...\"\n site=\"...\"\n customRenderers={customRenderers}\n/>\n\\`\\`\\`\n `,\n },\n },\n },\n tags: ['autodocs'],\n argTypes: {\n apiBaseUrl: {\n control: 'text',\n description: 'API \u57FA\u7840 URL',\n },\n headers: {\n control: 'object',\n description: '\u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\uFF0C\u5C06\u5728\u6240\u6709 API \u8BF7\u6C42\u4E2D\u6DFB\u52A0',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n recaptchaSitekey: {\n control: 'text',\n description: 'Google reCAPTCHA v3 site key\uFF0C\u63D0\u4F9B\u6B64\u53C2\u6570\u5C06\u81EA\u52A8\u542F\u7528 reCAPTCHA v3 \u9A8C\u8BC1',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n recaptchaAction: {\n control: 'text',\n description: 'reCAPTCHA action \u540D\u79F0\uFF0C\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7684\u9A8C\u8BC1\u573A\u666F',\n table: {\n defaultValue: { summary: '\"activity\"' },\n },\n },\n site: {\n control: 'text',\n description: 'Shopify \u5E97\u94FA URL',\n },\n channelCode: {\n control: 'text',\n description: '\u6E20\u9053\u7F16\u7801\uFF0C\u7528\u4E8E\u6807\u8BC6\u6765\u6E90\u6E20\u9053',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n welcomeMessage: {\n control: 'text',\n description: '\u6B22\u8FCE\u6D88\u606F',\n table: {\n defaultValue: { summary: '\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F' },\n },\n },\n logoUrl: {\n control: 'text',\n description: 'Logo URL',\n },\n position: {\n control: 'object',\n description: '\u6C14\u6CE1\u6309\u94AE\u4F4D\u7F6E\u5BF9\u8C61',\n table: {\n defaultValue: { summary: '{ bottom: \"1.5rem\", right: \"1.5rem\" }' },\n },\n },\n },\n args: {\n apiBaseUrl: 'http://172.16.38.183:3003',\n site: 'www.eufy.com',\n loginUserId: 'test_test',\n welcomeMessage: '\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F',\n },\n}\n\nexport default meta\ntype Story = StoryObj<typeof LiveChatWidget>\n\n/**\n * \u9ED8\u8BA4\u914D\u7F6E - \u5C55\u793A\u6240\u6709\u529F\u80FD\n */\nexport const Default: Story = {\n args: {\n // \u57FA\u7840\u914D\u7F6E\n loginUserId: 'test_test1',\n apiBaseUrl: 'https://beta-api-v2-livechat.anker.com',\n site: 'beta.eufy.com',\n channelCode: 'dtc',\n title: 'eufy AI Assistant',\n cartId: 'gid://shopify/Cart/hWN7wB3Pa12gh78d8hPOAUBI?key=0e73db1d3fb5ac21da19099c45033253',\n accessToken: '47b1aa2c0797043f9baba39388029d70',\n\n // \u81EA\u5B9A\u4E49\u4F4D\u7F6E\n position: { bottom: '24px', right: '30px' },\n\n // \u6B22\u8FCE\u6D88\u606F\n welcomeMessage: '',\n\n // \u5FEB\u6377\u56DE\u590D\n quickReplies: [\n { id: '1', label: 'Product Info', value: 'Tell me about your products', icon: '\uD83D\uDCE6' },\n { id: '2', label: 'Track Order', value: 'I want to track my order', icon: '\uD83D\uDE9A' },\n { id: '3', label: 'Support', value: 'I need help with my device', icon: '\uD83D\uDD27' },\n { id: '4', label: 'Recommendations', value: 'Recommend products for me', icon: '\u2B50' },\n ],\n\n // \u6CD5\u89C4\u534F\u8BAE\u5F39\u7A97\n complianceConfig: {\n title: \"Hi! I'm your eufy AI assistant.\",\n content:\n 'AI-generated responses can be inaccurate. Please verify important info. Do not input sensitive personal data.',\n checkboxText:\n 'By starting to use \"Live Chat\", you agree to Anker\\'s <a href=\"https://www.anker.com/pages/privacy-policy\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"text-decoration: underline;\">LIVE CHAT PRIVACY NOTICE</a>.',\n agreeButtonText: 'Agree',\n },\n\n // reCAPTCHA \u914D\u7F6E\uFF08\u53D6\u6D88\u6CE8\u91CA\u4EE5\u542F\u7528\uFF09\n // recaptchaSitekey: '6LfS4J4pAAAAACX1e_WrxutmxxzCK7FU4WzVqL14',\n recaptchaAction: 'livechat',\n\n // \u663E\u793A\u65B0\u4F1A\u8BDD\u6309\u94AE\n showNewSessionButton: true,\n\n // \u81EA\u5B9A\u4E49\u6587\u6848\n commonText: {\n learnMore: 'Learn More',\n total: 'Total',\n },\n\n // \u81EA\u5B9A\u4E49\u6D88\u606F\u6E32\u67D3\u5668\n customRenderers: {\n video: {\n render: (content: MessageContent) => {\n const videoContent = content as any\n return (\n <div className=\"w-full\">\n <video src={videoContent.url} controls className=\"w-full rounded-lg\" poster={videoContent.poster}>\n Your browser does not support video playback\n </video>\n {videoContent.title && <p className=\"mt-2 text-sm text-gray-600\">{videoContent.title}</p>}\n </div>\n )\n },\n } as MessageRenderer,\n image_gallery: {\n render: (content: MessageContent) => {\n const galleryContent = content as any\n const images = galleryContent.images || []\n return (\n <div className=\"grid grid-cols-2 gap-2\">\n {images.map((image: any, index: number) => (\n <div key={index} className=\"relative aspect-square\">\n <img\n src={image.url}\n alt={image.alt || `Image ${index + 1}`}\n className=\"size-full rounded-lg object-cover\"\n />\n </div>\n ))}\n </div>\n )\n },\n } as MessageRenderer,\n },\n\n // \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5361\u7247\u6E32\u67D3\n productCardRender: (product, productHandle) => {\n // product \u53EF\u80FD\u4E3A undefined\uFF0C\u6B64\u65F6\u53EF\u7528 productHandle \u67E5\u8BE2\n if (!product) {\n return (\n <div style={{ padding: '16px', border: '1px dashed #ccc', borderRadius: '8px', textAlign: 'center' }}>\n <p>Product loading... (handle: {productHandle})</p>\n </div>\n )\n }\n\n const imageUrl = product?.featured_image || ''\n const title = product?.title || ''\n const description = product?.description || ''\n const averageRating = product?.average_rating\n\n return (\n <div\n style={{\n border: '2px solid #4CAF50',\n borderRadius: '16px',\n padding: '16px',\n margin: '12px 0',\n backgroundColor: '#f0f9ff',\n boxShadow: '0 4px 12px rgba(76, 175, 80, 0.15)',\n }}\n >\n <div style={{ display: 'flex', gap: '12px', alignItems: 'center' }}>\n {imageUrl && (\n <img\n src={imageUrl}\n alt={title}\n style={{ width: '60px', height: '60px', borderRadius: '8px', objectFit: 'cover' }}\n />\n )}\n <div style={{ flex: 1 }}>\n <h4 style={{ margin: '0 0 4px 0', fontSize: '16px', fontWeight: 'bold' }}>{title}</h4>\n {description && (\n <p style={{ margin: 0, fontSize: '12px', color: '#666', lineHeight: 1.4 }}>\n {description.slice(0, 80)}...\n </p>\n )}\n {averageRating && (\n <span style={{ fontSize: '12px', color: '#FFB800' }}>Rating: {averageRating.toFixed(1)}</span>\n )}\n </div>\n <button\n style={{\n padding: '8px 16px',\n backgroundColor: '#4CAF50',\n color: 'white',\n borderRadius: '8px',\n border: 'none',\n cursor: 'pointer',\n }}\n onClick={() => console.log('View product:', productHandle, product)}\n >\n View\n </button>\n </div>\n </div>\n )\n },\n },\n\n render: args => (\n <LiveChatWidget\n {...args}\n // \u6240\u6709\u4E8B\u4EF6\u56DE\u8C03\n onOpen={() => console.log('[LiveChat] Chat opened')}\n onClose={() => console.log('[LiveChat] Chat closed')}\n onMessageSend={(message: string) => console.log('[LiveChat] Message sent:', message)}\n onError={(error: Error) => console.error('[LiveChat] Error:', error)}\n onTextMessage={() => console.log('[LiveChat] AI text message received')}\n onProductList={() => console.log('[LiveChat] Product list received')}\n onPromotionList={() => console.log('[LiveChat] Promotion list received')}\n onAddToCart={(product: any) => {\n console.log('[LiveChat] Add to cart:', product)\n alert(`Added \"${product.title}\" to cart!`)\n }}\n onCart={(cartId: string, checkoutUrl?: string) => {\n console.log('[LiveChat] Cart clicked:', { cartId, checkoutUrl })\n alert(`Cart ID: ${cartId}`)\n }}\n />\n ),\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["LiveChatWidget_stories_exports", "__export", "Default", "LiveChatWidget_stories_default", "__toCommonJS", "import_jsx_runtime", "import_LiveChatWidget", "import_livechat", "meta", "content", "videoContent", "images", "image", "index", "product", "productHandle", "imageUrl", "title", "description", "averageRating", "args", "message", "error", "cartId", "checkoutUrl"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Fragment as
|
|
1
|
+
import{Fragment as st,jsx as x,jsxs as at}from"react/jsx-runtime";import f,{useEffect as Be,useCallback as w}from"react";import*as G from"@radix-ui/react-dialog";import{DEFAULT_COMMON_TEXT as Le}from"./constants";import{ChatBubble as We}from"./components/ChatBubble";import{ChatWindow as Ne}from"./components/ChatWindow";import{ComplianceDialog as $e}from"./components/ComplianceDialog";import{useChatState as ke}from"./hooks/useChatState";import{useChatAPI as ze}from"./hooks/useChatAPI";import{MessageRendererRegistry as Qe}from"./utils/messageRenderers";import{sanitizeInput as He}from"./utils/validation";import{saveUserId as re}from"./utils/userId";import{transformProducts as ie}from"./utils/productTransformers.js";import{transformCartData as Ye}from"./utils/cartTransformers.js";import oe from"js-cookie";import{TextBlock as Ge,ProductCard as Ve,ProductList as Xe,ProductComparisonRenderer as Ke,PolicyBlock as Je,createQuickRepliesRenderer as Ze,ThinkingBlock as je,ErrorBlock as Ue,FAQListRenderer as be,PromotionListRenderer as et,CartCard as tt}from"./components/MessageContent/index.js";const _t=({apiBaseUrl:de,headers:ce,recaptchaSitekey:V,recaptchaAction:le,site:i,channelCode:m,loginUserId:p,cartId:X,accessToken:K,position:pe,welcomeMessage:g,quickReplies:u,customRenderers:B,logoUrl:ue,title:fe,chatBubbleIcon:me,open:ge,onOpenChange:he,onOpen:ye,onClose:_e,onMessageSend:L,onError:h,onTextMessage:we,onProductList:Ce,onPromotionList:Re,onAddToCart:M,onCart:W,showNewSessionButton:xe,commonText:J,productCardRender:Se,productComparisonRender:Z,bottomTips:De,complianceConfig:C})=>{const N=C?.cookieName||"livechat_compliance_agreed",[j,$]=f.useState(!1),[U,Ee]=f.useState(()=>C?oe.get(N)!==void 0:!0),S=f.useMemo(()=>({...Le,...J}),[J]),Pe=ke({welcomeMessage:g,site:i,open:ge,onOpenChange:he,onOpen:ye,onClose:_e,onMessageSend:L,onError:h,onTextMessage:we,onProductList:Ce,onPromotionList:Re,onAddToCart:M,onCart:W,productCardRender:Se,productComparisonRender:Z}),{messages:T,isOpen:v,userId:o,sessionId:k,inputValue:z,isStreaming:Ie,openChat:D,closeChat:b,setInputValue:Q,setUserId:ee,addMessage:l,setMessages:R,clearMessages:A,handleSSEEvent:te,saveSession:E,clearSession:P}=Pe,[Me,q]=f.useState(!1),{sendMessageStream:se,createSession:y}=ze({apiBaseUrl:de,headers:ce,recaptchaConfig:{needRecaptcha:!!V,recaptchaSitekey:V,recaptchaAction:le},onError:h}),ae=f.useRef(async e=>{}),Te=f.useMemo(()=>{const e=new Qe;e.register("text",Ge),e.register("product_card",Ve),e.register("product_list",Xe),e.register("product_comparison",Ke),e.register("policy",Je),e.register("thinking",je),e.register("error",Ue),e.register("faq_list",be),e.register("promotion_list",et),e.register("cart",tt);const s=Ze(n=>{ae.current(n.value)});return e.register("quick_replies",s),B&&e.registerMany(B),e},[B]),H=f.useRef(!1);Be(()=>{if(!v){H.current=!1;return}if(o===void 0||H.current)return;H.current=!0;const e=k;e?ve(e):I()},[v,o]);const ne=w(e=>{if(Array.isArray(e.content))return e;const s=[];typeof e.content=="string"&&e.content.trim()&&s.push({type:"text",text:e.content});const n=e.structuredContent||e.structured_content;return Array.isArray(n)&&n.forEach(t=>{if(t.type==="product_list"&&Array.isArray(t.data))s.push({type:"product_list",data:{products:ie(t.data,i),title:void 0,commonText:S}});else if(t.type==="quick_replies"&&t.data?.replies)s.push({type:"quick_replies",data:{replies:t.data.replies}});else if(t.type==="policy"&&t.data?.title&&t.data?.content)s.push({type:"policy",data:{title:t.data.title,content:t.data.content}});else if(t.type==="product_comparison"&&t.data?.products&&t.data?.dimensions)s.push({type:"product_comparison",data:{products:ie(t.data.products,i),dimensions:t.data.dimensions,onAddToCart:M,commonText:S,productComparisonRender:Z}});else if(t.type==="faq_list"&&t.data?.found!==void 0)s.push({type:"faq_list",data:t.data});else if(t.type==="promotion_list"&&t.data?.found!==void 0)s.push({type:"promotion_list",data:{...t.data,commonText:S}});else if(t.type==="cart"&&t.data?.id!==void 0){const d=Ye(t.data);s.push({type:"cart",data:{...d,onCart:W,commonText:S}})}else s.push(t)}),s.length===0&&s.push({type:"text",text:""}),{...e,content:s}},[i,W,M,S]),I=w(async()=>{if(o!==void 0){g||q(!0);try{const e=await y({user_id:o??"",site:i,channel_code:m,real_user_id:p,page_url:typeof window<"u"?window.location.href:void 0});if(e.success){E(e.sessionId),e.userId&&(re(e.userId),ee(e.userId)),A();const s=e.welcomeMessage||g;if(s){const n=[{type:"text",text:s}],t=e.quickQuestions;if(t&&t.length>0){const d=t.map((c,a)=>({id:`quick-${a}`,label:c,value:c}));n.push({type:"quick_replies",data:{replies:d}})}else u&&u.length>0&&n.push({type:"quick_replies",data:{replies:u}});l({id:`welcome-${Date.now()}`,role:"assistant",content:n,timestamp:Date.now()})}}}catch(e){console.error("[LiveChatWidget] Failed to create new session:",e),h?.(e);const s=e?.type==="GoogleRecaptchaError";l({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{q(!1)}}},[o,i,m,p,y,E,A,g,u,l,h]),ve=w(async e=>{g||q(!0);try{const s=await y({user_id:o??"",session_id:e,site:i,channel_code:m,real_user_id:p,page_url:typeof window<"u"?window.location.href:void 0});if(s.success&&s.resumed){s.userId&&(re(s.userId),ee(s.userId));const n=s.welcomeMessage||g,t=n?[{type:"text",text:n}]:[],d=s.quickQuestions;if(d&&d.length>0){const c=d.map((a,F)=>({id:`quick-${F}`,label:a,value:a}));t.push({type:"quick_replies",data:{replies:c}})}else u&&u.length>0&&t.push({type:"quick_replies",data:{replies:u}});if(s.messages&&s.messages.length>0){const c=s.messages.filter(a=>a!=null).map(ne).filter(a=>a.content&&a.content.length>0&&!(a.content.length===1&&a.content[0].type==="text"&&!a.content[0].text));if(t.length>0){const a={id:`welcome-${Date.now()}`,role:"assistant",content:t,timestamp:Date.now()};R([a,...c])}else R(c)}else A(),t.length>0&&l({id:`welcome-${Date.now()}`,role:"assistant",content:t,timestamp:Date.now()})}else s.resumed||(P(),I())}catch(s){console.error("[LiveChatWidget] Failed to resume session:",s),s?.type==="GoogleRecaptchaError"?l({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()}):(l({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()}),P(),I())}finally{q(!1)}},[o,i,m,p,y,R,P,A,ne,I,g,u,l]),O=w(async(e,s=!1)=>{const n=e||z.trim();if(!n)return;!e&&!s&&Q("");const t=He(n);if(!t){h?.(new Error("Invalid message"));return}if(!s){const a={id:`user-${Date.now()}`,role:"user",content:[{type:"text",text:t}],timestamp:Date.now()};l(a)}const d={id:`thinking-${Date.now()}`,role:"assistant",content:[{type:"thinking",data:{status:"thinking"}}],timestamp:Date.now()};l(d),s||L?.(t);let c=!1;try{let a=k;if(!a){const r=await y({user_id:o??"",site:i,channel_code:m,real_user_id:p,page_url:typeof window<"u"?window.location.href:void 0});if(r.success)a=r.sessionId,E(a);else throw new Error("Failed to create session")}if(await se({message:t,user_id:o??"",session_id:a,context:{cartId:X,accessToken:K,real_user_id:p}},r=>{te(r),r.event==="error"&&r.data.type==="validation_error"&&(c=!0,P())}),c&&!s){console.log("[LiveChatWidget] Session expired (validation_error), creating new session and retrying...");const r=T.filter(Y=>Y.id!==d.id);R(r);const _=await y({user_id:o??"",site:i,channel_code:m,real_user_id:p,page_url:typeof window<"u"?window.location.href:void 0});if(_.success)E(_.sessionId),await O(t,!0);else throw new Error("Failed to recreate session after expiration")}}catch(a){console.error("[LiveChatWidget] Failed to send message:",a),h?.(a);const F=a?.type==="GoogleRecaptchaError";let r,_;F?(r="Your session has expired. Please refresh the page and try again.",_="RECAPTCHA_ERROR"):c?(r="Your session has expired. We tried to reconnect but failed. Please try again.",_="SESSION_EXPIRED"):(r="Failed to send message. Please check your network connection and try again.",_="NETWORK_ERROR");const Y=T.filter(Fe=>Fe.id!==d.id);R([...Y,{id:`error-${Date.now()}`,role:"system",content:[{type:"error",data:{message:r,code:_}}],timestamp:Date.now()}])}},[z,o,k,i,m,p,X,K,T,Q,l,R,y,se,te,E,P,L,h]);f.useEffect(()=>{ae.current=O},[O]);const Ae=w(()=>{C&&!U?$(!0):D()},[C,U,D]),qe=w(()=>{Ee(!0),$(!1),oe.set(N,"true",{expires:365}),D()},[D,N]),Oe=w(()=>{$(!1)},[]);return at(st,{children:[C&&x($e,{open:j,config:C,onAgree:qe,onClose:Oe}),x(We,{position:pe,onClick:Ae,visible:!v&&!j,iconImageUrl:me}),x(G.Root,{open:v,onOpenChange:e=>e?D():b(),children:x(G.Portal,{children:x(G.Content,{className:"livechat-window-enter",style:{position:"fixed",zIndex:9998},children:x(Ne,{messages:T,inputValue:z,onInputChange:Q,onSend:()=>O(),onClose:b,onNewSession:I,title:fe,logoUrl:ue,isSending:Ie,isLoadingHistory:Me,rendererRegistry:Te,inputPlaceholder:"",onAddToCart:M,showNewSessionButton:xe,bottomTips:De})})})})]})};export{_t as LiveChatWidget};
|
|
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 // \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": ["Fragment", "jsx", "jsxs", "React", "useEffect", "useCallback", "Dialog", "DEFAULT_COMMON_TEXT", "ChatBubble", "ChatWindow", "ComplianceDialog", "useChatState", "useChatAPI", "MessageRendererRegistry", "sanitizeInput", "transformProducts", "transformCartData", "Cookies", "TextBlock", "ProductCard", "ProductList", "ProductComparisonRenderer", "PolicyBlock", "createQuickRepliesRenderer", "ThinkingBlock", "ErrorBlock", "FAQListRenderer", "PromotionListRenderer", "CartCard", "LiveChatWidget", "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", "hasAgreedCompliance", "setHasAgreedCompliance", "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"]
|
|
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 { saveUserId } from './utils/userId'\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 productComparisonRender,\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 productComparisonRender,\n })\n\n const {\n messages,\n isOpen,\n userId,\n sessionId,\n inputValue,\n isStreaming,\n openChat,\n closeChat,\n setInputValue,\n setUserId,\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 // \u6807\u8BB0\u662F\u5426\u5DF2\u7ECF\u521D\u59CB\u5316\u8FC7\u4F1A\u8BDD\uFF0C\u9632\u6B62\u91CD\u590D\u8C03\u7528\n const sessionInitializedRef = React.useRef(false)\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 // \u7A97\u53E3\u5173\u95ED\u65F6\u91CD\u7F6E\u521D\u59CB\u5316\u6807\u8BB0\n if (!isOpen) {\n sessionInitializedRef.current = false\n return\n }\n\n // userId \u4E3A undefined \u8868\u793A\u5C1A\u672A\u521D\u59CB\u5316\uFF0C\u7B49\u5F85\u521D\u59CB\u5316\u5B8C\u6210\n if (userId === undefined) return\n\n // \u5982\u679C\u5DF2\u7ECF\u521D\u59CB\u5316\u8FC7\uFF0C\u4E0D\u518D\u91CD\u590D\u8C03\u7528\n if (sessionInitializedRef.current) return\n sessionInitializedRef.current = true\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\u548C\u81EA\u5B9A\u4E49\u6E32\u67D3\u51FD\u6570\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 productComparisonRender: productComparisonRender,\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 // userId \u4E3A undefined \u8868\u793A\u5C1A\u672A\u521D\u59CB\u5316\uFF0C\u7B49\u5F85\u521D\u59CB\u5316\u5B8C\u6210\n if (userId === undefined) 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 page_url: typeof window !== 'undefined' ? window.location.href : undefined,\n })\n\n if (response.success) {\n // \u4FDD\u5B58\u65B0\u4F1A\u8BDD ID\n saveSession(response.sessionId)\n\n // \u4FDD\u5B58\u540E\u7AEF\u8FD4\u56DE\u7684 userId\uFF08\u5982\u679C\u6709\uFF09\n if (response.userId) {\n saveUserId(response.userId)\n setUserId(response.userId)\n }\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 page_url: typeof window !== 'undefined' ? window.location.href : undefined,\n })\n\n if (response.success && response.resumed) {\n // \u4F1A\u8BDD\u6062\u590D\u6210\u529F\n\n // \u4FDD\u5B58\u540E\u7AEF\u8FD4\u56DE\u7684 userId\uFF08\u5982\u679C\u6709\uFF09\n if (response.userId) {\n saveUserId(response.userId)\n setUserId(response.userId)\n }\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 page_url: typeof window !== 'undefined' ? window.location.href : undefined,\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 page_url: typeof window !== 'undefined' ? window.location.href : undefined,\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": ["Fragment", "jsx", "jsxs", "React", "useEffect", "useCallback", "Dialog", "DEFAULT_COMMON_TEXT", "ChatBubble", "ChatWindow", "ComplianceDialog", "useChatState", "useChatAPI", "MessageRendererRegistry", "sanitizeInput", "saveUserId", "transformProducts", "transformCartData", "Cookies", "TextBlock", "ProductCard", "ProductList", "ProductComparisonRenderer", "PolicyBlock", "createQuickRepliesRenderer", "ThinkingBlock", "ErrorBlock", "FAQListRenderer", "PromotionListRenderer", "CartCard", "LiveChatWidget", "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", "productComparisonRender", "bottomTips", "complianceConfig", "cookieName", "showComplianceDialog", "setShowComplianceDialog", "hasAgreedCompliance", "setHasAgreedCompliance", "mergedText", "chatState", "messages", "isOpen", "userId", "sessionId", "inputValue", "isStreaming", "openChat", "closeChat", "setInputValue", "setUserId", "addMessage", "setMessages", "clearMessages", "handleSSEEvent", "saveSession", "clearSession", "isInitializing", "setIsInitializing", "sendMessageStream", "createSession", "handleSendMessageRef", "_message", "rendererRegistry", "registry", "quickRepliesRenderer", "reply", "sessionInitializedRef", "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,2 +1,2 @@
|
|
|
1
|
-
import{jsx as t,jsxs as
|
|
1
|
+
import{Fragment as A,jsx as t,jsxs as c}from"react/jsx-runtime";import{useState as T}from"react";import{DEFAULT_COMMON_TEXT as _,CURRENCY_SYMBOLS as I}from"../../constants";const d=(l,a="USD")=>`${I[a]||a}${l}`,M=({data:l,onAddToCart:a,commonText:m})=>{const{products:i,dimensions:g}=l,y={..._,...m},p=i?.filter(e=>e&&e.shopifyId)||[],f=2,D=p.slice(0,f),[x,h]=T(D);if(p.length===0)return null;const N=(e,n)=>{const r=p.find(o=>o.shopifyId===n);if(r){const o=[...x];o[e]=r,h(o)}},C=x.slice(0,f),b=(e,n)=>!e||!e.values||!Array.isArray(e.values)?null:e.values.find(r=>r&&r.product_id===n),k=(e,n)=>n?c("div",{className:"border-b border-[#DADCE0] pb-2",children:[t("div",{className:"mb-1",children:t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#86868C]",children:e==="price"?"has member price":e})}),t("div",{className:"flex gap-4",style:{gap:"36px"},children:C.map((r,o)=>{if(!r||!r.shopifyId)return null;const u=b(n,r.shopifyId);return t("div",{className:"flex-1",children:P(u,n.label)},`comparison-${o}`)})})]}):null,P=(e,n)=>{if(!e)return t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:"-"});if(n.toLowerCase().includes("price")){const r=e?.has_member_price,o=e?.available?e.min===e.max?d(e.min,e.currency):`${d(e.min,e.currency)} - ${d(e.max,e.currency)}`:"-";return t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:r?"Yes":"No"})}if(n.toLowerCase().includes("variant"))return c("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:[e.count||0," ",e.count===1?"variant":"variants"]});if(n.toLowerCase().includes("review")){const r=e.rating||0,o=e.count||0;return c("div",{className:"flex items-center gap-1",children:[c("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:["\u2B50 ",r.toFixed(1)]}),c("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#86868C]",children:["(",o,")"]})]})}return t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:e.display||e.value||"-"})};return c("div",{className:"w-full overflow-hidden rounded-2xl bg-[#F5F6F7]",children:[t("div",{className:"flex p-4",style:{gap:"36px",paddingBottom:"0px"},children:C.map((e,n)=>{if(!e||!e.shopifyId)return null;const r=g.price?b(g.price,e.shopifyId):null,o=e.variants?.[0],u=o?.discount?.has_discount,v=u?o?.discount?.discount_price:null,w=v||r?.min||e.price.amount,F=e.price.amount,R=s=>{s.preventDefault(),s.stopPropagation(),a&&a(e)};return c("div",{className:"flex flex-1 flex-col items-center",children:[t("div",{className:"mb-4 w-full",children:t("select",{value:e.shopifyId,onChange:s=>N(n,s.target.value),className:"w-full rounded-lg border border-[#DADCE0] bg-[#F5F6F7] px-3 py-2 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",style:{appearance:"none",backgroundImage:`url("data:image/svg+xml,%3Csvg width='12' height='8' viewBox='0 0 12 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%231D1D1F' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")`,backgroundRepeat:"no-repeat",backgroundPosition:"right 12px center",paddingRight:"32px"},children:p.map(s=>t("option",{value:s.shopifyId,children:s.title.length>30?`${s.title.slice(0,30)}...`:s.title},s.shopifyId))})}),t("a",{href:e.productUrl,target:"_blank",rel:"noopener noreferrer",className:"mb-4 block w-full max-w-[160px]",children:t("div",{className:"aspect-square w-full overflow-hidden rounded-lg",children:e.imageUrl?t("img",{src:e.imageUrl,alt:e.title,className:"size-full object-contain",loading:"lazy"}):t("div",{className:"flex size-full items-center justify-center text-gray-400",children:t("svg",{className:"size-12",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:t("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"})})})})}),t("div",{className:"mb-4 flex flex-col items-center gap-1",children:c("div",{className:"flex items-center gap-2",children:[t("span",{className:"text-base font-bold leading-[1.2] tracking-[-0.02em] text-[#1D1D1F]",children:d(w,r?.currency||e.price.currency)}),u&&v&&t("span",{className:"text-base font-bold leading-[1.2] tracking-[-0.02em] text-[#4A4C56] line-through",children:d(F,e.price.currency)})]})}),a&&t("button",{type:"button",onClick:R,className:"mb-3 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white",style:{backgroundColor:"#1D1D1F"},children:y.addToCart})]},`product-column-${n}`)})}),t("div",{className:"flex flex-col gap-4 p-4",children:Object.entries(g).map(([e,n])=>n?t("div",{children:k(n.label,n)},e):null)})]})},U={render:(l,a,m)=>{if(l.type!=="product_comparison"||!l.data)return null;const i=l.data;return i.productComparisonRender?t(A,{children:i.productComparisonRender(i)}):t(M,{data:i,isUser:a,isSystem:m,onAddToCart:i.onAddToCart,commonText:i.commonText})}};export{M as ProductComparison,U as ProductComparisonRenderer};
|
|
2
2
|
//# sourceMappingURL=ProductComparison.js.map
|