@anker-in/campaign-ui 0.3.3 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/dist/cjs/components/LiveChatWidget/LiveChatWidget.d.ts +21 -1
  2. package/dist/cjs/components/LiveChatWidget/LiveChatWidget.js +1 -1
  3. package/dist/cjs/components/LiveChatWidget/LiveChatWidget.js.map +3 -3
  4. package/dist/cjs/components/LiveChatWidget/api/chat.d.ts +23 -2
  5. package/dist/cjs/components/LiveChatWidget/api/chat.js +2 -2
  6. package/dist/cjs/components/LiveChatWidget/api/chat.js.map +3 -3
  7. package/dist/cjs/components/LiveChatWidget/components/ChatHeader.js +1 -1
  8. package/dist/cjs/components/LiveChatWidget/components/ChatHeader.js.map +2 -2
  9. package/dist/cjs/components/LiveChatWidget/components/ChatInput.d.ts +5 -0
  10. package/dist/cjs/components/LiveChatWidget/components/ChatInput.js +1 -1
  11. package/dist/cjs/components/LiveChatWidget/components/ChatInput.js.map +3 -3
  12. package/dist/cjs/components/LiveChatWidget/components/ChatMessage.js +2 -2
  13. package/dist/cjs/components/LiveChatWidget/components/ChatMessage.js.map +3 -3
  14. package/dist/cjs/components/LiveChatWidget/components/ChatWindow.d.ts +5 -0
  15. package/dist/cjs/components/LiveChatWidget/components/ChatWindow.js +1 -1
  16. package/dist/cjs/components/LiveChatWidget/components/ChatWindow.js.map +3 -3
  17. package/dist/cjs/components/LiveChatWidget/components/ComplianceDialog.d.ts +51 -0
  18. package/dist/cjs/components/LiveChatWidget/components/ComplianceDialog.js +33 -0
  19. package/dist/cjs/components/LiveChatWidget/components/ComplianceDialog.js.map +7 -0
  20. package/dist/cjs/components/LiveChatWidget/components/MessageContent/CartCard.js +1 -1
  21. package/dist/cjs/components/LiveChatWidget/components/MessageContent/CartCard.js.map +3 -3
  22. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ErrorBlock.js +1 -1
  23. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ErrorBlock.js.map +2 -2
  24. package/dist/cjs/components/LiveChatWidget/components/MessageContent/FAQList.js +1 -1
  25. package/dist/cjs/components/LiveChatWidget/components/MessageContent/FAQList.js.map +3 -3
  26. package/dist/cjs/components/LiveChatWidget/components/MessageContent/PolicyBlock.js +2 -2
  27. package/dist/cjs/components/LiveChatWidget/components/MessageContent/PolicyBlock.js.map +3 -3
  28. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductCard.d.ts +17 -24
  29. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductCard.js +1 -4
  30. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductCard.js.map +3 -3
  31. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductComparison.d.ts +7 -1
  32. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductComparison.js +1 -1
  33. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductComparison.js.map +3 -3
  34. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductList.js +1 -1
  35. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductList.js.map +3 -3
  36. package/dist/cjs/components/LiveChatWidget/components/MessageContent/PromotionList.d.ts +4 -1
  37. package/dist/cjs/components/LiveChatWidget/components/MessageContent/PromotionList.js +1 -1
  38. package/dist/cjs/components/LiveChatWidget/components/MessageContent/PromotionList.js.map +3 -3
  39. package/dist/cjs/components/LiveChatWidget/components/MessageContent/QuickReplies.js +1 -1
  40. package/dist/cjs/components/LiveChatWidget/components/MessageContent/QuickReplies.js.map +2 -2
  41. package/dist/cjs/components/LiveChatWidget/components/MessageContent/TextBlock.js +1 -1
  42. package/dist/cjs/components/LiveChatWidget/components/MessageContent/TextBlock.js.map +3 -3
  43. package/dist/cjs/components/LiveChatWidget/components/MessageContent.js +1 -1
  44. package/dist/cjs/components/LiveChatWidget/components/MessageContent.js.map +2 -2
  45. package/dist/cjs/components/LiveChatWidget/components/MessageList.js +2 -2
  46. package/dist/cjs/components/LiveChatWidget/components/MessageList.js.map +2 -2
  47. package/dist/cjs/components/LiveChatWidget/constants.d.ts +5 -0
  48. package/dist/cjs/components/LiveChatWidget/constants.js +1 -1
  49. package/dist/cjs/components/LiveChatWidget/constants.js.map +3 -3
  50. package/dist/cjs/components/LiveChatWidget/hooks/useChatAPI.d.ts +9 -0
  51. package/dist/cjs/components/LiveChatWidget/hooks/useChatAPI.js +1 -1
  52. package/dist/cjs/components/LiveChatWidget/hooks/useChatAPI.js.map +3 -3
  53. package/dist/cjs/components/LiveChatWidget/hooks/useChatState.d.ts +35 -2
  54. package/dist/cjs/components/LiveChatWidget/hooks/useChatState.js +1 -1
  55. package/dist/cjs/components/LiveChatWidget/hooks/useChatState.js.map +3 -3
  56. package/dist/cjs/components/LiveChatWidget/index.d.ts +1 -1
  57. package/dist/cjs/components/LiveChatWidget/index.js +1 -1
  58. package/dist/cjs/components/LiveChatWidget/index.js.map +2 -2
  59. package/dist/cjs/components/LiveChatWidget/types.d.ts +212 -3
  60. package/dist/cjs/components/LiveChatWidget/types.js +1 -1
  61. package/dist/cjs/components/LiveChatWidget/types.js.map +1 -1
  62. package/dist/cjs/components/LiveChatWidget/utils/fetcher.d.ts +42 -0
  63. package/dist/cjs/components/LiveChatWidget/utils/fetcher.js +2 -0
  64. package/dist/cjs/components/LiveChatWidget/utils/fetcher.js.map +7 -0
  65. package/dist/cjs/components/chat/markdown.js +1 -1
  66. package/dist/cjs/components/chat/markdown.js.map +2 -2
  67. package/dist/cjs/components/credits/creditsBanner/index.js +2 -2
  68. package/dist/cjs/components/credits/creditsBanner/index.js.map +2 -2
  69. package/dist/cjs/components/index.d.ts +2 -0
  70. package/dist/cjs/components/index.js +1 -1
  71. package/dist/cjs/components/index.js.map +3 -3
  72. package/dist/cjs/stories/LiveChatWidget.stories.d.ts +1 -79
  73. package/dist/cjs/stories/LiveChatWidget.stories.js +8 -47
  74. package/dist/cjs/stories/LiveChatWidget.stories.js.map +3 -3
  75. package/dist/esm/components/LiveChatWidget/LiveChatWidget.d.ts +21 -1
  76. package/dist/esm/components/LiveChatWidget/LiveChatWidget.js +1 -1
  77. package/dist/esm/components/LiveChatWidget/LiveChatWidget.js.map +3 -3
  78. package/dist/esm/components/LiveChatWidget/api/chat.d.ts +23 -2
  79. package/dist/esm/components/LiveChatWidget/api/chat.js +2 -2
  80. package/dist/esm/components/LiveChatWidget/api/chat.js.map +3 -3
  81. package/dist/esm/components/LiveChatWidget/components/ChatHeader.js +1 -1
  82. package/dist/esm/components/LiveChatWidget/components/ChatHeader.js.map +2 -2
  83. package/dist/esm/components/LiveChatWidget/components/ChatInput.d.ts +5 -0
  84. package/dist/esm/components/LiveChatWidget/components/ChatInput.js +1 -1
  85. package/dist/esm/components/LiveChatWidget/components/ChatInput.js.map +3 -3
  86. package/dist/esm/components/LiveChatWidget/components/ChatMessage.js +2 -2
  87. package/dist/esm/components/LiveChatWidget/components/ChatMessage.js.map +3 -3
  88. package/dist/esm/components/LiveChatWidget/components/ChatWindow.d.ts +5 -0
  89. package/dist/esm/components/LiveChatWidget/components/ChatWindow.js +1 -1
  90. package/dist/esm/components/LiveChatWidget/components/ChatWindow.js.map +3 -3
  91. package/dist/esm/components/LiveChatWidget/components/ComplianceDialog.d.ts +51 -0
  92. package/dist/esm/components/LiveChatWidget/components/ComplianceDialog.js +33 -0
  93. package/dist/esm/components/LiveChatWidget/components/ComplianceDialog.js.map +7 -0
  94. package/dist/esm/components/LiveChatWidget/components/MessageContent/CartCard.js +1 -1
  95. package/dist/esm/components/LiveChatWidget/components/MessageContent/CartCard.js.map +3 -3
  96. package/dist/esm/components/LiveChatWidget/components/MessageContent/ErrorBlock.js +1 -1
  97. package/dist/esm/components/LiveChatWidget/components/MessageContent/ErrorBlock.js.map +2 -2
  98. package/dist/esm/components/LiveChatWidget/components/MessageContent/FAQList.js +1 -1
  99. package/dist/esm/components/LiveChatWidget/components/MessageContent/FAQList.js.map +3 -3
  100. package/dist/esm/components/LiveChatWidget/components/MessageContent/PolicyBlock.js +2 -2
  101. package/dist/esm/components/LiveChatWidget/components/MessageContent/PolicyBlock.js.map +3 -3
  102. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductCard.d.ts +17 -24
  103. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductCard.js +1 -4
  104. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductCard.js.map +3 -3
  105. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductComparison.d.ts +7 -1
  106. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductComparison.js +1 -1
  107. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductComparison.js.map +3 -3
  108. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductList.js +1 -1
  109. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductList.js.map +3 -3
  110. package/dist/esm/components/LiveChatWidget/components/MessageContent/PromotionList.d.ts +4 -1
  111. package/dist/esm/components/LiveChatWidget/components/MessageContent/PromotionList.js +1 -1
  112. package/dist/esm/components/LiveChatWidget/components/MessageContent/PromotionList.js.map +3 -3
  113. package/dist/esm/components/LiveChatWidget/components/MessageContent/QuickReplies.js +1 -1
  114. package/dist/esm/components/LiveChatWidget/components/MessageContent/QuickReplies.js.map +2 -2
  115. package/dist/esm/components/LiveChatWidget/components/MessageContent/TextBlock.js +1 -1
  116. package/dist/esm/components/LiveChatWidget/components/MessageContent/TextBlock.js.map +3 -3
  117. package/dist/esm/components/LiveChatWidget/components/MessageContent.js +1 -1
  118. package/dist/esm/components/LiveChatWidget/components/MessageContent.js.map +2 -2
  119. package/dist/esm/components/LiveChatWidget/components/MessageList.js +2 -2
  120. package/dist/esm/components/LiveChatWidget/components/MessageList.js.map +2 -2
  121. package/dist/esm/components/LiveChatWidget/constants.d.ts +5 -0
  122. package/dist/esm/components/LiveChatWidget/constants.js +1 -1
  123. package/dist/esm/components/LiveChatWidget/constants.js.map +3 -3
  124. package/dist/esm/components/LiveChatWidget/hooks/useChatAPI.d.ts +9 -0
  125. package/dist/esm/components/LiveChatWidget/hooks/useChatAPI.js +1 -1
  126. package/dist/esm/components/LiveChatWidget/hooks/useChatAPI.js.map +3 -3
  127. package/dist/esm/components/LiveChatWidget/hooks/useChatState.d.ts +35 -2
  128. package/dist/esm/components/LiveChatWidget/hooks/useChatState.js +1 -1
  129. package/dist/esm/components/LiveChatWidget/hooks/useChatState.js.map +3 -3
  130. package/dist/esm/components/LiveChatWidget/index.d.ts +1 -1
  131. package/dist/esm/components/LiveChatWidget/index.js +1 -1
  132. package/dist/esm/components/LiveChatWidget/index.js.map +2 -2
  133. package/dist/esm/components/LiveChatWidget/types.d.ts +212 -3
  134. package/dist/esm/components/LiveChatWidget/utils/fetcher.d.ts +42 -0
  135. package/dist/esm/components/LiveChatWidget/utils/fetcher.js +2 -0
  136. package/dist/esm/components/LiveChatWidget/utils/fetcher.js.map +7 -0
  137. package/dist/esm/components/chat/markdown.js +1 -1
  138. package/dist/esm/components/chat/markdown.js.map +2 -2
  139. package/dist/esm/components/credits/creditsBanner/index.js +2 -2
  140. package/dist/esm/components/credits/creditsBanner/index.js.map +2 -2
  141. package/dist/esm/components/index.d.ts +2 -0
  142. package/dist/esm/components/index.js +1 -1
  143. package/dist/esm/components/index.js.map +3 -3
  144. package/dist/esm/stories/LiveChatWidget.stories.d.ts +1 -79
  145. package/dist/esm/stories/LiveChatWidget.stories.js +8 -47
  146. package/dist/esm/stories/LiveChatWidget.stories.js.map +3 -3
  147. package/dist/index.d.mts +1305 -0
  148. package/dist/index.d.ts +1305 -0
  149. package/dist/index.js +26656 -0
  150. package/dist/index.js.map +1 -0
  151. package/dist/index.mjs +26641 -0
  152. package/dist/index.mjs.map +1 -0
  153. package/package.json +9 -2
  154. package/src/components/LiveChatWidget/LiveChatWidget.tsx +887 -0
  155. package/src/components/LiveChatWidget/api/chat.ts +175 -0
  156. package/src/components/LiveChatWidget/components/ChatBubble.tsx +152 -0
  157. package/src/components/LiveChatWidget/components/ChatHeader.tsx +150 -0
  158. package/src/components/LiveChatWidget/components/ChatInput.tsx +253 -0
  159. package/src/components/LiveChatWidget/components/ChatMessage.tsx +190 -0
  160. package/src/components/LiveChatWidget/components/ChatWindow.tsx +363 -0
  161. package/src/components/LiveChatWidget/components/ComplianceDialog.tsx +216 -0
  162. package/src/components/LiveChatWidget/components/MessageContent/CartCard.tsx +202 -0
  163. package/src/components/LiveChatWidget/components/MessageContent/ErrorBlock.tsx +75 -0
  164. package/src/components/LiveChatWidget/components/MessageContent/FAQList.tsx +128 -0
  165. package/src/components/LiveChatWidget/components/MessageContent/PolicyBlock.tsx +152 -0
  166. package/src/components/LiveChatWidget/components/MessageContent/ProductCard.tsx +227 -0
  167. package/src/components/LiveChatWidget/components/MessageContent/ProductComparison.tsx +377 -0
  168. package/src/components/LiveChatWidget/components/MessageContent/ProductList.tsx +293 -0
  169. package/src/components/LiveChatWidget/components/MessageContent/PromotionList.tsx +170 -0
  170. package/src/components/LiveChatWidget/components/MessageContent/QuickReplies.tsx +91 -0
  171. package/src/components/LiveChatWidget/components/MessageContent/TextBlock.tsx +110 -0
  172. package/src/components/LiveChatWidget/components/MessageContent/ThinkingBlock.tsx +53 -0
  173. package/src/components/LiveChatWidget/components/MessageContent/index.ts +16 -0
  174. package/src/components/LiveChatWidget/components/MessageContent.tsx +113 -0
  175. package/src/components/LiveChatWidget/components/MessageList.tsx +261 -0
  176. package/src/components/LiveChatWidget/components/ScrollAnchor.tsx +75 -0
  177. package/src/components/LiveChatWidget/constants.ts +36 -0
  178. package/src/components/LiveChatWidget/hooks/useChatAPI.ts +146 -0
  179. package/src/components/LiveChatWidget/hooks/useChatState.ts +1090 -0
  180. package/src/components/LiveChatWidget/hooks/useSession.ts +123 -0
  181. package/src/components/LiveChatWidget/index.tsx +63 -0
  182. package/src/components/LiveChatWidget/types.ts +1011 -0
  183. package/src/components/LiveChatWidget/utils/cartTransformers.ts +72 -0
  184. package/src/components/LiveChatWidget/utils/fetcher.ts +131 -0
  185. package/src/components/LiveChatWidget/utils/messageRenderers.ts +120 -0
  186. package/src/components/LiveChatWidget/utils/productTransformers.ts +149 -0
  187. package/src/components/LiveChatWidget/utils/userId.ts +140 -0
  188. package/src/components/LiveChatWidget/utils/validation.ts +99 -0
  189. package/src/components/chat/markdown.tsx +1 -1
  190. package/src/components/credits/creditsBanner/index.tsx +5 -5
  191. package/src/components/index.ts +23 -0
  192. package/src/stories/LiveChatWidget.stories.tsx +322 -0
  193. package/src/styles/livechat.css +317 -0
  194. package/dist/cjs/components/credits/context/hooks/useFunctionMemberPrice.d.ts +0 -7
  195. package/dist/cjs/components/credits/context/hooks/useFunctionMemberPrice.js +0 -2
  196. package/dist/cjs/components/credits/context/hooks/useFunctionMemberPrice.js.map +0 -7
  197. package/dist/cjs/components/credits/context/utils/atobID.d.ts +0 -1
  198. package/dist/cjs/components/credits/context/utils/atobID.js +0 -2
  199. package/dist/cjs/components/credits/context/utils/atobID.js.map +0 -7
  200. package/dist/cjs/components/credits/context/utils/functionDiscountCalculate.d.ts +0 -5
  201. package/dist/cjs/components/credits/context/utils/functionDiscountCalculate.js +0 -2
  202. package/dist/cjs/components/credits/context/utils/functionDiscountCalculate.js.map +0 -7
  203. package/dist/cjs/components/credits/context/utils/getFunctionMemberPrice.d.ts +0 -8
  204. package/dist/cjs/components/credits/context/utils/getFunctionMemberPrice.js +0 -2
  205. package/dist/cjs/components/credits/context/utils/getFunctionMemberPrice.js.map +0 -7
  206. package/dist/cjs/components/credits/context/utils/getFunctionMemberPriceDiscountConfig.d.ts +0 -9
  207. package/dist/cjs/components/credits/context/utils/getFunctionMemberPriceDiscountConfig.js +0 -2
  208. package/dist/cjs/components/credits/context/utils/getFunctionMemberPriceDiscountConfig.js.map +0 -7
  209. package/dist/cjs/components/credits/context/utils/variantGetCoupon.d.ts +0 -6
  210. package/dist/cjs/components/credits/context/utils/variantGetCoupon.js +0 -2
  211. package/dist/cjs/components/credits/context/utils/variantGetCoupon.js.map +0 -7
  212. package/dist/esm/components/credits/context/hooks/useFunctionMemberPrice.d.ts +0 -7
  213. package/dist/esm/components/credits/context/hooks/useFunctionMemberPrice.js +0 -2
  214. package/dist/esm/components/credits/context/hooks/useFunctionMemberPrice.js.map +0 -7
  215. package/dist/esm/components/credits/context/utils/atobID.d.ts +0 -1
  216. package/dist/esm/components/credits/context/utils/atobID.js +0 -2
  217. package/dist/esm/components/credits/context/utils/atobID.js.map +0 -7
  218. package/dist/esm/components/credits/context/utils/functionDiscountCalculate.d.ts +0 -5
  219. package/dist/esm/components/credits/context/utils/functionDiscountCalculate.js +0 -2
  220. package/dist/esm/components/credits/context/utils/functionDiscountCalculate.js.map +0 -7
  221. package/dist/esm/components/credits/context/utils/getFunctionMemberPrice.d.ts +0 -8
  222. package/dist/esm/components/credits/context/utils/getFunctionMemberPrice.js +0 -2
  223. package/dist/esm/components/credits/context/utils/getFunctionMemberPrice.js.map +0 -7
  224. package/dist/esm/components/credits/context/utils/getFunctionMemberPriceDiscountConfig.d.ts +0 -9
  225. package/dist/esm/components/credits/context/utils/getFunctionMemberPriceDiscountConfig.js +0 -2
  226. package/dist/esm/components/credits/context/utils/getFunctionMemberPriceDiscountConfig.js.map +0 -7
  227. package/dist/esm/components/credits/context/utils/variantGetCoupon.d.ts +0 -6
  228. package/dist/esm/components/credits/context/utils/variantGetCoupon.js +0 -2
  229. package/dist/esm/components/credits/context/utils/variantGetCoupon.js.map +0 -7
@@ -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 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 site: {\n control: 'text',\n description: 'Shopify \u5E97\u94FA URL',\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\n *\n * \u6700\u7B80\u5355\u7684\u4F7F\u7528\u65B9\u5F0F\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E\u3002\n */\nexport const Default: Story = {\n args: {\n loginUserId: 'test_test',\n apiBaseUrl: 'http://172.16.38.183:3003',\n cartId: 'gid://shopify/Cart/hWN7oFnMh7jKxbO1CYSzWVue?key=68f4cf2c4c772b9aed2fab2902e6dab3',\n accessToken: '92301d516a0a38a0a483bc230e5bfaad',\n title: 'eufy',\n },\n}\n\n/**\n * \u81EA\u5B9A\u4E49\u4F4D\u7F6E\n *\n * \u4F7F\u7528\u81EA\u5B9A\u4E49\u4F4D\u7F6E\u5BF9\u8C61\u6765\u63A7\u5236\u6C14\u6CE1\u6309\u94AE\u7684\u4F4D\u7F6E\u3002\n */\nexport const CustomPosition: Story = {\n args: {\n position: { bottom: '1.5rem', left: '1.5rem' },\n },\n}\n\n/**\n * \u81EA\u5B9A\u4E49\u54C1\u724C\u6837\u5F0F\n *\n * \u81EA\u5B9A\u4E49 Logo \u548C\u6B22\u8FCE\u6D88\u606F\u3002\n */\nexport const CustomBranding: Story = {\n args: {\n logoUrl: 'https://images.unsplash.com/photo-1599305445671-ac291c95aaa9?w=100&h=100&fit=crop',\n welcomeMessage: '\u6B22\u8FCE\u6765\u5230 Soundcore\uFF01\u6211\u662F\u60A8\u7684\u4E13\u5C5E AI \u52A9\u624B \uD83C\uDFA7',\n },\n}\n\n/**\n * \u5E26\u5FEB\u6377\u56DE\u590D\n *\n * \u5728\u6B22\u8FCE\u6D88\u606F\u540E\u663E\u793A\u5FEB\u6377\u56DE\u590D\u6309\u94AE\u3002\n */\nexport const WithQuickReplies: Story = {\n args: {\n quickReplies: [\n {\n id: '1',\n label: '\u67E5\u8BE2\u4EF7\u683C',\n value: '\u6211\u60F3\u4E86\u89E3\u4EA7\u54C1\u4EF7\u683C',\n icon: '\uD83D\uDCB0',\n },\n {\n id: '2',\n label: '\u67E5\u8BE2\u7269\u6D41',\n value: '\u6211\u60F3\u67E5\u8BE2\u8BA2\u5355\u7269\u6D41',\n icon: '\uD83D\uDCE6',\n },\n {\n id: '3',\n label: '\u552E\u540E\u670D\u52A1',\n value: '\u6211\u9700\u8981\u552E\u540E\u5E2E\u52A9',\n icon: '\uD83D\uDD27',\n },\n {\n id: '4',\n label: '\u4EA7\u54C1\u63A8\u8350',\n value: '\u8BF7\u63A8\u8350\u9002\u5408\u6211\u7684\u4EA7\u54C1',\n icon: '\u2B50',\n },\n ],\n },\n}\n\n/**\n * \u81EA\u5B9A\u4E49\u6B22\u8FCE\u6D88\u606F\n *\n * \u81EA\u5B9A\u4E49\u9996\u6B21\u6253\u5F00\u804A\u5929\u7A97\u53E3\u65F6\u7684\u6B22\u8FCE\u6D88\u606F\u3002\n */\nexport const CustomWelcomeMessage: Story = {\n args: {\n welcomeMessage: `\n\uD83D\uDC4B \u60A8\u597D\uFF01\u6B22\u8FCE\u6765\u5230 Soundcore \u5B98\u65B9\u5546\u57CE\u3002\n\n\u6211\u662F\u60A8\u7684 AI \u8D2D\u7269\u52A9\u624B\uFF0C\u53EF\u4EE5\u5E2E\u60A8\uFF1A\n- \uD83D\uDD0D \u67E5\u627E\u4EA7\u54C1\n- \uD83D\uDCB0 \u6BD4\u8F83\u4EF7\u683C\n- \uD83D\uDCE6 \u8DDF\u8E2A\u8BA2\u5355\n- \uD83D\uDCAC \u89E3\u7B54\u7591\u95EE\n\n\u6709\u4EC0\u4E48\u6211\u53EF\u4EE5\u5E2E\u52A9\u60A8\u7684\u5417\uFF1F\n `.trim(),\n },\n}\n\n/**\n * \u4E8B\u4EF6\u56DE\u8C03\n *\n * \u76D1\u542C\u7EC4\u4EF6\u4E8B\u4EF6\u8FDB\u884C\u81EA\u5B9A\u4E49\u5904\u7406\u3002\n */\nexport const WithEventCallbacks: Story = {\n args: {\n title: '',\n showNewSessionButton: false,\n\n position: {\n bottom: '24px',\n right: '30px',\n },\n\n chatBubbleIcon: 'https://cdn.shopify.com/s/files/1/0504/7094/4954/files/Rectangle_400770314.png?v=1768894153',\n },\n\n render: args => (\n <LiveChatWidget\n {...args}\n onOpen={() => {\n console.log('[Story] Chat opened')\n }}\n onClose={() => {\n console.log('[Story] Chat closed')\n }}\n onMessageSend={(message: string) => {\n console.log('[Story] Message sent:', message)\n }}\n onError={(error: Error) => {\n console.error('[Story] Error occurred:', error)\n }}\n onAddToCart={(product: any) => {\n console.log('\uD83D\uDED2 [Story] Add to Cart clicked!')\n console.log('\uD83D\uDCE6 Product Info:', {\n id: product.shopifyId,\n title: product.title,\n price: product.price,\n imageUrl: product.imageUrl,\n productUrl: product.productUrl,\n })\n console.log('\uD83D\uDCCB Full Product Object:', product)\n\n // \u6A21\u62DF\u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u6210\u529F\n alert(`\u2705 \"${product.title}\" \u5DF2\u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\uFF01\\n\\n\u4EF7\u683C: ${product.price.currency} ${product.price.amount}`)\n }}\n onCart={(cartId: string, checkoutUrl?: string) => {\n console.log('\uD83D\uDED2 [Story] Cart button clicked!')\n console.log('\uD83D\uDCCB Cart ID:', cartId)\n console.log('\uD83D\uDD17 Checkout URL:', checkoutUrl)\n\n // \u6A21\u62DF\u8D2D\u7269\u8F66\u6309\u94AE\u70B9\u51FB\u6210\u529F\n alert(`\u8D2D\u7269\u8F66\u6309\u94AE\u88AB\u70B9\u51FB\uFF01\\n\\nCart ID: ${cartId}\\nCheckout URL: ${checkoutUrl || '\u65E0'}`)\n }}\n />\n ),\n}\n\n/**\n * \u81EA\u5B9A\u4E49\u89C6\u9891\u6D88\u606F\u6E32\u67D3\u5668\n *\n * \u6269\u5C55\u6D88\u606F\u7C7B\u578B\uFF0C\u6DFB\u52A0\u89C6\u9891\u6D88\u606F\u652F\u6301\u3002\n */\nexport const CustomVideoRenderer: Story = {\n args: {\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 \u60A8\u7684\u6D4F\u89C8\u5668\u4E0D\u652F\u6301\u89C6\u9891\u64AD\u653E\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 },\n },\n}\n\n/**\n * \u81EA\u5B9A\u4E49\u56FE\u7247\u753B\u5ECA\u6E32\u67D3\u5668\n *\n * \u6269\u5C55\u6D88\u606F\u7C7B\u578B\uFF0C\u6DFB\u52A0\u56FE\u7247\u753B\u5ECA\u652F\u6301\u3002\n */\nexport const CustomImageGalleryRenderer: Story = {\n args: {\n customRenderers: {\n image_gallery: {\n render: (content: MessageContent) => {\n const galleryContent = content as any\n const images = galleryContent.images || []\n\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}\n\n/**\n * \u79FB\u52A8\u7AEF\u9884\u89C8\n *\n * \u5728\u79FB\u52A8\u7AEF\u5C3A\u5BF8\u4E0B\u67E5\u770B\u6548\u679C\uFF08\u5168\u5C4F\u663E\u793A\uFF09\u3002\n */\nexport const MobileView: Story = {\n parameters: {\n viewport: {\n defaultViewport: 'mobile1',\n },\n },\n args: {},\n}\n\n/**\n * \u5E73\u677F\u7AEF\u9884\u89C8\n *\n * \u5728\u5E73\u677F\u7AEF\u5C3A\u5BF8\u4E0B\u67E5\u770B\u6548\u679C\u3002\n */\nexport const TabletView: Story = {\n parameters: {\n viewport: {\n defaultViewport: 'tablet',\n },\n },\n args: {},\n}\n\n/**\n * \u9ED8\u8BA4\u4F4D\u7F6E\u5C55\u793A\n *\n * \u5C55\u793A\u6C14\u6CE1\u6309\u94AE\u7684\u9ED8\u8BA4\u4F4D\u7F6E\uFF08\u53F3\u4E0B\u89D2\uFF09\u3002\n */\nexport const DefaultPositionDemo: Story = {\n render: () => (\n <div className=\"relative h-screen w-full bg-gray-50\">\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <p className=\"text-gray-500\">\u9875\u9762\u5185\u5BB9\u533A\u57DF</p>\n </div>\n\n {/* \u6F14\u793A\u9ED8\u8BA4\u4F4D\u7F6E */}\n <div className=\"absolute bottom-4 right-4 text-xs text-gray-400\">\u9ED8\u8BA4\u4F4D\u7F6E (\u53F3\u4E0B\u89D2)</div>\n\n <LiveChatWidget apiBaseUrl=\"https://beta-api-livechat.anker.com\" site=\"www.eufy.com\" />\n </div>\n ),\n}\n\n/**\n * \u4EA7\u54C1\u5BF9\u6BD4\u6D88\u606F\n *\n * \u5C55\u793A\u4EA7\u54C1\u5BF9\u6BD4\u7C7B\u578B\u7684\u6D88\u606F\u6E32\u67D3\u6548\u679C\uFF0C\u5305\u62EC\u4EF7\u683C\u3001\u4F1A\u5458\u4EF7\u3001\u53D8\u4F53\u6570\u91CF\u3001\u6298\u6263\u7B49\u591A\u4E2A\u7EF4\u5EA6\u7684\u5BF9\u6BD4\u3002\n *\n * \u4EA7\u54C1\u5BF9\u6BD4\u7EC4\u4EF6\u4F1A\u4EE5\u7F51\u683C\u5E03\u5C40\u5C55\u793A\u591A\u4E2A\u4EA7\u54C1\u7684\u57FA\u672C\u4FE1\u606F\uFF0C\u5E76\u5728\u4E0B\u65B9\u663E\u793A\u5404\u7EF4\u5EA6\u7684\u5BF9\u6BD4\u6570\u636E\u3002\n */\nexport const ProductComparisonMessage: Story = {\n render: args => (\n <LiveChatWidget\n {...args}\n onAddToCart={(product: any) => {\n console.log('\uD83D\uDED2 [ProductComparison Story] Add to Cart clicked!')\n console.log('\uD83D\uDCE6 Product Info:', {\n id: product.shopifyId,\n title: product.title,\n price: product.price,\n imageUrl: product.imageUrl,\n productUrl: product.productUrl,\n })\n console.log('\uD83D\uDCCB Full Product Object:', product)\n\n // \u6A21\u62DF\u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u6210\u529F\n alert(`\u2705 \"${product.title}\" \u5DF2\u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\uFF01\\n\\n\u4EF7\u683C: ${product.price.currency} ${product.price.amount}`)\n }}\n />\n ),\n args: {\n welcomeMessage: '\u4EE5\u4E0B\u662F\u60A8\u5173\u6CE8\u7684\u4EA7\u54C1\u5BF9\u6BD4\u4FE1\u606F\uFF1A',\n },\n parameters: {\n docs: {\n description: {\n story: `\n\u4EA7\u54C1\u5BF9\u6BD4\u6D88\u606F\u652F\u6301\u4EE5\u4E0B\u7EF4\u5EA6\uFF1A\n\n- **\u4EF7\u683C\u5BF9\u6BD4**: \u663E\u793A\u4EA7\u54C1\u7684\u4EF7\u683C\u533A\u95F4\u548C\u4FC3\u9500\u6807\u7B7E\n- **\u4F1A\u5458\u4EF7\u5BF9\u6BD4**: \u663E\u793A\u4F1A\u5458\u4E13\u4EAB\u4EF7\u683C\uFF08\u5982\u679C\u53EF\u7528\uFF09\n- **\u53D8\u4F53\u6570\u91CF\u5BF9\u6BD4**: \u663E\u793A\u4EA7\u54C1\u7684\u53EF\u9009\u53D8\u4F53\u6570\u91CF\n- **\u6298\u6263\u5BF9\u6BD4**: \u663E\u793A\u4EA7\u54C1\u662F\u5426\u6709\u6298\u6263\u6D3B\u52A8\n\n\u7EC4\u4EF6\u4F1A\u81EA\u52A8\u5904\u7406\u4ECE\u540E\u7AEF\u8FD4\u56DE\u7684\u4EA7\u54C1\u5BF9\u6BD4\u6570\u636E\uFF0C\u5305\u62EC\uFF1A\n- \u4EA7\u54C1\u57FA\u672C\u4FE1\u606F\uFF08\u56FE\u7247\u3001\u6807\u9898\u3001\u4EF7\u683C\u7B49\uFF09\n- \u591A\u7EF4\u5EA6\u5BF9\u6BD4\u6570\u636E\uFF08\u4EF7\u683C\u3001\u4F1A\u5458\u4EF7\u3001\u53D8\u4F53\u3001\u6298\u6263\uFF09\n- \u54CD\u5E94\u5F0F\u5E03\u5C40\uFF08\u79FB\u52A8\u7AEF\u53EF\u6A2A\u5411\u6EDA\u52A8\uFF09\n\n**\u6D4B\u8BD5 Add to Cart \u529F\u80FD\uFF1A**\n- \u70B9\u51FB\u4EA7\u54C1\u5BF9\u6BD4\u5361\u7247\u4E2D\u7684 \"Add to Cart\" \u6309\u94AE\n- \u67E5\u770B\u63A7\u5236\u53F0\u8F93\u51FA\u7684\u4EA7\u54C1\u4FE1\u606F\n- \u4F1A\u5F39\u51FA\u786E\u8BA4\u63D0\u793A\u6846\u663E\u793A\u5DF2\u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\n `,\n },\n },\n },\n}\n\n/**\n * FAQ \u5217\u8868\u6D88\u606F\n *\n * \u5C55\u793A\u5E38\u89C1\u95EE\u9898\u5217\u8868\uFF0C\u652F\u6301\u6298\u53E0/\u5C55\u5F00\u3002\n *\n * FAQ \u7EC4\u4EF6\u4F1A\u663E\u793A\u641C\u7D22\u7ED3\u679C\u7684\u5E38\u89C1\u95EE\u9898\uFF0C\u6BCF\u4E2A\u95EE\u9898\u53EF\u4EE5\u70B9\u51FB\u5C55\u5F00\u67E5\u770B\u7B54\u6848\u3002\n */\nexport const FAQListMessage: Story = {\n args: {\n welcomeMessage: '\u4EE5\u4E0B\u662F\u4E0E\u60A8\u7684\u95EE\u9898\u76F8\u5173\u7684\u5E38\u89C1\u89E3\u7B54\uFF1A',\n },\n parameters: {\n docs: {\n description: {\n story: `\nFAQ \u5217\u8868\u6D88\u606F\u652F\u6301\uFF1A\n\n- **\u53EF\u6298\u53E0\u95EE\u9898**: \u70B9\u51FB\u95EE\u9898\u6807\u9898\u5C55\u5F00/\u6298\u53E0\u7B54\u6848\n- **Markdown \u7B54\u6848**: \u7B54\u6848\u652F\u6301 Markdown \u683C\u5F0F\uFF0C\u53EF\u663E\u793A\u5BCC\u6587\u672C\n- **\u76F8\u5173\u95EE\u9898**: \u5C55\u5F00\u7B54\u6848\u540E\u663E\u793A\u76F8\u5173\u95EE\u9898\uFF0C\u70B9\u51FB\u53EF\u89E6\u53D1\u65B0\u641C\u7D22\n- **\u5206\u7C7B\u6807\u8BB0**: \u6839\u636E\u95EE\u9898\u5206\u7C7B\u663E\u793A\uFF08\u914D\u9001\u3001\u9000\u8D27\u3001\u4EA7\u54C1\u3001\u652F\u4ED8\u3001\u901A\u7528\uFF09\n- **\u641C\u7D22\u7ED3\u679C\u7EDF\u8BA1**: \u663E\u793A\u627E\u5230\u7684\u95EE\u9898\u6570\u91CF\n\n\u4F7F\u7528\u573A\u666F\uFF1A\n- \u7528\u6237\u8BE2\u95EE\u5E38\u89C1\u95EE\u9898\u65F6\u8FD4\u56DE FAQ \u5217\u8868\n- \u4EA7\u54C1\u4E13\u5C5E\u95EE\u9898\u67E5\u8BE2\n- \u6309\u5206\u7C7B\u67E5\u8BE2 FAQ\n `,\n },\n },\n },\n}\n"],
5
- "mappings": "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",
6
- "names": ["LiveChatWidget_stories_exports", "__export", "CustomBranding", "CustomImageGalleryRenderer", "CustomPosition", "CustomVideoRenderer", "CustomWelcomeMessage", "Default", "DefaultPositionDemo", "FAQListMessage", "MobileView", "ProductComparisonMessage", "TabletView", "WithEventCallbacks", "WithQuickReplies", "LiveChatWidget_stories_default", "__toCommonJS", "import_jsx_runtime", "import_LiveChatWidget", "import_livechat", "meta", "args", "message", "error", "product", "cartId", "checkoutUrl", "content", "videoContent", "images", "image", "index"]
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_test',\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: `Welcome to eufy AI Assistant!\n\nI can help you with:\n- Product recommendations\n- Order tracking\n- FAQs and support\n\nHow can I assist you today?`,\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: \"AI-generated responses can be inaccurate. Please verify important info. Do not input sensitive personal data.\",\n 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>.',\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
+ "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
  }
@@ -15,6 +15,7 @@ import type { LiveChatWidgetProps } from './types';
15
15
  * - 历史消息加载
16
16
  * - 多种消息类型渲染
17
17
  * - 自定义扩展机制
18
+ * - reCAPTCHA v3 安全防护
18
19
  *
19
20
  * 架构:
20
21
  * - UI Layer: ChatBubble, ChatWindow, MessageList, etc.
@@ -23,7 +24,7 @@ import type { LiveChatWidgetProps } from './types';
23
24
  *
24
25
  * @example
25
26
  * ```tsx
26
- * // 使用默认位置(右下角)
27
+ * // 基础使用(使用默认位置)
27
28
  * <LiveChatWidget
28
29
  * apiBaseUrl="https://beta-api-livechat.anker.com"
29
30
  * site="www.eufy.com"
@@ -38,6 +39,25 @@ import type { LiveChatWidgetProps } from './types';
38
39
  * position={{ bottom: "20px", right: "30px" }}
39
40
  * onMessageSend={(msg) => console.log('Sent:', msg)}
40
41
  * />
42
+ *
43
+ * // 启用 reCAPTCHA v3 安全防护(提供 sitekey 即自动启用)
44
+ * <LiveChatWidget
45
+ * apiBaseUrl="https://beta-api-livechat.anker.com"
46
+ * site="www.eufy.com"
47
+ * recaptchaSitekey="6LfS4J4pAAAAACX1e_WrxutmxxzCK7FU4WzVqL14"
48
+ * recaptchaAction="livechat"
49
+ * />
50
+ *
51
+ * // 使用自定义 headers 和 reCAPTCHA
52
+ * <LiveChatWidget
53
+ * apiBaseUrl="https://beta-api-livechat.anker.com"
54
+ * site="www.eufy.com"
55
+ * headers={{
56
+ * "Authorization": "Bearer your-token",
57
+ * "X-Custom-Header": "value"
58
+ * }}
59
+ * recaptchaSitekey="your-site-key"
60
+ * />
41
61
  * ```
42
62
  */
43
63
  export declare const LiveChatWidget: React.FC<LiveChatWidgetProps>;
@@ -1,2 +1,2 @@
1
- import{Fragment as Se,jsx as h,jsxs as xe}from"react/jsx-runtime";import L,{useEffect as se,useCallback as x}from"react";import*as F from"@radix-ui/react-dialog";import{ChatBubble as re}from"./components/ChatBubble";import{ChatWindow as ae}from"./components/ChatWindow";import{useChatState as ie}from"./hooks/useChatState";import{useChatAPI as ne}from"./hooks/useChatAPI";import{MessageRendererRegistry as oe}from"./utils/messageRenderers";import{sanitizeInput as de}from"./utils/validation";import{transformProducts as V}from"./utils/productTransformers.js";import{transformCartData as ce}from"./utils/cartTransformers.js";import{TextBlock as pe,ProductCard as ue,ProductList as le,ProductComparisonRenderer as me,PolicyBlock as fe,createQuickRepliesRenderer as ge,ThinkingBlock as ye,ErrorBlock as he,FAQListRenderer as _e,PromotionListRenderer as Ce,CartCard as we}from"./components/MessageContent/index.js";const We=({apiBaseUrl:O,site:n,loginUserId:c,cartId:A,accessToken:W,position:G,welcomeMessage:m,quickReplies:d,customRenderers:M,logoUrl:H,title:J,chatBubbleIcon:K,onOpen:X,onClose:Y,onMessageSend:D,onError:p,onAddToCart:_,onCart:P,showNewSessionButton:Z})=>{const j=ie({welcomeMessage:m,site:n,onOpen:X,onClose:Y,onMessageSend:D,onError:p,onAddToCart:_,onCart:P}),{messages:k,isOpen:C,userId:o,sessionId:R,inputValue:q,isStreaming:U,openChat:I,closeChat:Q,setInputValue:v,addMessage:u,setMessages:z,clearMessages:w,handleSSEEvent:$,saveSession:S,clearSession:f}=j,{sendMessageStream:E,createSession:l}=ne({apiBaseUrl:O,onError:p}),N=L.useRef(async e=>{}),b=L.useMemo(()=>{const e=new oe;e.register("text",pe),e.register("product_card",ue),e.register("product_list",le),e.register("product_comparison",me),e.register("policy",fe),e.register("thinking",ye),e.register("error",he),e.register("faq_list",_e),e.register("promotion_list",Ce),e.register("cart",we);const s=ge(r=>{N.current(r.value)});return e.register("quick_replies",s),M&&e.registerMany(M),e},[M]);se(()=>{if(!C||!o)return;const e=R;e?ee(e):g()},[C,o]);const T=x(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 r=e.structuredContent||e.structured_content;return Array.isArray(r)&&r.forEach(t=>{if(t.type==="product_list"&&Array.isArray(t.data))s.push({type:"product_list",data:{products:V(t.data,n),title:void 0}});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:V(t.data.products,n),dimensions:t.data.dimensions,onAddToCart:_}});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});else if(t.type==="cart"&&t.data?.id!==void 0){const a=ce(t.data);s.push({type:"cart",data:{...a,onCart:P}})}else s.push(t)}),s.length===0&&s.push({type:"text",text:""}),{...e,content:s}},[n,P,_]),g=x(async()=>{if(o)try{const e=await l({user_id:o,site:n,real_user_id:c});if(e.success){S(e.sessionId),w();const s=e.welcomeMessage||m;if(s){const r=[{type:"text",text:s}],t=e.quickQuestions;if(t&&t.length>0){const a=t.map((y,i)=>({id:`quick-${i}`,label:y,value:y}));r.push({type:"quick_replies",data:{replies:a}})}else d&&d.length>0&&r.push({type:"quick_replies",data:{replies:d}});u({id:`welcome-${Date.now()}`,role:"assistant",content:r,timestamp:Date.now()})}}}catch(e){console.error("[LiveChatWidget] Failed to create new session:",e),p?.(e)}},[o,n,c,l,S,w,m,d,u,p]),ee=x(async e=>{try{const s=await l({user_id:o,session_id:e,site:n,real_user_id:c});if(s.success&&s.resumed)if(s.messages&&s.messages.length>0){const r=s.messages.map(T);z(r)}else{w();const r=s.welcomeMessage||m;if(r){const t=[{type:"text",text:r}],a=s.quickQuestions;if(a&&a.length>0){const y=a.map((i,te)=>({id:`quick-${te}`,label:i,value:i}));t.push({type:"quick_replies",data:{replies:y}})}else d&&d.length>0&&t.push({type:"quick_replies",data:{replies:d}});u({id:`welcome-${Date.now()}`,role:"assistant",content:t,timestamp:Date.now()})}}else s.resumed||(f(),g())}catch(s){console.error("[LiveChatWidget] Failed to resume session:",s),f(),g()}},[o,n,c,l,z,f,w,T,g,m,d,u]),B=x(async e=>{const s=e||q.trim();if(!s)return;e||v("");const r=de(s);if(!r){p?.(new Error("\u65E0\u6548\u7684\u6D88\u606F\u5185\u5BB9"));return}const t={id:`user-${Date.now()}`,role:"user",content:[{type:"text",text:r}],timestamp:Date.now()};u(t),D?.(r);try{let a=R;if(!a){const i=await l({user_id:o,site:n,real_user_id:c});if(i.success)a=i.sessionId,S(a);else throw new Error("Failed to create session")}await E({message:r,user_id:o,session_id:a,context:{cartId:A,accessToken:W,real_user_id:c}},i=>{$(i),i.event==="status"&&i.data.type==="session_expired"&&f()})}catch(a){console.error("[LiveChatWidget] Failed to send message:",a),p?.(a)}},[q,o,R,n,c,A,W,v,u,l,E,$,S,f,D,p]);return L.useEffect(()=>{N.current=B},[B]),xe(Se,{children:[h(re,{position:G,onClick:I,visible:!C,iconImageUrl:K}),h(F.Root,{open:C,onOpenChange:e=>e?I():Q(),children:h(F.Portal,{children:h(F.Content,{className:"livechat-window-enter",style:{position:"fixed",zIndex:9998},children:h(ae,{messages:k,inputValue:q,onInputChange:v,onSend:()=>B(),onClose:Q,onNewSession:g,title:J,logoUrl:H,isSending:U,rendererRegistry:b,inputPlaceholder:"",onAddToCart:_,showNewSessionButton:Z})})})})]})};export{We as LiveChatWidget};
1
+ import{Fragment as Ze,jsx as R,jsxs as je}from"react/jsx-runtime";import w,{useEffect as Ae,useCallback as y}from"react";import*as H from"@radix-ui/react-dialog";import{DEFAULT_COMMON_TEXT as ve}from"./constants";import{ChatBubble as qe}from"./components/ChatBubble";import{ChatWindow as Oe}from"./components/ChatWindow";import{ComplianceDialog as Fe}from"./components/ComplianceDialog";import{useChatState as Be}from"./hooks/useChatState";import{useChatAPI as We}from"./hooks/useChatAPI";import{MessageRendererRegistry as Ie}from"./utils/messageRenderers";import{sanitizeInput as Le}from"./utils/validation";import{transformProducts as te}from"./utils/productTransformers.js";import{transformCartData as Ne}from"./utils/cartTransformers.js";import se from"js-cookie";import{TextBlock as $e,ProductCard as ke,ProductList as Qe,ProductComparisonRenderer as ze,PolicyBlock as He,createQuickRepliesRenderer as Ye,ThinkingBlock as Ge,ErrorBlock as Ve,FAQListRenderer as Xe,PromotionListRenderer as Ke,CartCard as Je}from"./components/MessageContent/index.js";const lt=({apiBaseUrl:ae,headers:re,recaptchaSitekey:Y,recaptchaAction:ne,site:o,channelCode:m,loginUserId:l,cartId:G,accessToken:V,position:oe,welcomeMessage:x,quickReplies:u,customRenderers:B,logoUrl:ie,title:ce,chatBubbleIcon:de,open:pe,onOpenChange:le,onOpen:ue,onClose:me,onMessageSend:W,onError:g,onTextMessage:ge,onProductList:he,onPromotionList:fe,onAddToCart:T,onCart:I,showNewSessionButton:ye,commonText:X,productCardRender:_e,bottomTips:Ce,complianceConfig:_})=>{const L=_?.cookieName||"livechat_compliance_agreed",[K,N]=w.useState(!1),[J,we]=w.useState(()=>_?se.get(L)!==void 0:!0),D=w.useMemo(()=>({...ve,...X}),[X]),Re=Be({welcomeMessage:x,site:o,open:pe,onOpenChange:le,onOpen:ue,onClose:me,onMessageSend:W,onError:g,onTextMessage:ge,onProductList:he,onPromotionList:fe,onAddToCart:T,onCart:I,productCardRender:_e}),{messages:A,isOpen:v,userId:i,sessionId:$,inputValue:k,isStreaming:xe,openChat:S,closeChat:Z,setInputValue:Q,addMessage:p,setMessages:C,clearMessages:q,handleSSEEvent:j,saveSession:E,clearSession:M}=Re,{sendMessageStream:U,createSession:h}=We({apiBaseUrl:ae,headers:re,recaptchaConfig:{needRecaptcha:!!Y,recaptchaSitekey:Y,recaptchaAction:ne},onError:g}),b=w.useRef(async t=>{}),De=w.useMemo(()=>{const t=new Ie;t.register("text",$e),t.register("product_card",ke),t.register("product_list",Qe),t.register("product_comparison",ze),t.register("policy",He),t.register("thinking",Ge),t.register("error",Ve),t.register("faq_list",Xe),t.register("promotion_list",Ke),t.register("cart",Je);const s=Ye(r=>{b.current(r.value)});return t.register("quick_replies",s),B&&t.registerMany(B),t},[B]);Ae(()=>{if(!v||!i)return;const t=$;t?Se(t):P()},[v,i]);const ee=y(t=>{if(Array.isArray(t.content))return t;const s=[];typeof t.content=="string"&&t.content.trim()&&s.push({type:"text",text:t.content});const r=t.structuredContent||t.structured_content;return Array.isArray(r)&&r.forEach(e=>{if(e.type==="product_list"&&Array.isArray(e.data))s.push({type:"product_list",data:{products:te(e.data,o),title:void 0,commonText:D}});else if(e.type==="quick_replies"&&e.data?.replies)s.push({type:"quick_replies",data:{replies:e.data.replies}});else if(e.type==="policy"&&e.data?.title&&e.data?.content)s.push({type:"policy",data:{title:e.data.title,content:e.data.content}});else if(e.type==="product_comparison"&&e.data?.products&&e.data?.dimensions)s.push({type:"product_comparison",data:{products:te(e.data.products,o),dimensions:e.data.dimensions,onAddToCart:T,commonText:D}});else if(e.type==="faq_list"&&e.data?.found!==void 0)s.push({type:"faq_list",data:e.data});else if(e.type==="promotion_list"&&e.data?.found!==void 0)s.push({type:"promotion_list",data:{...e.data,commonText:D}});else if(e.type==="cart"&&e.data?.id!==void 0){const c=Ne(e.data);s.push({type:"cart",data:{...c,onCart:I,commonText:D}})}else s.push(e)}),s.length===0&&s.push({type:"text",text:""}),{...t,content:s}},[o,I,T,D]),P=y(async()=>{if(i)try{const t=await h({user_id:i,site:o,channel_code:m,real_user_id:l});if(t.success){E(t.sessionId),q();const s=t.welcomeMessage||x;if(s){const r=[{type:"text",text:s}],e=t.quickQuestions;if(e&&e.length>0){const c=e.map((d,a)=>({id:`quick-${a}`,label:d,value:d}));r.push({type:"quick_replies",data:{replies:c}})}else u&&u.length>0&&r.push({type:"quick_replies",data:{replies:u}});p({id:`welcome-${Date.now()}`,role:"assistant",content:r,timestamp:Date.now()})}}}catch(t){console.error("[LiveChatWidget] Failed to create new session:",t),g?.(t);const s=t?.type==="GoogleRecaptchaError";p({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()})}},[i,o,m,l,h,E,q,x,u,p,g]),Se=y(async t=>{try{const s=await h({user_id:i,session_id:t,site:o,channel_code:m,real_user_id:l});if(s.success&&s.resumed){const r=s.welcomeMessage||x,e=r?[{type:"text",text:r}]:[],c=s.quickQuestions;if(c&&c.length>0){const d=c.map((a,F)=>({id:`quick-${F}`,label:a,value:a}));e.push({type:"quick_replies",data:{replies:d}})}else u&&u.length>0&&e.push({type:"quick_replies",data:{replies:u}});if(s.messages&&s.messages.length>0){const d=s.messages.filter(a=>a!=null).map(ee).filter(a=>a.content&&a.content.length>0&&!(a.content.length===1&&a.content[0].type==="text"&&!a.content[0].text));if(e.length>0){const a={id:`welcome-${Date.now()}`,role:"assistant",content:e,timestamp:Date.now()};C([a,...d])}else C(d)}else q(),e.length>0&&p({id:`welcome-${Date.now()}`,role:"assistant",content:e,timestamp:Date.now()})}else s.resumed||(M(),P())}catch(s){console.error("[LiveChatWidget] Failed to resume session:",s),s?.type==="GoogleRecaptchaError"?p({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()}):(p({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()}),M(),P())}},[i,o,m,l,h,C,M,q,ee,P,x,u,p]),O=y(async(t,s=!1)=>{const r=t||k.trim();if(!r)return;!t&&!s&&Q("");const e=Le(r);if(!e){g?.(new Error("Invalid message"));return}if(!s){const a={id:`user-${Date.now()}`,role:"user",content:[{type:"text",text:e}],timestamp:Date.now()};p(a)}const c={id:`thinking-${Date.now()}`,role:"assistant",content:[{type:"thinking",data:{status:"thinking"}}],timestamp:Date.now()};p(c),s||W?.(e);let d=!1;try{let a=$;if(!a){const n=await h({user_id:i,site:o,channel_code:m,real_user_id:l});if(n.success)a=n.sessionId,E(a);else throw new Error("Failed to create session")}if(await U({message:e,user_id:i,session_id:a,context:{cartId:G,accessToken:V,real_user_id:l}},n=>{j(n),n.event==="error"&&n.data.type==="validation_error"&&(d=!0,M())}),d&&!s){console.log("[LiveChatWidget] Session expired (validation_error), creating new session and retrying...");const n=A.filter(z=>z.id!==c.id);C(n);const f=await h({user_id:i,site:o,channel_code:m,real_user_id:l});if(f.success)E(f.sessionId),await O(e,!0);else throw new Error("Failed to recreate session after expiration")}}catch(a){console.error("[LiveChatWidget] Failed to send message:",a),g?.(a);const F=a?.type==="GoogleRecaptchaError";let n,f;F?(n="Your session has expired. Please refresh the page and try again.",f="RECAPTCHA_ERROR"):d?(n="Your session has expired. We tried to reconnect but failed. Please try again.",f="SESSION_EXPIRED"):(n="Failed to send message. Please check your network connection and try again.",f="NETWORK_ERROR");const z=A.filter(Te=>Te.id!==c.id);C([...z,{id:`error-${Date.now()}`,role:"system",content:[{type:"error",data:{message:n,code:f}}],timestamp:Date.now()}])}},[k,i,$,o,m,l,G,V,A,Q,p,C,h,U,j,E,M,W,g]);w.useEffect(()=>{b.current=O},[O]);const Ee=y(()=>{_&&!J?N(!0):S()},[_,J,S]),Me=y(()=>{we(!0),N(!1),se.set(L,"true",{expires:365}),S()},[S,L]),Pe=y(()=>{N(!1)},[]);return je(Ze,{children:[_&&R(Fe,{open:K,config:_,onAgree:Me,onClose:Pe}),R(qe,{position:oe,onClick:Ee,visible:!v&&!K,iconImageUrl:de}),R(H.Root,{open:v,onOpenChange:t=>t?S():Z(),children:R(H.Portal,{children:R(H.Content,{className:"livechat-window-enter",style:{position:"fixed",zIndex:9998},children:R(Oe,{messages:A,inputValue:k,onInputChange:Q,onSend:()=>O(),onClose:Z,onNewSession:P,title:ce,logoUrl:ie,isSending:xe,rendererRegistry:De,inputPlaceholder:"",onAddToCart:T,showNewSessionButton:ye,bottomTips:Ce})})})})]})};export{lt 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} from './types'\nimport { ChatBubble } from './components/ChatBubble'\nimport { ChatWindow } from './components/ChatWindow'\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 {\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 *\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 * // \u4F7F\u7528\u9ED8\u8BA4\u4F4D\u7F6E\uFF08\u53F3\u4E0B\u89D2\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 */\nexport const LiveChatWidget: React.FC<LiveChatWidgetProps> = ({\n apiBaseUrl,\n site,\n loginUserId,\n cartId,\n accessToken,\n position,\n welcomeMessage,\n quickReplies,\n customRenderers,\n logoUrl,\n title,\n chatBubbleIcon,\n onOpen,\n onClose,\n onMessageSend,\n onError,\n onAddToCart,\n onCart,\n showNewSessionButton,\n}) => {\n // \u72B6\u6001\u7BA1\u7406\n const chatState = useChatState({\n welcomeMessage,\n site,\n onOpen,\n onClose,\n onMessageSend,\n onError,\n onAddToCart,\n onCart,\n })\n\n const {\n messages,\n isOpen,\n userId,\n sessionId,\n inputValue,\n isStreaming,\n openChat,\n closeChat,\n setInputValue,\n addMessage,\n setMessages,\n clearMessages,\n handleSSEEvent,\n saveSession,\n clearSession,\n } = chatState\n\n // API \u8C03\u7528\n const { sendMessageStream, createSession } = useChatAPI({\n apiBaseUrl,\n 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 },\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 },\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: block.data,\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 },\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]\n )\n\n /**\n * \u521B\u5EFA\u65B0\u4F1A\u8BDD\n */\n const handleCreateNewSession = useCallback(async () => {\n if (!userId) return\n\n try {\n const response = await createSession({\n user_id: userId,\n site: site,\n 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 }, [\n userId,\n site,\n loginUserId,\n createSession,\n saveSession,\n clearMessages,\n welcomeMessage,\n quickReplies,\n addMessage,\n onError,\n ])\n\n /**\n * \u6062\u590D\u4F1A\u8BDD\u548C\u5386\u53F2\u6D88\u606F\uFF08\u4F7F\u7528\u65B0\u7684 API v2.0.0\uFF09\n */\n const handleResumeSession = useCallback(\n async (existingSessionId: string) => {\n try {\n const response = await createSession({\n user_id: userId,\n session_id: existingSessionId,\n site: site,\n real_user_id: loginUserId,\n })\n\n if (response.success && response.resumed) {\n // \u4F1A\u8BDD\u6062\u590D\u6210\u529F\n if (response.messages && response.messages.length > 0) {\n // \u6709\u5386\u53F2\u6D88\u606F\uFF0C\u89C4\u8303\u5316\u5E76\u52A0\u8F7D\n const normalizedMessages = response.messages.map(normalizeMessage)\n setMessages(normalizedMessages)\n } else {\n // \u6CA1\u6709\u5386\u53F2\u6D88\u606F\uFF0C\u663E\u793A\u6B22\u8FCE\u6D88\u606F\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\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 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 // \u6062\u590D\u5931\u8D25\uFF0C\u6E05\u7A7A\u4F1A\u8BDD\u5E76\u521B\u5EFA\u65B0\u7684\n clearSession()\n handleCreateNewSession()\n }\n },\n [\n userId,\n site,\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) => {\n const textToSend = message || inputValue.trim()\n\n if (!textToSend) return\n\n // \u6E05\u7A7A\u8F93\u5165\u6846\n if (!message) {\n setInputValue('')\n }\n\n // \u8F93\u5165\u9A8C\u8BC1\n const sanitized = sanitizeInput(textToSend)\n if (!sanitized) {\n onError?.(new Error('\u65E0\u6548\u7684\u6D88\u606F\u5185\u5BB9'))\n return\n }\n\n // \u6DFB\u52A0\u7528\u6237\u6D88\u606F\u5230\u754C\u9762\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 // \u89E6\u53D1\u6D88\u606F\u53D1\u9001\u56DE\u8C03\n onMessageSend?.(sanitized)\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 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\n if (event.event === 'status' && event.data.type === 'session_expired') {\n clearSession()\n }\n })\n } catch (error) {\n console.error('[LiveChatWidget] Failed to send message:', error)\n onError?.(error as Error)\n }\n },\n [\n inputValue,\n userId,\n sessionId,\n site,\n loginUserId,\n cartId,\n accessToken,\n setInputValue,\n addMessage,\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 return (\n <>\n {/* \u6C14\u6CE1\u6309\u94AE */}\n <ChatBubble position={position} onClick={openChat} visible={!isOpen} iconImageUrl={chatBubbleIcon} />\n\n {/* \u804A\u5929\u7A97\u53E3\uFF08\u4F7F\u7528 Radix UI Dialog\uFF09 */}\n <Dialog.Root open={isOpen} onOpenChange={open => (open ? openChat() : closeChat())}>\n <Dialog.Portal>\n <Dialog.Content\n className=\"livechat-window-enter\"\n style={{\n position: 'fixed',\n zIndex: 9998,\n }}\n >\n <ChatWindow\n messages={messages}\n inputValue={inputValue}\n onInputChange={setInputValue}\n onSend={() => handleSendMessage()}\n onClose={closeChat}\n onNewSession={handleCreateNewSession}\n title={title}\n logoUrl={logoUrl}\n isSending={isStreaming}\n rendererRegistry={rendererRegistry}\n inputPlaceholder=\"\"\n onAddToCart={onAddToCart}\n showNewSessionButton={showNewSessionButton}\n />\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", "ChatBubble", "ChatWindow", "useChatState", "useChatAPI", "MessageRendererRegistry", "sanitizeInput", "transformProducts", "transformCartData", "TextBlock", "ProductCard", "ProductList", "ProductComparisonRenderer", "PolicyBlock", "createQuickRepliesRenderer", "ThinkingBlock", "ErrorBlock", "FAQListRenderer", "PromotionListRenderer", "CartCard", "LiveChatWidget", "apiBaseUrl", "site", "loginUserId", "cartId", "accessToken", "position", "welcomeMessage", "quickReplies", "customRenderers", "logoUrl", "title", "chatBubbleIcon", "onOpen", "onClose", "onMessageSend", "onError", "onAddToCart", "onCart", "showNewSessionButton", "chatState", "messages", "isOpen", "userId", "sessionId", "inputValue", "isStreaming", "openChat", "closeChat", "setInputValue", "addMessage", "setMessages", "clearMessages", "handleSSEEvent", "saveSession", "clearSession", "sendMessageStream", "createSession", "handleSendMessageRef", "_message", "rendererRegistry", "registry", "quickRepliesRenderer", "reply", "currentSessionId", "handleResumeSession", "handleCreateNewSession", "normalizeMessage", "message", "contentBlocks", "structuredData", "block", "transformedData", "response", "messageText", "welcomeContent", "questions", "quickRepliesFromBackend", "question", "index", "error", "existingSessionId", "normalizedMessages", "handleSendMessage", "textToSend", "sanitized", "userMessage", "event", "open"]
4
+ "sourcesContent": ["/**\n * LiveChat \u4E3B\u7EC4\u4EF6\n * \u96C6\u6210\u6240\u6709\u5B50\u7EC4\u4EF6\uFF0C\u63D0\u4F9B\u5B8C\u6574\u7684\u804A\u5929\u529F\u80FD\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u4E09\u5C42\u67B6\u6784\u8BBE\u8BA1\n */\n\nimport React, { useEffect, useCallback } from 'react'\nimport * as Dialog from '@radix-ui/react-dialog'\nimport type {\n LiveChatWidgetProps,\n QuickReply,\n Message,\n MessageContent,\n ChatStreamRequest,\n BackendCartData,\n CommonText,\n} from './types'\nimport { DEFAULT_COMMON_TEXT } from './constants'\nimport { ChatBubble } from './components/ChatBubble'\nimport { ChatWindow } from './components/ChatWindow'\nimport { ComplianceDialog } from './components/ComplianceDialog'\nimport { useChatState } from './hooks/useChatState'\nimport { useChatAPI } from './hooks/useChatAPI'\nimport { MessageRendererRegistry } from './utils/messageRenderers'\nimport { sanitizeInput } from './utils/validation'\nimport { transformProducts } from './utils/productTransformers.js'\nimport { transformCartData } from './utils/cartTransformers.js'\nimport Cookies from 'js-cookie'\nimport {\n TextBlock,\n ProductCard,\n ProductList,\n ProductComparisonRenderer,\n PolicyBlock,\n createQuickRepliesRenderer,\n ThinkingBlock,\n ErrorBlock,\n FAQListRenderer,\n PromotionListRenderer,\n CartCard,\n} from './components/MessageContent/index.js'\n\n/**\n * LiveChat \u804A\u5929\u7EC4\u4EF6\n *\n * \u529F\u80FD\uFF1A\n * - \u6C14\u6CE1\u5F39\u7A97\u804A\u5929\u754C\u9762\n * - SSE \u6D41\u5F0F\u6D88\u606F\u63A5\u6536\n * - \u4F1A\u8BDD\u7BA1\u7406\uFF08userId, sessionId\uFF09\n * - \u5386\u53F2\u6D88\u606F\u52A0\u8F7D\n * - \u591A\u79CD\u6D88\u606F\u7C7B\u578B\u6E32\u67D3\n * - \u81EA\u5B9A\u4E49\u6269\u5C55\u673A\u5236\n * - reCAPTCHA v3 \u5B89\u5168\u9632\u62A4\n *\n * \u67B6\u6784\uFF1A\n * - UI Layer: ChatBubble, ChatWindow, MessageList, etc.\n * - Logic Layer: useChatState, useChatAPI, useSession\n * - Core Layer: MessageRendererRegistry, \u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\n *\n * @example\n * ```tsx\n * // \u57FA\u7840\u4F7F\u7528\uFF08\u4F7F\u7528\u9ED8\u8BA4\u4F4D\u7F6E\uFF09\n * <LiveChatWidget\n * apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n * site=\"www.eufy.com\"\n * welcomeMessage=\"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\"\n * onMessageSend={(msg) => console.log('Sent:', msg)}\n * />\n *\n * // \u4F7F\u7528\u81EA\u5B9A\u4E49\u4F4D\u7F6E\n * <LiveChatWidget\n * apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n * site=\"www.eufy.com\"\n * position={{ bottom: \"20px\", right: \"30px\" }}\n * onMessageSend={(msg) => console.log('Sent:', msg)}\n * />\n *\n * // \u542F\u7528 reCAPTCHA v3 \u5B89\u5168\u9632\u62A4\uFF08\u63D0\u4F9B sitekey \u5373\u81EA\u52A8\u542F\u7528\uFF09\n * <LiveChatWidget\n * apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n * site=\"www.eufy.com\"\n * recaptchaSitekey=\"6LfS4J4pAAAAACX1e_WrxutmxxzCK7FU4WzVqL14\"\n * recaptchaAction=\"livechat\"\n * />\n *\n * // \u4F7F\u7528\u81EA\u5B9A\u4E49 headers \u548C reCAPTCHA\n * <LiveChatWidget\n * apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n * site=\"www.eufy.com\"\n * headers={{\n * \"Authorization\": \"Bearer your-token\",\n * \"X-Custom-Header\": \"value\"\n * }}\n * recaptchaSitekey=\"your-site-key\"\n * />\n * ```\n */\nexport const LiveChatWidget: React.FC<LiveChatWidgetProps> = ({\n apiBaseUrl,\n headers,\n recaptchaSitekey,\n recaptchaAction,\n site,\n channelCode,\n loginUserId,\n cartId,\n accessToken,\n position,\n welcomeMessage,\n quickReplies,\n customRenderers,\n logoUrl,\n title,\n chatBubbleIcon,\n open,\n onOpenChange,\n onOpen,\n onClose,\n onMessageSend,\n onError,\n onTextMessage,\n onProductList,\n onPromotionList,\n onAddToCart,\n onCart,\n showNewSessionButton,\n commonText,\n productCardRender,\n bottomTips,\n complianceConfig,\n}) => {\n // \u6CD5\u89C4\u534F\u8BAE\u5F39\u7A97\u72B6\u6001\n // \u4ECE Cookie \u8BFB\u53D6\u7528\u6237\u662F\u5426\u5DF2\u540C\u610F\uFF08\u6709\u6548\u671F 365 \u5929\uFF09\n const cookieName = complianceConfig?.cookieName || 'livechat_compliance_agreed'\n const [showComplianceDialog, setShowComplianceDialog] = React.useState(false)\n const [hasAgreedCompliance, setHasAgreedCompliance] = React.useState(() => {\n // \u521D\u59CB\u5316\u65F6\u68C0\u67E5 Cookie\n return complianceConfig ? Cookies.get(cookieName) !== undefined : true\n })\n\n // \u5408\u5E76\u9ED8\u8BA4\u6587\u6848\u548C\u81EA\u5B9A\u4E49\u6587\u6848\n const mergedText: Required<CommonText> = React.useMemo(\n () => ({\n ...DEFAULT_COMMON_TEXT,\n ...commonText,\n }),\n [commonText]\n )\n\n // \u72B6\u6001\u7BA1\u7406\n const chatState = useChatState({\n welcomeMessage,\n site,\n open,\n onOpenChange,\n onOpen,\n onClose,\n onMessageSend,\n onError,\n onTextMessage,\n onProductList,\n onPromotionList,\n onAddToCart,\n onCart,\n productCardRender,\n })\n\n const {\n messages,\n isOpen,\n userId,\n sessionId,\n inputValue,\n isStreaming,\n openChat,\n closeChat,\n setInputValue,\n addMessage,\n setMessages,\n clearMessages,\n handleSSEEvent,\n saveSession,\n clearSession,\n } = chatState\n\n // API \u8C03\u7528\n const { sendMessageStream, createSession } = useChatAPI({\n apiBaseUrl,\n headers,\n recaptchaConfig: {\n needRecaptcha: !!recaptchaSitekey, // \u6839\u636E sitekey \u81EA\u52A8\u5224\u65AD\u662F\u5426\u542F\u7528\n recaptchaSitekey,\n recaptchaAction,\n },\n onError,\n })\n\n // \u4F7F\u7528 ref \u5B58\u50A8\u6700\u65B0\u7684 handleSendMessage\uFF0C\u907F\u514D\u5FAA\u73AF\u4F9D\u8D56\n const handleSendMessageRef = React.useRef<(_message?: string) => Promise<void>>(async (_message?: string) => {})\n\n // \u6D88\u606F\u6E32\u67D3\u5668\u6CE8\u518C\u8868\n const rendererRegistry = React.useMemo(() => {\n const registry = new MessageRendererRegistry()\n\n // \u6CE8\u518C\u9ED8\u8BA4\u6E32\u67D3\u5668\n registry.register('text', TextBlock)\n registry.register('product_card', ProductCard)\n registry.register('product_list', ProductList)\n registry.register('product_comparison', ProductComparisonRenderer)\n registry.register('policy', PolicyBlock)\n registry.register('thinking', ThinkingBlock)\n registry.register('error', ErrorBlock)\n registry.register('faq_list', FAQListRenderer)\n registry.register('promotion_list', PromotionListRenderer)\n registry.register('cart', CartCard)\n\n // \u6CE8\u518C\u5FEB\u6377\u56DE\u590D\u6E32\u67D3\u5668\uFF08\u5E26\u56DE\u8C03\uFF09\n const quickRepliesRenderer = createQuickRepliesRenderer((reply: QuickReply) => {\n // \u4F7F\u7528 ref \u8C03\u7528\u6700\u65B0\u7684 handleSendMessage\n handleSendMessageRef.current(reply.value)\n })\n registry.register('quick_replies', quickRepliesRenderer)\n\n // \u6CE8\u518C\u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\n if (customRenderers) {\n registry.registerMany(customRenderers)\n }\n\n return registry\n }, [customRenderers])\n\n /**\n * T043: \u6253\u5F00\u804A\u5929\u7A97\u53E3\u65F6\u521D\u59CB\u5316\u4F1A\u8BDD\n * \u4F7F\u7528 API v2.0.0 \u7684\u7EDF\u4E00\u63A5\u53E3\uFF1A\n * - \u5982\u679C\u6CA1\u6709 sessionId\uFF0C\u521B\u5EFA\u65B0\u4F1A\u8BDD\n * - \u5982\u679C\u6709 sessionId\uFF0C\u6062\u590D\u4F1A\u8BDD\u5E76\u52A0\u8F7D\u5386\u53F2\u6D88\u606F\n */\n useEffect(() => {\n if (!isOpen || !userId) return\n\n const currentSessionId = sessionId\n\n if (!currentSessionId) {\n // \u6CA1\u6709\u4F1A\u8BDD\uFF0C\u521B\u5EFA\u65B0\u4F1A\u8BDD\n handleCreateNewSession()\n } else {\n // \u6709\u4F1A\u8BDD\uFF0C\u5C1D\u8BD5\u6062\u590D\u4F1A\u8BDD\u548C\u5386\u53F2\u6D88\u606F\n handleResumeSession(currentSessionId)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen, userId])\n\n /**\n * \u89C4\u8303\u5316\u6D88\u606F\u683C\u5F0F\uFF08\u786E\u4FDD content \u662F\u6570\u7EC4\uFF09\n * \u540E\u7AEF\u8FD4\u56DE\u683C\u5F0F\uFF1A\n * - content: \u5B57\u7B26\u4E32\uFF08\u6587\u672C\u5185\u5BB9\uFF09\n * - structuredContent: \u6570\u7EC4\uFF08\u7ED3\u6784\u5316\u5185\u5BB9\uFF0C\u5982\u4EA7\u54C1\u5217\u8868\u3001\u653F\u7B56\u7B49\uFF09\n * \u9700\u8981\u5408\u5E76\u4E3A\u7EDF\u4E00\u7684 content \u6570\u7EC4\u683C\u5F0F\n */\n const normalizeMessage = useCallback(\n (message: any): Message => {\n // \u5982\u679C content \u5DF2\u7ECF\u662F\u6570\u7EC4\uFF0C\u76F4\u63A5\u8FD4\u56DE\n if (Array.isArray(message.content)) {\n return message as Message\n }\n\n const contentBlocks: MessageContent[] = []\n\n // \u5904\u7406\u6587\u672C\u5185\u5BB9\n if (typeof message.content === 'string' && message.content.trim()) {\n contentBlocks.push({\n type: 'text',\n text: message.content,\n })\n }\n\n // \u5904\u7406\u7ED3\u6784\u5316\u5185\u5BB9\n // \u5386\u53F2\u6D88\u606F\u683C\u5F0F: structured_content: [{type, data}]\n const structuredData = message.structuredContent || message.structured_content\n\n if (Array.isArray(structuredData)) {\n structuredData.forEach((block: any) => {\n if (block.type === 'product_list' && Array.isArray(block.data)) {\n // \u8F6C\u6362\u4EA7\u54C1\u5217\u8868\u6570\u636E\u7ED3\u6784 - data \u76F4\u63A5\u662F\u4EA7\u54C1\u6570\u7EC4\n contentBlocks.push({\n type: 'product_list',\n data: {\n products: transformProducts(block.data, site),\n title: undefined, // \u5386\u53F2\u6D88\u606F\u4E0D\u5305\u542B title\n commonText: mergedText,\n },\n })\n } else if (block.type === 'quick_replies' && block.data?.replies) {\n contentBlocks.push({\n type: 'quick_replies',\n data: {\n replies: block.data.replies,\n },\n })\n } else if (block.type === 'policy' && block.data?.title && block.data?.content) {\n contentBlocks.push({\n type: 'policy',\n data: {\n title: block.data.title,\n content: block.data.content,\n },\n })\n } else if (block.type === 'product_comparison' && block.data?.products && block.data?.dimensions) {\n // \u8F6C\u6362\u4EA7\u54C1\u5BF9\u6BD4\u6570\u636E\u7ED3\u6784\u5E76\u6CE8\u5165 onAddToCart \u56DE\u8C03\n contentBlocks.push({\n type: 'product_comparison',\n data: {\n products: transformProducts(block.data.products, site),\n dimensions: block.data.dimensions,\n onAddToCart: onAddToCart,\n commonText: mergedText,\n },\n })\n } else if (block.type === 'faq_list' && block.data?.found !== undefined) {\n // FAQ \u5217\u8868\u5361\u7247 - \u76F4\u63A5\u4F7F\u7528\u540E\u7AEF\u6570\u636E\n contentBlocks.push({\n type: 'faq_list',\n data: block.data,\n })\n } else if (block.type === 'promotion_list' && block.data?.found !== undefined) {\n // \u4FC3\u9500\u6D3B\u52A8\u5217\u8868\u5361\u7247 - \u76F4\u63A5\u4F7F\u7528\u540E\u7AEF\u6570\u636E\n contentBlocks.push({\n type: 'promotion_list',\n data: {\n ...block.data,\n commonText: mergedText,\n },\n })\n } else if (block.type === 'cart' && block.data?.id !== undefined) {\n // \u8D2D\u7269\u8F66\u5361\u7247 - \u8F6C\u6362\u540E\u7AEF\u6570\u636E\u683C\u5F0F\u5E76\u6CE8\u5165 onCart \u56DE\u8C03\n const transformedData = transformCartData(block.data as BackendCartData)\n contentBlocks.push({\n type: 'cart',\n data: {\n ...transformedData,\n onCart: onCart,\n commonText: mergedText,\n },\n })\n } else {\n // \u5176\u4ED6\u7C7B\u578B\u76F4\u63A5\u6DFB\u52A0\n contentBlocks.push(block)\n }\n })\n }\n\n // \u5982\u679C\u6CA1\u6709\u4EFB\u4F55\u5185\u5BB9\u5757\uFF0C\u8FD4\u56DE\u7A7A\u6587\u672C\u5757\n if (contentBlocks.length === 0) {\n contentBlocks.push({\n type: 'text',\n text: '',\n })\n }\n\n return {\n ...message,\n content: contentBlocks,\n } as Message\n },\n [site, onCart, onAddToCart, mergedText]\n )\n\n /**\n * \u521B\u5EFA\u65B0\u4F1A\u8BDD\n */\n const handleCreateNewSession = useCallback(async () => {\n if (!userId) return\n\n try {\n const response = await createSession({\n user_id: userId,\n site: site,\n channel_code: channelCode,\n real_user_id: loginUserId,\n })\n\n if (response.success) {\n // \u4FDD\u5B58\u65B0\u4F1A\u8BDD ID\n saveSession(response.sessionId)\n\n // \u6E05\u7A7A\u6D88\u606F\u5217\u8868\n clearMessages()\n\n // \u4F7F\u7528\u540E\u7AEF\u8FD4\u56DE\u7684\u6B22\u8FCE\u6D88\u606F\uFF0C\u5982\u679C\u6CA1\u6709\u5219\u4F7F\u7528 props \u4E2D\u7684\u9ED8\u8BA4\u503C\n const messageText = response.welcomeMessage || welcomeMessage\n\n if (messageText) {\n const welcomeContent: MessageContent[] = [{ type: 'text', text: messageText }]\n\n // \u4F7F\u7528\u540E\u7AEF\u8FD4\u56DE\u7684\u5FEB\u6377\u95EE\u9898\uFF0C\u5982\u679C\u6CA1\u6709\u5219\u4F7F\u7528 props \u4E2D\u7684\u5FEB\u6377\u56DE\u590D\n const questions = response.quickQuestions\n if (questions && questions.length > 0) {\n // \u5C06\u540E\u7AEF\u7684 quickQuestions (\u5B57\u7B26\u4E32\u6570\u7EC4) \u8F6C\u6362\u4E3A QuickReply \u683C\u5F0F\n const quickRepliesFromBackend = questions.map((question, index) => ({\n id: `quick-${index}`,\n label: question,\n value: question,\n }))\n\n welcomeContent.push({\n type: 'quick_replies',\n data: {\n replies: quickRepliesFromBackend,\n },\n })\n } else if (quickReplies && quickReplies.length > 0) {\n // \u5982\u679C\u540E\u7AEF\u6CA1\u6709\u8FD4\u56DE\uFF0C\u4F7F\u7528 props \u4E2D\u7684\u5FEB\u6377\u56DE\u590D\n welcomeContent.push({\n type: 'quick_replies',\n data: {\n replies: quickReplies,\n },\n })\n }\n\n addMessage({\n id: `welcome-${Date.now()}`,\n role: 'assistant',\n content: welcomeContent,\n timestamp: Date.now(),\n })\n }\n }\n } catch (error) {\n console.error('[LiveChatWidget] Failed to create new session:', error)\n onError?.(error as Error)\n\n // Check if it's a reCAPTCHA error\n const isRecaptcha = (error as any)?.type === 'GoogleRecaptchaError'\n\n // \u6DFB\u52A0\u9519\u8BEF\u6D88\u606F\u5230\u754C\u9762\n addMessage({\n id: `error-${Date.now()}`,\n role: 'system',\n content: [\n {\n type: 'error',\n data: {\n message: isRecaptcha\n ? 'Your session has expired. Please refresh the page and try again.'\n : 'Failed to create session. Please refresh the page and try again.',\n code: isRecaptcha ? 'RECAPTCHA_ERROR' : 'SESSION_CREATE_ERROR',\n },\n },\n ],\n timestamp: Date.now(),\n })\n }\n }, [\n userId,\n site,\n channelCode,\n loginUserId,\n createSession,\n saveSession,\n clearMessages,\n welcomeMessage,\n quickReplies,\n addMessage,\n onError,\n ])\n\n /**\n * \u6062\u590D\u4F1A\u8BDD\u548C\u5386\u53F2\u6D88\u606F\uFF08\u4F7F\u7528\u65B0\u7684 API v2.0.0\uFF09\n */\n const handleResumeSession = useCallback(\n async (existingSessionId: string) => {\n try {\n const response = await createSession({\n user_id: userId,\n session_id: existingSessionId,\n site: site,\n channel_code: channelCode,\n real_user_id: loginUserId,\n })\n\n if (response.success && response.resumed) {\n // \u4F1A\u8BDD\u6062\u590D\u6210\u529F\n\n // \u51C6\u5907\u6B22\u8FCE\u6D88\u606F\uFF08\u65E0\u8BBA\u662F\u5426\u6709\u5386\u53F2\u6D88\u606F\u90FD\u9700\u8981\uFF09\n const messageText = response.welcomeMessage || welcomeMessage\n const welcomeContent: MessageContent[] = messageText ? [{ type: 'text', text: messageText }] : []\n\n // \u6DFB\u52A0\u5FEB\u6377\u56DE\u590D\u5230\u6B22\u8FCE\u6D88\u606F\n const questions = response.quickQuestions\n if (questions && questions.length > 0) {\n const quickRepliesFromBackend = questions.map((question, index) => ({\n id: `quick-${index}`,\n label: question,\n value: question,\n }))\n\n welcomeContent.push({\n type: 'quick_replies',\n data: {\n replies: quickRepliesFromBackend,\n },\n })\n } else if (quickReplies && quickReplies.length > 0) {\n welcomeContent.push({\n type: 'quick_replies',\n data: {\n replies: quickReplies,\n },\n })\n }\n\n if (response.messages && response.messages.length > 0) {\n // \u6709\u5386\u53F2\u6D88\u606F\uFF0C\u89C4\u8303\u5316\u5E76\u52A0\u8F7D\uFF08\u8FC7\u6EE4\u6389 null/undefined \u503C\u548C\u7A7A\u5185\u5BB9\u6D88\u606F\uFF09\n const normalizedMessages = response.messages\n .filter((msg: any) => msg != null)\n .map(normalizeMessage)\n .filter((msg: Message) => msg.content && msg.content.length > 0 && !(msg.content.length === 1 && msg.content[0].type === 'text' && !msg.content[0].text))\n\n // \u5982\u679C\u6709\u6B22\u8FCE\u6D88\u606F\uFF0C\u5C06\u5176\u6DFB\u52A0\u5230\u5386\u53F2\u6D88\u606F\u7684\u5F00\u5934\n if (welcomeContent.length > 0) {\n const welcomeMsg: Message = {\n id: `welcome-${Date.now()}`,\n role: 'assistant',\n content: welcomeContent,\n timestamp: Date.now(),\n }\n setMessages([welcomeMsg, ...normalizedMessages])\n } else {\n setMessages(normalizedMessages)\n }\n } else {\n // \u6CA1\u6709\u5386\u53F2\u6D88\u606F\uFF0C\u4EC5\u663E\u793A\u6B22\u8FCE\u6D88\u606F\n clearMessages()\n\n if (welcomeContent.length > 0) {\n addMessage({\n id: `welcome-${Date.now()}`,\n role: 'assistant',\n content: welcomeContent,\n timestamp: Date.now(),\n })\n }\n }\n } else if (!response.resumed) {\n // \u4F1A\u8BDD\u65E0\u6548\u6216\u8FC7\u671F\uFF0C\u521B\u5EFA\u65B0\u4F1A\u8BDD\n clearSession()\n handleCreateNewSession()\n }\n } catch (error) {\n console.error('[LiveChatWidget] Failed to resume session:', error)\n\n // Check if it's a reCAPTCHA error\n const isRecaptcha = (error as any)?.type === 'GoogleRecaptchaError'\n\n if (isRecaptcha) {\n // reCAPTCHA error - show refresh page message, don't retry\n addMessage({\n id: `error-${Date.now()}`,\n role: 'system',\n content: [\n {\n type: 'error',\n data: {\n message: 'Your session has expired. Please refresh the page and try again.',\n code: 'RECAPTCHA_ERROR',\n },\n },\n ],\n timestamp: Date.now(),\n })\n } else {\n // Other errors - show message and try to create new session\n addMessage({\n id: `error-${Date.now()}`,\n role: 'system',\n content: [\n {\n type: 'error',\n data: {\n message: 'Failed to resume session. Creating a new session...',\n code: 'SESSION_RESUME_ERROR',\n },\n },\n ],\n timestamp: Date.now(),\n })\n\n // \u6062\u590D\u5931\u8D25\uFF0C\u6E05\u7A7A\u4F1A\u8BDD\u5E76\u521B\u5EFA\u65B0\u7684\n clearSession()\n handleCreateNewSession()\n }\n }\n },\n [\n userId,\n site,\n channelCode,\n loginUserId,\n createSession,\n setMessages,\n clearSession,\n clearMessages,\n normalizeMessage,\n handleCreateNewSession,\n welcomeMessage,\n quickReplies,\n addMessage,\n ]\n )\n\n /**\n * \u53D1\u9001\u6D88\u606F\n */\n const handleSendMessage = useCallback(\n async (message?: string, isRetry: boolean = false) => {\n const textToSend = message || inputValue.trim()\n\n if (!textToSend) return\n\n // \u6E05\u7A7A\u8F93\u5165\u6846\uFF08\u4EC5\u5728\u975E\u91CD\u8BD5\u65F6\uFF09\n if (!message && !isRetry) {\n setInputValue('')\n }\n\n // \u8F93\u5165\u9A8C\u8BC1\n const sanitized = sanitizeInput(textToSend)\n if (!sanitized) {\n onError?.(new Error('Invalid message'))\n return\n }\n\n // \u6DFB\u52A0\u7528\u6237\u6D88\u606F\u5230\u754C\u9762\uFF08\u4EC5\u5728\u975E\u91CD\u8BD5\u65F6\uFF09\n if (!isRetry) {\n const userMessage = {\n id: `user-${Date.now()}`,\n role: 'user' as const,\n content: [{ type: 'text' as const, text: sanitized }],\n timestamp: Date.now(),\n }\n addMessage(userMessage)\n }\n\n // \u7ACB\u5373\u6DFB\u52A0\u601D\u8003\u72B6\u6001\u6D88\u606F\uFF0C\u63D0\u5347\u7528\u6237\u4F53\u9A8C\n const thinkingMessage = {\n id: `thinking-${Date.now()}`,\n role: 'assistant' as const,\n content: [{ type: 'thinking' as const, data: { status: 'thinking' } }],\n timestamp: Date.now(),\n }\n addMessage(thinkingMessage)\n\n // \u89E6\u53D1\u6D88\u606F\u53D1\u9001\u56DE\u8C03\uFF08\u4EC5\u5728\u975E\u91CD\u8BD5\u65F6\uFF09\n if (!isRetry) {\n onMessageSend?.(sanitized)\n }\n\n // \u6807\u8BB0\u662F\u5426\u68C0\u6D4B\u5230\u4F1A\u8BDD\u8FC7\u671F\n let sessionExpiredDetected = false\n\n try {\n // \u786E\u4FDD\u6709 sessionId\uFF0C\u5982\u679C\u6CA1\u6709\u5219\u5148\u521B\u5EFA\u4F1A\u8BDD\n let currentSessionId = sessionId\n if (!currentSessionId) {\n // \u6CA1\u6709\u4F1A\u8BDD\uFF0C\u521B\u5EFA\u65B0\u4F1A\u8BDD\n const response = await createSession({\n user_id: userId,\n site: site,\n channel_code: channelCode,\n real_user_id: loginUserId,\n })\n if (response.success) {\n currentSessionId = response.sessionId\n saveSession(currentSessionId)\n } else {\n throw new Error('Failed to create session')\n }\n }\n\n // \u6784\u5EFA\u8BF7\u6C42\u53C2\u6570\uFF08session_id \u73B0\u5728\u662F\u5FC5\u586B\u7684\uFF09\n const requestPayload: ChatStreamRequest = {\n message: sanitized,\n user_id: userId,\n session_id: currentSessionId,\n context: {\n cartId: cartId,\n accessToken: accessToken,\n real_user_id: loginUserId,\n },\n }\n\n // \u53D1\u9001\u6D88\u606F\u5230\u540E\u7AEF\n await sendMessageStream(requestPayload, event => {\n // \u5904\u7406 SSE \u4E8B\u4EF6\n handleSSEEvent(event)\n\n // \u7279\u6B8A\u5904\u7406\uFF1A\u4F1A\u8BDD\u8FC7\u671F\uFF08error \u4E8B\u4EF6\u4E14 type \u4E3A validation_error\uFF09\n if (event.event === 'error' && event.data.type === 'validation_error') {\n sessionExpiredDetected = true\n clearSession()\n }\n })\n\n // \u5982\u679C\u68C0\u6D4B\u5230\u4F1A\u8BDD\u8FC7\u671F\u4E14\u4E0D\u662F\u91CD\u8BD5\uFF0C\u81EA\u52A8\u521B\u5EFA\u65B0\u4F1A\u8BDD\u5E76\u91CD\u8BD5\n if (sessionExpiredDetected && !isRetry) {\n console.log('[LiveChatWidget] Session expired (validation_error), creating new session and retrying...')\n\n // \u79FB\u9664 thinking \u6D88\u606F\n const messagesWithoutThinking = messages.filter(msg => msg.id !== thinkingMessage.id)\n setMessages(messagesWithoutThinking)\n\n // \u521B\u5EFA\u65B0\u4F1A\u8BDD\n const response = await createSession({\n user_id: userId,\n site: site,\n channel_code: channelCode,\n real_user_id: loginUserId,\n })\n\n if (response.success) {\n saveSession(response.sessionId)\n // \u91CD\u8BD5\u53D1\u9001\u6D88\u606F\n await handleSendMessage(sanitized, true)\n } else {\n throw new Error('Failed to recreate session after expiration')\n }\n }\n } catch (error) {\n console.error('[LiveChatWidget] Failed to send message:', error)\n onError?.(error as Error)\n\n // Check if it's a reCAPTCHA error\n const isRecaptcha = (error as any)?.type === 'GoogleRecaptchaError'\n\n // Determine error message based on error type\n let errorMessage: string\n let errorCode: string\n\n if (isRecaptcha) {\n errorMessage = 'Your session has expired. Please refresh the page and try again.'\n errorCode = 'RECAPTCHA_ERROR'\n } else if (sessionExpiredDetected) {\n errorMessage = 'Your session has expired. We tried to reconnect but failed. Please try again.'\n errorCode = 'SESSION_EXPIRED'\n } else {\n errorMessage = 'Failed to send message. Please check your network connection and try again.'\n errorCode = 'NETWORK_ERROR'\n }\n\n // \u79FB\u9664\u521A\u624D\u6DFB\u52A0\u7684 thinking \u6D88\u606F\uFF0C\u5E76\u6DFB\u52A0\u9519\u8BEF\u6D88\u606F\n const messagesWithoutThinking = messages.filter(msg => msg.id !== thinkingMessage.id)\n setMessages([\n ...messagesWithoutThinking,\n {\n id: `error-${Date.now()}`,\n role: 'system',\n content: [\n {\n type: 'error',\n data: {\n message: errorMessage,\n code: errorCode,\n },\n },\n ],\n timestamp: Date.now(),\n },\n ])\n }\n },\n [\n inputValue,\n userId,\n sessionId,\n site,\n channelCode,\n loginUserId,\n cartId,\n accessToken,\n messages,\n setInputValue,\n addMessage,\n setMessages,\n createSession,\n sendMessageStream,\n handleSSEEvent,\n saveSession,\n clearSession,\n onMessageSend,\n onError,\n ]\n )\n\n // \u66F4\u65B0 ref \u4EE5\u4FDD\u6301\u6700\u65B0\u7684 handleSendMessage\n React.useEffect(() => {\n handleSendMessageRef.current = handleSendMessage\n }, [handleSendMessage])\n\n /**\n * \u5904\u7406\u6C14\u6CE1\u6309\u94AE\u70B9\u51FB\n * \u5982\u679C\u914D\u7F6E\u4E86\u6CD5\u89C4\u534F\u8BAE\u4E14\u7528\u6237\u672A\u540C\u610F\uFF0C\u5148\u663E\u793A\u6CD5\u89C4\u5F39\u7A97\n * \u5426\u5219\u76F4\u63A5\u6253\u5F00\u804A\u5929\u7A97\u53E3\n */\n const handleBubbleClick = useCallback(() => {\n if (complianceConfig && !hasAgreedCompliance) {\n // \u663E\u793A\u6CD5\u89C4\u534F\u8BAE\u5F39\u7A97\n setShowComplianceDialog(true)\n } else {\n // \u76F4\u63A5\u6253\u5F00\u804A\u5929\u7A97\u53E3\n openChat()\n }\n }, [complianceConfig, hasAgreedCompliance, openChat])\n\n /**\n * \u5904\u7406\u7528\u6237\u540C\u610F\u6CD5\u89C4\u534F\u8BAE\n */\n const handleComplianceAgree = useCallback(() => {\n // \u8BBE\u7F6E\u540C\u610F\u72B6\u6001\n setHasAgreedCompliance(true)\n setShowComplianceDialog(false)\n\n // \u4FDD\u5B58\u5230 Cookie\uFF08\u6709\u6548\u671F 365 \u5929\uFF09\n Cookies.set(cookieName, 'true', { expires: 365 })\n\n // \u540C\u610F\u540E\u7ACB\u5373\u6253\u5F00\u804A\u5929\u7A97\u53E3\n openChat()\n }, [openChat, cookieName])\n\n /**\n * \u5904\u7406\u6CD5\u89C4\u5F39\u7A97\u5173\u95ED\n */\n const handleComplianceClose = useCallback(() => {\n setShowComplianceDialog(false)\n }, [])\n\n return (\n <>\n {/* \u6CD5\u89C4\u534F\u8BAE\u5F39\u7A97 */}\n {complianceConfig && (\n <ComplianceDialog\n open={showComplianceDialog}\n config={complianceConfig}\n onAgree={handleComplianceAgree}\n onClose={handleComplianceClose}\n />\n )}\n\n {/* \u6C14\u6CE1\u6309\u94AE */}\n <ChatBubble\n position={position}\n onClick={handleBubbleClick}\n visible={!isOpen && !showComplianceDialog}\n iconImageUrl={chatBubbleIcon}\n />\n\n {/* \u804A\u5929\u7A97\u53E3\uFF08\u4F7F\u7528 Radix UI Dialog\uFF09 */}\n <Dialog.Root open={isOpen} onOpenChange={open => (open ? openChat() : closeChat())}>\n <Dialog.Portal>\n <Dialog.Content\n className=\"livechat-window-enter\"\n style={{\n position: 'fixed',\n zIndex: 9998,\n }}\n >\n <ChatWindow\n messages={messages}\n inputValue={inputValue}\n onInputChange={setInputValue}\n onSend={() => handleSendMessage()}\n onClose={closeChat}\n onNewSession={handleCreateNewSession}\n title={title}\n logoUrl={logoUrl}\n isSending={isStreaming}\n rendererRegistry={rendererRegistry}\n inputPlaceholder=\"\"\n onAddToCart={onAddToCart}\n showNewSessionButton={showNewSessionButton}\n bottomTips={bottomTips}\n />\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n </>\n )\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["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", "sendMessageStream", "createSession", "handleSendMessageRef", "_message", "rendererRegistry", "registry", "quickRepliesRenderer", "reply", "currentSessionId", "handleResumeSession", "handleCreateNewSession", "normalizeMessage", "message", "contentBlocks", "structuredData", "block", "transformedData", "response", "messageText", "welcomeContent", "questions", "quickRepliesFromBackend", "question", "index", "error", "isRecaptcha", "existingSessionId", "normalizedMessages", "msg", "welcomeMsg", "handleSendMessage", "isRetry", "textToSend", "sanitized", "userMessage", "thinkingMessage", "sessionExpiredDetected", "event", "messagesWithoutThinking", "errorMessage", "errorCode", "handleBubbleClick", "handleComplianceAgree", "handleComplianceClose"]
7
7
  }
@@ -4,13 +4,32 @@
4
4
  * 基于 specs/livechat-widget/contracts/*.yaml
5
5
  */
6
6
  import type { ChatStreamRequest, SSEEvent, NewSessionRequest, NewSessionResponse } from '../types';
7
+ /**
8
+ * Recaptcha 配置
9
+ */
10
+ export interface RecaptchaConfig {
11
+ /**
12
+ * 是否启用 reCAPTCHA
13
+ */
14
+ needRecaptcha?: boolean;
15
+ /**
16
+ * reCAPTCHA site key
17
+ */
18
+ recaptchaSitekey?: string;
19
+ /**
20
+ * reCAPTCHA action 名称
21
+ */
22
+ recaptchaAction?: string;
23
+ }
7
24
  /**
8
25
  * 发送消息并接收 SSE 流式响应
9
26
  * @param apiBaseUrl API 基础 URL
10
27
  * @param request 请求参数
11
28
  * @param onEvent SSE 事件回调
29
+ * @param customHeaders 自定义请求头
30
+ * @param recaptchaConfig reCAPTCHA 配置
12
31
  */
13
- export declare function sendMessage(apiBaseUrl: string, request: ChatStreamRequest, onEvent: (event: SSEEvent) => void): Promise<void>;
32
+ export declare function sendMessage(apiBaseUrl: string, request: ChatStreamRequest, onEvent: (event: SSEEvent) => void, customHeaders?: Record<string, string>, recaptchaConfig?: RecaptchaConfig): Promise<void>;
14
33
  /**
15
34
  * 创建新会话或恢复现有会话
16
35
  *
@@ -20,6 +39,8 @@ export declare function sendMessage(apiBaseUrl: string, request: ChatStreamReque
20
39
  *
21
40
  * @param apiBaseUrl API 基础 URL
22
41
  * @param request 请求参数
42
+ * @param customHeaders 自定义请求头
43
+ * @param recaptchaConfig reCAPTCHA 配置
23
44
  * @returns 会话信息,可能包含历史消息
24
45
  */
25
- export declare function createNewSession(apiBaseUrl: string, request: NewSessionRequest): Promise<NewSessionResponse>;
46
+ export declare function createNewSession(apiBaseUrl: string, request: NewSessionRequest, customHeaders?: Record<string, string>, recaptchaConfig?: RecaptchaConfig): Promise<NewSessionResponse>;
@@ -1,3 +1,3 @@
1
- async function f(o,a,e){const t=await fetch(`${o}/api/chat/stream`,{method:"POST",headers:{"Content-Type":"application/json",Accept:"text/event-stream"},body:JSON.stringify(a)});if(!t.ok)throw new Error(`HTTP ${t.status}: ${t.statusText}`);const n=t.body?.getReader();if(!n)throw new Error("Response body is not readable");const S=new TextDecoder;let i="",c=null;try{for(;;){const{done:r,value:u}=await n.read();if(r)break;i+=S.decode(u,{stream:!0});const p=i.split(`
2
- `);i=p.pop()||"";for(const h of p){const s=h.trim();if(s===""){c=null;continue}if(s.startsWith("event:"))c=s.substring(6).trim();else if(s.startsWith("data:")){const l=s.substring(5).trim();try{const d=JSON.parse(l);e({event:c||"message",data:d})}catch(d){console.error("[LiveChat API] Failed to parse SSE data:",l,d),e({event:"error",data:{message:"Failed to parse SSE data",code:"PARSE_ERROR"}})}}}}}catch(r){throw console.error("[LiveChat API] SSE stream error:",r),r}finally{n.releaseLock()}}async function m(o,a){const e=await fetch(`${o}/api/chat/new-session`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)});if(!e.ok){const t=await e.json().catch(()=>({success:!1,error:`HTTP ${e.status}: ${e.statusText}`,code:"HTTP_ERROR"}));throw new Error(t.error||"Failed to create session")}return e.json()}export{m as createNewSession,f as sendMessage};
1
+ import{fetcher as u}from"../utils/fetcher";async function g(i,p,n,a,e){const t=await u({url:`${i}/api/chat/stream`,method:"POST",headers:{Accept:"text/event-stream",...a},body:p,needRecaptcha:e?.needRecaptcha,recaptchaSitekey:e?.recaptchaSitekey,recaptchaAction:e?.recaptchaAction||"send_message"});if(!t.ok){const r=await t.json().catch(()=>null),c=new Error(r?.message||`HTTP ${t.status}`);throw c.type=r?.type,c}const s=t.body?.getReader();if(!s)throw new Error("Response body is not readable");const y=new TextDecoder;let d="",h=null;try{for(;;){const{done:r,value:c}=await s.read();if(r)break;d+=y.decode(c,{stream:!0});const S=d.split(`
2
+ `);d=S.pop()||"";for(const R of S){const o=R.trim();if(o===""){h=null;continue}if(o.startsWith("event:"))h=o.substring(6).trim();else if(o.startsWith("data:")){const m=o.substring(5).trim();try{const l=JSON.parse(m);n({event:h||"message",data:l})}catch(l){console.error("[LiveChat API] Failed to parse SSE data:",m,l),n({event:"error",data:{message:"Failed to parse SSE data",code:"PARSE_ERROR"}})}}}}}catch(r){throw console.error("[LiveChat API] SSE stream error:",r),r}finally{s.releaseLock()}}async function f(i,p,n,a){const e=await u({url:`${i}/api/chat/new-session`,method:"POST",headers:n,body:p,needRecaptcha:a?.needRecaptcha,recaptchaSitekey:a?.recaptchaSitekey,recaptchaAction:a?.recaptchaAction||"new_session"});if(!e.ok){const t=await e.json().catch(()=>null),s=new Error(t?.message||`HTTP ${e.status}`);throw s.type=t?.type,s}return e.json()}export{f as createNewSession,g as sendMessage};
3
3
  //# sourceMappingURL=chat.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/components/LiveChatWidget/api/chat.ts"],
4
- "sourcesContent": ["/**\n * LiveChat API \u5C42\n * \u5904\u7406 SSE \u6D41\u5F0F\u901A\u4FE1\u548C HTTP \u8BF7\u6C42\n * \u57FA\u4E8E specs/livechat-widget/contracts/*.yaml\n */\n\nimport type { ChatStreamRequest, SSEEvent, NewSessionRequest, NewSessionResponse, ErrorResponse } from '../types'\n\n// ============================================================================\n// SSE \u6D41\u5F0F\u6D88\u606F\u5904\u7406 (T006)\n// ============================================================================\n\n/**\n * \u53D1\u9001\u6D88\u606F\u5E76\u63A5\u6536 SSE \u6D41\u5F0F\u54CD\u5E94\n * @param apiBaseUrl API \u57FA\u7840 URL\n * @param request \u8BF7\u6C42\u53C2\u6570\n * @param onEvent SSE \u4E8B\u4EF6\u56DE\u8C03\n */\nexport async function sendMessage(\n apiBaseUrl: string,\n request: ChatStreamRequest,\n onEvent: (event: SSEEvent) => void\n): Promise<void> {\n const response = await fetch(`${apiBaseUrl}/api/chat/stream`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n },\n body: JSON.stringify(request),\n })\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`)\n }\n\n const reader = response.body?.getReader()\n if (!reader) {\n throw new Error('Response body is not readable')\n }\n\n const decoder = new TextDecoder()\n let buffer = ''\n let currentEvent: string | null = null\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n // \u89E3\u7801\u5E76\u8FFD\u52A0\u5230\u7F13\u51B2\u533A\n buffer += decoder.decode(value, { stream: true })\n\n // \u6309\u884C\u5206\u5272\n const lines = buffer.split('\\n')\n\n // \u4FDD\u7559\u6700\u540E\u4E00\u4E2A\u4E0D\u5B8C\u6574\u7684\u884C\n buffer = lines.pop() || ''\n\n for (const line of lines) {\n const trimmed = line.trim()\n\n if (trimmed === '') {\n // \u7A7A\u884C\u8868\u793A\u4E8B\u4EF6\u8FB9\u754C\uFF0C\u91CD\u7F6E\u5F53\u524D\u4E8B\u4EF6\u7C7B\u578B\n currentEvent = null\n continue\n }\n\n if (trimmed.startsWith('event:')) {\n // \u63D0\u53D6\u4E8B\u4EF6\u7C7B\u578B\n currentEvent = trimmed.substring(6).trim()\n } else if (trimmed.startsWith('data:')) {\n // \u63D0\u53D6\u6570\u636E\u5E76\u89E3\u6790 JSON\n const dataStr = trimmed.substring(5).trim()\n try {\n const data = JSON.parse(dataStr)\n onEvent({\n event: (currentEvent as any) || 'message',\n data,\n })\n } catch (err) {\n console.error('[LiveChat API] Failed to parse SSE data:', dataStr, err)\n onEvent({\n event: 'error',\n data: {\n message: 'Failed to parse SSE data',\n code: 'PARSE_ERROR',\n },\n })\n }\n }\n }\n }\n } catch (error) {\n console.error('[LiveChat API] SSE stream error:', error)\n throw error\n } finally {\n reader.releaseLock()\n }\n}\n\n// ============================================================================\n// \u521B\u5EFA/\u6062\u590D\u4F1A\u8BDD (T009)\n// ============================================================================\n\n/**\n * \u521B\u5EFA\u65B0\u4F1A\u8BDD\u6216\u6062\u590D\u73B0\u6709\u4F1A\u8BDD\n *\n * \u4F7F\u7528\u573A\u666F\uFF1A\n * 1. \u521B\u5EFA\u65B0\u4F1A\u8BDD\uFF1A\u4E0D\u4F20 session_id\uFF0C\u8FD4\u56DE\u65B0\u7684 sessionId\n * 2. \u6062\u590D\u4F1A\u8BDD\uFF1A\u4F20\u5165 session_id\uFF0C\u9A8C\u8BC1\u4F1A\u8BDD\u6709\u6548\u6027\u5E76\u8FD4\u56DE\u5386\u53F2\u6D88\u606F\uFF08resumed: true, messages: [...]\uFF09\n *\n * @param apiBaseUrl API \u57FA\u7840 URL\n * @param request \u8BF7\u6C42\u53C2\u6570\n * @returns \u4F1A\u8BDD\u4FE1\u606F\uFF0C\u53EF\u80FD\u5305\u542B\u5386\u53F2\u6D88\u606F\n */\nexport async function createNewSession(apiBaseUrl: string, request: NewSessionRequest): Promise<NewSessionResponse> {\n const response = await fetch(`${apiBaseUrl}/api/chat/new-session`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(request),\n })\n\n if (!response.ok) {\n const errorData: ErrorResponse = await response.json().catch(() => ({\n success: false,\n error: `HTTP ${response.status}: ${response.statusText}`,\n code: 'HTTP_ERROR',\n }))\n throw new Error(errorData.error || 'Failed to create session')\n }\n\n return response.json()\n}\n"],
5
- "mappings": "AAkBA,eAAsBA,EACpBC,EACAC,EACAC,EACe,CACf,MAAMC,EAAW,MAAM,MAAM,GAAGH,CAAU,mBAAoB,CAC5D,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,OAAQ,mBACV,EACA,KAAM,KAAK,UAAUC,CAAO,CAC9B,CAAC,EAED,GAAI,CAACE,EAAS,GACZ,MAAM,IAAI,MAAM,QAAQA,EAAS,MAAM,KAAKA,EAAS,UAAU,EAAE,EAGnE,MAAMC,EAASD,EAAS,MAAM,UAAU,EACxC,GAAI,CAACC,EACH,MAAM,IAAI,MAAM,+BAA+B,EAGjD,MAAMC,EAAU,IAAI,YACpB,IAAIC,EAAS,GACTC,EAA8B,KAElC,GAAI,CACF,OAAa,CACX,KAAM,CAAE,KAAAC,EAAM,MAAAC,CAAM,EAAI,MAAML,EAAO,KAAK,EAC1C,GAAII,EAAM,MAGVF,GAAUD,EAAQ,OAAOI,EAAO,CAAE,OAAQ,EAAK,CAAC,EAGhD,MAAMC,EAAQJ,EAAO,MAAM;AAAA,CAAI,EAG/BA,EAASI,EAAM,IAAI,GAAK,GAExB,UAAWC,KAAQD,EAAO,CACxB,MAAME,EAAUD,EAAK,KAAK,EAE1B,GAAIC,IAAY,GAAI,CAElBL,EAAe,KACf,QACF,CAEA,GAAIK,EAAQ,WAAW,QAAQ,EAE7BL,EAAeK,EAAQ,UAAU,CAAC,EAAE,KAAK,UAChCA,EAAQ,WAAW,OAAO,EAAG,CAEtC,MAAMC,EAAUD,EAAQ,UAAU,CAAC,EAAE,KAAK,EAC1C,GAAI,CACF,MAAME,EAAO,KAAK,MAAMD,CAAO,EAC/BX,EAAQ,CACN,MAAQK,GAAwB,UAChC,KAAAO,CACF,CAAC,CACH,OAASC,EAAK,CACZ,QAAQ,MAAM,2CAA4CF,EAASE,CAAG,EACtEb,EAAQ,CACN,MAAO,QACP,KAAM,CACJ,QAAS,2BACT,KAAM,aACR,CACF,CAAC,CACH,CACF,CACF,CACF,CACF,OAASc,EAAO,CACd,cAAQ,MAAM,mCAAoCA,CAAK,EACjDA,CACR,QAAE,CACAZ,EAAO,YAAY,CACrB,CACF,CAiBA,eAAsBa,EAAiBjB,EAAoBC,EAAyD,CAClH,MAAME,EAAW,MAAM,MAAM,GAAGH,CAAU,wBAAyB,CACjE,OAAQ,OACR,QAAS,CACP,eAAgB,kBAClB,EACA,KAAM,KAAK,UAAUC,CAAO,CAC9B,CAAC,EAED,GAAI,CAACE,EAAS,GAAI,CAChB,MAAMe,EAA2B,MAAMf,EAAS,KAAK,EAAE,MAAM,KAAO,CAClE,QAAS,GACT,MAAO,QAAQA,EAAS,MAAM,KAAKA,EAAS,UAAU,GACtD,KAAM,YACR,EAAE,EACF,MAAM,IAAI,MAAMe,EAAU,OAAS,0BAA0B,CAC/D,CAEA,OAAOf,EAAS,KAAK,CACvB",
6
- "names": ["sendMessage", "apiBaseUrl", "request", "onEvent", "response", "reader", "decoder", "buffer", "currentEvent", "done", "value", "lines", "line", "trimmed", "dataStr", "data", "err", "error", "createNewSession", "errorData"]
4
+ "sourcesContent": ["/**\n * LiveChat API \u5C42\n * \u5904\u7406 SSE \u6D41\u5F0F\u901A\u4FE1\u548C HTTP \u8BF7\u6C42\n * \u57FA\u4E8E specs/livechat-widget/contracts/*.yaml\n */\n\nimport type { ChatStreamRequest, SSEEvent, NewSessionRequest, NewSessionResponse, ErrorResponse } from '../types'\nimport { fetcher } from '../utils/fetcher'\n\n/**\n * Recaptcha \u914D\u7F6E\n */\nexport interface RecaptchaConfig {\n /**\n * \u662F\u5426\u542F\u7528 reCAPTCHA\n */\n needRecaptcha?: boolean\n /**\n * reCAPTCHA site key\n */\n recaptchaSitekey?: string\n /**\n * reCAPTCHA action \u540D\u79F0\n */\n recaptchaAction?: string\n}\n\n// ============================================================================\n// SSE \u6D41\u5F0F\u6D88\u606F\u5904\u7406 (T006)\n// ============================================================================\n\n/**\n * \u53D1\u9001\u6D88\u606F\u5E76\u63A5\u6536 SSE \u6D41\u5F0F\u54CD\u5E94\n * @param apiBaseUrl API \u57FA\u7840 URL\n * @param request \u8BF7\u6C42\u53C2\u6570\n * @param onEvent SSE \u4E8B\u4EF6\u56DE\u8C03\n * @param customHeaders \u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\n * @param recaptchaConfig reCAPTCHA \u914D\u7F6E\n */\nexport async function sendMessage(\n apiBaseUrl: string,\n request: ChatStreamRequest,\n onEvent: (event: SSEEvent) => void,\n customHeaders?: Record<string, string>,\n recaptchaConfig?: RecaptchaConfig\n): Promise<void> {\n // \u4F7F\u7528 fetcher \u5904\u7406 reCAPTCHA \u548C\u81EA\u5B9A\u4E49 headers\n const response = await fetcher({\n url: `${apiBaseUrl}/api/chat/stream`,\n method: 'POST',\n headers: {\n Accept: 'text/event-stream',\n ...customHeaders,\n },\n body: request,\n needRecaptcha: recaptchaConfig?.needRecaptcha,\n recaptchaSitekey: recaptchaConfig?.recaptchaSitekey,\n recaptchaAction: recaptchaConfig?.recaptchaAction || 'send_message',\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => null)\n const error = new Error(errorData?.message || `HTTP ${response.status}`) as Error & { type?: string }\n error.type = errorData?.type\n throw error\n }\n\n const reader = response.body?.getReader()\n if (!reader) {\n throw new Error('Response body is not readable')\n }\n\n const decoder = new TextDecoder()\n let buffer = ''\n let currentEvent: string | null = null\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n // \u89E3\u7801\u5E76\u8FFD\u52A0\u5230\u7F13\u51B2\u533A\n buffer += decoder.decode(value, { stream: true })\n\n // \u6309\u884C\u5206\u5272\n const lines = buffer.split('\\n')\n\n // \u4FDD\u7559\u6700\u540E\u4E00\u4E2A\u4E0D\u5B8C\u6574\u7684\u884C\n buffer = lines.pop() || ''\n\n for (const line of lines) {\n const trimmed = line.trim()\n\n if (trimmed === '') {\n // \u7A7A\u884C\u8868\u793A\u4E8B\u4EF6\u8FB9\u754C\uFF0C\u91CD\u7F6E\u5F53\u524D\u4E8B\u4EF6\u7C7B\u578B\n currentEvent = null\n continue\n }\n\n if (trimmed.startsWith('event:')) {\n // \u63D0\u53D6\u4E8B\u4EF6\u7C7B\u578B\n currentEvent = trimmed.substring(6).trim()\n } else if (trimmed.startsWith('data:')) {\n // \u63D0\u53D6\u6570\u636E\u5E76\u89E3\u6790 JSON\n const dataStr = trimmed.substring(5).trim()\n try {\n const data = JSON.parse(dataStr)\n onEvent({\n event: (currentEvent as any) || 'message',\n data,\n })\n } catch (err) {\n console.error('[LiveChat API] Failed to parse SSE data:', dataStr, err)\n onEvent({\n event: 'error',\n data: {\n message: 'Failed to parse SSE data',\n code: 'PARSE_ERROR',\n },\n })\n }\n }\n }\n }\n } catch (error) {\n console.error('[LiveChat API] SSE stream error:', error)\n throw error\n } finally {\n reader.releaseLock()\n }\n}\n\n// ============================================================================\n// \u521B\u5EFA/\u6062\u590D\u4F1A\u8BDD (T009)\n// ============================================================================\n\n/**\n * \u521B\u5EFA\u65B0\u4F1A\u8BDD\u6216\u6062\u590D\u73B0\u6709\u4F1A\u8BDD\n *\n * \u4F7F\u7528\u573A\u666F\uFF1A\n * 1. \u521B\u5EFA\u65B0\u4F1A\u8BDD\uFF1A\u4E0D\u4F20 session_id\uFF0C\u8FD4\u56DE\u65B0\u7684 sessionId\n * 2. \u6062\u590D\u4F1A\u8BDD\uFF1A\u4F20\u5165 session_id\uFF0C\u9A8C\u8BC1\u4F1A\u8BDD\u6709\u6548\u6027\u5E76\u8FD4\u56DE\u5386\u53F2\u6D88\u606F\uFF08resumed: true, messages: [...]\uFF09\n *\n * @param apiBaseUrl API \u57FA\u7840 URL\n * @param request \u8BF7\u6C42\u53C2\u6570\n * @param customHeaders \u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\n * @param recaptchaConfig reCAPTCHA \u914D\u7F6E\n * @returns \u4F1A\u8BDD\u4FE1\u606F\uFF0C\u53EF\u80FD\u5305\u542B\u5386\u53F2\u6D88\u606F\n */\nexport async function createNewSession(\n apiBaseUrl: string,\n request: NewSessionRequest,\n customHeaders?: Record<string, string>,\n recaptchaConfig?: RecaptchaConfig\n): Promise<NewSessionResponse> {\n // \u4F7F\u7528 fetcher \u5904\u7406 reCAPTCHA \u548C\u81EA\u5B9A\u4E49 headers\n const response = await fetcher({\n url: `${apiBaseUrl}/api/chat/new-session`,\n method: 'POST',\n headers: customHeaders,\n body: request,\n needRecaptcha: recaptchaConfig?.needRecaptcha,\n recaptchaSitekey: recaptchaConfig?.recaptchaSitekey,\n recaptchaAction: recaptchaConfig?.recaptchaAction || 'new_session',\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => null)\n const error = new Error(errorData?.message || `HTTP ${response.status}`) as Error & { type?: string }\n error.type = errorData?.type\n throw error\n }\n\n return response.json()\n}\n"],
5
+ "mappings": "AAOA,OAAS,WAAAA,MAAe,mBAgCxB,eAAsBC,EACpBC,EACAC,EACAC,EACAC,EACAC,EACe,CAEf,MAAMC,EAAW,MAAMP,EAAQ,CAC7B,IAAK,GAAGE,CAAU,mBAClB,OAAQ,OACR,QAAS,CACP,OAAQ,oBACR,GAAGG,CACL,EACA,KAAMF,EACN,cAAeG,GAAiB,cAChC,iBAAkBA,GAAiB,iBACnC,gBAAiBA,GAAiB,iBAAmB,cACvD,CAAC,EAED,GAAI,CAACC,EAAS,GAAI,CAChB,MAAMC,EAAY,MAAMD,EAAS,KAAK,EAAE,MAAM,IAAM,IAAI,EAClDE,EAAQ,IAAI,MAAMD,GAAW,SAAW,QAAQD,EAAS,MAAM,EAAE,EACvE,MAAAE,EAAM,KAAOD,GAAW,KAClBC,CACR,CAEA,MAAMC,EAASH,EAAS,MAAM,UAAU,EACxC,GAAI,CAACG,EACH,MAAM,IAAI,MAAM,+BAA+B,EAGjD,MAAMC,EAAU,IAAI,YACpB,IAAIC,EAAS,GACTC,EAA8B,KAElC,GAAI,CACF,OAAa,CACX,KAAM,CAAE,KAAAC,EAAM,MAAAC,CAAM,EAAI,MAAML,EAAO,KAAK,EAC1C,GAAII,EAAM,MAGVF,GAAUD,EAAQ,OAAOI,EAAO,CAAE,OAAQ,EAAK,CAAC,EAGhD,MAAMC,EAAQJ,EAAO,MAAM;AAAA,CAAI,EAG/BA,EAASI,EAAM,IAAI,GAAK,GAExB,UAAWC,KAAQD,EAAO,CACxB,MAAME,EAAUD,EAAK,KAAK,EAE1B,GAAIC,IAAY,GAAI,CAElBL,EAAe,KACf,QACF,CAEA,GAAIK,EAAQ,WAAW,QAAQ,EAE7BL,EAAeK,EAAQ,UAAU,CAAC,EAAE,KAAK,UAChCA,EAAQ,WAAW,OAAO,EAAG,CAEtC,MAAMC,EAAUD,EAAQ,UAAU,CAAC,EAAE,KAAK,EAC1C,GAAI,CACF,MAAME,EAAO,KAAK,MAAMD,CAAO,EAC/Bf,EAAQ,CACN,MAAQS,GAAwB,UAChC,KAAAO,CACF,CAAC,CACH,OAASC,EAAK,CACZ,QAAQ,MAAM,2CAA4CF,EAASE,CAAG,EACtEjB,EAAQ,CACN,MAAO,QACP,KAAM,CACJ,QAAS,2BACT,KAAM,aACR,CACF,CAAC,CACH,CACF,CACF,CACF,CACF,OAASK,EAAO,CACd,cAAQ,MAAM,mCAAoCA,CAAK,EACjDA,CACR,QAAE,CACAC,EAAO,YAAY,CACrB,CACF,CAmBA,eAAsBY,EACpBpB,EACAC,EACAE,EACAC,EAC6B,CAE7B,MAAMC,EAAW,MAAMP,EAAQ,CAC7B,IAAK,GAAGE,CAAU,wBAClB,OAAQ,OACR,QAASG,EACT,KAAMF,EACN,cAAeG,GAAiB,cAChC,iBAAkBA,GAAiB,iBACnC,gBAAiBA,GAAiB,iBAAmB,aACvD,CAAC,EAED,GAAI,CAACC,EAAS,GAAI,CAChB,MAAMC,EAAY,MAAMD,EAAS,KAAK,EAAE,MAAM,IAAM,IAAI,EAClDE,EAAQ,IAAI,MAAMD,GAAW,SAAW,QAAQD,EAAS,MAAM,EAAE,EACvE,MAAAE,EAAM,KAAOD,GAAW,KAClBC,CACR,CAEA,OAAOF,EAAS,KAAK,CACvB",
6
+ "names": ["fetcher", "sendMessage", "apiBaseUrl", "request", "onEvent", "customHeaders", "recaptchaConfig", "response", "errorData", "error", "reader", "decoder", "buffer", "currentEvent", "done", "value", "lines", "line", "trimmed", "dataStr", "data", "err", "createNewSession"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{jsx as e,jsxs as t}from"react/jsx-runtime";const l=()=>t("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),e("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]}),c=()=>t("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e("line",{x1:"12",y1:"5",x2:"12",y2:"19"}),e("line",{x1:"5",y1:"12",x2:"19",y2:"12"})]}),x=({title:r="AI \u52A9\u624B",logoUrl:o,onClose:i,onNewSession:n,showNewSessionButton:s=!0,className:a=""})=>t("div",{className:`flex items-center justify-between border-b border-[#DADCE0] bg-white px-4 py-3 ${a}`,style:{minHeight:"48px"},children:[t("div",{className:"flex items-center gap-3",children:[o&&e("img",{src:o,alt:"Logo",className:"size-8 rounded-full object-cover"}),e("h2",{className:"text-lg font-semibold text-gray-900",children:r})]}),t("div",{className:"flex items-center gap-2",children:[s&&n&&e("button",{type:"button",onClick:n,className:"rounded-lg p-2 text-gray-600","aria-label":"\u5F00\u59CB\u65B0\u4F1A\u8BDD",title:"\u5F00\u59CB\u65B0\u4F1A\u8BDD",children:e(c,{})}),i&&e("button",{type:"button",onClick:i,className:"tablet:block rounded-lg text-gray-600","aria-label":"\u5173\u95ED\u804A\u5929\u7A97\u53E3",children:e(l,{})})]})]});export{x as ChatHeader};
1
+ import{jsx as e,jsxs as t}from"react/jsx-runtime";const l=()=>t("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),e("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]}),c=()=>t("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e("line",{x1:"12",y1:"5",x2:"12",y2:"19"}),e("line",{x1:"5",y1:"12",x2:"19",y2:"12"})]}),g=({title:s="",logoUrl:o,onClose:n,onNewSession:r,showNewSessionButton:i=!0,className:a=""})=>t("div",{className:`flex items-center justify-between border-b border-[#DADCE0] bg-white px-4 pb-3 pt-0 tablet:pt-4 ${a}`,children:[t("div",{className:"flex items-center gap-3",children:[o&&e("img",{src:o,alt:"Logo",className:"size-8 rounded-full object-cover"}),e("h2",{className:"text-lg font-semibold text-gray-900",children:s})]}),t("div",{className:"flex items-center gap-2",children:[i&&r&&e("button",{type:"button",onClick:r,className:"rounded-lg p-2 text-gray-600","aria-label":"\u5F00\u59CB\u65B0\u4F1A\u8BDD",title:"\u5F00\u59CB\u65B0\u4F1A\u8BDD",children:e(c,{})}),n&&e("button",{type:"button",onClick:n,className:"tablet:block rounded-lg text-gray-600","aria-label":"Close chat",children:e(l,{})})]})]});export{g as ChatHeader};
2
2
  //# sourceMappingURL=ChatHeader.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/components/LiveChatWidget/components/ChatHeader.tsx"],
4
- "sourcesContent": ["/**\n * \u804A\u5929\u7A97\u53E3\u5934\u90E8\u7EC4\u4EF6\n * \u663E\u793A\u6807\u9898\u3001Logo\u3001\u5173\u95ED\u6309\u94AE\u548C\u65B0\u4F1A\u8BDD\u6309\u94AE\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u5934\u90E8\u8BBE\u8BA1\n */\n\nimport React from 'react'\n\nexport interface ChatHeaderProps {\n /**\n * \u5934\u90E8\u6807\u9898\n */\n title?: string\n\n /**\n * Logo URL\n */\n logoUrl?: string\n\n /**\n * \u5173\u95ED\u6309\u94AE\u70B9\u51FB\u56DE\u8C03\n */\n onClose?: () => void\n\n /**\n * \u65B0\u4F1A\u8BDD\u6309\u94AE\u70B9\u51FB\u56DE\u8C03\n */\n onNewSession?: () => void\n\n /**\n * \u662F\u5426\u663E\u793A\u65B0\u4F1A\u8BDD\u6309\u94AE\n * @default true\n */\n showNewSessionButton?: boolean\n\n /**\n * \u81EA\u5B9A\u4E49\u6837\u5F0F\u7C7B\u540D\n */\n className?: string\n}\n\n/**\n * \u9ED8\u8BA4\u5173\u95ED\u56FE\u6807 (X)\n */\nconst CloseIcon: React.FC = () => (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n)\n\n/**\n * \u65B0\u4F1A\u8BDD\u56FE\u6807 (\u52A0\u53F7)\n */\nconst NewSessionIcon: React.FC = () => (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n)\n\n/**\n * \u804A\u5929\u7A97\u53E3\u5934\u90E8\u7EC4\u4EF6\n *\n * \u529F\u80FD\uFF1A\n * - \u663E\u793A\u6807\u9898\u548C Logo\n * - \u5173\u95ED\u6309\u94AE\uFF08\u79FB\u52A8\u7AEF\u9690\u85CF\uFF0C\u684C\u9762\u7AEF\u663E\u793A\uFF09\n * - \u65B0\u4F1A\u8BDD\u6309\u94AE\uFF08\u6E05\u7A7A\u5F53\u524D\u5BF9\u8BDD\uFF09\n *\n * \u5E03\u5C40\uFF1A\n * - Logo (\u53EF\u9009) + \u6807\u9898 | \u65B0\u4F1A\u8BDD\u6309\u94AE + \u5173\u95ED\u6309\u94AE\n * - \u56FA\u5B9A\u9AD8\u5EA6 64px\n * - \u8FB9\u6846\u5206\u9694\u4E0B\u65B9\u5185\u5BB9\n *\n * @example\n * ```tsx\n * <ChatHeader\n * title=\"AI \u52A9\u624B\"\n * logoUrl=\"/logo.png\"\n * onClose={() => setIsOpen(false)}\n * onNewSession={() => createNewSession()}\n * />\n * ```\n */\nexport const ChatHeader: React.FC<ChatHeaderProps> = ({\n title = 'AI \u52A9\u624B',\n logoUrl,\n onClose,\n onNewSession,\n showNewSessionButton = true,\n className = '',\n}) => {\n return (\n <div\n className={`flex items-center justify-between border-b border-[#DADCE0] bg-white px-4 py-3 ${className}`}\n style={{ minHeight: '48px' }}\n >\n {/* \u5DE6\u4FA7\uFF1ALogo + \u6807\u9898 */}\n <div className=\"flex items-center gap-3\">\n {logoUrl && <img src={logoUrl} alt=\"Logo\" className=\"size-8 rounded-full object-cover\" />}\n <h2 className=\"text-lg font-semibold text-gray-900\">{title}</h2>\n </div>\n\n {/* \u53F3\u4FA7\uFF1A\u65B0\u4F1A\u8BDD\u6309\u94AE + \u5173\u95ED\u6309\u94AE */}\n <div className=\"flex items-center gap-2\">\n {/* \u65B0\u4F1A\u8BDD\u6309\u94AE */}\n {showNewSessionButton && onNewSession && (\n <button\n type=\"button\"\n onClick={onNewSession}\n className=\"rounded-lg p-2 text-gray-600\"\n aria-label=\"\u5F00\u59CB\u65B0\u4F1A\u8BDD\"\n title=\"\u5F00\u59CB\u65B0\u4F1A\u8BDD\"\n >\n <NewSessionIcon />\n </button>\n )}\n\n {/* \u5173\u95ED\u6309\u94AE */}\n {onClose && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"tablet:block rounded-lg text-gray-600\"\n aria-label=\"\u5173\u95ED\u804A\u5929\u7A97\u53E3\"\n >\n <CloseIcon />\n </button>\n )}\n </div>\n </div>\n )\n}\n"],
5
- "mappings": "AA6CE,OAUE,OAAAA,EAVF,QAAAC,MAAA,oBADF,MAAMC,EAAsB,IAC1BD,EAAC,OACC,MAAM,KACN,OAAO,KACP,QAAQ,YACR,KAAK,OACL,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QAEf,UAAAD,EAAC,QAAK,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,EACpCA,EAAC,QAAK,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GACtC,EAMIG,EAA2B,IAC/BF,EAAC,OACC,MAAM,KACN,OAAO,KACP,QAAQ,YACR,KAAK,OACL,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QAEf,UAAAD,EAAC,QAAK,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,EACrCA,EAAC,QAAK,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GACvC,EA0BWI,EAAwC,CAAC,CACpD,MAAAC,EAAQ,kBACR,QAAAC,EACA,QAAAC,EACA,aAAAC,EACA,qBAAAC,EAAuB,GACvB,UAAAC,EAAY,EACd,IAEIT,EAAC,OACC,UAAW,kFAAkFS,CAAS,GACtG,MAAO,CAAE,UAAW,MAAO,EAG3B,UAAAT,EAAC,OAAI,UAAU,0BACZ,UAAAK,GAAWN,EAAC,OAAI,IAAKM,EAAS,IAAI,OAAO,UAAU,mCAAmC,EACvFN,EAAC,MAAG,UAAU,sCAAuC,SAAAK,EAAM,GAC7D,EAGAJ,EAAC,OAAI,UAAU,0BAEZ,UAAAQ,GAAwBD,GACvBR,EAAC,UACC,KAAK,SACL,QAASQ,EACT,UAAU,+BACV,aAAW,iCACX,MAAM,iCAEN,SAAAR,EAACG,EAAA,EAAe,EAClB,EAIDI,GACCP,EAAC,UACC,KAAK,SACL,QAASO,EACT,UAAU,yCACV,aAAW,uCAEX,SAAAP,EAACE,EAAA,EAAU,EACb,GAEJ,GACF",
4
+ "sourcesContent": ["/**\n * \u804A\u5929\u7A97\u53E3\u5934\u90E8\u7EC4\u4EF6\n * \u663E\u793A\u6807\u9898\u3001Logo\u3001\u5173\u95ED\u6309\u94AE\u548C\u65B0\u4F1A\u8BDD\u6309\u94AE\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u5934\u90E8\u8BBE\u8BA1\n */\n\nimport React from 'react'\n\nexport interface ChatHeaderProps {\n /**\n * \u5934\u90E8\u6807\u9898\n */\n title?: string\n\n /**\n * Logo URL\n */\n logoUrl?: string\n\n /**\n * \u5173\u95ED\u6309\u94AE\u70B9\u51FB\u56DE\u8C03\n */\n onClose?: () => void\n\n /**\n * \u65B0\u4F1A\u8BDD\u6309\u94AE\u70B9\u51FB\u56DE\u8C03\n */\n onNewSession?: () => void\n\n /**\n * \u662F\u5426\u663E\u793A\u65B0\u4F1A\u8BDD\u6309\u94AE\n * @default true\n */\n showNewSessionButton?: boolean\n\n /**\n * \u81EA\u5B9A\u4E49\u6837\u5F0F\u7C7B\u540D\n */\n className?: string\n}\n\n/**\n * \u9ED8\u8BA4\u5173\u95ED\u56FE\u6807 (X)\n */\nconst CloseIcon: React.FC = () => (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n)\n\n/**\n * \u65B0\u4F1A\u8BDD\u56FE\u6807 (\u52A0\u53F7)\n */\nconst NewSessionIcon: React.FC = () => (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n)\n\n/**\n * \u804A\u5929\u7A97\u53E3\u5934\u90E8\u7EC4\u4EF6\n *\n * \u529F\u80FD\uFF1A\n * - \u663E\u793A\u6807\u9898\u548C Logo\n * - \u5173\u95ED\u6309\u94AE\uFF08\u79FB\u52A8\u7AEF\u9690\u85CF\uFF0C\u684C\u9762\u7AEF\u663E\u793A\uFF09\n * - \u65B0\u4F1A\u8BDD\u6309\u94AE\uFF08\u6E05\u7A7A\u5F53\u524D\u5BF9\u8BDD\uFF09\n *\n * \u5E03\u5C40\uFF1A\n * - Logo (\u53EF\u9009) + \u6807\u9898 | \u65B0\u4F1A\u8BDD\u6309\u94AE + \u5173\u95ED\u6309\u94AE\n * - \u56FA\u5B9A\u9AD8\u5EA6 64px\n * - \u8FB9\u6846\u5206\u9694\u4E0B\u65B9\u5185\u5BB9\n *\n * @example\n * ```tsx\n * <ChatHeader\n * title=\"AI \u52A9\u624B\"\n * logoUrl=\"/logo.png\"\n * onClose={() => setIsOpen(false)}\n * onNewSession={() => createNewSession()}\n * />\n * ```\n */\nexport const ChatHeader: React.FC<ChatHeaderProps> = ({\n title = '',\n logoUrl,\n onClose,\n onNewSession,\n showNewSessionButton = true,\n className = '',\n}) => {\n return (\n <div\n className={`flex items-center justify-between border-b border-[#DADCE0] bg-white px-4 pb-3 pt-0 tablet:pt-4 ${className}`}\n >\n {/* \u5DE6\u4FA7\uFF1ALogo + \u6807\u9898 */}\n <div className=\"flex items-center gap-3\">\n {logoUrl && <img src={logoUrl} alt=\"Logo\" className=\"size-8 rounded-full object-cover\" />}\n <h2 className=\"text-lg font-semibold text-gray-900\">{title}</h2>\n </div>\n\n {/* \u53F3\u4FA7\uFF1A\u65B0\u4F1A\u8BDD\u6309\u94AE + \u5173\u95ED\u6309\u94AE */}\n <div className=\"flex items-center gap-2\">\n {/* \u65B0\u4F1A\u8BDD\u6309\u94AE */}\n {showNewSessionButton && onNewSession && (\n <button\n type=\"button\"\n onClick={onNewSession}\n className=\"rounded-lg p-2 text-gray-600\"\n aria-label=\"\u5F00\u59CB\u65B0\u4F1A\u8BDD\"\n title=\"\u5F00\u59CB\u65B0\u4F1A\u8BDD\"\n >\n <NewSessionIcon />\n </button>\n )}\n\n {/* \u5173\u95ED\u6309\u94AE */}\n {onClose && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"tablet:block rounded-lg text-gray-600\"\n aria-label=\"Close chat\"\n >\n <CloseIcon />\n </button>\n )}\n </div>\n </div>\n )\n}\n"],
5
+ "mappings": "AA6CE,OAUE,OAAAA,EAVF,QAAAC,MAAA,oBADF,MAAMC,EAAsB,IAC1BD,EAAC,OACC,MAAM,KACN,OAAO,KACP,QAAQ,YACR,KAAK,OACL,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QAEf,UAAAD,EAAC,QAAK,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,EACpCA,EAAC,QAAK,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GACtC,EAMIG,EAA2B,IAC/BF,EAAC,OACC,MAAM,KACN,OAAO,KACP,QAAQ,YACR,KAAK,OACL,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QAEf,UAAAD,EAAC,QAAK,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,EACrCA,EAAC,QAAK,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GACvC,EA0BWI,EAAwC,CAAC,CACpD,MAAAC,EAAQ,GACR,QAAAC,EACA,QAAAC,EACA,aAAAC,EACA,qBAAAC,EAAuB,GACvB,UAAAC,EAAY,EACd,IAEIT,EAAC,OACC,UAAW,mGAAmGS,CAAS,GAGvH,UAAAT,EAAC,OAAI,UAAU,0BACZ,UAAAK,GAAWN,EAAC,OAAI,IAAKM,EAAS,IAAI,OAAO,UAAU,mCAAmC,EACvFN,EAAC,MAAG,UAAU,sCAAuC,SAAAK,EAAM,GAC7D,EAGAJ,EAAC,OAAI,UAAU,0BAEZ,UAAAQ,GAAwBD,GACvBR,EAAC,UACC,KAAK,SACL,QAASQ,EACT,UAAU,+BACV,aAAW,iCACX,MAAM,iCAEN,SAAAR,EAACG,EAAA,EAAe,EAClB,EAIDI,GACCP,EAAC,UACC,KAAK,SACL,QAASO,EACT,UAAU,yCACV,aAAW,aAEX,SAAAP,EAACE,EAAA,EAAU,EACb,GAEJ,GACF",
6
6
  "names": ["jsx", "jsxs", "CloseIcon", "NewSessionIcon", "ChatHeader", "title", "logoUrl", "onClose", "onNewSession", "showNewSessionButton", "className"]
7
7
  }