@anker-in/campaign-ui 0.2.11-beta.3 → 0.2.11-beta.31

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 (491) hide show
  1. package/dist/cjs/components/LiveChatWidget/LiveChatWidget.d.ts +63 -0
  2. package/dist/cjs/components/LiveChatWidget/LiveChatWidget.js +2 -0
  3. package/dist/cjs/components/LiveChatWidget/LiveChatWidget.js.map +7 -0
  4. package/dist/cjs/components/LiveChatWidget/api/chat.d.ts +46 -0
  5. package/dist/cjs/components/LiveChatWidget/api/chat.js +3 -0
  6. package/dist/cjs/components/LiveChatWidget/api/chat.js.map +7 -0
  7. package/dist/cjs/components/LiveChatWidget/components/ChatBubble.d.ts +68 -0
  8. package/dist/cjs/components/LiveChatWidget/components/ChatBubble.js +2 -0
  9. package/dist/cjs/components/LiveChatWidget/components/ChatBubble.js.map +7 -0
  10. package/dist/cjs/components/LiveChatWidget/components/ChatHeader.d.ts +57 -0
  11. package/dist/cjs/components/LiveChatWidget/components/ChatHeader.js +2 -0
  12. package/dist/cjs/components/LiveChatWidget/components/ChatHeader.js.map +7 -0
  13. package/dist/cjs/components/LiveChatWidget/components/ChatInput.d.ts +70 -0
  14. package/dist/cjs/components/LiveChatWidget/components/ChatInput.js +2 -0
  15. package/dist/cjs/components/LiveChatWidget/components/ChatInput.js.map +7 -0
  16. package/dist/cjs/components/LiveChatWidget/components/ChatMessage.d.ts +59 -0
  17. package/dist/cjs/components/LiveChatWidget/components/ChatMessage.js +5 -0
  18. package/dist/cjs/components/LiveChatWidget/components/ChatMessage.js.map +7 -0
  19. package/dist/cjs/components/LiveChatWidget/components/ChatWindow.d.ts +127 -0
  20. package/dist/cjs/components/LiveChatWidget/components/ChatWindow.js +2 -0
  21. package/dist/cjs/components/LiveChatWidget/components/ChatWindow.js.map +7 -0
  22. package/dist/cjs/components/LiveChatWidget/components/MessageContent/CartCard.d.ts +54 -0
  23. package/dist/cjs/components/LiveChatWidget/components/MessageContent/CartCard.js +2 -0
  24. package/dist/cjs/components/LiveChatWidget/components/MessageContent/CartCard.js.map +7 -0
  25. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ErrorBlock.d.ts +33 -0
  26. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ErrorBlock.js +2 -0
  27. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ErrorBlock.js.map +7 -0
  28. package/dist/cjs/components/LiveChatWidget/components/MessageContent/FAQList.d.ts +16 -0
  29. package/dist/cjs/components/LiveChatWidget/components/MessageContent/FAQList.js +2 -0
  30. package/dist/cjs/components/LiveChatWidget/components/MessageContent/FAQList.js.map +7 -0
  31. package/dist/cjs/components/LiveChatWidget/components/MessageContent/PolicyBlock.d.ts +45 -0
  32. package/dist/cjs/components/LiveChatWidget/components/MessageContent/PolicyBlock.js +5 -0
  33. package/dist/cjs/components/LiveChatWidget/components/MessageContent/PolicyBlock.js.map +7 -0
  34. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductCard.d.ts +41 -0
  35. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductCard.js +2 -0
  36. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductCard.js.map +7 -0
  37. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductComparison.d.ts +75 -0
  38. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductComparison.js +2 -0
  39. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductComparison.js.map +7 -0
  40. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductList.d.ts +47 -0
  41. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductList.js +2 -0
  42. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductList.js.map +7 -0
  43. package/dist/cjs/components/LiveChatWidget/components/MessageContent/PromotionList.d.ts +81 -0
  44. package/dist/cjs/components/LiveChatWidget/components/MessageContent/PromotionList.js +2 -0
  45. package/dist/cjs/components/LiveChatWidget/components/MessageContent/PromotionList.js.map +7 -0
  46. package/dist/cjs/components/LiveChatWidget/components/MessageContent/QuickReplies.d.ts +54 -0
  47. package/dist/cjs/components/LiveChatWidget/components/MessageContent/QuickReplies.js +2 -0
  48. package/dist/cjs/components/LiveChatWidget/components/MessageContent/QuickReplies.js.map +7 -0
  49. package/dist/cjs/components/LiveChatWidget/components/MessageContent/TextBlock.d.ts +31 -0
  50. package/dist/cjs/components/LiveChatWidget/components/MessageContent/TextBlock.js +2 -0
  51. package/dist/cjs/components/LiveChatWidget/components/MessageContent/TextBlock.js.map +7 -0
  52. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ThinkingBlock.d.ts +31 -0
  53. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js +2 -0
  54. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js.map +7 -0
  55. package/dist/cjs/components/LiveChatWidget/components/MessageContent/index.d.ts +15 -0
  56. package/dist/cjs/components/LiveChatWidget/components/MessageContent/index.js +2 -0
  57. package/dist/cjs/components/LiveChatWidget/components/MessageContent/index.js.map +7 -0
  58. package/dist/cjs/components/LiveChatWidget/components/MessageContent.d.ts +63 -0
  59. package/dist/cjs/components/LiveChatWidget/components/MessageContent.js +2 -0
  60. package/dist/cjs/components/LiveChatWidget/components/MessageContent.js.map +7 -0
  61. package/dist/cjs/components/LiveChatWidget/components/MessageList.d.ts +74 -0
  62. package/dist/cjs/components/LiveChatWidget/components/MessageList.js +5 -0
  63. package/dist/cjs/components/LiveChatWidget/components/MessageList.js.map +7 -0
  64. package/dist/cjs/components/LiveChatWidget/components/ScrollAnchor.d.ts +44 -0
  65. package/dist/cjs/components/LiveChatWidget/components/ScrollAnchor.js +2 -0
  66. package/dist/cjs/components/LiveChatWidget/components/ScrollAnchor.js.map +7 -0
  67. package/dist/cjs/components/LiveChatWidget/constants.d.ts +13 -0
  68. package/dist/cjs/components/LiveChatWidget/constants.js +2 -0
  69. package/dist/cjs/components/LiveChatWidget/constants.js.map +7 -0
  70. package/dist/cjs/components/LiveChatWidget/hooks/useChatAPI.d.ts +60 -0
  71. package/dist/cjs/components/LiveChatWidget/hooks/useChatAPI.js +2 -0
  72. package/dist/cjs/components/LiveChatWidget/hooks/useChatAPI.js.map +7 -0
  73. package/dist/cjs/components/LiveChatWidget/hooks/useChatState.d.ts +151 -0
  74. package/dist/cjs/components/LiveChatWidget/hooks/useChatState.js +2 -0
  75. package/dist/cjs/components/LiveChatWidget/hooks/useChatState.js.map +7 -0
  76. package/dist/cjs/components/LiveChatWidget/hooks/useSession.d.ts +37 -0
  77. package/dist/cjs/components/LiveChatWidget/hooks/useSession.js +2 -0
  78. package/dist/cjs/components/LiveChatWidget/hooks/useSession.js.map +7 -0
  79. package/dist/cjs/components/LiveChatWidget/index.d.ts +12 -0
  80. package/dist/cjs/components/LiveChatWidget/index.js +2 -0
  81. package/dist/cjs/components/LiveChatWidget/index.js.map +7 -0
  82. package/dist/cjs/components/LiveChatWidget/types.d.ts +767 -0
  83. package/dist/cjs/components/LiveChatWidget/types.js +2 -0
  84. package/dist/cjs/components/LiveChatWidget/types.js.map +7 -0
  85. package/dist/cjs/components/LiveChatWidget/utils/cartTransformers.d.ts +25 -0
  86. package/dist/cjs/components/LiveChatWidget/utils/cartTransformers.js +2 -0
  87. package/dist/cjs/components/LiveChatWidget/utils/cartTransformers.js.map +7 -0
  88. package/dist/cjs/components/LiveChatWidget/utils/fetcher.d.ts +36 -0
  89. package/dist/cjs/components/LiveChatWidget/utils/fetcher.js +2 -0
  90. package/dist/cjs/components/LiveChatWidget/utils/fetcher.js.map +7 -0
  91. package/dist/cjs/components/LiveChatWidget/utils/messageRenderers.d.ts +64 -0
  92. package/dist/cjs/components/LiveChatWidget/utils/messageRenderers.js +2 -0
  93. package/dist/cjs/components/LiveChatWidget/utils/messageRenderers.js.map +7 -0
  94. package/dist/cjs/components/LiveChatWidget/utils/productTransformers.d.ts +43 -0
  95. package/dist/cjs/components/LiveChatWidget/utils/productTransformers.js +2 -0
  96. package/dist/cjs/components/LiveChatWidget/utils/productTransformers.js.map +7 -0
  97. package/dist/cjs/components/LiveChatWidget/utils/userId.d.ts +18 -0
  98. package/dist/cjs/components/LiveChatWidget/utils/userId.js +2 -0
  99. package/dist/cjs/components/LiveChatWidget/utils/userId.js.map +7 -0
  100. package/dist/cjs/components/LiveChatWidget/utils/validation.d.ts +37 -0
  101. package/dist/cjs/components/LiveChatWidget/utils/validation.js +2 -0
  102. package/dist/cjs/components/LiveChatWidget/utils/validation.js.map +7 -0
  103. package/dist/cjs/components/chat/markdown.js +1 -1
  104. package/dist/cjs/components/chat/markdown.js.map +2 -2
  105. package/dist/cjs/components/credits/context/hooks/useRedeemableList.js +1 -1
  106. package/dist/cjs/components/credits/context/hooks/useRedeemableList.js.map +2 -2
  107. package/dist/cjs/components/credits/context/memberPriceConst.d.ts +0 -5
  108. package/dist/cjs/components/credits/context/memberPriceConst.js +1 -1
  109. package/dist/cjs/components/credits/context/memberPriceConst.js.map +3 -3
  110. package/dist/cjs/components/credits/context/memberPriceTypes.d.ts +1 -22
  111. package/dist/cjs/components/credits/context/memberPriceTypes.js +1 -1
  112. package/dist/cjs/components/credits/context/memberPriceTypes.js.map +1 -1
  113. package/dist/cjs/components/credits/context/provider.d.ts +16 -1
  114. package/dist/cjs/components/credits/context/provider.js +1 -1
  115. package/dist/cjs/components/credits/context/provider.js.map +3 -3
  116. package/dist/cjs/components/credits/creditsAnkersolixTask/CreditsAnkersolixTask.js +1 -1
  117. package/dist/cjs/components/credits/creditsAnkersolixTask/CreditsAnkersolixTask.js.map +3 -3
  118. package/dist/cjs/components/credits/creditsBanner/index.d.ts +2 -0
  119. package/dist/cjs/components/credits/creditsBanner/index.js +12 -1
  120. package/dist/cjs/components/credits/creditsBanner/index.js.map +3 -3
  121. package/dist/cjs/components/credits/creditsBenefits/BenefitItem.js +2 -0
  122. package/dist/cjs/components/credits/creditsBenefits/BenefitItem.js.map +7 -0
  123. package/dist/cjs/components/credits/creditsBenefits/{iconInfo.js → IconInfo.js} +1 -1
  124. package/dist/cjs/components/credits/creditsBenefits/{iconInfo.js.map → IconInfo.js.map} +1 -1
  125. package/dist/cjs/components/credits/creditsCash/CreditsCash.js +1 -1
  126. package/dist/cjs/components/credits/creditsCash/CreditsCash.js.map +3 -3
  127. package/dist/cjs/components/credits/creditsCash/RedeemableItem.js +1 -1
  128. package/dist/cjs/components/credits/creditsCash/RedeemableItem.js.map +3 -3
  129. package/dist/cjs/components/credits/creditsCash/type.d.ts +1 -0
  130. package/dist/cjs/components/credits/creditsCash/type.js +1 -1
  131. package/dist/cjs/components/credits/creditsCash/type.js.map +1 -1
  132. package/dist/cjs/components/credits/creditsFaq/faqItem/FaqItem.js +1 -1
  133. package/dist/cjs/components/credits/creditsFaq/faqItem/FaqItem.js.map +3 -3
  134. package/dist/cjs/components/credits/creditsInfoCard/index.js +1 -1
  135. package/dist/cjs/components/credits/creditsInfoCard/index.js.map +2 -2
  136. package/dist/cjs/components/credits/creditsMemberPrice/CreditsMemberPrice.js +1 -1
  137. package/dist/cjs/components/credits/creditsMemberPrice/CreditsMemberPrice.js.map +3 -3
  138. package/dist/cjs/components/credits/creditsMemberPrice/MemberPriceItem.js +1 -1
  139. package/dist/cjs/components/credits/creditsMemberPrice/MemberPriceItem.js.map +3 -3
  140. package/dist/cjs/components/credits/creditsMemberPrice/type.d.ts +3 -5
  141. package/dist/cjs/components/credits/creditsMemberPrice/type.js +1 -1
  142. package/dist/cjs/components/credits/creditsMemberPrice/type.js.map +1 -1
  143. package/dist/cjs/components/credits/creditsNavigation/CreditsNavigation.js +1 -1
  144. package/dist/cjs/components/credits/creditsNavigation/CreditsNavigation.js.map +2 -2
  145. package/dist/cjs/components/credits/creditsRedeemList/CreditsRedeemList.js +1 -1
  146. package/dist/cjs/components/credits/creditsRedeemList/CreditsRedeemList.js.map +3 -3
  147. package/dist/cjs/components/credits/creditsRedeemList/RedeemProductModal/ProductInfo.js +1 -1
  148. package/dist/cjs/components/credits/creditsRedeemList/RedeemProductModal/ProductInfo.js.map +2 -2
  149. package/dist/cjs/components/credits/creditsRedeemList/RedeemableItem.js +1 -1
  150. package/dist/cjs/components/credits/creditsRedeemList/RedeemableItem.js.map +3 -3
  151. package/dist/cjs/components/credits/creditsWaysToGetCredits/CreditsWaysToGetCredits.js +1 -1
  152. package/dist/cjs/components/credits/creditsWaysToGetCredits/CreditsWaysToGetCredits.js.map +3 -3
  153. package/dist/cjs/components/index.d.ts +3 -1
  154. package/dist/cjs/components/index.js +1 -1
  155. package/dist/cjs/components/index.js.map +3 -3
  156. package/dist/cjs/components/registration/authCodeActivate/index.js +1 -1
  157. package/dist/cjs/components/registration/authCodeActivate/index.js.map +2 -2
  158. package/dist/cjs/stories/CartCard.stories.d.ts +33 -0
  159. package/dist/cjs/stories/CartCard.stories.js +21 -0
  160. package/dist/cjs/stories/CartCard.stories.js.map +7 -0
  161. package/dist/cjs/stories/LiveChatWidget.stories.d.ts +108 -0
  162. package/dist/cjs/stories/LiveChatWidget.stories.js +149 -0
  163. package/dist/cjs/stories/LiveChatWidget.stories.js.map +7 -0
  164. package/dist/cjs/templates/{credits.d.ts → Credits.d.ts} +16 -1
  165. package/dist/cjs/templates/Credits.js +2 -0
  166. package/dist/cjs/templates/Credits.js.map +7 -0
  167. package/dist/esm/components/LiveChatWidget/LiveChatWidget.d.ts +63 -0
  168. package/dist/esm/components/LiveChatWidget/LiveChatWidget.js +2 -0
  169. package/dist/esm/components/LiveChatWidget/LiveChatWidget.js.map +7 -0
  170. package/dist/esm/components/LiveChatWidget/api/chat.d.ts +46 -0
  171. package/dist/esm/components/LiveChatWidget/api/chat.js +3 -0
  172. package/dist/esm/components/LiveChatWidget/api/chat.js.map +7 -0
  173. package/dist/esm/components/LiveChatWidget/components/ChatBubble.d.ts +68 -0
  174. package/dist/esm/components/LiveChatWidget/components/ChatBubble.js +2 -0
  175. package/dist/esm/components/LiveChatWidget/components/ChatBubble.js.map +7 -0
  176. package/dist/esm/components/LiveChatWidget/components/ChatHeader.d.ts +57 -0
  177. package/dist/esm/components/LiveChatWidget/components/ChatHeader.js +2 -0
  178. package/dist/esm/components/LiveChatWidget/components/ChatHeader.js.map +7 -0
  179. package/dist/esm/components/LiveChatWidget/components/ChatInput.d.ts +70 -0
  180. package/dist/esm/components/LiveChatWidget/components/ChatInput.js +2 -0
  181. package/dist/esm/components/LiveChatWidget/components/ChatInput.js.map +7 -0
  182. package/dist/esm/components/LiveChatWidget/components/ChatMessage.d.ts +59 -0
  183. package/dist/esm/components/LiveChatWidget/components/ChatMessage.js +5 -0
  184. package/dist/esm/components/LiveChatWidget/components/ChatMessage.js.map +7 -0
  185. package/dist/esm/components/LiveChatWidget/components/ChatWindow.d.ts +127 -0
  186. package/dist/esm/components/LiveChatWidget/components/ChatWindow.js +2 -0
  187. package/dist/esm/components/LiveChatWidget/components/ChatWindow.js.map +7 -0
  188. package/dist/esm/components/LiveChatWidget/components/MessageContent/CartCard.d.ts +54 -0
  189. package/dist/esm/components/LiveChatWidget/components/MessageContent/CartCard.js +2 -0
  190. package/dist/esm/components/LiveChatWidget/components/MessageContent/CartCard.js.map +7 -0
  191. package/dist/esm/components/LiveChatWidget/components/MessageContent/ErrorBlock.d.ts +33 -0
  192. package/dist/esm/components/LiveChatWidget/components/MessageContent/ErrorBlock.js +2 -0
  193. package/dist/esm/components/LiveChatWidget/components/MessageContent/ErrorBlock.js.map +7 -0
  194. package/dist/esm/components/LiveChatWidget/components/MessageContent/FAQList.d.ts +16 -0
  195. package/dist/esm/components/LiveChatWidget/components/MessageContent/FAQList.js +2 -0
  196. package/dist/esm/components/LiveChatWidget/components/MessageContent/FAQList.js.map +7 -0
  197. package/dist/esm/components/LiveChatWidget/components/MessageContent/PolicyBlock.d.ts +45 -0
  198. package/dist/esm/components/LiveChatWidget/components/MessageContent/PolicyBlock.js +5 -0
  199. package/dist/esm/components/LiveChatWidget/components/MessageContent/PolicyBlock.js.map +7 -0
  200. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductCard.d.ts +41 -0
  201. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductCard.js +2 -0
  202. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductCard.js.map +7 -0
  203. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductComparison.d.ts +75 -0
  204. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductComparison.js +2 -0
  205. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductComparison.js.map +7 -0
  206. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductList.d.ts +47 -0
  207. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductList.js +2 -0
  208. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductList.js.map +7 -0
  209. package/dist/esm/components/LiveChatWidget/components/MessageContent/PromotionList.d.ts +81 -0
  210. package/dist/esm/components/LiveChatWidget/components/MessageContent/PromotionList.js +2 -0
  211. package/dist/esm/components/LiveChatWidget/components/MessageContent/PromotionList.js.map +7 -0
  212. package/dist/esm/components/LiveChatWidget/components/MessageContent/QuickReplies.d.ts +54 -0
  213. package/dist/esm/components/LiveChatWidget/components/MessageContent/QuickReplies.js +2 -0
  214. package/dist/esm/components/LiveChatWidget/components/MessageContent/QuickReplies.js.map +7 -0
  215. package/dist/esm/components/LiveChatWidget/components/MessageContent/TextBlock.d.ts +31 -0
  216. package/dist/esm/components/LiveChatWidget/components/MessageContent/TextBlock.js +2 -0
  217. package/dist/esm/components/LiveChatWidget/components/MessageContent/TextBlock.js.map +7 -0
  218. package/dist/esm/components/LiveChatWidget/components/MessageContent/ThinkingBlock.d.ts +31 -0
  219. package/dist/esm/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js +2 -0
  220. package/dist/esm/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js.map +7 -0
  221. package/dist/esm/components/LiveChatWidget/components/MessageContent/index.d.ts +15 -0
  222. package/dist/esm/components/LiveChatWidget/components/MessageContent/index.js +2 -0
  223. package/dist/esm/components/LiveChatWidget/components/MessageContent/index.js.map +7 -0
  224. package/dist/esm/components/LiveChatWidget/components/MessageContent.d.ts +63 -0
  225. package/dist/esm/components/LiveChatWidget/components/MessageContent.js +2 -0
  226. package/dist/esm/components/LiveChatWidget/components/MessageContent.js.map +7 -0
  227. package/dist/esm/components/LiveChatWidget/components/MessageList.d.ts +74 -0
  228. package/dist/esm/components/LiveChatWidget/components/MessageList.js +5 -0
  229. package/dist/esm/components/LiveChatWidget/components/MessageList.js.map +7 -0
  230. package/dist/esm/components/LiveChatWidget/components/ScrollAnchor.d.ts +44 -0
  231. package/dist/esm/components/LiveChatWidget/components/ScrollAnchor.js +2 -0
  232. package/dist/esm/components/LiveChatWidget/components/ScrollAnchor.js.map +7 -0
  233. package/dist/esm/components/LiveChatWidget/constants.d.ts +13 -0
  234. package/dist/esm/components/LiveChatWidget/constants.js +2 -0
  235. package/dist/esm/components/LiveChatWidget/constants.js.map +7 -0
  236. package/dist/esm/components/LiveChatWidget/hooks/useChatAPI.d.ts +60 -0
  237. package/dist/esm/components/LiveChatWidget/hooks/useChatAPI.js +2 -0
  238. package/dist/esm/components/LiveChatWidget/hooks/useChatAPI.js.map +7 -0
  239. package/dist/esm/components/LiveChatWidget/hooks/useChatState.d.ts +151 -0
  240. package/dist/esm/components/LiveChatWidget/hooks/useChatState.js +2 -0
  241. package/dist/esm/components/LiveChatWidget/hooks/useChatState.js.map +7 -0
  242. package/dist/esm/components/LiveChatWidget/hooks/useSession.d.ts +37 -0
  243. package/dist/esm/components/LiveChatWidget/hooks/useSession.js +2 -0
  244. package/dist/esm/components/LiveChatWidget/hooks/useSession.js.map +7 -0
  245. package/dist/esm/components/LiveChatWidget/index.d.ts +12 -0
  246. package/dist/esm/components/LiveChatWidget/index.js +2 -0
  247. package/dist/esm/components/LiveChatWidget/index.js.map +7 -0
  248. package/dist/esm/components/LiveChatWidget/types.d.ts +767 -0
  249. package/dist/esm/components/LiveChatWidget/types.js +1 -0
  250. package/dist/esm/components/LiveChatWidget/types.js.map +7 -0
  251. package/dist/esm/components/LiveChatWidget/utils/cartTransformers.d.ts +25 -0
  252. package/dist/esm/components/LiveChatWidget/utils/cartTransformers.js +2 -0
  253. package/dist/esm/components/LiveChatWidget/utils/cartTransformers.js.map +7 -0
  254. package/dist/esm/components/LiveChatWidget/utils/fetcher.d.ts +36 -0
  255. package/dist/esm/components/LiveChatWidget/utils/fetcher.js +2 -0
  256. package/dist/esm/components/LiveChatWidget/utils/fetcher.js.map +7 -0
  257. package/dist/esm/components/LiveChatWidget/utils/messageRenderers.d.ts +64 -0
  258. package/dist/esm/components/LiveChatWidget/utils/messageRenderers.js +2 -0
  259. package/dist/esm/components/LiveChatWidget/utils/messageRenderers.js.map +7 -0
  260. package/dist/esm/components/LiveChatWidget/utils/productTransformers.d.ts +43 -0
  261. package/dist/esm/components/LiveChatWidget/utils/productTransformers.js +2 -0
  262. package/dist/esm/components/LiveChatWidget/utils/productTransformers.js.map +7 -0
  263. package/dist/esm/components/LiveChatWidget/utils/userId.d.ts +18 -0
  264. package/dist/esm/components/LiveChatWidget/utils/userId.js +2 -0
  265. package/dist/esm/components/LiveChatWidget/utils/userId.js.map +7 -0
  266. package/dist/esm/components/LiveChatWidget/utils/validation.d.ts +37 -0
  267. package/dist/esm/components/LiveChatWidget/utils/validation.js +2 -0
  268. package/dist/esm/components/LiveChatWidget/utils/validation.js.map +7 -0
  269. package/dist/esm/components/chat/markdown.js +1 -1
  270. package/dist/esm/components/chat/markdown.js.map +2 -2
  271. package/dist/esm/components/credits/context/hooks/useRedeemableList.js +1 -1
  272. package/dist/esm/components/credits/context/hooks/useRedeemableList.js.map +2 -2
  273. package/dist/esm/components/credits/context/memberPriceConst.d.ts +0 -5
  274. package/dist/esm/components/credits/context/memberPriceConst.js +1 -1
  275. package/dist/esm/components/credits/context/memberPriceConst.js.map +3 -3
  276. package/dist/esm/components/credits/context/memberPriceTypes.d.ts +1 -22
  277. package/dist/esm/components/credits/context/provider.d.ts +16 -1
  278. package/dist/esm/components/credits/context/provider.js +1 -1
  279. package/dist/esm/components/credits/context/provider.js.map +3 -3
  280. package/dist/esm/components/credits/creditsAnkersolixTask/CreditsAnkersolixTask.js +1 -1
  281. package/dist/esm/components/credits/creditsAnkersolixTask/CreditsAnkersolixTask.js.map +3 -3
  282. package/dist/esm/components/credits/creditsBanner/index.d.ts +2 -0
  283. package/dist/esm/components/credits/creditsBanner/index.js +12 -1
  284. package/dist/esm/components/credits/creditsBanner/index.js.map +3 -3
  285. package/dist/esm/components/credits/creditsBenefits/BenefitItem.js +2 -0
  286. package/dist/esm/components/credits/creditsBenefits/BenefitItem.js.map +7 -0
  287. package/dist/esm/components/credits/creditsBenefits/{iconInfo.js → IconInfo.js} +1 -1
  288. package/dist/esm/components/credits/creditsBenefits/{iconInfo.js.map → IconInfo.js.map} +1 -1
  289. package/dist/esm/components/credits/creditsCash/CreditsCash.js +1 -1
  290. package/dist/esm/components/credits/creditsCash/CreditsCash.js.map +3 -3
  291. package/dist/esm/components/credits/creditsCash/RedeemableItem.js +1 -1
  292. package/dist/esm/components/credits/creditsCash/RedeemableItem.js.map +3 -3
  293. package/dist/esm/components/credits/creditsCash/type.d.ts +1 -0
  294. package/dist/esm/components/credits/creditsFaq/faqItem/FaqItem.js +1 -1
  295. package/dist/esm/components/credits/creditsFaq/faqItem/FaqItem.js.map +3 -3
  296. package/dist/esm/components/credits/creditsInfoCard/index.js +1 -1
  297. package/dist/esm/components/credits/creditsInfoCard/index.js.map +2 -2
  298. package/dist/esm/components/credits/creditsMemberPrice/CreditsMemberPrice.js +1 -1
  299. package/dist/esm/components/credits/creditsMemberPrice/CreditsMemberPrice.js.map +3 -3
  300. package/dist/esm/components/credits/creditsMemberPrice/MemberPriceItem.js +1 -1
  301. package/dist/esm/components/credits/creditsMemberPrice/MemberPriceItem.js.map +3 -3
  302. package/dist/esm/components/credits/creditsMemberPrice/type.d.ts +3 -5
  303. package/dist/esm/components/credits/creditsNavigation/CreditsNavigation.js +1 -1
  304. package/dist/esm/components/credits/creditsNavigation/CreditsNavigation.js.map +2 -2
  305. package/dist/esm/components/credits/creditsRedeemList/CreditsRedeemList.js +1 -1
  306. package/dist/esm/components/credits/creditsRedeemList/CreditsRedeemList.js.map +3 -3
  307. package/dist/esm/components/credits/creditsRedeemList/RedeemProductModal/ProductInfo.js +1 -1
  308. package/dist/esm/components/credits/creditsRedeemList/RedeemProductModal/ProductInfo.js.map +2 -2
  309. package/dist/esm/components/credits/creditsRedeemList/RedeemableItem.js +1 -1
  310. package/dist/esm/components/credits/creditsRedeemList/RedeemableItem.js.map +3 -3
  311. package/dist/esm/components/credits/creditsWaysToGetCredits/CreditsWaysToGetCredits.js +1 -1
  312. package/dist/esm/components/credits/creditsWaysToGetCredits/CreditsWaysToGetCredits.js.map +3 -3
  313. package/dist/esm/components/index.d.ts +3 -1
  314. package/dist/esm/components/index.js +1 -1
  315. package/dist/esm/components/index.js.map +3 -3
  316. package/dist/esm/components/registration/authCodeActivate/index.js +1 -1
  317. package/dist/esm/components/registration/authCodeActivate/index.js.map +2 -2
  318. package/dist/esm/stories/CartCard.stories.d.ts +33 -0
  319. package/dist/esm/stories/CartCard.stories.js +21 -0
  320. package/dist/esm/stories/CartCard.stories.js.map +7 -0
  321. package/dist/esm/stories/LiveChatWidget.stories.d.ts +108 -0
  322. package/dist/esm/stories/LiveChatWidget.stories.js +149 -0
  323. package/dist/esm/stories/LiveChatWidget.stories.js.map +7 -0
  324. package/dist/esm/templates/{credits.d.ts → Credits.d.ts} +16 -1
  325. package/dist/esm/templates/Credits.js +2 -0
  326. package/dist/esm/templates/Credits.js.map +7 -0
  327. package/dist/index.d.mts +1305 -0
  328. package/dist/index.d.ts +1305 -0
  329. package/dist/index.js +26656 -0
  330. package/dist/index.js.map +1 -0
  331. package/dist/index.mjs +26641 -0
  332. package/dist/index.mjs.map +1 -0
  333. package/package.json +7 -3
  334. package/src/components/LiveChatWidget/LiveChatWidget.tsx +732 -0
  335. package/src/components/LiveChatWidget/api/chat.ts +174 -0
  336. package/src/components/LiveChatWidget/components/ChatBubble.tsx +152 -0
  337. package/src/components/LiveChatWidget/components/ChatHeader.tsx +150 -0
  338. package/src/components/LiveChatWidget/components/ChatInput.tsx +241 -0
  339. package/src/components/LiveChatWidget/components/ChatMessage.tsx +190 -0
  340. package/src/components/LiveChatWidget/components/ChatWindow.tsx +353 -0
  341. package/src/components/LiveChatWidget/components/MessageContent/CartCard.tsx +202 -0
  342. package/src/components/LiveChatWidget/components/MessageContent/ErrorBlock.tsx +75 -0
  343. package/src/components/LiveChatWidget/components/MessageContent/FAQList.tsx +127 -0
  344. package/src/components/LiveChatWidget/components/MessageContent/PolicyBlock.tsx +150 -0
  345. package/src/components/LiveChatWidget/components/MessageContent/ProductCard.tsx +218 -0
  346. package/src/components/LiveChatWidget/components/MessageContent/ProductComparison.tsx +359 -0
  347. package/src/components/LiveChatWidget/components/MessageContent/ProductList.tsx +293 -0
  348. package/src/components/LiveChatWidget/components/MessageContent/PromotionList.tsx +170 -0
  349. package/src/components/LiveChatWidget/components/MessageContent/QuickReplies.tsx +91 -0
  350. package/src/components/LiveChatWidget/components/MessageContent/TextBlock.tsx +89 -0
  351. package/src/components/LiveChatWidget/components/MessageContent/ThinkingBlock.tsx +53 -0
  352. package/src/components/LiveChatWidget/components/MessageContent/index.ts +16 -0
  353. package/src/components/LiveChatWidget/components/MessageContent.tsx +113 -0
  354. package/src/components/LiveChatWidget/components/MessageList.tsx +261 -0
  355. package/src/components/LiveChatWidget/components/ScrollAnchor.tsx +75 -0
  356. package/src/components/LiveChatWidget/constants.ts +36 -0
  357. package/src/components/LiveChatWidget/hooks/useChatAPI.ts +146 -0
  358. package/src/components/LiveChatWidget/hooks/useChatState.ts +1086 -0
  359. package/src/components/LiveChatWidget/hooks/useSession.ts +123 -0
  360. package/src/components/LiveChatWidget/index.tsx +62 -0
  361. package/src/components/LiveChatWidget/types.ts +949 -0
  362. package/src/components/LiveChatWidget/utils/cartTransformers.ts +72 -0
  363. package/src/components/LiveChatWidget/utils/fetcher.ts +126 -0
  364. package/src/components/LiveChatWidget/utils/messageRenderers.ts +120 -0
  365. package/src/components/LiveChatWidget/utils/productTransformers.ts +149 -0
  366. package/src/components/LiveChatWidget/utils/userId.ts +140 -0
  367. package/src/components/LiveChatWidget/utils/validation.ts +99 -0
  368. package/src/components/chat/markdown.tsx +1 -1
  369. package/src/components/credits/context/hooks/useRedeemableList.ts +1 -1
  370. package/src/components/credits/context/memberPriceConst.ts +0 -7
  371. package/src/components/credits/context/memberPriceTypes.ts +1 -26
  372. package/src/components/credits/context/provider.tsx +16 -0
  373. package/src/components/credits/creditsAnkersolixTask/CreditsAnkersolixTask.tsx +26 -26
  374. package/src/components/credits/creditsBanner/index.tsx +31 -3
  375. package/src/components/credits/creditsBenefits/BenefitItem.tsx +11 -4
  376. package/src/components/credits/creditsBenefits/IconInfo.tsx +1 -1
  377. package/src/components/credits/creditsCash/CreditsCash.tsx +6 -3
  378. package/src/components/credits/creditsCash/RedeemableItem.tsx +23 -10
  379. package/src/components/credits/creditsCash/type.ts +1 -0
  380. package/src/components/credits/creditsFaq/faqItem/FaqItem.tsx +25 -23
  381. package/src/components/credits/creditsInfoCard/index.tsx +8 -2
  382. package/src/components/credits/creditsMemberPrice/CreditsMemberPrice.tsx +124 -25
  383. package/src/components/credits/creditsMemberPrice/MemberPriceItem.tsx +113 -31
  384. package/src/components/credits/creditsMemberPrice/type.ts +3 -5
  385. package/src/components/credits/creditsNavigation/CreditsNavigation.tsx +3 -3
  386. package/src/components/credits/creditsRedeemList/CreditsRedeemList.tsx +31 -18
  387. package/src/components/credits/creditsRedeemList/RedeemProductModal/ProductInfo.tsx +6 -4
  388. package/src/components/credits/creditsRedeemList/RedeemableItem.tsx +19 -6
  389. package/src/components/credits/creditsWaysToGetCredits/CreditsWaysToGetCredits.tsx +20 -17
  390. package/src/components/index.ts +23 -1
  391. package/src/components/registration/authCodeActivate/index.tsx +2 -0
  392. package/src/stories/CartCard.stories.tsx +459 -0
  393. package/src/stories/LiveChatWidget.stories.tsx +754 -0
  394. package/src/styles/livechat.css +268 -0
  395. package/src/templates/Credits.tsx +27 -9
  396. package/dist/cjs/components/credits/context/hooks/useFunctionMemberPrice.d.ts +0 -7
  397. package/dist/cjs/components/credits/context/hooks/useFunctionMemberPrice.js +0 -2
  398. package/dist/cjs/components/credits/context/hooks/useFunctionMemberPrice.js.map +0 -7
  399. package/dist/cjs/components/credits/context/hooks/useSendEmailValidation.d.ts +0 -1
  400. package/dist/cjs/components/credits/context/hooks/useSendEmailValidation.js +0 -2
  401. package/dist/cjs/components/credits/context/hooks/useSendEmailValidation.js.map +0 -7
  402. package/dist/cjs/components/credits/context/hooks/useSubscriptions.d.ts +0 -9
  403. package/dist/cjs/components/credits/context/hooks/useSubscriptions.js +0 -2
  404. package/dist/cjs/components/credits/context/hooks/useSubscriptions.js.map +0 -7
  405. package/dist/cjs/components/credits/context/utils/atobID.d.ts +0 -1
  406. package/dist/cjs/components/credits/context/utils/atobID.js +0 -2
  407. package/dist/cjs/components/credits/context/utils/atobID.js.map +0 -7
  408. package/dist/cjs/components/credits/context/utils/functionDiscountCalculate.d.ts +0 -5
  409. package/dist/cjs/components/credits/context/utils/functionDiscountCalculate.js +0 -2
  410. package/dist/cjs/components/credits/context/utils/functionDiscountCalculate.js.map +0 -7
  411. package/dist/cjs/components/credits/context/utils/getFunctionMemberPrice.d.ts +0 -8
  412. package/dist/cjs/components/credits/context/utils/getFunctionMemberPrice.js +0 -2
  413. package/dist/cjs/components/credits/context/utils/getFunctionMemberPrice.js.map +0 -7
  414. package/dist/cjs/components/credits/context/utils/getFunctionMemberPriceDiscountConfig.d.ts +0 -9
  415. package/dist/cjs/components/credits/context/utils/getFunctionMemberPriceDiscountConfig.js +0 -2
  416. package/dist/cjs/components/credits/context/utils/getFunctionMemberPriceDiscountConfig.js.map +0 -7
  417. package/dist/cjs/components/credits/context/utils/variantGetCoupon.d.ts +0 -6
  418. package/dist/cjs/components/credits/context/utils/variantGetCoupon.js +0 -2
  419. package/dist/cjs/components/credits/context/utils/variantGetCoupon.js.map +0 -7
  420. package/dist/cjs/components/credits/creditsBenefits/benefitItem.js +0 -2
  421. package/dist/cjs/components/credits/creditsBenefits/benefitItem.js.map +0 -7
  422. package/dist/cjs/helpers/fetchResponse.d.ts +0 -14
  423. package/dist/cjs/helpers/fetchResponse.js +0 -2
  424. package/dist/cjs/helpers/fetchResponse.js.map +0 -7
  425. package/dist/cjs/helpers/fetcher.d.ts +0 -2
  426. package/dist/cjs/helpers/fetcher.js +0 -2
  427. package/dist/cjs/helpers/fetcher.js.map +0 -7
  428. package/dist/cjs/helpers/index.d.ts +0 -2
  429. package/dist/cjs/helpers/index.js +0 -2
  430. package/dist/cjs/helpers/index.js.map +0 -7
  431. package/dist/cjs/helpers/track.d.ts +0 -19
  432. package/dist/cjs/helpers/track.js +0 -2
  433. package/dist/cjs/helpers/track.js.map +0 -7
  434. package/dist/cjs/helpers/utils.d.ts +0 -3
  435. package/dist/cjs/helpers/utils.js +0 -2
  436. package/dist/cjs/helpers/utils.js.map +0 -7
  437. package/dist/cjs/templates/credits.js +0 -2
  438. package/dist/cjs/templates/credits.js.map +0 -7
  439. package/dist/esm/components/credits/context/hooks/useFunctionMemberPrice.d.ts +0 -7
  440. package/dist/esm/components/credits/context/hooks/useFunctionMemberPrice.js +0 -2
  441. package/dist/esm/components/credits/context/hooks/useFunctionMemberPrice.js.map +0 -7
  442. package/dist/esm/components/credits/context/hooks/useSendEmailValidation.d.ts +0 -1
  443. package/dist/esm/components/credits/context/hooks/useSendEmailValidation.js +0 -2
  444. package/dist/esm/components/credits/context/hooks/useSendEmailValidation.js.map +0 -7
  445. package/dist/esm/components/credits/context/hooks/useSubscriptions.d.ts +0 -9
  446. package/dist/esm/components/credits/context/hooks/useSubscriptions.js +0 -2
  447. package/dist/esm/components/credits/context/hooks/useSubscriptions.js.map +0 -7
  448. package/dist/esm/components/credits/context/utils/atobID.d.ts +0 -1
  449. package/dist/esm/components/credits/context/utils/atobID.js +0 -2
  450. package/dist/esm/components/credits/context/utils/atobID.js.map +0 -7
  451. package/dist/esm/components/credits/context/utils/functionDiscountCalculate.d.ts +0 -5
  452. package/dist/esm/components/credits/context/utils/functionDiscountCalculate.js +0 -2
  453. package/dist/esm/components/credits/context/utils/functionDiscountCalculate.js.map +0 -7
  454. package/dist/esm/components/credits/context/utils/getFunctionMemberPrice.d.ts +0 -8
  455. package/dist/esm/components/credits/context/utils/getFunctionMemberPrice.js +0 -2
  456. package/dist/esm/components/credits/context/utils/getFunctionMemberPrice.js.map +0 -7
  457. package/dist/esm/components/credits/context/utils/getFunctionMemberPriceDiscountConfig.d.ts +0 -9
  458. package/dist/esm/components/credits/context/utils/getFunctionMemberPriceDiscountConfig.js +0 -2
  459. package/dist/esm/components/credits/context/utils/getFunctionMemberPriceDiscountConfig.js.map +0 -7
  460. package/dist/esm/components/credits/context/utils/variantGetCoupon.d.ts +0 -6
  461. package/dist/esm/components/credits/context/utils/variantGetCoupon.js +0 -2
  462. package/dist/esm/components/credits/context/utils/variantGetCoupon.js.map +0 -7
  463. package/dist/esm/components/credits/creditsBenefits/benefitItem.js +0 -2
  464. package/dist/esm/components/credits/creditsBenefits/benefitItem.js.map +0 -7
  465. package/dist/esm/helpers/fetchResponse.d.ts +0 -14
  466. package/dist/esm/helpers/fetchResponse.js +0 -2
  467. package/dist/esm/helpers/fetchResponse.js.map +0 -7
  468. package/dist/esm/helpers/fetcher.d.ts +0 -2
  469. package/dist/esm/helpers/fetcher.js +0 -2
  470. package/dist/esm/helpers/fetcher.js.map +0 -7
  471. package/dist/esm/helpers/index.d.ts +0 -2
  472. package/dist/esm/helpers/index.js +0 -2
  473. package/dist/esm/helpers/index.js.map +0 -7
  474. package/dist/esm/helpers/track.d.ts +0 -19
  475. package/dist/esm/helpers/track.js +0 -2
  476. package/dist/esm/helpers/track.js.map +0 -7
  477. package/dist/esm/helpers/utils.d.ts +0 -3
  478. package/dist/esm/helpers/utils.js +0 -2
  479. package/dist/esm/helpers/utils.js.map +0 -7
  480. package/dist/esm/templates/credits.js +0 -2
  481. package/dist/esm/templates/credits.js.map +0 -7
  482. package/src/components/credits/context/hooks/useFunctionMemberPrice.ts +0 -33
  483. package/src/components/credits/context/utils/atobID.ts +0 -8
  484. package/src/components/credits/context/utils/functionDiscountCalculate.ts +0 -57
  485. package/src/components/credits/context/utils/getFunctionMemberPrice.ts +0 -135
  486. package/src/components/credits/context/utils/getFunctionMemberPriceDiscountConfig.ts +0 -51
  487. package/src/components/credits/context/utils/variantGetCoupon.ts +0 -34
  488. /package/dist/cjs/components/credits/creditsBenefits/{benefitItem.d.ts → BenefitItem.d.ts} +0 -0
  489. /package/dist/cjs/components/credits/creditsBenefits/{iconInfo.d.ts → IconInfo.d.ts} +0 -0
  490. /package/dist/esm/components/credits/creditsBenefits/{benefitItem.d.ts → BenefitItem.d.ts} +0 -0
  491. /package/dist/esm/components/credits/creditsBenefits/{iconInfo.d.ts → IconInfo.d.ts} +0 -0
@@ -0,0 +1,1086 @@
1
+ /**
2
+ * 聊天状态管理 Hook
3
+ * 管理消息列表、窗口状态、输入框状态、流式消息累积
4
+ * 基于 specs/livechat-widget/plan.md 的状态管理策略
5
+ */
6
+
7
+ import { useState, useCallback, useRef, useEffect } from 'react'
8
+ import type { Message, MessageContent, SSEEvent, StatusData, ErrorData, MessageStartData, BackendCartData, Product, TextContent, ProductCardContent, ProductListContent } from '../types'
9
+ import { getUserId } from '../utils/userId'
10
+ import { useSession } from './useSession'
11
+ import { transformProducts } from '../utils/productTransformers'
12
+ import { transformCartData } from '../utils/cartTransformers'
13
+
14
+ // ============================================================================
15
+ // 辅助函数:文本解析和消息重组
16
+ // ============================================================================
17
+
18
+ /**
19
+ * 实时解析流式文本中的产品占位符
20
+ * 处理缓冲区中的文本,检测完整的 {{product:xxx}} 占位符
21
+ *
22
+ * @param buffer 当前缓冲区内容(包含新接收的文本)
23
+ * @param productMap shopifyId → Product 的映射表
24
+ * @param rawProductMap shopifyId → raw backend product 的映射表
25
+ * @param onAddToCart 添加到购物车回调
26
+ * @param productCardRender 自定义产品卡片渲染函数
27
+ * @returns { contents: 需要添加的内容数组, remainingBuffer: 剩余缓冲区内容 }
28
+ */
29
+ function parseStreamingText(
30
+ buffer: string,
31
+ productMap: Map<string, Product>,
32
+ rawProductMap: Map<string, any>,
33
+ onAddToCart?: (product: Product) => void,
34
+ productCardRender?: (product: any) => React.ReactNode
35
+ ): { contents: MessageContent[]; remainingBuffer: string } {
36
+ const contents: MessageContent[] = []
37
+ const regex = /\{\{(?:product:)?([^}]+)\}\}/g
38
+
39
+ let lastIndex = 0
40
+ let match: RegExpExecArray | null
41
+ let foundMatch = false
42
+
43
+ // 查找所有完整的占位符
44
+ while ((match = regex.exec(buffer)) !== null) {
45
+ foundMatch = true
46
+
47
+ // 提取占位符前的文本
48
+ const beforeText = buffer.slice(lastIndex, match.index)
49
+ if (beforeText) {
50
+ contents.push({ type: 'text', text: beforeText } as TextContent)
51
+ }
52
+
53
+ // 提取产品 ID 并创建产品卡片
54
+ const productId = match[1].trim()
55
+ const product = productMap.get(productId)
56
+ const rawProduct = rawProductMap.get(productId)
57
+
58
+ if (product) {
59
+ console.log('[useChatState] 🎯 实时检测到产品:', productId, '→', product.title)
60
+ contents.push({
61
+ type: 'product_card',
62
+ data: {
63
+ product: product,
64
+ rawProduct: rawProduct,
65
+ onAddToCart: onAddToCart,
66
+ productCardRender: productCardRender
67
+ }
68
+ } as ProductCardContent)
69
+ } else {
70
+ // 产品未找到,保留原始文本
71
+ console.warn('[useChatState] ⚠️ 实时解析未找到产品:', productId)
72
+ contents.push({ type: 'text', text: match[0] } as TextContent)
73
+ }
74
+
75
+ lastIndex = regex.lastIndex
76
+ }
77
+
78
+ // 如果找到了至少一个完整占位符
79
+ if (foundMatch) {
80
+ // 返回剩余的文本作为缓冲区(可能包含不完整的占位符)
81
+ const remainingBuffer = buffer.slice(lastIndex)
82
+ return { contents, remainingBuffer }
83
+ } else {
84
+ // 没有找到完整占位符,检查是否有不完整的占位符开头
85
+ // 例如:缓冲区是 "some text {{prod",我们需要保留 "{{prod" 等待更多文本
86
+ const incompleteMatch = buffer.match(/\{\{[^}]*$/)
87
+
88
+ if (incompleteMatch) {
89
+ // 有不完整的占位符开头
90
+ const completeText = buffer.slice(0, incompleteMatch.index)
91
+ if (completeText) {
92
+ contents.push({ type: 'text', text: completeText } as TextContent)
93
+ }
94
+ return { contents, remainingBuffer: incompleteMatch[0] }
95
+ } else {
96
+ // 没有不完整的占位符,整个缓冲区都是普通文本
97
+ if (buffer) {
98
+ contents.push({ type: 'text', text: buffer } as TextContent)
99
+ }
100
+ return { contents, remainingBuffer: '' }
101
+ }
102
+ }
103
+ }
104
+
105
+ /**
106
+ * 解析文本中的 {{shopifyId}},返回 [text, product_card, text, ...] 数组(用于历史消息重组)
107
+ *
108
+ * @param text 包含 {{shopifyId}} 标记的文本
109
+ * @param productMap shopifyId → Product 的映射表
110
+ * @param onAddToCart 添加到购物车回调
111
+ * @param productCardRender 自定义产品卡片渲染函数
112
+ * @returns MessageContent 数组
113
+ *
114
+ * @example
115
+ * 输入:
116
+ * text: "我推荐以下产品:\n{{12345}}\n这款产品性价比很高。"
117
+ * productMap: Map { '12345' => Product {...} }
118
+ * 输出:
119
+ * [
120
+ * { type: 'text', text: '我推荐以下产品:' },
121
+ * { type: 'product_card', data: { product: {...}, onAddToCart } },
122
+ * { type: 'text', text: '这款产品性价比很高。' }
123
+ * ]
124
+ */
125
+ function parseTextWithProductIds(
126
+ text: string,
127
+ productMap: Map<string, Product>,
128
+ rawProductMap: Map<string, any>,
129
+ onAddToCart?: (product: Product) => void,
130
+ productCardRender?: (product: any) => React.ReactNode
131
+ ): MessageContent[] {
132
+ const result: MessageContent[] = []
133
+ // 修改正则表达式以匹配 {{product:ID}} 格式
134
+ // 匹配 {{product:xxx}} 或 {{xxx}}(兼容两种格式)
135
+ const regex = /\{\{(?:product:)?([^}]+)\}\}/g
136
+
137
+ let lastIndex = 0
138
+ let match: RegExpExecArray | null
139
+
140
+ while ((match = regex.exec(text)) !== null) {
141
+ const beforeText = text.slice(lastIndex, match.index).trim()
142
+ // match[1] 是捕获组中的内容,即 product: 后面的 ID
143
+ const productId = match[1].trim()
144
+
145
+ // 添加前面的文本(如果有)
146
+ if (beforeText) {
147
+ result.push({
148
+ type: 'text',
149
+ text: beforeText,
150
+ } as TextContent)
151
+ }
152
+
153
+ // 添加产品卡片
154
+ const product = productMap.get(productId)
155
+ const rawProduct = rawProductMap.get(productId)
156
+ if (product) {
157
+ console.log(`[useChatState] ✅ 找到产品匹配: ${productId} → ${product.title}`)
158
+ result.push({
159
+ type: 'product_card',
160
+ data: {
161
+ product: product,
162
+ rawProduct: rawProduct,
163
+ onAddToCart: onAddToCart,
164
+ productCardRender: productCardRender,
165
+ },
166
+ } as ProductCardContent)
167
+ } else {
168
+ // 找不到产品时,保留原始标记(不应该发生,但做兜底处理)
169
+ const availableKeys = Array.from(productMap.keys())
170
+ console.warn(`[useChatState] ❌ Product not found for ID: "${productId}"`)
171
+ console.warn('[useChatState] 可用的产品ID列表:', availableKeys)
172
+ console.warn('[useChatState] ID类型:', typeof productId, '长度:', productId.length)
173
+ result.push({
174
+ type: 'text',
175
+ text: match[0], // 保留原始完整标记,包括 product: 前缀
176
+ } as TextContent)
177
+ }
178
+
179
+ lastIndex = regex.lastIndex
180
+ }
181
+
182
+ // 添加最后剩余的文本
183
+ const remainingText = text.slice(lastIndex).trim()
184
+ if (remainingText) {
185
+ result.push({
186
+ type: 'text',
187
+ text: remainingText,
188
+ } as TextContent)
189
+ }
190
+
191
+ return result
192
+ }
193
+
194
+ /**
195
+ * 重组消息内容:解析文本中的 {{shopifyId}},替换为产品卡片
196
+ *
197
+ * 处理逻辑:
198
+ * 1. 遍历消息的所有 content blocks
199
+ * 2. 对于 text 类型,解析其中的 {{shopifyId}} 并拆分为多个 content
200
+ * 3. 跳过 product_list 类型(已经被拆分到文本中)
201
+ * 4. 其他类型直接保留
202
+ *
203
+ * @param contents 原始消息内容数组
204
+ * @param productMap shopifyId → Product 的映射表
205
+ * @param onAddToCart 添加到购物车回调
206
+ * @param productCardRender 自定义产品卡片渲染函数
207
+ * @returns 重组后的消息内容数组
208
+ */
209
+ function reorganizeMessageContent(
210
+ contents: MessageContent[],
211
+ productMap: Map<string, Product>,
212
+ rawProductMap: Map<string, any>,
213
+ onAddToCart?: (product: Product) => void,
214
+ productCardRender?: (product: any) => React.ReactNode
215
+ ): MessageContent[] {
216
+ const result: MessageContent[] = []
217
+
218
+ for (const content of contents) {
219
+ // 只处理文本类型
220
+ if (content.type === 'text') {
221
+ const textContent = content as TextContent
222
+ const segments = parseTextWithProductIds(textContent.text, productMap, rawProductMap, onAddToCart, productCardRender)
223
+ result.push(...segments)
224
+ }
225
+ // 跳过 product_list(已经被拆分到文本中)
226
+ else if (content.type === 'product_list') {
227
+ continue
228
+ }
229
+ // 其他类型直接保留
230
+ else {
231
+ result.push(content)
232
+ }
233
+ }
234
+
235
+ return result
236
+ }
237
+
238
+ /**
239
+ * 处理单条消息的重组(用于历史消息加载)
240
+ * 如果消息包含 product_list 和带有 {{}} 的文本,则进行重组
241
+ *
242
+ * @param message 原始消息
243
+ * @param onAddToCart 添加到购物车回调
244
+ * @param productCardRender 自定义产品卡片渲染函数
245
+ * @returns 重组后的消息(如果需要重组),否则返回原消息
246
+ */
247
+ function maybeReorganizeHistoricalMessage(
248
+ message: Message,
249
+ onAddToCart?: (product: Product) => void,
250
+ productCardRender?: (product: any) => React.ReactNode
251
+ ): Message {
252
+ // 检查消息是否包含 product_list
253
+ const hasProductList = message.content.some(c => c.type === 'product_list')
254
+ if (!hasProductList) {
255
+ return message // 没有 product_list,不需要重组
256
+ }
257
+
258
+ // 检查消息是否包含带有 {{}} 的文本
259
+ const hasPlaceholder = message.content.some(
260
+ c => c.type === 'text' && /\{\{(?:product:)?[^}]+\}\}/.test((c as TextContent).text)
261
+ )
262
+ if (!hasPlaceholder) {
263
+ return message // 没有占位符,不需要重组
264
+ }
265
+
266
+ console.log('[useChatState] 检测到历史消息需要重组, 消息ID:', message.id)
267
+
268
+ // 构建产品映射
269
+ const productMap = new Map<string, Product>()
270
+ // 从 structured_content 中提取原始后端产品数据
271
+ const rawProductMap = new Map<string, any>()
272
+
273
+ // 优先从 structured_content 获取原始产品数据(如果存在)
274
+ if (message.structured_content) {
275
+ message.structured_content.forEach(structuredContent => {
276
+ if (structuredContent.type === 'product_list' && Array.isArray(structuredContent.data)) {
277
+ structuredContent.data.forEach((rawProduct: any) => {
278
+ if (rawProduct && rawProduct.shopify_product_id) {
279
+ const shopifyId = rawProduct.shopify_product_id
280
+ // 1. 使用完整的 shopifyId 作为key
281
+ rawProductMap.set(shopifyId, rawProduct)
282
+
283
+ // 2. 同时提取数字部分作为key
284
+ const numericId = shopifyId.match(/\d+$/)?.[0]
285
+ if (numericId) {
286
+ rawProductMap.set(numericId, rawProduct)
287
+ }
288
+
289
+ console.log('[useChatState] 从 structured_content 提取原始产品数据:', {
290
+ fullId: shopifyId,
291
+ numericId,
292
+ title: rawProduct.title,
293
+ })
294
+ }
295
+ })
296
+ }
297
+ })
298
+ }
299
+
300
+ // 构建转换后的产品映射(用于默认渲染)
301
+ message.content.forEach(content => {
302
+ if (content.type === 'product_list') {
303
+ const productListContent = content as ProductListContent
304
+ productListContent.data.products.forEach(product => {
305
+ if (product && product.shopifyId) {
306
+ // 1. 使用完整的 shopifyId 作为key
307
+ productMap.set(product.shopifyId, product)
308
+
309
+ // 2. 同时提取数字部分作为key
310
+ const numericId = product.shopifyId.match(/\d+$/)?.[0]
311
+ if (numericId) {
312
+ productMap.set(numericId, product)
313
+ }
314
+ }
315
+ })
316
+ }
317
+ })
318
+
319
+ // 重组消息内容
320
+ const reorganizedContent = reorganizeMessageContent(message.content, productMap, rawProductMap, onAddToCart, productCardRender)
321
+
322
+ // 返回新消息对象
323
+ return {
324
+ ...message,
325
+ content: reorganizedContent,
326
+ }
327
+ }
328
+
329
+ export interface UseChatStateOptions {
330
+ /**
331
+ * 初始欢迎消息
332
+ */
333
+ welcomeMessage?: string
334
+
335
+ /**
336
+ * Shopify 店铺域名
337
+ */
338
+ site?: string
339
+
340
+ /**
341
+ * 受控模式:是否打开聊天窗口
342
+ * 提供此参数时,组件处于受控模式
343
+ */
344
+ open?: boolean
345
+
346
+ /**
347
+ * 受控模式:状态变化回调(必需)
348
+ * 用于同步状态到父组件
349
+ */
350
+ onOpenChange?: (open: boolean) => void
351
+
352
+ /**
353
+ * 窗口打开事件监听(可选)
354
+ * 用于埋点、日志等副作用
355
+ */
356
+ onOpen?: () => void
357
+
358
+ /**
359
+ * 窗口关闭事件监听(可选)
360
+ * 用于埋点、日志等副作用
361
+ */
362
+ onClose?: () => void
363
+
364
+ /**
365
+ * 消息发送回调
366
+ */
367
+ onMessageSend?: (message: string) => void
368
+
369
+ /**
370
+ * 错误处理回调
371
+ */
372
+ onError?: (error: Error) => void
373
+
374
+ /**
375
+ * AI 消息回调
376
+ */
377
+ /**
378
+ * AI 回复文本消息时触发
379
+ */
380
+ onTextMessage?: () => void
381
+
382
+ /**
383
+ * AI 回复商品列表卡片时触发
384
+ */
385
+ onProductList?: () => void
386
+
387
+ /**
388
+ * AI 回复促销卡片时触发
389
+ */
390
+ onPromotionList?: () => void
391
+
392
+ /**
393
+ * 商品添加到购物车回调
394
+ */
395
+ onAddToCart?: (product: any) => void
396
+
397
+ /**
398
+ * 购物车按钮点击回调
399
+ */
400
+ onCart?: (cartId: string, checkoutUrl?: string) => void
401
+
402
+ /**
403
+ * 自定义产品卡片渲染函数
404
+ */
405
+ productCardRender?: (product: Product) => React.ReactNode
406
+ }
407
+
408
+ export interface UseChatStateReturn {
409
+ /**
410
+ * 消息列表
411
+ */
412
+ messages: Message[]
413
+
414
+ /**
415
+ * 聊天窗口是否打开
416
+ */
417
+ isOpen: boolean
418
+
419
+ /**
420
+ * 用户 ID
421
+ */
422
+ userId: string
423
+
424
+ /**
425
+ * 会话 ID
426
+ */
427
+ sessionId: string | null
428
+
429
+ /**
430
+ * 输入框内容
431
+ */
432
+ inputValue: string
433
+
434
+ /**
435
+ * 是否正在接收流式消息
436
+ */
437
+ isStreaming: boolean
438
+
439
+ /**
440
+ * 打开聊天窗口
441
+ */
442
+ openChat: () => void
443
+
444
+ /**
445
+ * 关闭聊天窗口
446
+ */
447
+ closeChat: () => void
448
+
449
+ /**
450
+ * 切换聊天窗口状态
451
+ */
452
+ toggleChat: () => void
453
+
454
+ /**
455
+ * 设置输入框内容
456
+ */
457
+ setInputValue: (value: string) => void
458
+
459
+ /**
460
+ * 添加消息到列表
461
+ */
462
+ addMessage: (message: Message) => void
463
+
464
+ /**
465
+ * 批量设置消息列表(用于加载历史)
466
+ */
467
+ setMessages: (messages: Message[]) => void
468
+
469
+ /**
470
+ * 清空消息列表
471
+ */
472
+ clearMessages: () => void
473
+
474
+ /**
475
+ * 处理 SSE 事件
476
+ */
477
+ handleSSEEvent: (event: SSEEvent) => void
478
+
479
+ /**
480
+ * 保存会话 ID
481
+ */
482
+ saveSession: (id: string) => void
483
+
484
+ /**
485
+ * 清空会话
486
+ */
487
+ clearSession: () => void
488
+ }
489
+
490
+ /**
491
+ * 聊天状态管理 Hook
492
+ *
493
+ * 功能:
494
+ * 1. 管理消息列表(添加、清空、批量设置)
495
+ * 2. 管理窗口状态(打开、关闭、切换)
496
+ * 3. 管理输入框状态
497
+ * 4. 处理 SSE 流式消息事件
498
+ * 5. 累积流式文本内容
499
+ *
500
+ * @param options Hook 配置选项
501
+ * @returns 状态管理工具对象
502
+ */
503
+ export function useChatState(options: UseChatStateOptions = {}): UseChatStateReturn {
504
+ const {
505
+ welcomeMessage,
506
+ site,
507
+ open: controlledOpen,
508
+ onOpenChange,
509
+ onOpen,
510
+ onClose,
511
+ onMessageSend,
512
+ onError,
513
+ onTextMessage,
514
+ onProductList,
515
+ onPromotionList,
516
+ onAddToCart,
517
+ onCart,
518
+ productCardRender,
519
+ } = options
520
+
521
+ // 会话管理
522
+ const { sessionId, saveSession, clearSession } = useSession()
523
+
524
+ // 用户 ID (初始化时异步生成)
525
+ const [userId, setUserId] = useState<string>('')
526
+
527
+ // 初始化 userId
528
+ useEffect(() => {
529
+ getUserId().then(id => setUserId(id))
530
+ }, [])
531
+
532
+ // 消息列表
533
+ const [messages, setMessagesState] = useState<Message[]>(() => {
534
+ // 如果有欢迎消息,初始化时添加
535
+ if (welcomeMessage) {
536
+ return [
537
+ {
538
+ id: `welcome-${Date.now()}`,
539
+ role: 'assistant',
540
+ content: [{ type: 'text', text: welcomeMessage }],
541
+ timestamp: Date.now(),
542
+ },
543
+ ]
544
+ }
545
+ return []
546
+ })
547
+
548
+ // 聊天窗口是否打开(支持受控和非受控两种模式)
549
+ const [internalOpen, setInternalOpen] = useState(false)
550
+ const isControlled = controlledOpen !== undefined
551
+ const isOpen = isControlled ? controlledOpen : internalOpen
552
+
553
+ // 输入框内容
554
+ const [inputValue, setInputValue] = useState('')
555
+
556
+ // 是否正在接收流式消息
557
+ const [isStreaming, setIsStreaming] = useState(false)
558
+
559
+ // 当前正在累积的流式消息 (临时存储)
560
+ const currentMessageRef = useRef<Message | null>(null)
561
+
562
+ // 标记当前消息是否已触发 onTextMessage 回调(避免重复触发)
563
+ const textMessageCallbackTriggeredRef = useRef<boolean>(false)
564
+
565
+ // 产品映射缓存 (shopifyId → Product),用于实时解析占位符
566
+ const productMapRef = useRef<Map<string, Product>>(new Map())
567
+
568
+ // 原始产品数据缓存 (shopifyId → raw backend product),用于 productCardRender
569
+ const rawProductMapRef = useRef<Map<string, any>>(new Map())
570
+
571
+ // 文本缓冲区,用于存储未完成的文本(处理占位符跨越多个 delta 的情况)
572
+ const textBufferRef = useRef<string>('')
573
+
574
+ /**
575
+ * 打开聊天窗口
576
+ */
577
+ const openChat = useCallback(() => {
578
+ if (!isControlled) {
579
+ setInternalOpen(true)
580
+ }
581
+ onOpenChange?.(true)
582
+ onOpen?.()
583
+ }, [isControlled, onOpenChange, onOpen])
584
+
585
+ /**
586
+ * 关闭聊天窗口
587
+ */
588
+ const closeChat = useCallback(() => {
589
+ if (!isControlled) {
590
+ setInternalOpen(false)
591
+ }
592
+ onOpenChange?.(false)
593
+ onClose?.()
594
+ }, [isControlled, onOpenChange, onClose])
595
+
596
+ /**
597
+ * 切换聊天窗口状态
598
+ */
599
+ const toggleChat = useCallback(() => {
600
+ const newState = !isOpen
601
+ if (!isControlled) {
602
+ setInternalOpen(newState)
603
+ }
604
+ onOpenChange?.(newState)
605
+ if (newState) {
606
+ onOpen?.()
607
+ } else {
608
+ onClose?.()
609
+ }
610
+ }, [isControlled, isOpen, onOpenChange, onOpen, onClose])
611
+
612
+ /**
613
+ * 添加消息到列表
614
+ */
615
+ const addMessage = useCallback((message: Message) => {
616
+ // 防护:如果消息为 null 或 undefined,不添加
617
+ if (!message) {
618
+ console.warn('[useChatState] Attempted to add null/undefined message')
619
+ return
620
+ }
621
+ setMessagesState(prev => [...prev, message])
622
+ }, [])
623
+
624
+ /**
625
+ * 批量设置消息列表(用于加载历史)
626
+ */
627
+ const setMessages = useCallback(
628
+ (newMessages: Message[]) => {
629
+ // 防护:过滤掉 null/undefined 消息
630
+ const validMessages = newMessages.filter(msg => msg != null)
631
+ if (validMessages.length !== newMessages.length) {
632
+ console.warn('[useChatState] Filtered out null/undefined messages from batch set')
633
+ }
634
+
635
+ // 对每条历史消息进行重组(如果需要)
636
+ const reorganizedMessages = validMessages.map(msg => maybeReorganizeHistoricalMessage(msg, onAddToCart, productCardRender))
637
+
638
+ setMessagesState(reorganizedMessages)
639
+ },
640
+ [onAddToCart, productCardRender]
641
+ )
642
+
643
+ /**
644
+ * 清空消息列表
645
+ */
646
+ const clearMessages = useCallback(() => {
647
+ setMessagesState([])
648
+ }, [])
649
+
650
+ /**
651
+ * 处理 SSE 事件
652
+ * 根据事件类型进行不同的处理
653
+ */
654
+ const handleSSEEvent = useCallback(
655
+ (event: SSEEvent) => {
656
+ const { event: eventType, data } = event
657
+
658
+ switch (eventType) {
659
+ case 'message_start': {
660
+ // 开始接收新消息
661
+ setIsStreaming(true)
662
+
663
+ // 重置文本消息回调标记
664
+ textMessageCallbackTriggeredRef.current = false
665
+
666
+ // 重置文本缓冲区
667
+ textBufferRef.current = ''
668
+
669
+ // T039: 保存 sessionId(如果后端返回)
670
+ const messageStartData = data as MessageStartData
671
+ if (messageStartData.sessionId && messageStartData.sessionId !== sessionId) {
672
+ saveSession(messageStartData.sessionId)
673
+ }
674
+
675
+ // 检查最后一条消息是否是 thinking 消息(用户发送消息时已添加)
676
+ setMessagesState(prev => {
677
+ const lastMessage = prev[prev.length - 1]
678
+ const hasThinking =
679
+ lastMessage &&
680
+ lastMessage.role === 'assistant' &&
681
+ lastMessage.content.length === 1 &&
682
+ lastMessage.content[0].type === 'thinking'
683
+
684
+ if (hasThinking) {
685
+ // 复用已存在的 thinking 消息
686
+ currentMessageRef.current = lastMessage
687
+ return prev // 不需要添加新消息
688
+ } else {
689
+ // 没有 thinking 消息,创建新的(兼容其他场景)
690
+ const messageId = `msg-${Date.now()}`
691
+ currentMessageRef.current = {
692
+ id: messageId,
693
+ role: 'assistant',
694
+ content: [{ type: 'thinking', data: { status: 'thinking' } }],
695
+ timestamp: Date.now(),
696
+ }
697
+ return [...prev, currentMessageRef.current!]
698
+ }
699
+ })
700
+ break
701
+ }
702
+
703
+ case 'content_delta': {
704
+ // 累积流式文本内容,并实时检测产品占位符
705
+ const deltaData = data as any
706
+ const deltaText = deltaData.delta || deltaData.text || ''
707
+
708
+ if (currentMessageRef.current && deltaText) {
709
+ // 触发文本消息回调(仅触发一次)
710
+ if (!textMessageCallbackTriggeredRef.current) {
711
+ textMessageCallbackTriggeredRef.current = true
712
+ onTextMessage?.()
713
+ }
714
+
715
+ // 移除思考气泡(如果存在)
716
+ const hasThinking = currentMessageRef.current.content.some(c => c.type === 'thinking')
717
+ if (hasThinking) {
718
+ currentMessageRef.current.content = currentMessageRef.current.content.filter(c => c.type !== 'thinking')
719
+ }
720
+
721
+ // 将新文本添加到缓冲区
722
+ textBufferRef.current += deltaText
723
+
724
+ // 实时解析缓冲区中的占位符
725
+ const { contents, remainingBuffer } = parseStreamingText(
726
+ textBufferRef.current,
727
+ productMapRef.current,
728
+ rawProductMapRef.current,
729
+ onAddToCart,
730
+ productCardRender
731
+ )
732
+
733
+ // 更新缓冲区为剩余内容
734
+ textBufferRef.current = remainingBuffer
735
+
736
+ // 将解析出的内容添加到消息中
737
+ if (contents.length > 0) {
738
+ contents.forEach(content => {
739
+ const lastContent = currentMessageRef.current!.content[
740
+ currentMessageRef.current!.content.length - 1
741
+ ] as MessageContent | undefined
742
+
743
+ // 如果是文本内容且最后一个也是文本,则合并
744
+ if (content.type === 'text' && lastContent && lastContent.type === 'text') {
745
+ lastContent.text += content.text
746
+ } else {
747
+ // 否则添加新内容
748
+ currentMessageRef.current!.content.push(content)
749
+ }
750
+ })
751
+
752
+ // 更新消息列表以触发渲染
753
+ setMessagesState(prev => {
754
+ if (!currentMessageRef.current) return prev
755
+
756
+ const updated = [...prev]
757
+ const existingIndex = updated.findIndex(m => m && m.id === currentMessageRef.current!.id)
758
+
759
+ if (existingIndex >= 0) {
760
+ updated[existingIndex] = { ...currentMessageRef.current! }
761
+ } else {
762
+ updated.push({ ...currentMessageRef.current! })
763
+ }
764
+
765
+ return updated
766
+ })
767
+ }
768
+ }
769
+ break
770
+ }
771
+
772
+ case 'content_block': {
773
+ // 接收结构化内容块(商品、政策等)
774
+ // API 返回格式变更:
775
+ // 新格式: {index: number, type: string, data: {...}} <- type 在外层
776
+ // 旧格式: {index: number, data: {type: string, ...}} <- type 在 data 内
777
+ const blockData = data as any
778
+ if (currentMessageRef.current) {
779
+ // 获取 type 和 data
780
+ // 优先从外层获取 type,兼容旧格式从 data 内获取
781
+ const contentType = blockData.type || blockData.data?.type
782
+ const contentData = blockData.data
783
+
784
+ if (!contentType || !contentData) {
785
+ console.warn('[useChatState] Invalid content_block:', blockData)
786
+ break
787
+ }
788
+
789
+ // ============================================================
790
+ // 转换数据结构以匹配类型定义
791
+ // 根据后端数据结构规范(飞书文档)进行转换
792
+ // ============================================================
793
+ let messageContent: MessageContent
794
+
795
+ // ========== 1. 产品列表卡片 (Product List) ==========
796
+ // 后端格式: {type: "product_list", data: [product1, product2, ...]}
797
+ // data 直接是产品数组,不是 {products: [...]}
798
+ if (contentType === 'product_list' && Array.isArray(contentData)) {
799
+ // 触发商品列表回调
800
+ onProductList?.()
801
+
802
+ // 缓存原始后端产品数据(用于 productCardRender)
803
+ contentData.forEach((rawProduct: any) => {
804
+ if (rawProduct && rawProduct.shopify_product_id) {
805
+ const shopifyId = rawProduct.shopify_product_id
806
+ // 1. 使用完整的 shopifyId 作为key
807
+ rawProductMapRef.current.set(shopifyId, rawProduct)
808
+
809
+ // 2. 同时提取数字部分作为key
810
+ const numericId = shopifyId.match(/\d+$/)?.[0]
811
+ if (numericId) {
812
+ rawProductMapRef.current.set(numericId, rawProduct)
813
+ }
814
+ }
815
+ })
816
+
817
+ // 使用统一的产品转换工具函数
818
+ const transformedProducts = transformProducts(contentData, site)
819
+
820
+ // 建立产品映射缓存 (shopifyId → Product)
821
+ // 用于后续在 message_end 时解析文本中的 {{shopifyId}}
822
+ transformedProducts.forEach(product => {
823
+ if (product && product.shopifyId) {
824
+ // 1. 使用完整的 shopifyId 作为key(如 "gid://shopify/Product/123")
825
+ productMapRef.current.set(product.shopifyId, product)
826
+
827
+ // 2. 同时提取数字部分作为key(如 "123"),支持简写格式
828
+ // 从 "gid://shopify/Product/123" 或 "123" 中提取纯数字
829
+ const numericId = product.shopifyId.match(/\d+$/)?.[0]
830
+ if (numericId) {
831
+ productMapRef.current.set(numericId, product)
832
+ }
833
+
834
+ console.log('[useChatState] 建立产品映射:', {
835
+ fullId: product.shopifyId,
836
+ numericId,
837
+ title: product.title,
838
+ })
839
+ }
840
+ })
841
+
842
+ // ⚠️ 不要把 product_list 添加到消息中,避免闪烁
843
+ // 等到 message_end 时,通过文本解析创建 product_card,直接显示最终的交替格式
844
+ console.log('[useChatState] ✅ 产品列表已缓存,不添加到消息中(避免闪烁)')
845
+ break // 直接跳出,不执行后续的 push 操作
846
+ }
847
+ // ========== 2. 产品对比卡片 (Product Comparison) ==========
848
+ // 后端格式: {type: "product_comparison", data: {products: [...], dimensions: {...}}}
849
+ else if (contentType === 'product_comparison' && contentData.products) {
850
+ // 使用统一的产品转换工具函数
851
+ const transformedProducts = transformProducts(contentData.products, site)
852
+
853
+ messageContent = {
854
+ type: 'product_comparison',
855
+ data: {
856
+ products: transformedProducts,
857
+ dimensions: contentData.dimensions || {},
858
+ },
859
+ } as MessageContent
860
+ }
861
+ // ========== 3. FAQ 列表卡片 (FAQ List) ==========
862
+ // 后端格式: {type: "faq_list", data: {found, count, total, results: [...]}}
863
+ else if (contentType === 'faq_list' && contentData.found !== undefined) {
864
+ messageContent = {
865
+ type: 'faq_list',
866
+ data: contentData, // 直接使用,结构已匹配
867
+ } as MessageContent
868
+ }
869
+ // ========== 4. 快捷回复 (Quick Replies) ==========
870
+ else if (contentType === 'quick_replies' && contentData.replies) {
871
+ messageContent = {
872
+ type: 'quick_replies',
873
+ data: {
874
+ replies: contentData.replies,
875
+ },
876
+ } as MessageContent
877
+ }
878
+ // ========== 5. 政策内容 (Policy) ==========
879
+ else if (contentType === 'policy' && contentData.title && contentData.content) {
880
+ messageContent = {
881
+ type: 'policy',
882
+ data: {
883
+ title: contentData.title,
884
+ content: contentData.content,
885
+ },
886
+ } as MessageContent
887
+ }
888
+ // ========== 6. 促销活动列表 (Promotion List) ==========
889
+ // 后端格式: {type: "promotion_list", data: {found, count, total, results: [...]}}
890
+ else if (contentType === 'promotion_list' && contentData.found !== undefined) {
891
+ // 触发促销卡片回调
892
+ onPromotionList?.()
893
+
894
+ messageContent = {
895
+ type: 'promotion_list',
896
+ data: contentData, // 直接使用,结构已匹配
897
+ } as MessageContent
898
+ }
899
+ // ========== 7. 购物车 (Cart) ==========
900
+ // 后端格式: {type: "cart", data: {id, lines: {edges: [...]}, cost, ...}} (Shopify GraphQL)
901
+ // 需要转换为前端格式: {cartId, lines: [...], cost, ...}
902
+ else if (contentType === 'cart' && contentData.id !== undefined) {
903
+ // 转换后端 Shopify GraphQL 格式为前端标准格式
904
+ const transformedData = transformCartData(contentData as BackendCartData)
905
+ messageContent = {
906
+ type: 'cart',
907
+ data: {
908
+ ...transformedData,
909
+ onCart: onCart, // 注入购物车按钮回调
910
+ },
911
+ } as MessageContent
912
+ }
913
+ // ========== 8. 其他类型(通用处理) ==========
914
+ else {
915
+ messageContent = {
916
+ type: contentType,
917
+ data: contentData,
918
+ } as MessageContent
919
+ }
920
+
921
+ currentMessageRef.current.content.push(messageContent)
922
+
923
+ setMessagesState(prev => {
924
+ if (!currentMessageRef.current) return prev
925
+
926
+ const updated = [...prev]
927
+ const existingIndex = updated.findIndex(m => m && m.id === currentMessageRef.current!.id)
928
+
929
+ if (existingIndex >= 0) {
930
+ updated[existingIndex] = { ...currentMessageRef.current! }
931
+ } else {
932
+ updated.push({ ...currentMessageRef.current! })
933
+ }
934
+
935
+ return updated
936
+ })
937
+ }
938
+ break
939
+ }
940
+
941
+ case 'tool_start':
942
+ case 'tool_end': {
943
+ // 工具调用事件,暂时忽略
944
+ // 可以在未来用于显示工具调用状态
945
+ break
946
+ }
947
+
948
+ case 'message_end': {
949
+ // 消息接收完成
950
+ setIsStreaming(false)
951
+
952
+ // 处理缓冲区中剩余的文本(如果有)
953
+ if (currentMessageRef.current && textBufferRef.current) {
954
+ console.log('[useChatState] 处理剩余缓冲区:', textBufferRef.current)
955
+
956
+ const lastContent = currentMessageRef.current.content[
957
+ currentMessageRef.current.content.length - 1
958
+ ] as MessageContent | undefined
959
+
960
+ // 如果最后一个内容是文本,则合并
961
+ if (lastContent && lastContent.type === 'text') {
962
+ lastContent.text += textBufferRef.current
963
+ } else {
964
+ // 否则添加为新的文本块
965
+ currentMessageRef.current.content.push({
966
+ type: 'text',
967
+ text: textBufferRef.current,
968
+ })
969
+ }
970
+
971
+ // 更新消息列表
972
+ setMessagesState(prev => {
973
+ if (!currentMessageRef.current) return prev
974
+
975
+ const updated = [...prev]
976
+ const existingIndex = updated.findIndex(m => m && m.id === currentMessageRef.current!.id)
977
+
978
+ if (existingIndex >= 0) {
979
+ updated[existingIndex] = { ...currentMessageRef.current! }
980
+ }
981
+
982
+ return updated
983
+ })
984
+ }
985
+
986
+ // 清空缓冲区和产品映射
987
+ textBufferRef.current = ''
988
+ productMapRef.current.clear()
989
+ rawProductMapRef.current.clear()
990
+ currentMessageRef.current = null
991
+ break
992
+ }
993
+
994
+ case 'status': {
995
+ // T040: 状态更新(如会话过期)
996
+ const statusData = data as StatusData
997
+ if (statusData.type === 'session_expired') {
998
+ // 会话过期,清空消息列表和会话
999
+ clearMessages()
1000
+ clearSession()
1001
+ if (welcomeMessage) {
1002
+ addMessage({
1003
+ id: `welcome-${Date.now()}`,
1004
+ role: 'assistant',
1005
+ content: [{ type: 'text', text: welcomeMessage }],
1006
+ timestamp: Date.now(),
1007
+ })
1008
+ }
1009
+ }
1010
+ break
1011
+ }
1012
+
1013
+ case 'error': {
1014
+ // 错误处理
1015
+ const errorData = data as ErrorData
1016
+ setIsStreaming(false)
1017
+ currentMessageRef.current = null
1018
+
1019
+ // 添加错误消息到界面
1020
+ addMessage({
1021
+ id: `error-${Date.now()}`,
1022
+ role: 'system',
1023
+ content: [
1024
+ {
1025
+ type: 'error',
1026
+ data: {
1027
+ message: errorData.message,
1028
+ code: errorData.code,
1029
+ },
1030
+ },
1031
+ ],
1032
+ timestamp: Date.now(),
1033
+ })
1034
+
1035
+ onError?.(new Error(errorData.message))
1036
+ break
1037
+ }
1038
+
1039
+ case 'done': {
1040
+ // 流结束
1041
+ setIsStreaming(false)
1042
+ currentMessageRef.current = null
1043
+ break
1044
+ }
1045
+
1046
+ default:
1047
+ // 其他事件类型(tool_start, tool_end 等)
1048
+ break
1049
+ }
1050
+ },
1051
+ [
1052
+ welcomeMessage,
1053
+ site,
1054
+ addMessage,
1055
+ clearMessages,
1056
+ clearSession,
1057
+ saveSession,
1058
+ sessionId,
1059
+ onError,
1060
+ onTextMessage,
1061
+ onProductList,
1062
+ onPromotionList,
1063
+ onAddToCart,
1064
+ onCart,
1065
+ ]
1066
+ )
1067
+
1068
+ return {
1069
+ messages,
1070
+ isOpen,
1071
+ userId,
1072
+ sessionId,
1073
+ inputValue,
1074
+ isStreaming,
1075
+ openChat,
1076
+ closeChat,
1077
+ toggleChat,
1078
+ setInputValue,
1079
+ addMessage,
1080
+ setMessages,
1081
+ clearMessages,
1082
+ handleSSEEvent,
1083
+ saveSession,
1084
+ clearSession,
1085
+ }
1086
+ }