@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/components/LiveChatWidget/components/MessageContent/FAQList.tsx"],
4
- "sourcesContent": ["/**\n * FAQ \u5217\u8868\u7EC4\u4EF6\n * \u663E\u793A\u5E38\u89C1\u95EE\u9898\u5217\u8868\uFF0C\u652F\u6301\u6298\u53E0/\u5C55\u5F00\n */\n\nimport React, { useState } from 'react'\nimport ReactMarkdown from 'react-markdown'\nimport type { FAQListContent, FAQItem, MessageRenderer, MessageContent } from '../../types'\n\nexport interface FAQListProps {\n content: FAQListContent\n onQuestionClick?: (question: string) => void\n}\n\n/**\n * FAQ \u5217\u8868\u6E32\u67D3\u5668\n * \u7528\u4E8E\u6CE8\u518C\u5230 MessageRendererRegistry\n */\nexport const FAQListRenderer: MessageRenderer = {\n render: (content: MessageContent) => {\n if (content.type !== 'faq_list') {\n return null\n }\n return <FAQList content={content as FAQListContent} />\n },\n}\n\nexport const FAQList: React.FC<FAQListProps> = ({ content, onQuestionClick }) => {\n const { found, count, total, results } = content.data\n const [expandedIds, setExpandedIds] = useState<Set<string>>(new Set())\n\n // \u5982\u679C\u6CA1\u6709\u627E\u5230\u7ED3\u679C\n if (!found || results.length === 0) {\n return (\n <div className=\"rounded-lg border border-gray-200 bg-white p-4\">\n <p className=\"text-sm text-gray-500\">\u672A\u627E\u5230\u76F8\u5173\u95EE\u9898</p>\n </div>\n )\n }\n\n // \u5207\u6362\u5C55\u5F00/\u6298\u53E0\n const toggleExpand = (id: string) => {\n setExpandedIds(prev => {\n const newSet = new Set(prev)\n if (newSet.has(id)) {\n newSet.delete(id)\n } else {\n newSet.add(id)\n }\n return newSet\n })\n }\n\n // \u5904\u7406\u76F8\u5173\u95EE\u9898\u70B9\u51FB\n const handleRelatedQuestionClick = (question: string) => {\n onQuestionClick?.(question)\n }\n\n return (\n <div className=\"space-y-2\">\n {/* FAQ \u5217\u8868 */}\n <div className=\"space-y-2\">\n {results.map(item => {\n const isExpanded = expandedIds.has(item.id)\n\n return (\n <div key={item.id} className=\"overflow-hidden rounded-2xl bg-[#F5F6F7] transition-all\">\n {/* \u95EE\u9898\u6807\u9898 - \u53EF\u70B9\u51FB\u5C55\u5F00/\u6298\u53E0 */}\n <button\n onClick={() => toggleExpand(item.id)}\n className=\"flex w-full items-center justify-between gap-3 p-4 text-left transition-colors \"\n >\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]\">\n {item.question}\n </span>\n </div>\n </div>\n\n {/* \u5C55\u5F00/\u6298\u53E0\u56FE\u6807 */}\n <svg\n className={`size-5 shrink-0 text-[#080A0F] transition-transform ${isExpanded ? 'rotate-180' : ''}`}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n </button>\n\n {/* \u7B54\u6848\u5185\u5BB9 - \u5C55\u5F00\u65F6\u663E\u793A */}\n {isExpanded && (\n <div className=\" bg-[#F5F6F7] px-4 py-3 pt-0\">\n <div\n className=\"prose prose-sm max-w-none border-t border-gray-100 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#4A4C56]\"\n style={{ paddingTop: '12px' }}\n >\n <ReactMarkdown>{item.answer}</ReactMarkdown>\n </div>\n\n {/* \u76F8\u5173\u95EE\u9898 */}\n {item.relatedQuestions && item.relatedQuestions.length > 0 && (\n <div className=\"mt-4 border-t border-gray-200 pt-3\">\n <p className=\"mb-2 text-xs font-medium text-gray-500\">\u60A8\u53EF\u80FD\u8FD8\u60F3\u4E86\u89E3\uFF1A</p>\n <div className=\"space-y-1\">\n {item.relatedQuestions.map((q, idx) => (\n <button\n key={idx}\n onClick={() => handleRelatedQuestionClick(q)}\n className=\"block w-full text-left text-xs text-blue-600 hover:text-blue-700 hover:underline\"\n >\n {q}\n </button>\n ))}\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n )\n })}\n </div>\n </div>\n )\n}\n"],
5
- "mappings": "AAuBW,cAAAA,EA6CG,QAAAC,MA7CH,oBAlBX,OAAgB,YAAAC,MAAgB,QAChC,OAAOC,MAAmB,iBAYnB,MAAMC,EAAmC,CAC9C,OAASC,GACHA,EAAQ,OAAS,WACZ,KAEFL,EAACM,EAAA,CAAQ,QAASD,EAA2B,CAExD,EAEaC,EAAkC,CAAC,CAAE,QAAAD,EAAS,gBAAAE,CAAgB,IAAM,CAC/E,KAAM,CAAE,MAAAC,EAAO,MAAAC,EAAO,MAAAC,EAAO,QAAAC,CAAQ,EAAIN,EAAQ,KAC3C,CAACO,EAAaC,CAAc,EAAIX,EAAsB,IAAI,GAAK,EAGrE,GAAI,CAACM,GAASG,EAAQ,SAAW,EAC/B,OACEX,EAAC,OAAI,UAAU,iDACb,SAAAA,EAAC,KAAE,UAAU,wBAAwB,sDAAO,EAC9C,EAKJ,MAAMc,EAAgBC,GAAe,CACnCF,EAAeG,GAAQ,CACrB,MAAMC,EAAS,IAAI,IAAID,CAAI,EAC3B,OAAIC,EAAO,IAAIF,CAAE,EACfE,EAAO,OAAOF,CAAE,EAEhBE,EAAO,IAAIF,CAAE,EAERE,CACT,CAAC,CACH,EAGMC,EAA8BC,GAAqB,CACvDZ,IAAkBY,CAAQ,CAC5B,EAEA,OACEnB,EAAC,OAAI,UAAU,YAEb,SAAAA,EAAC,OAAI,UAAU,YACZ,SAAAW,EAAQ,IAAIS,GAAQ,CACnB,MAAMC,EAAaT,EAAY,IAAIQ,EAAK,EAAE,EAE1C,OACEnB,EAAC,OAAkB,UAAU,2DAE3B,UAAAA,EAAC,UACC,QAAS,IAAMa,EAAaM,EAAK,EAAE,EACnC,UAAU,kFAEV,UAAApB,EAAC,OAAI,UAAU,SACb,SAAAA,EAAC,OAAI,UAAU,0BACb,SAAAA,EAAC,QAAK,UAAU,oEACb,SAAAoB,EAAK,SACR,EACF,EACF,EAGApB,EAAC,OACC,UAAW,uDAAuDqB,EAAa,aAAe,EAAE,GAChG,KAAK,OACL,QAAQ,YACR,OAAO,eAEP,SAAArB,EAAC,QAAK,cAAc,QAAQ,eAAe,QAAQ,YAAa,EAAG,EAAE,iBAAiB,EACxF,GACF,EAGCqB,GACCpB,EAAC,OAAI,UAAU,+BACb,UAAAD,EAAC,OACC,UAAU,wHACV,MAAO,CAAE,WAAY,MAAO,EAE5B,SAAAA,EAACG,EAAA,CAAe,SAAAiB,EAAK,OAAO,EAC9B,EAGCA,EAAK,kBAAoBA,EAAK,iBAAiB,OAAS,GACvDnB,EAAC,OAAI,UAAU,qCACb,UAAAD,EAAC,KAAE,UAAU,yCAAyC,4DAAQ,EAC9DA,EAAC,OAAI,UAAU,YACZ,SAAAoB,EAAK,iBAAiB,IAAI,CAACE,EAAGC,IAC7BvB,EAAC,UAEC,QAAS,IAAMkB,EAA2BI,CAAC,EAC3C,UAAU,mFAET,SAAAA,GAJIC,CAKP,CACD,EACH,GACF,GAEJ,IApDMH,EAAK,EAsDf,CAEJ,CAAC,EACH,EACF,CAEJ",
6
- "names": ["jsx", "jsxs", "useState", "ReactMarkdown", "FAQListRenderer", "content", "FAQList", "onQuestionClick", "found", "count", "total", "results", "expandedIds", "setExpandedIds", "toggleExpand", "id", "prev", "newSet", "handleRelatedQuestionClick", "question", "item", "isExpanded", "q", "idx"]
4
+ "sourcesContent": ["/**\n * FAQ \u5217\u8868\u7EC4\u4EF6\n * \u663E\u793A\u5E38\u89C1\u95EE\u9898\u5217\u8868\uFF0C\u652F\u6301\u6298\u53E0/\u5C55\u5F00\n */\n\nimport React, { useState } from 'react'\nimport ReactMarkdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\nimport type { FAQListContent, FAQItem, MessageRenderer, MessageContent } from '../../types'\n\nexport interface FAQListProps {\n content: FAQListContent\n onQuestionClick?: (question: string) => void\n}\n\n/**\n * FAQ \u5217\u8868\u6E32\u67D3\u5668\n * \u7528\u4E8E\u6CE8\u518C\u5230 MessageRendererRegistry\n */\nexport const FAQListRenderer: MessageRenderer = {\n render: (content: MessageContent) => {\n if (content.type !== 'faq_list') {\n return null\n }\n return <FAQList content={content as FAQListContent} />\n },\n}\n\nexport const FAQList: React.FC<FAQListProps> = ({ content, onQuestionClick }) => {\n const { found, count, total, results } = content.data\n const [expandedIds, setExpandedIds] = useState<Set<string>>(new Set())\n\n // \u5982\u679C\u6CA1\u6709\u627E\u5230\u7ED3\u679C\n if (!found || results.length === 0) {\n return (\n <div className=\"rounded-lg border border-gray-200 bg-white p-4\">\n <p className=\"text-sm text-gray-500\">\u672A\u627E\u5230\u76F8\u5173\u95EE\u9898</p>\n </div>\n )\n }\n\n // \u5207\u6362\u5C55\u5F00/\u6298\u53E0\n const toggleExpand = (id: string) => {\n setExpandedIds(prev => {\n const newSet = new Set(prev)\n if (newSet.has(id)) {\n newSet.delete(id)\n } else {\n newSet.add(id)\n }\n return newSet\n })\n }\n\n // \u5904\u7406\u76F8\u5173\u95EE\u9898\u70B9\u51FB\n const handleRelatedQuestionClick = (question: string) => {\n onQuestionClick?.(question)\n }\n\n return (\n <div className=\"space-y-2\">\n {/* FAQ \u5217\u8868 */}\n <div className=\"space-y-2\">\n {results.map(item => {\n const isExpanded = expandedIds.has(item.id)\n\n return (\n <div key={item.id} className=\"overflow-hidden rounded-2xl bg-[#F5F6F7] transition-all\">\n {/* \u95EE\u9898\u6807\u9898 - \u53EF\u70B9\u51FB\u5C55\u5F00/\u6298\u53E0 */}\n <button\n onClick={() => toggleExpand(item.id)}\n className=\"flex w-full items-center justify-between gap-3 p-4 text-left transition-colors \"\n >\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]\">\n {item.question}\n </span>\n </div>\n </div>\n\n {/* \u5C55\u5F00/\u6298\u53E0\u56FE\u6807 */}\n <svg\n className={`size-5 shrink-0 text-[#080A0F] transition-transform ${isExpanded ? 'rotate-180' : ''}`}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n </button>\n\n {/* \u7B54\u6848\u5185\u5BB9 - \u5C55\u5F00\u65F6\u663E\u793A */}\n {isExpanded && (\n <div className=\" bg-[#F5F6F7] px-4 py-3 pt-0\">\n <div\n className=\"prose prose-sm max-w-none border-t border-gray-100 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#4A4C56]\"\n style={{ paddingTop: '12px' }}\n >\n <ReactMarkdown remarkPlugins={[remarkGfm]}>{item.answer}</ReactMarkdown>\n </div>\n\n {/* \u76F8\u5173\u95EE\u9898 */}\n {item.relatedQuestions && item.relatedQuestions.length > 0 && (\n <div className=\"mt-4 border-t border-gray-200 pt-3\">\n <p className=\"mb-2 text-xs font-medium text-gray-500\">You may also want to know:</p>\n <div className=\"space-y-1\">\n {item.relatedQuestions.map((q, idx) => (\n <button\n key={idx}\n onClick={() => handleRelatedQuestionClick(q)}\n className=\"block w-full text-left text-xs text-blue-600 hover:text-blue-700 hover:underline\"\n >\n {q}\n </button>\n ))}\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n )\n })}\n </div>\n </div>\n )\n}\n"],
5
+ "mappings": "AAwBW,cAAAA,EA6CG,QAAAC,MA7CH,oBAnBX,OAAgB,YAAAC,MAAgB,QAChC,OAAOC,MAAmB,iBAC1B,OAAOC,MAAe,aAYf,MAAMC,EAAmC,CAC9C,OAASC,GACHA,EAAQ,OAAS,WACZ,KAEFN,EAACO,EAAA,CAAQ,QAASD,EAA2B,CAExD,EAEaC,EAAkC,CAAC,CAAE,QAAAD,EAAS,gBAAAE,CAAgB,IAAM,CAC/E,KAAM,CAAE,MAAAC,EAAO,MAAAC,EAAO,MAAAC,EAAO,QAAAC,CAAQ,EAAIN,EAAQ,KAC3C,CAACO,EAAaC,CAAc,EAAIZ,EAAsB,IAAI,GAAK,EAGrE,GAAI,CAACO,GAASG,EAAQ,SAAW,EAC/B,OACEZ,EAAC,OAAI,UAAU,iDACb,SAAAA,EAAC,KAAE,UAAU,wBAAwB,sDAAO,EAC9C,EAKJ,MAAMe,EAAgBC,GAAe,CACnCF,EAAeG,GAAQ,CACrB,MAAMC,EAAS,IAAI,IAAID,CAAI,EAC3B,OAAIC,EAAO,IAAIF,CAAE,EACfE,EAAO,OAAOF,CAAE,EAEhBE,EAAO,IAAIF,CAAE,EAERE,CACT,CAAC,CACH,EAGMC,EAA8BC,GAAqB,CACvDZ,IAAkBY,CAAQ,CAC5B,EAEA,OACEpB,EAAC,OAAI,UAAU,YAEb,SAAAA,EAAC,OAAI,UAAU,YACZ,SAAAY,EAAQ,IAAIS,GAAQ,CACnB,MAAMC,EAAaT,EAAY,IAAIQ,EAAK,EAAE,EAE1C,OACEpB,EAAC,OAAkB,UAAU,2DAE3B,UAAAA,EAAC,UACC,QAAS,IAAMc,EAAaM,EAAK,EAAE,EACnC,UAAU,kFAEV,UAAArB,EAAC,OAAI,UAAU,SACb,SAAAA,EAAC,OAAI,UAAU,0BACb,SAAAA,EAAC,QAAK,UAAU,sEACb,SAAAqB,EAAK,SACR,EACF,EACF,EAGArB,EAAC,OACC,UAAW,uDAAuDsB,EAAa,aAAe,EAAE,GAChG,KAAK,OACL,QAAQ,YACR,OAAO,eAEP,SAAAtB,EAAC,QAAK,cAAc,QAAQ,eAAe,QAAQ,YAAa,EAAG,EAAE,iBAAiB,EACxF,GACF,EAGCsB,GACCrB,EAAC,OAAI,UAAU,+BACb,UAAAD,EAAC,OACC,UAAU,wHACV,MAAO,CAAE,WAAY,MAAO,EAE5B,SAAAA,EAACG,EAAA,CAAc,cAAe,CAACC,CAAS,EAAI,SAAAiB,EAAK,OAAO,EAC1D,EAGCA,EAAK,kBAAoBA,EAAK,iBAAiB,OAAS,GACvDpB,EAAC,OAAI,UAAU,qCACb,UAAAD,EAAC,KAAE,UAAU,yCAAyC,sCAA0B,EAChFA,EAAC,OAAI,UAAU,YACZ,SAAAqB,EAAK,iBAAiB,IAAI,CAACE,EAAGC,IAC7BxB,EAAC,UAEC,QAAS,IAAMmB,EAA2BI,CAAC,EAC3C,UAAU,mFAET,SAAAA,GAJIC,CAKP,CACD,EACH,GACF,GAEJ,IApDMH,EAAK,EAsDf,CAEJ,CAAC,EACH,EACF,CAEJ",
6
+ "names": ["jsx", "jsxs", "useState", "ReactMarkdown", "remarkGfm", "FAQListRenderer", "content", "FAQList", "onQuestionClick", "found", "count", "total", "results", "expandedIds", "setExpandedIds", "toggleExpand", "id", "prev", "newSet", "handleRelatedQuestionClick", "question", "item", "isExpanded", "q", "idx"]
7
7
  }
@@ -1,5 +1,5 @@
1
- import{jsx as e,jsxs as s}from"react/jsx-runtime";import{useState as c}from"react";import m from"react-markdown";const g={render:(a,d,l)=>{const n=a,{title:i,content:r}=n.data;if(!i||!r)return null;const o=r.length>200;return e(p,{title:i,content:r,isLong:o})}},p=({title:a,content:d,isLong:l})=>{const[n,i]=c(!l);return s("div",{className:"overflow-hidden rounded-lg border border-blue-200 bg-blue-50",children:[s("div",{className:"flex items-center gap-2 border-b border-blue-200 bg-blue-100 px-3 py-2",children:[s("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"shrink-0 text-blue-700",children:[e("path",{d:"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"}),e("polyline",{points:"14 2 14 8 20 8"}),e("line",{x1:"16",y1:"13",x2:"8",y2:"13"}),e("line",{x1:"16",y1:"17",x2:"8",y2:"17"}),e("polyline",{points:"10 9 9 9 8 9"})]}),e("h3",{className:"text-sm font-semibold text-blue-900",children:a})]}),s("div",{className:"px-3 py-2",children:[e("div",{className:`
1
+ import{jsx as e,jsxs as s}from"react/jsx-runtime";import{useState as c}from"react";import m from"react-markdown";import p from"remark-gfm";const v={render:(a,d,l)=>{const n=a,{title:i,content:r}=n.data;if(!i||!r)return null;const o=r.length>200;return e(b,{title:i,content:r,isLong:o})}},b=({title:a,content:d,isLong:l})=>{const[n,i]=c(!l);return s("div",{className:"overflow-hidden rounded-lg border border-blue-200 bg-blue-50",children:[s("div",{className:"flex items-center gap-2 border-b border-blue-200 bg-blue-100 px-3 py-2",children:[s("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"shrink-0 text-blue-700",children:[e("path",{d:"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"}),e("polyline",{points:"14 2 14 8 20 8"}),e("line",{x1:"16",y1:"13",x2:"8",y2:"13"}),e("line",{x1:"16",y1:"17",x2:"8",y2:"17"}),e("polyline",{points:"10 9 9 9 8 9"})]}),e("h3",{className:"text-sm font-semibold text-blue-900",children:a})]}),s("div",{className:"px-3 py-2",children:[e("div",{className:`
2
2
  text-sm leading-relaxed text-blue-900
3
3
  ${!n&&l?"line-clamp-3":""}
4
- `,children:e(m,{components:{p:({node:o,...t})=>e("p",{...t,className:"mb-2 last:mb-0"}),ul:({node:o,...t})=>e("ul",{...t,className:"mb-2 ml-4 list-disc"}),ol:({node:o,...t})=>e("ol",{...t,className:"mb-2 ml-4 list-decimal"}),li:({node:o,...t})=>e("li",{...t,className:"mb-1"}),strong:({node:o,...t})=>e("strong",{...t,className:"font-semibold"})},children:d})}),l&&s("button",{type:"button",onClick:()=>{i(o=>!o)},className:"mt-2 flex items-center gap-1 text-xs font-medium text-blue-700 hover:text-blue-800",children:[e("span",{children:n?"\u6536\u8D77":"\u5C55\u5F00"}),e("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:`transition-transform ${n?"rotate-180":""}`,children:e("polyline",{points:"6 9 12 15 18 9"})})]})]})]})};export{g as PolicyBlock};
4
+ `,children:e(m,{remarkPlugins:[p],components:{p:({node:o,...t})=>e("p",{...t,className:"mb-2 last:mb-0"}),ul:({node:o,...t})=>e("ul",{...t,className:"mb-2 ml-4 list-disc"}),ol:({node:o,...t})=>e("ol",{...t,className:"mb-2 ml-4 list-decimal"}),li:({node:o,...t})=>e("li",{...t,className:"mb-1"}),strong:({node:o,...t})=>e("strong",{...t,className:"font-bold"})},children:d})}),l&&s("button",{type:"button",onClick:()=>{i(o=>!o)},className:"mt-2 flex items-center gap-1 text-xs font-medium text-blue-700 hover:text-blue-800",children:[e("span",{children:n?"\u6536\u8D77":"\u5C55\u5F00"}),e("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:`transition-transform ${n?"rotate-180":""}`,children:e("polyline",{points:"6 9 12 15 18 9"})})]})]})]})};export{v as PolicyBlock};
5
5
  //# sourceMappingURL=PolicyBlock.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/components/LiveChatWidget/components/MessageContent/PolicyBlock.tsx"],
4
- "sourcesContent": ["/**\n * \u653F\u7B56\u8BF4\u660E\u6E32\u67D3\u5668\n * \u663E\u793A\u9000\u8D27\u3001\u4FDD\u4FEE\u7B49\u653F\u7B56\u4FE1\u606F\n * \u57FA\u4E8E specs/livechat-widget/data-model.md \u7684\u653F\u7B56\u6570\u636E\u6A21\u578B\n */\n\nimport React, { useState } from 'react'\nimport ReactMarkdown from 'react-markdown'\nimport type { MessageRenderer, PolicyContent } from '../../types'\n\n/**\n * \u653F\u7B56\u8BF4\u660E\u6E32\u67D3\u5668\n *\n * \u529F\u80FD\uFF1A\n * - \u663E\u793A\u653F\u7B56\u6807\u9898\u548C\u5185\u5BB9\n * - \u652F\u6301 Markdown \u683C\u5F0F\n * - \u53EF\u6298\u53E0/\u5C55\u5F00\uFF08\u5185\u5BB9\u8F83\u957F\u65F6\uFF09\n *\n * \u653F\u7B56\u7C7B\u578B\uFF1A\n * - \u9000\u8D27\u653F\u7B56\n * - \u4FDD\u4FEE\u653F\u7B56\n * - \u8FD0\u8D39\u653F\u7B56\n * - \u9690\u79C1\u653F\u7B56\n *\n * \u5E03\u5C40\uFF1A\n * ```\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 \uD83D\uDCCB \u653F\u7B56\u6807\u9898 \u2502\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 \u653F\u7B56\u5185\u5BB9... \u2502\n * \u2502 (\u652F\u6301 Markdown) \u2502\n * \u2502 \u2502\n * \u2502 [\u5C55\u5F00/\u6536\u8D77] \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * ```\n *\n * @example\n * ```tsx\n * const content: PolicyContent = {\n * type: 'policy',\n * data: {\n * title: '\u9000\u8D27\u653F\u7B56',\n * content: '\u6211\u4EEC\u63D0\u4F9B 30 \u5929\u65E0\u7406\u7531\u9000\u8D27...'\n * }\n * }\n * <PolicyBlock.render(content, false, false) />\n * ```\n */\nexport const PolicyBlock: MessageRenderer = {\n render: (content, isUser, isSystem) => {\n const policyContent = content as PolicyContent\n const { title, content: policyText } = policyContent.data\n\n if (!title || !policyText) {\n return null\n }\n\n // \u5224\u65AD\u5185\u5BB9\u662F\u5426\u8F83\u957F\uFF08\u8D85\u8FC7 200 \u5B57\u7B26\uFF09\n const isLongContent = policyText.length > 200\n\n return <PolicyCard title={title} content={policyText} isLong={isLongContent} />\n },\n}\n\n/**\n * \u653F\u7B56\u5361\u7247\u7EC4\u4EF6\uFF08\u652F\u6301\u6298\u53E0\uFF09\n */\nconst PolicyCard: React.FC<{\n title: string\n content: string\n isLong: boolean\n}> = ({ title, content, isLong }) => {\n const [isExpanded, setIsExpanded] = useState(!isLong)\n\n const toggleExpand = () => {\n setIsExpanded(prev => !prev)\n }\n\n return (\n <div className=\"overflow-hidden rounded-lg border border-blue-200 bg-blue-50\">\n {/* \u6807\u9898 */}\n <div className=\"flex items-center gap-2 border-b border-blue-200 bg-blue-100 px-3 py-2\">\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 className=\"shrink-0 text-blue-700\"\n >\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n <line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\" />\n <line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\" />\n <polyline points=\"10 9 9 9 8 9\" />\n </svg>\n <h3 className=\"text-sm font-semibold text-blue-900\">{title}</h3>\n </div>\n\n {/* \u5185\u5BB9 */}\n <div className=\"px-3 py-2\">\n <div\n className={`\n text-sm leading-relaxed text-blue-900\n ${!isExpanded && isLong ? 'line-clamp-3' : ''}\n `}\n >\n <ReactMarkdown\n components={{\n p: ({ node, ...props }) => <p {...props} className=\"mb-2 last:mb-0\" />,\n ul: ({ node, ...props }) => <ul {...props} className=\"mb-2 ml-4 list-disc\" />,\n ol: ({ node, ...props }) => <ol {...props} className=\"mb-2 ml-4 list-decimal\" />,\n li: ({ node, ...props }) => <li {...props} className=\"mb-1\" />,\n strong: ({ node, ...props }) => <strong {...props} className=\"font-semibold\" />,\n }}\n >\n {content}\n </ReactMarkdown>\n </div>\n\n {/* \u5C55\u5F00/\u6536\u8D77\u6309\u94AE\uFF08\u4EC5\u957F\u5185\u5BB9\u663E\u793A\uFF09 */}\n {isLong && (\n <button\n type=\"button\"\n onClick={toggleExpand}\n className=\"mt-2 flex items-center gap-1 text-xs font-medium text-blue-700 hover:text-blue-800\"\n >\n <span>{isExpanded ? '\u6536\u8D77' : '\u5C55\u5F00'}</span>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={`transition-transform ${isExpanded ? 'rotate-180' : ''}`}\n >\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </button>\n )}\n </div>\n </div>\n )\n}\n"],
5
- "mappings": "AA4DW,cAAAA,EAsBH,QAAAC,MAtBG,oBAtDX,OAAgB,YAAAC,MAAgB,QAChC,OAAOC,MAAmB,iBAyCnB,MAAMC,EAA+B,CAC1C,OAAQ,CAACC,EAASC,EAAQC,IAAa,CACrC,MAAMC,EAAgBH,EAChB,CAAE,MAAAI,EAAO,QAASC,CAAW,EAAIF,EAAc,KAErD,GAAI,CAACC,GAAS,CAACC,EACb,OAAO,KAIT,MAAMC,EAAgBD,EAAW,OAAS,IAE1C,OAAOV,EAACY,EAAA,CAAW,MAAOH,EAAO,QAASC,EAAY,OAAQC,EAAe,CAC/E,CACF,EAKMC,EAID,CAAC,CAAE,MAAAH,EAAO,QAAAJ,EAAS,OAAAQ,CAAO,IAAM,CACnC,KAAM,CAACC,EAAYC,CAAa,EAAIb,EAAS,CAACW,CAAM,EAMpD,OACEZ,EAAC,OAAI,UAAU,+DAEb,UAAAA,EAAC,OAAI,UAAU,yEACb,UAAAA,EAAC,OACC,MAAM,KACN,OAAO,KACP,QAAQ,YACR,KAAK,OACL,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QACf,UAAU,yBAEV,UAAAD,EAAC,QAAK,EAAE,6DAA6D,EACrEA,EAAC,YAAS,OAAO,iBAAiB,EAClCA,EAAC,QAAK,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,EACrCA,EAAC,QAAK,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,EACrCA,EAAC,YAAS,OAAO,eAAe,GAClC,EACAA,EAAC,MAAG,UAAU,sCAAuC,SAAAS,EAAM,GAC7D,EAGAR,EAAC,OAAI,UAAU,YACb,UAAAD,EAAC,OACC,UAAW;AAAA;AAAA,cAEP,CAACc,GAAcD,EAAS,eAAiB,EAAE;AAAA,YAG/C,SAAAb,EAACG,EAAA,CACC,WAAY,CACV,EAAG,CAAC,CAAE,KAAAa,EAAM,GAAGC,CAAM,IAAMjB,EAAC,KAAG,GAAGiB,EAAO,UAAU,iBAAiB,EACpE,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMjB,EAAC,MAAI,GAAGiB,EAAO,UAAU,sBAAsB,EAC3E,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMjB,EAAC,MAAI,GAAGiB,EAAO,UAAU,yBAAyB,EAC9E,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMjB,EAAC,MAAI,GAAGiB,EAAO,UAAU,OAAO,EAC5D,OAAQ,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMjB,EAAC,UAAQ,GAAGiB,EAAO,UAAU,gBAAgB,CAC/E,EAEC,SAAAZ,EACH,EACF,EAGCQ,GACCZ,EAAC,UACC,KAAK,SACL,QArDW,IAAM,CACzBc,EAAcG,GAAQ,CAACA,CAAI,CAC7B,EAoDU,UAAU,qFAEV,UAAAlB,EAAC,QAAM,SAAAc,EAAa,eAAO,eAAK,EAChCd,EAAC,OACC,MAAM,KACN,OAAO,KACP,QAAQ,YACR,KAAK,OACL,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QACf,UAAW,wBAAwBc,EAAa,aAAe,EAAE,GAEjE,SAAAd,EAAC,YAAS,OAAO,iBAAiB,EACpC,GACF,GAEJ,GACF,CAEJ",
6
- "names": ["jsx", "jsxs", "useState", "ReactMarkdown", "PolicyBlock", "content", "isUser", "isSystem", "policyContent", "title", "policyText", "isLongContent", "PolicyCard", "isLong", "isExpanded", "setIsExpanded", "node", "props", "prev"]
4
+ "sourcesContent": ["/**\n * \u653F\u7B56\u8BF4\u660E\u6E32\u67D3\u5668\n * \u663E\u793A\u9000\u8D27\u3001\u4FDD\u4FEE\u7B49\u653F\u7B56\u4FE1\u606F\n * \u57FA\u4E8E specs/livechat-widget/data-model.md \u7684\u653F\u7B56\u6570\u636E\u6A21\u578B\n */\n\nimport React, { useState } from 'react'\nimport ReactMarkdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\nimport type { MessageRenderer, PolicyContent } from '../../types'\n\n/**\n * \u653F\u7B56\u8BF4\u660E\u6E32\u67D3\u5668\n *\n * \u529F\u80FD\uFF1A\n * - \u663E\u793A\u653F\u7B56\u6807\u9898\u548C\u5185\u5BB9\n * - \u652F\u6301 Markdown \u683C\u5F0F\n * - \u53EF\u6298\u53E0/\u5C55\u5F00\uFF08\u5185\u5BB9\u8F83\u957F\u65F6\uFF09\n *\n * \u653F\u7B56\u7C7B\u578B\uFF1A\n * - \u9000\u8D27\u653F\u7B56\n * - \u4FDD\u4FEE\u653F\u7B56\n * - \u8FD0\u8D39\u653F\u7B56\n * - \u9690\u79C1\u653F\u7B56\n *\n * \u5E03\u5C40\uFF1A\n * ```\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 \uD83D\uDCCB \u653F\u7B56\u6807\u9898 \u2502\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 \u653F\u7B56\u5185\u5BB9... \u2502\n * \u2502 (\u652F\u6301 Markdown) \u2502\n * \u2502 \u2502\n * \u2502 [\u5C55\u5F00/\u6536\u8D77] \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * ```\n *\n * @example\n * ```tsx\n * const content: PolicyContent = {\n * type: 'policy',\n * data: {\n * title: '\u9000\u8D27\u653F\u7B56',\n * content: '\u6211\u4EEC\u63D0\u4F9B 30 \u5929\u65E0\u7406\u7531\u9000\u8D27...'\n * }\n * }\n * <PolicyBlock.render(content, false, false) />\n * ```\n */\nexport const PolicyBlock: MessageRenderer = {\n render: (content, isUser, isSystem) => {\n const policyContent = content as PolicyContent\n const { title, content: policyText } = policyContent.data\n\n if (!title || !policyText) {\n return null\n }\n\n // \u5224\u65AD\u5185\u5BB9\u662F\u5426\u8F83\u957F\uFF08\u8D85\u8FC7 200 \u5B57\u7B26\uFF09\n const isLongContent = policyText.length > 200\n\n return <PolicyCard title={title} content={policyText} isLong={isLongContent} />\n },\n}\n\n/**\n * \u653F\u7B56\u5361\u7247\u7EC4\u4EF6\uFF08\u652F\u6301\u6298\u53E0\uFF09\n */\nconst PolicyCard: React.FC<{\n title: string\n content: string\n isLong: boolean\n}> = ({ title, content, isLong }) => {\n const [isExpanded, setIsExpanded] = useState(!isLong)\n\n const toggleExpand = () => {\n setIsExpanded(prev => !prev)\n }\n\n return (\n <div className=\"overflow-hidden rounded-lg border border-blue-200 bg-blue-50\">\n {/* \u6807\u9898 */}\n <div className=\"flex items-center gap-2 border-b border-blue-200 bg-blue-100 px-3 py-2\">\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 className=\"shrink-0 text-blue-700\"\n >\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n <line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\" />\n <line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\" />\n <polyline points=\"10 9 9 9 8 9\" />\n </svg>\n <h3 className=\"text-sm font-semibold text-blue-900\">{title}</h3>\n </div>\n\n {/* \u5185\u5BB9 */}\n <div className=\"px-3 py-2\">\n <div\n className={`\n text-sm leading-relaxed text-blue-900\n ${!isExpanded && isLong ? 'line-clamp-3' : ''}\n `}\n >\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n components={{\n p: ({ node, ...props }) => <p {...props} className=\"mb-2 last:mb-0\" />,\n ul: ({ node, ...props }) => <ul {...props} className=\"mb-2 ml-4 list-disc\" />,\n ol: ({ node, ...props }) => <ol {...props} className=\"mb-2 ml-4 list-decimal\" />,\n li: ({ node, ...props }) => <li {...props} className=\"mb-1\" />,\n strong: ({ node, ...props }) => <strong {...props} className=\"font-bold\" />,\n }}\n >\n {content}\n </ReactMarkdown>\n </div>\n\n {/* \u5C55\u5F00/\u6536\u8D77\u6309\u94AE\uFF08\u4EC5\u957F\u5185\u5BB9\u663E\u793A\uFF09 */}\n {isLong && (\n <button\n type=\"button\"\n onClick={toggleExpand}\n className=\"mt-2 flex items-center gap-1 text-xs font-medium text-blue-700 hover:text-blue-800\"\n >\n <span>{isExpanded ? '\u6536\u8D77' : '\u5C55\u5F00'}</span>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={`transition-transform ${isExpanded ? 'rotate-180' : ''}`}\n >\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </button>\n )}\n </div>\n </div>\n )\n}\n"],
5
+ "mappings": "AA6DW,cAAAA,EAsBH,QAAAC,MAtBG,oBAvDX,OAAgB,YAAAC,MAAgB,QAChC,OAAOC,MAAmB,iBAC1B,OAAOC,MAAe,aAyCf,MAAMC,EAA+B,CAC1C,OAAQ,CAACC,EAASC,EAAQC,IAAa,CACrC,MAAMC,EAAgBH,EAChB,CAAE,MAAAI,EAAO,QAASC,CAAW,EAAIF,EAAc,KAErD,GAAI,CAACC,GAAS,CAACC,EACb,OAAO,KAIT,MAAMC,EAAgBD,EAAW,OAAS,IAE1C,OAAOX,EAACa,EAAA,CAAW,MAAOH,EAAO,QAASC,EAAY,OAAQC,EAAe,CAC/E,CACF,EAKMC,EAID,CAAC,CAAE,MAAAH,EAAO,QAAAJ,EAAS,OAAAQ,CAAO,IAAM,CACnC,KAAM,CAACC,EAAYC,CAAa,EAAId,EAAS,CAACY,CAAM,EAMpD,OACEb,EAAC,OAAI,UAAU,+DAEb,UAAAA,EAAC,OAAI,UAAU,yEACb,UAAAA,EAAC,OACC,MAAM,KACN,OAAO,KACP,QAAQ,YACR,KAAK,OACL,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QACf,UAAU,yBAEV,UAAAD,EAAC,QAAK,EAAE,6DAA6D,EACrEA,EAAC,YAAS,OAAO,iBAAiB,EAClCA,EAAC,QAAK,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,EACrCA,EAAC,QAAK,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,EACrCA,EAAC,YAAS,OAAO,eAAe,GAClC,EACAA,EAAC,MAAG,UAAU,sCAAuC,SAAAU,EAAM,GAC7D,EAGAT,EAAC,OAAI,UAAU,YACb,UAAAD,EAAC,OACC,UAAW;AAAA;AAAA,cAEP,CAACe,GAAcD,EAAS,eAAiB,EAAE;AAAA,YAG/C,SAAAd,EAACG,EAAA,CACC,cAAe,CAACC,CAAS,EACzB,WAAY,CACV,EAAG,CAAC,CAAE,KAAAa,EAAM,GAAGC,CAAM,IAAMlB,EAAC,KAAG,GAAGkB,EAAO,UAAU,iBAAiB,EACpE,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMlB,EAAC,MAAI,GAAGkB,EAAO,UAAU,sBAAsB,EAC3E,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMlB,EAAC,MAAI,GAAGkB,EAAO,UAAU,yBAAyB,EAC9E,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMlB,EAAC,MAAI,GAAGkB,EAAO,UAAU,OAAO,EAC5D,OAAQ,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMlB,EAAC,UAAQ,GAAGkB,EAAO,UAAU,YAAY,CAC3E,EAEC,SAAAZ,EACH,EACF,EAGCQ,GACCb,EAAC,UACC,KAAK,SACL,QAtDW,IAAM,CACzBe,EAAcG,GAAQ,CAACA,CAAI,CAC7B,EAqDU,UAAU,qFAEV,UAAAnB,EAAC,QAAM,SAAAe,EAAa,eAAO,eAAK,EAChCf,EAAC,OACC,MAAM,KACN,OAAO,KACP,QAAQ,YACR,KAAK,OACL,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QACf,UAAW,wBAAwBe,EAAa,aAAe,EAAE,GAEjE,SAAAf,EAAC,YAAS,OAAO,iBAAiB,EACpC,GACF,GAEJ,GACF,CAEJ",
6
+ "names": ["jsx", "jsxs", "useState", "ReactMarkdown", "remarkGfm", "PolicyBlock", "content", "isUser", "isSystem", "policyContent", "title", "policyText", "isLongContent", "PolicyCard", "isLong", "isExpanded", "setIsExpanded", "node", "props", "prev"]
7
7
  }
@@ -1,6 +1,6 @@
1
1
  /**
2
- * 商品卡片渲染器
3
- * 显示单个商品的详细信息
2
+ * 商品卡片渲染器 - 紧凑型
3
+ * 显示单个商品的详细信息(横向布局)
4
4
  * 基于 specs/livechat-widget/data-model.md 的商品数据模型
5
5
  */
6
6
  import type { MessageRenderer } from '../../types';
@@ -8,20 +8,21 @@ import type { MessageRenderer } from '../../types';
8
8
  * 商品卡片渲染器
9
9
  *
10
10
  * 功能:
11
- * - 显示商品图片、标题、价格
12
- * - 显示库存状态
13
- * - 可选:评分、评论数、热度
14
- * - 点击跳转到商品页面
11
+ * - 紧凑型横向布局(图片在左,信息在右)
12
+ * - 显示折扣标签、价格、评分
13
+ * - 支持 Add to Cart 按钮
14
+ * - 独立成段展示
15
+ * - 支持自定义渲染函数
15
16
  *
16
17
  * 布局:
17
18
  * ```
18
- * ┌─────────────────────────┐
19
- * │ [图片]
20
- * ├─────────────────────────┤
21
- * │ 商品标题
22
- * │ $29.99 [有货]
23
- * │ 4.5 (120 评论)
24
- * └─────────────────────────┘
19
+ * ┌─────────────────────────────┐
20
+ * │ [图片] 折扣标签
21
+ * │ 商品标题 │
22
+ * │ $29.99 (原价)
23
+ * │ ⭐ 4.5
24
+ * │ [Add to Cart]
25
+ * └─────────────────────────────┘
25
26
  * ```
26
27
  *
27
28
  * @example
@@ -29,17 +30,9 @@ import type { MessageRenderer } from '../../types';
29
30
  * const content: ProductCardContent = {
30
31
  * type: 'product_card',
31
32
  * data: {
32
- * product: {
33
- * shopifyId: '123',
34
- * handle: 'product-name',
35
- * title: 'Example Product',
36
- * price: { amount: 29.99, currency: 'USD' },
37
- * imageUrl: 'https://...',
38
- * productUrl: 'https://...',
39
- * stockStatus: 'in_stock',
40
- * averageRating: 4.5,
41
- * reviewCount: 120
42
- * }
33
+ * product: { ... },
34
+ * onAddToCart: (product) => { ... },
35
+ * productCardRender: (product, productHandle) => <CustomCard product={product} handle={productHandle} />
43
36
  * }
44
37
  * }
45
38
  * <ProductCard.render(content, false, false) />
@@ -1,5 +1,2 @@
1
- import{jsx as e,jsxs as a}from"react/jsx-runtime";import{CURRENCY_SYMBOLS as f}from"../../constants.js";function g(s){const{amount:n,currency:t}=s,o=f[t]||t,r=n.toFixed(2);return`${o}${r}`}const N=({status:s})=>{const t={in_stock:{text:"\u6709\u8D27",className:"bg-green-100 text-green-800"},low_stock:{text:"\u5E93\u5B58\u7D27\u5F20",className:"bg-yellow-100 text-yellow-800"},out_of_stock:{text:"\u7F3A\u8D27",className:"bg-red-100 text-red-800"}}[s];return e("span",{className:`
2
- inline-flex items-center rounded px-2 py-0.5 text-xs font-medium
3
- ${t.className}
4
- `,children:t.text})},b={render:(s,n,t)=>{const o=s,{product:r}=o.data;if(!r)return null;const{title:c,price:m,imageUrl:u,productUrl:p,stockStatus:x,averageRating:l,reviewCount:i,description:d}=r;return a("a",{href:p,target:"_blank",rel:"noopener noreferrer",className:"livechat-product-card block max-w-sm overflow-hidden",children:[e("div",{className:"relative aspect-square w-full bg-gray-100",children:e("img",{src:u,alt:c,className:"size-full object-cover",loading:"lazy"})}),a("div",{className:"flex flex-col gap-2 p-3",children:[e("h3",{className:"line-clamp-2 text-sm font-medium text-gray-900",children:c}),d&&e("p",{className:"line-clamp-2 text-xs text-gray-600",children:d}),a("div",{className:"flex items-center justify-between",children:[e("span",{className:"text-lg font-bold text-gray-900",children:g(m)}),e(N,{status:x})]}),l!==void 0&&i!==void 0&&a("div",{className:"flex items-center gap-1 text-xs text-gray-600",children:[e("span",{className:"text-yellow-500",children:"\u2B50"}),e("span",{className:"font-medium",children:l.toFixed(1)}),a("span",{children:["(",i," \u8BC4\u8BBA)"]})]})]})]})}};export{b as ProductCard};
1
+ import{Fragment as F,jsx as e,jsxs as c}from"react/jsx-runtime";import{CURRENCY_SYMBOLS as y,DEFAULT_COMMON_TEXT as p}from"../../constants.js";function C(t){const{amount:o,currency:n}=t;return`${y[n]||n}${o.toFixed(2)}`}function k(t,o,n=p.off){if(!t.discount_type||t.discount_value===void 0)return"";const r=typeof t.discount_value=="string"?parseFloat(t.discount_value):t.discount_value;return isNaN(r)?"":t.discount_type==="percentage"?`${Math.round(r)}% ${n}`:t.discount_type==="fixed_amount"?`${y[o]||o}${Math.round(r)} ${n}`:""}const w=({product:t,onAddToCart:o,addToCartText:n=p.addToCart,offText:r=p.off})=>{const{title:a,description:i,price:s,imageUrl:l,stockStatus:d,averageRating:f,variants:h}=t,N=d==="out_of_stock",u=h?.[0],m=u?.discount?.has_discount,g=m?u?.discount?.discount_price:null,x=u?.discount,P=g?{amount:g,currency:s.currency}:s,v=x&&m?k(x,s.currency,r):"",_=b=>{b.preventDefault(),b.stopPropagation(),o&&o(t)};return e("div",{className:"block w-full overflow-hidden rounded-2xl bg-[#F5F6F7] transition-shadow mb-[32px]",children:e("div",{className:"block",children:c("div",{className:"flex gap-2 p-4 bg-white",children:[e("div",{className:" flex shrink-0 items-center overflow-hidden rounded-md ",style:{width:"40%"},children:e("img",{src:l,alt:a,className:`h-auto w-full object-cover ${N?"opacity-50":""}`,loading:"lazy"})}),c("div",{className:"flex flex-1 flex-col justify-center",children:[v&&e("div",{className:"mb-1 w-fit rounded-full px-2 text-sm font-bold leading-none tracking-[-0.04em] text-white",style:{backgroundColor:"#005D8E",paddingTop:"6px",paddingBottom:"4px"},children:v}),e("h4",{className:"line-clamp-2 text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]",children:a}),c("div",{className:"mt-4 flex items-center gap-2",children:[c("div",{className:"flex items-center gap-1",children:[e("span",{className:"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:C(P)}),m&&e("span",{className:"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#6D6D6F] line-through",children:C(s)})]}),f!==void 0&&c("div",{className:"flex items-center gap-0.5 text-xs text-gray-600",children:[e("span",{className:"text-yellow-500",children:"\u2B50"}),e("span",{children:f.toFixed(1)})]})]}),e("button",{type:"button",onClick:_,className:"mt-2 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white",style:{backgroundColor:"#1D1D1F"},children:n})]})]})})})},M={render:(t,o,n)=>{const r=t,{product:a,rawProduct:i,productHandle:s,onAddToCart:l,productCardRender:d}=r.data;return console.log("[ProductCard] \u6E32\u67D3\u4EA7\u54C1\u5361\u7247:",{productHandle:s,hasProduct:!!a,hasRawProduct:!!i,hasCustomRender:!!d}),d?(console.log("[ProductCard] \u4F7F\u7528\u81EA\u5B9A\u4E49\u6E32\u67D3, productHandle:",s),e(F,{children:d(i||a,s)})):a?e(w,{product:a,onAddToCart:l}):null}};export{M as ProductCard};
5
2
  //# sourceMappingURL=ProductCard.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/components/LiveChatWidget/components/MessageContent/ProductCard.tsx"],
4
- "sourcesContent": ["/**\n * \u5546\u54C1\u5361\u7247\u6E32\u67D3\u5668\n * \u663E\u793A\u5355\u4E2A\u5546\u54C1\u7684\u8BE6\u7EC6\u4FE1\u606F\n * \u57FA\u4E8E specs/livechat-widget/data-model.md \u7684\u5546\u54C1\u6570\u636E\u6A21\u578B\n */\n\nimport React from 'react'\nimport type { MessageRenderer, ProductCardContent, Product } from '../../types'\nimport { CURRENCY_SYMBOLS } from '../../constants.js'\n\n/**\n * \u683C\u5F0F\u5316\u4EF7\u683C\n * @param price \u4EF7\u683C\u5BF9\u8C61\n * @returns \u683C\u5F0F\u5316\u540E\u7684\u4EF7\u683C\u5B57\u7B26\u4E32 (\u5982 \"$29.99\")\n */\nfunction formatPrice(price: Product['price']): string {\n const { amount, currency } = price\n\n const symbol = CURRENCY_SYMBOLS[currency] || currency\n const formattedAmount = amount.toFixed(2)\n\n return `${symbol}${formattedAmount}`\n}\n\n/**\n * \u5E93\u5B58\u72B6\u6001\u5FBD\u7AE0\n */\nconst StockBadge: React.FC<{ status: Product['stockStatus'] }> = ({ status }) => {\n const statusConfig = {\n in_stock: { text: '\u6709\u8D27', className: 'bg-green-100 text-green-800' },\n low_stock: { text: '\u5E93\u5B58\u7D27\u5F20', className: 'bg-yellow-100 text-yellow-800' },\n out_of_stock: { text: '\u7F3A\u8D27', className: 'bg-red-100 text-red-800' },\n }\n\n const config = statusConfig[status]\n\n return (\n <span\n className={`\n inline-flex items-center rounded px-2 py-0.5 text-xs font-medium\n ${config.className}\n `}\n >\n {config.text}\n </span>\n )\n}\n\n/**\n * \u5546\u54C1\u5361\u7247\u6E32\u67D3\u5668\n *\n * \u529F\u80FD\uFF1A\n * - \u663E\u793A\u5546\u54C1\u56FE\u7247\u3001\u6807\u9898\u3001\u4EF7\u683C\n * - \u663E\u793A\u5E93\u5B58\u72B6\u6001\n * - \u53EF\u9009\uFF1A\u8BC4\u5206\u3001\u8BC4\u8BBA\u6570\u3001\u70ED\u5EA6\n * - \u70B9\u51FB\u8DF3\u8F6C\u5230\u5546\u54C1\u9875\u9762\n *\n * \u5E03\u5C40\uFF1A\n * ```\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u56FE\u7247] \u2502\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 \u5546\u54C1\u6807\u9898 \u2502\n * \u2502 $29.99 [\u6709\u8D27] \u2502\n * \u2502 \u2B50 4.5 (120 \u8BC4\u8BBA) \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * ```\n *\n * @example\n * ```tsx\n * const content: ProductCardContent = {\n * type: 'product_card',\n * data: {\n * product: {\n * shopifyId: '123',\n * handle: 'product-name',\n * title: 'Example Product',\n * price: { amount: 29.99, currency: 'USD' },\n * imageUrl: 'https://...',\n * productUrl: 'https://...',\n * stockStatus: 'in_stock',\n * averageRating: 4.5,\n * reviewCount: 120\n * }\n * }\n * }\n * <ProductCard.render(content, false, false) />\n * ```\n */\nexport const ProductCard: MessageRenderer = {\n render: (content, isUser, isSystem) => {\n const productContent = content as ProductCardContent\n const { product } = productContent.data\n\n if (!product) {\n return null\n }\n\n const { title, price, imageUrl, productUrl, stockStatus, averageRating, reviewCount, description } = product\n\n return (\n <a\n href={productUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"livechat-product-card block max-w-sm overflow-hidden\"\n >\n {/* \u5546\u54C1\u56FE\u7247 */}\n <div className=\"relative aspect-square w-full bg-gray-100\">\n <img src={imageUrl} alt={title} className=\"size-full object-cover\" loading=\"lazy\" />\n </div>\n\n {/* \u5546\u54C1\u4FE1\u606F */}\n <div className=\"flex flex-col gap-2 p-3\">\n {/* \u6807\u9898 */}\n <h3 className=\"line-clamp-2 text-sm font-medium text-gray-900\">{title}</h3>\n\n {/* \u63CF\u8FF0\uFF08\u53EF\u9009\uFF09 */}\n {description && <p className=\"line-clamp-2 text-xs text-gray-600\">{description}</p>}\n\n {/* \u4EF7\u683C + \u5E93\u5B58 */}\n <div className=\"flex items-center justify-between\">\n <span className=\"text-lg font-bold text-gray-900\">{formatPrice(price)}</span>\n <StockBadge status={stockStatus} />\n </div>\n\n {/* \u8BC4\u5206 + \u8BC4\u8BBA\u6570\uFF08\u53EF\u9009\uFF09 */}\n {averageRating !== undefined && reviewCount !== undefined && (\n <div className=\"flex items-center gap-1 text-xs text-gray-600\">\n <span className=\"text-yellow-500\">\u2B50</span>\n <span className=\"font-medium\">{averageRating.toFixed(1)}</span>\n <span>({reviewCount} \u8BC4\u8BBA)</span>\n </div>\n )}\n </div>\n </a>\n )\n },\n}\n"],
5
- "mappings": "AAqCI,cAAAA,EAoFM,QAAAC,MApFN,oBA7BJ,OAAS,oBAAAC,MAAwB,qBAOjC,SAASC,EAAYC,EAAiC,CACpD,KAAM,CAAE,OAAAC,EAAQ,SAAAC,CAAS,EAAIF,EAEvBG,EAASL,EAAiBI,CAAQ,GAAKA,EACvCE,EAAkBH,EAAO,QAAQ,CAAC,EAExC,MAAO,GAAGE,CAAM,GAAGC,CAAe,EACpC,CAKA,MAAMC,EAA2D,CAAC,CAAE,OAAAC,CAAO,IAAM,CAO/E,MAAMC,EANe,CACnB,SAAU,CAAE,KAAM,eAAM,UAAW,6BAA8B,EACjE,UAAW,CAAE,KAAM,2BAAQ,UAAW,+BAAgC,EACtE,aAAc,CAAE,KAAM,eAAM,UAAW,yBAA0B,CACnE,EAE4BD,CAAM,EAElC,OACEV,EAAC,QACC,UAAW;AAAA;AAAA,UAEPW,EAAO,SAAS;AAAA,QAGnB,SAAAA,EAAO,KACV,CAEJ,EA2CaC,EAA+B,CAC1C,OAAQ,CAACC,EAASC,EAAQC,IAAa,CACrC,MAAMC,EAAiBH,EACjB,CAAE,QAAAI,CAAQ,EAAID,EAAe,KAEnC,GAAI,CAACC,EACH,OAAO,KAGT,KAAM,CAAE,MAAAC,EAAO,MAAAd,EAAO,SAAAe,EAAU,WAAAC,EAAY,YAAAC,EAAa,cAAAC,EAAe,YAAAC,EAAa,YAAAC,CAAY,EAAIP,EAErG,OACEhB,EAAC,KACC,KAAMmB,EACN,OAAO,SACP,IAAI,sBACJ,UAAU,uDAGV,UAAApB,EAAC,OAAI,UAAU,4CACb,SAAAA,EAAC,OAAI,IAAKmB,EAAU,IAAKD,EAAO,UAAU,yBAAyB,QAAQ,OAAO,EACpF,EAGAjB,EAAC,OAAI,UAAU,0BAEb,UAAAD,EAAC,MAAG,UAAU,iDAAkD,SAAAkB,EAAM,EAGrEM,GAAexB,EAAC,KAAE,UAAU,qCAAsC,SAAAwB,EAAY,EAG/EvB,EAAC,OAAI,UAAU,oCACb,UAAAD,EAAC,QAAK,UAAU,kCAAmC,SAAAG,EAAYC,CAAK,EAAE,EACtEJ,EAACS,EAAA,CAAW,OAAQY,EAAa,GACnC,EAGCC,IAAkB,QAAaC,IAAgB,QAC9CtB,EAAC,OAAI,UAAU,gDACb,UAAAD,EAAC,QAAK,UAAU,kBAAkB,kBAAC,EACnCA,EAAC,QAAK,UAAU,cAAe,SAAAsB,EAAc,QAAQ,CAAC,EAAE,EACxDrB,EAAC,QAAK,cAAEsB,EAAY,kBAAI,GAC1B,GAEJ,GACF,CAEJ,CACF",
6
- "names": ["jsx", "jsxs", "CURRENCY_SYMBOLS", "formatPrice", "price", "amount", "currency", "symbol", "formattedAmount", "StockBadge", "status", "config", "ProductCard", "content", "isUser", "isSystem", "productContent", "product", "title", "imageUrl", "productUrl", "stockStatus", "averageRating", "reviewCount", "description"]
4
+ "sourcesContent": ["/**\n * \u5546\u54C1\u5361\u7247\u6E32\u67D3\u5668 - \u7D27\u51D1\u578B\n * \u663E\u793A\u5355\u4E2A\u5546\u54C1\u7684\u8BE6\u7EC6\u4FE1\u606F\uFF08\u6A2A\u5411\u5E03\u5C40\uFF09\n * \u57FA\u4E8E specs/livechat-widget/data-model.md \u7684\u5546\u54C1\u6570\u636E\u6A21\u578B\n */\n\nimport React from 'react'\nimport type { MessageRenderer, ProductCardContent, Product, CommonText } from '../../types'\nimport { CURRENCY_SYMBOLS, DEFAULT_COMMON_TEXT } from '../../constants.js'\n\n/**\n * \u683C\u5F0F\u5316\u4EF7\u683C\n */\nfunction formatPrice(price: Product['price']): string {\n const { amount, currency } = price\n\n const symbol = CURRENCY_SYMBOLS[currency] || currency\n return `${symbol}${amount.toFixed(2)}`\n}\n\n/**\n * \u683C\u5F0F\u5316\u6298\u6263\u6807\u7B7E\u6587\u672C\n * @param discount \u6298\u6263\u5BF9\u8C61\n * @param currency \u8D27\u5E01\u4EE3\u7801\n * @param offText \"OFF\" \u6587\u6848\n * @returns \u683C\u5F0F\u5316\u540E\u7684\u6298\u6263\u6587\u672C\uFF08\u5982 \"$10 OFF\" \u6216 \"20% OFF\"\uFF09\n */\nfunction formatDiscountLabel(\n discount: { discount_type?: string; discount_value?: string | number },\n currency: string,\n offText: string = DEFAULT_COMMON_TEXT.off\n): string {\n if (!discount.discount_type || discount.discount_value === undefined) {\n return ''\n }\n\n // \u5C06 discount_value \u8F6C\u6362\u4E3A\u6570\u5B57\n const value =\n typeof discount.discount_value === 'string' ? parseFloat(discount.discount_value) : discount.discount_value\n\n if (isNaN(value)) {\n return ''\n }\n\n if (discount.discount_type === 'percentage') {\n return `${Math.round(value)}% ${offText}`\n }\n\n if (discount.discount_type === 'fixed_amount') {\n const symbol = CURRENCY_SYMBOLS[currency] || currency\n return `${symbol}${Math.round(value)} ${offText}`\n }\n\n return ''\n}\n\n/**\n * \u7D27\u51D1\u578B\u5546\u54C1\u5361\u7247\u7EC4\u4EF6\uFF08\u6A2A\u5411\u5E03\u5C40\uFF09\n */\nconst CompactProductCard: React.FC<{\n product: Product\n onAddToCart?: (product: Product) => void\n addToCartText?: string\n offText?: string\n}> = ({ product, onAddToCart, addToCartText = DEFAULT_COMMON_TEXT.addToCart, offText = DEFAULT_COMMON_TEXT.off }) => {\n const { title, description, price, imageUrl, stockStatus, averageRating, variants } = product\n\n const isOutOfStock = stockStatus === 'out_of_stock'\n\n // \u83B7\u53D6\u7B2C\u4E00\u4E2A\u53D8\u4F53\u7684\u6298\u6263\u4FE1\u606F\n const firstVariant = variants?.[0]\n const hasDiscount = firstVariant?.discount?.has_discount\n const discountPrice = hasDiscount ? firstVariant?.discount?.discount_price : null\n const discount = firstVariant?.discount\n\n // \u5F53\u524D\u663E\u793A\u4EF7\u683C\uFF1A\u6709\u6298\u6263\u65F6\u663E\u793A\u6298\u6263\u4EF7\uFF0C\u5426\u5219\u663E\u793A\u539F\u4EF7\n const currentPrice = discountPrice ? { amount: discountPrice, currency: price.currency } : price\n\n // \u683C\u5F0F\u5316\u6298\u6263\u6807\u7B7E\n const discountLabel = discount && hasDiscount ? formatDiscountLabel(discount, price.currency, offText) : ''\n\n const handleAddToCart = (e: React.MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n if (onAddToCart) {\n onAddToCart(product)\n }\n }\n\n return (\n <div className=\"block w-full overflow-hidden rounded-2xl bg-[#F5F6F7] transition-shadow mb-[32px]\">\n <div className=\"block\">\n <div className=\"flex gap-2 p-4 bg-white\">\n {/* \u5546\u54C1\u56FE\u7247 */}\n <div className=\" flex shrink-0 items-center overflow-hidden rounded-md \" style={{ width: '40%' }}>\n <img\n src={imageUrl}\n alt={title}\n className={`h-auto w-full object-cover ${isOutOfStock ? 'opacity-50' : ''}`}\n loading=\"lazy\"\n />\n </div>\n\n {/* \u5546\u54C1\u4FE1\u606F */}\n <div className=\"flex flex-1 flex-col justify-center\">\n {/* \u6298\u6263\u6807\u7B7E */}\n {discountLabel && (\n <div\n className=\"mb-1 w-fit rounded-full px-2 text-sm font-bold leading-none tracking-[-0.04em] text-white\"\n style={{ backgroundColor: '#005D8E', paddingTop: '6px', paddingBottom: '4px' }}\n >\n {discountLabel}\n </div>\n )}\n\n {/* \u6807\u9898 */}\n <h4 className=\"line-clamp-2 text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]\">\n {title}\n </h4>\n\n {/* \u63CF\u8FF0\uFF08\u53EF\u9009\uFF09 */}\n {/* {description && (\n <p className=\"line-clamp-2 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n {description}\n </p>\n )} */}\n\n {/* \u4EF7\u683C\u548C\u8BC4\u5206 */}\n <div className=\"mt-4 flex items-center gap-2\">\n <div className=\"flex items-center gap-1\">\n {/* \u5F53\u524D\u4EF7\u683C\uFF08\u6709\u6298\u6263\u65F6\u663E\u793A\u6298\u6263\u4EF7\uFF0C\u5426\u5219\u663E\u793A\u539F\u4EF7\uFF09 */}\n <span className=\"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n {formatPrice(currentPrice)}\n </span>\n {/* \u539F\u4EF7\uFF08\u5212\u7EBF\u4EF7\uFF09- \u4EC5\u5728\u6709\u6298\u6263\u65F6\u663E\u793A */}\n {hasDiscount && (\n <span className=\"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#6D6D6F] line-through\">\n {formatPrice(price)}\n </span>\n )}\n </div>\n {/* \u8BC4\u5206\uFF08\u53EF\u9009\uFF09 */}\n {averageRating !== undefined && (\n <div className=\"flex items-center gap-0.5 text-xs text-gray-600\">\n <span className=\"text-yellow-500\">\u2B50</span>\n <span>{averageRating.toFixed(1)}</span>\n </div>\n )}\n </div>\n\n {/* Add to Cart \u6309\u94AE - \u5728\u4EF7\u683C\u4E0B\u65B9 */}\n <button\n type=\"button\"\n onClick={handleAddToCart}\n className=\"mt-2 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white\"\n style={{ backgroundColor: '#1D1D1F' }}\n >\n {addToCartText}\n </button>\n </div>\n </div>\n </div>\n </div>\n )\n}\n\n/**\n * \u5546\u54C1\u5361\u7247\u6E32\u67D3\u5668\n *\n * \u529F\u80FD\uFF1A\n * - \u7D27\u51D1\u578B\u6A2A\u5411\u5E03\u5C40\uFF08\u56FE\u7247\u5728\u5DE6\uFF0C\u4FE1\u606F\u5728\u53F3\uFF09\n * - \u663E\u793A\u6298\u6263\u6807\u7B7E\u3001\u4EF7\u683C\u3001\u8BC4\u5206\n * - \u652F\u6301 Add to Cart \u6309\u94AE\n * - \u72EC\u7ACB\u6210\u6BB5\u5C55\u793A\n * - \u652F\u6301\u81EA\u5B9A\u4E49\u6E32\u67D3\u51FD\u6570\n *\n * \u5E03\u5C40\uFF1A\n * ```\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u56FE\u7247] \u6298\u6263\u6807\u7B7E \u2502\n * \u2502 \u5546\u54C1\u6807\u9898 \u2502\n * \u2502 $29.99 (\u539F\u4EF7) \u2502\n * \u2502 \u2B50 4.5 \u2502\n * \u2502 [Add to Cart] \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * ```\n *\n * @example\n * ```tsx\n * const content: ProductCardContent = {\n * type: 'product_card',\n * data: {\n * product: { ... },\n * onAddToCart: (product) => { ... },\n * productCardRender: (product, productHandle) => <CustomCard product={product} handle={productHandle} />\n * }\n * }\n * <ProductCard.render(content, false, false) />\n * ```\n */\nexport const ProductCard: MessageRenderer = {\n render: (content, isUser, isSystem) => {\n const productContent = content as ProductCardContent\n const { product, rawProduct, productHandle, onAddToCart, productCardRender } = productContent.data\n\n console.log('[ProductCard] \u6E32\u67D3\u4EA7\u54C1\u5361\u7247:', {\n productHandle,\n hasProduct: !!product,\n hasRawProduct: !!rawProduct,\n hasCustomRender: !!productCardRender,\n })\n\n // \u5982\u679C\u63D0\u4F9B\u4E86\u81EA\u5B9A\u4E49\u6E32\u67D3\u51FD\u6570\uFF0C\u4F7F\u7528\u81EA\u5B9A\u4E49\u6E32\u67D3\uFF08\u4F20\u5165\u539F\u59CB\u540E\u7AEF\u6570\u636E\u548C productHandle\uFF09\n // \u5373\u4F7F product \u4E3A\u7A7A\uFF0C\u4E5F\u8C03\u7528\u81EA\u5B9A\u4E49\u6E32\u67D3\u51FD\u6570\uFF0C\u8BA9\u5E94\u7528\u5C42\u53EF\u4EE5\u7528 productHandle \u67E5\u8BE2\u4EA7\u54C1\n if (productCardRender) {\n console.log('[ProductCard] \u4F7F\u7528\u81EA\u5B9A\u4E49\u6E32\u67D3, productHandle:', productHandle)\n return <>{productCardRender(rawProduct || product, productHandle)}</>\n }\n\n // \u9ED8\u8BA4\u6E32\u67D3\uFF1A\u5982\u679C\u6CA1\u6709\u4EA7\u54C1\u6570\u636E\u5219\u4E0D\u6E32\u67D3\n if (!product) {\n return null\n }\n\n return <CompactProductCard product={product} onAddToCart={onAddToCart} />\n },\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["Fragment", "jsx", "jsxs", "CURRENCY_SYMBOLS", "DEFAULT_COMMON_TEXT", "formatPrice", "price", "amount", "currency", "formatDiscountLabel", "discount", "offText", "value", "CompactProductCard", "product", "onAddToCart", "addToCartText", "title", "description", "imageUrl", "stockStatus", "averageRating", "variants", "isOutOfStock", "firstVariant", "hasDiscount", "discountPrice", "currentPrice", "discountLabel", "handleAddToCart", "e", "ProductCard", "content", "isUser", "isSystem", "productContent", "rawProduct", "productHandle", "productCardRender"]
7
7
  }
@@ -4,7 +4,7 @@
4
4
  * 基于参考设计:顶部产品展示 + 底部对比表格
5
5
  */
6
6
  import React from 'react';
7
- import type { Product, MessageRenderer } from '../../types';
7
+ import type { Product, MessageRenderer, CommonText } from '../../types';
8
8
  /**
9
9
  * 对比维度数据结构
10
10
  */
@@ -25,8 +25,10 @@ export interface ProductComparisonData {
25
25
  variants?: ComparisonDimension;
26
26
  member_price?: ComparisonDimension;
27
27
  discount?: ComparisonDimension;
28
+ reviews?: ComparisonDimension;
28
29
  [key: string]: ComparisonDimension | undefined;
29
30
  };
31
+ commonText?: CommonText;
30
32
  }
31
33
  export interface ProductComparisonProps {
32
34
  /**
@@ -45,6 +47,10 @@ export interface ProductComparisonProps {
45
47
  * 添加到购物车回调
46
48
  */
47
49
  onAddToCart?: (product: Product) => void;
50
+ /**
51
+ * 通用文案配置
52
+ */
53
+ commonText?: CommonText;
48
54
  }
49
55
  /**
50
56
  * 产品对比组件
@@ -1,2 +1,2 @@
1
- import{jsx as t,jsxs as d}from"react/jsx-runtime";import{useState as A}from"react";const c=(o,i="USD")=>`${i==="USD"?"$":i}${o.toLocaleString("en-US",{minimumFractionDigits:2,maximumFractionDigits:2})}`,I=({data:o,onAddToCart:i})=>{const{products:m,dimensions:l}=o,p=m?.filter(e=>e&&e.shopifyId)||[],g=2,y=p.slice(0,g),[f,D]=A(y);if(p.length===0)return null;const C=(e,n)=>{const s=p.find(a=>a.shopifyId===n);if(s){const a=[...f];a[e]=s,D(a)}},x=f.slice(0,g),v=(e,n)=>!e||!e.values||!Array.isArray(e.values)?null:e.values.find(s=>s&&s.product_id===n),h=(e,n)=>n?d("div",{className:"border-b border-[#DADCE0] pb-2",children:[t("div",{className:"mb-3",children:t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#86868C]",children:e})}),t("div",{className:"flex gap-4",style:{gap:"36px"},children:x.map((s,a)=>{if(!s||!s.shopifyId)return null;const u=v(n,s.shopifyId);return t("div",{className:"flex-1",children:k(u,n.label)},`comparison-${a}`)})})]}):null,k=(e,n)=>{if(!e)return t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:"-"});if(n.toLowerCase().includes("price")){const s=e.min===e.max?c(e.min,e.currency):`${c(e.min,e.currency)} - ${c(e.max,e.currency)}`;return t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:s})}return n.toLowerCase().includes("variant")?d("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:[e.count||0," ",e.count===1?"variant":"variants"]}):t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:e.display||e.value||"-"})};return d("div",{className:"w-full overflow-hidden rounded-2xl bg-[#F5F6F7]",children:[t("div",{className:"flex p-4",style:{gap:"36px",paddingBottom:"0px"},children:x.map((e,n)=>{if(!e||!e.shopifyId)return null;const s=l.price?v(l.price,e.shopifyId):null,a=e.variants?.[0],u=a?.discount?.has_discount,b=u?a?.discount?.discount_price:null,N=b||s?.min||e.price.amount,P=e.price.amount,w=r=>{r.preventDefault(),r.stopPropagation(),i&&i(e)};return d("div",{className:"flex flex-1 flex-col items-center",children:[t("div",{className:"mb-4 w-full",children:t("select",{value:e.shopifyId,onChange:r=>C(n,r.target.value),className:"w-full rounded-lg border border-[#DADCE0] bg-[#F5F6F7] px-3 py-2 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",style:{appearance:"none",backgroundImage:`url("data:image/svg+xml,%3Csvg width='12' height='8' viewBox='0 0 12 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%231D1D1F' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")`,backgroundRepeat:"no-repeat",backgroundPosition:"right 12px center",paddingRight:"32px"},children:p.map(r=>t("option",{value:r.shopifyId,children:r.title.length>30?`${r.title.slice(0,30)}...`:r.title},r.shopifyId))})}),t("a",{href:e.productUrl,target:"_blank",rel:"noopener noreferrer",className:"mb-4 block w-full max-w-[160px]",children:t("div",{className:"aspect-square w-full overflow-hidden rounded-lg",children:e.imageUrl?t("img",{src:e.imageUrl,alt:e.title,className:"size-full object-contain",loading:"lazy"}):t("div",{className:"flex size-full items-center justify-center text-gray-400",children:t("svg",{className:"size-12",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:t("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"})})})})}),t("div",{className:"mb-4 flex flex-col items-center gap-1",children:d("div",{className:"flex items-center gap-2",children:[t("span",{className:"text-base font-bold leading-[1.2] tracking-[-0.02em] text-[#1D1D1F]",children:c(N,s?.currency||e.price.currency)}),u&&b&&t("span",{className:"text-base font-bold leading-[1.2] tracking-[-0.02em] text-[#4A4C56] line-through",children:c(P,e.price.currency)})]})}),i&&t("button",{type:"button",onClick:w,className:"mb-3 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white",style:{backgroundColor:"#1D1D1F"},children:"Add to Cart"}),e.variants&&e.variants.length>1&&t("div",{className:"flex gap-2",children:e.variants.slice(0,3).map((r,F)=>t("div",{className:"size-6 rounded-full border-2 border-[#DADCE0]",style:{backgroundColor:r.color||"#000"},title:r.title},r.id||F))})]},`product-column-${n}`)})}),t("div",{className:"flex flex-col gap-4 p-4",children:Object.entries(l).map(([e,n])=>!n||e==="price"?null:t("div",{children:h(n.label,n)},e))})]})},L={render:(o,i,m)=>{if(o.type!=="product_comparison"||!o.data)return null;const l=o.data;return t(I,{data:l,isUser:i,isSystem:m,onAddToCart:l.onAddToCart})}};export{I as ProductComparison,L as ProductComparisonRenderer};
1
+ import{jsx as t,jsxs as i}from"react/jsx-runtime";import{useState as A}from"react";import{DEFAULT_COMMON_TEXT as I,CURRENCY_SYMBOLS as M}from"../../constants";const d=(c,a="USD")=>`${M[a]||a}${c}`,R=({data:c,onAddToCart:a,commonText:m})=>{const{products:l,dimensions:g}=c,y={...I,...m},p=l?.filter(e=>e&&e.shopifyId)||[],f=2,D=p.slice(0,f),[x,h]=A(D);if(p.length===0)return null;const N=(e,n)=>{const s=p.find(o=>o.shopifyId===n);if(s){const o=[...x];o[e]=s,h(o)}},b=x.slice(0,f),v=(e,n)=>!e||!e.values||!Array.isArray(e.values)?null:e.values.find(s=>s&&s.product_id===n),k=(e,n)=>n?i("div",{className:"border-b border-[#DADCE0] pb-2",children:[t("div",{className:"mb-1",children:t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#86868C]",children:e==="price"?"has member price":e})}),t("div",{className:"flex gap-4",style:{gap:"36px"},children:b.map((s,o)=>{if(!s||!s.shopifyId)return null;const u=v(n,s.shopifyId);return t("div",{className:"flex-1",children:P(u,n.label)},`comparison-${o}`)})})]}):null,P=(e,n)=>{if(!e)return t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:"-"});if(n.toLowerCase().includes("price")){const s=e?.has_member_price,o=e?.available?e.min===e.max?d(e.min,e.currency):`${d(e.min,e.currency)} - ${d(e.max,e.currency)}`:"-";return t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:s?"Yes":"No"})}if(n.toLowerCase().includes("variant"))return i("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:[e.count||0," ",e.count===1?"variant":"variants"]});if(n.toLowerCase().includes("review")){const s=e.rating||0,o=e.count||0;return i("div",{className:"flex items-center gap-1",children:[i("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:["\u2B50 ",s.toFixed(1)]}),i("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#86868C]",children:["(",o,")"]})]})}return t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:e.display||e.value||"-"})};return i("div",{className:"w-full overflow-hidden rounded-2xl bg-[#F5F6F7]",children:[t("div",{className:"flex p-4",style:{gap:"36px",paddingBottom:"0px"},children:b.map((e,n)=>{if(!e||!e.shopifyId)return null;const s=g.price?v(g.price,e.shopifyId):null,o=e.variants?.[0],u=o?.discount?.has_discount,C=u?o?.discount?.discount_price:null,w=C||s?.min||e.price.amount,F=e.price.amount,T=r=>{r.preventDefault(),r.stopPropagation(),a&&a(e)};return i("div",{className:"flex flex-1 flex-col items-center",children:[t("div",{className:"mb-4 w-full",children:t("select",{value:e.shopifyId,onChange:r=>N(n,r.target.value),className:"w-full rounded-lg border border-[#DADCE0] bg-[#F5F6F7] px-3 py-2 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",style:{appearance:"none",backgroundImage:`url("data:image/svg+xml,%3Csvg width='12' height='8' viewBox='0 0 12 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%231D1D1F' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")`,backgroundRepeat:"no-repeat",backgroundPosition:"right 12px center",paddingRight:"32px"},children:p.map(r=>t("option",{value:r.shopifyId,children:r.title.length>30?`${r.title.slice(0,30)}...`:r.title},r.shopifyId))})}),t("a",{href:e.productUrl,target:"_blank",rel:"noopener noreferrer",className:"mb-4 block w-full max-w-[160px]",children:t("div",{className:"aspect-square w-full overflow-hidden rounded-lg",children:e.imageUrl?t("img",{src:e.imageUrl,alt:e.title,className:"size-full object-contain",loading:"lazy"}):t("div",{className:"flex size-full items-center justify-center text-gray-400",children:t("svg",{className:"size-12",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:t("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"})})})})}),t("div",{className:"mb-4 flex flex-col items-center gap-1",children:i("div",{className:"flex items-center gap-2",children:[t("span",{className:"text-base font-bold leading-[1.2] tracking-[-0.02em] text-[#1D1D1F]",children:d(w,s?.currency||e.price.currency)}),u&&C&&t("span",{className:"text-base font-bold leading-[1.2] tracking-[-0.02em] text-[#4A4C56] line-through",children:d(F,e.price.currency)})]})}),a&&t("button",{type:"button",onClick:T,className:"mb-3 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white",style:{backgroundColor:"#1D1D1F"},children:y.addToCart}),e.variants&&e.variants.length>1&&t("div",{className:"flex gap-2",children:e.variants.slice(0,3).map((r,_)=>t("div",{className:"size-6 rounded-full border-2 border-[#DADCE0]",style:{backgroundColor:r.color||"#000"},title:r.title},r.id||_))})]},`product-column-${n}`)})}),t("div",{className:"flex flex-col gap-4 p-4",children:Object.entries(g).map(([e,n])=>n?t("div",{children:k(n.label,n)},e):null)})]})},U={render:(c,a,m)=>{if(c.type!=="product_comparison"||!c.data)return null;const l=c.data;return t(R,{data:l,isUser:a,isSystem:m,onAddToCart:l.onAddToCart,commonText:l.commonText})}};export{R as ProductComparison,U as ProductComparisonRenderer};
2
2
  //# sourceMappingURL=ProductComparison.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/components/LiveChatWidget/components/MessageContent/ProductComparison.tsx"],
4
- "sourcesContent": ["/**\n * \u4EA7\u54C1\u5BF9\u6BD4\u7EC4\u4EF6\n * \u663E\u793A\u591A\u4E2A\u4EA7\u54C1\u7684\u5BF9\u6BD4\u4FE1\u606F\uFF0C\u91C7\u7528\u8868\u683C\u5E03\u5C40\u5C55\u793A\u5404\u7EF4\u5EA6\u5DEE\u5F02\n * \u57FA\u4E8E\u53C2\u8003\u8BBE\u8BA1\uFF1A\u9876\u90E8\u4EA7\u54C1\u5C55\u793A + \u5E95\u90E8\u5BF9\u6BD4\u8868\u683C\n */\n\nimport React, { useState } from 'react'\nimport type { Product, MessageRenderer } from '../../types'\n\n/**\n * \u5BF9\u6BD4\u7EF4\u5EA6\u6570\u636E\u7ED3\u6784\n */\ninterface ComparisonDimension {\n label: string\n values: Array<{\n product_id: string\n [key: string]: any\n }>\n}\n\n/**\n * \u4EA7\u54C1\u5BF9\u6BD4\u6570\u636E\u7ED3\u6784\n */\nexport interface ProductComparisonData {\n products: Product[]\n dimensions: {\n price?: ComparisonDimension\n variants?: ComparisonDimension\n member_price?: ComparisonDimension\n discount?: ComparisonDimension\n [key: string]: ComparisonDimension | undefined\n }\n}\n\nexport interface ProductComparisonProps {\n /**\n * \u4EA7\u54C1\u5BF9\u6BD4\u6570\u636E\n */\n data: ProductComparisonData\n\n /**\n * \u662F\u5426\u4E3A\u7528\u6237\u6D88\u606F\n */\n isUser?: boolean\n\n /**\n * \u662F\u5426\u4E3A\u7CFB\u7EDF\u6D88\u606F\n */\n isSystem?: boolean\n\n /**\n * \u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u56DE\u8C03\n */\n onAddToCart?: (product: Product) => void\n}\n\n/**\n * \u683C\u5F0F\u5316\u4EF7\u683C\u663E\u793A\n */\nconst formatPrice = (amount: number, currency: string = 'USD'): string => {\n const symbol = currency === 'USD' ? '$' : currency\n return `${symbol}${amount.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`\n}\n\n/**\n * \u4EA7\u54C1\u5BF9\u6BD4\u7EC4\u4EF6\n *\n * \u5E03\u5C40\uFF1A\n * ```\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u4EA7\u54C11\u56FE\u7247] [\u4EA7\u54C12\u56FE\u7247] \u2502\n * \u2502 \u4EF7\u683C1 \u4EF7\u683C2 \u2502\n * \u2502 \u989C\u8272\u9009\u9879 \u989C\u8272\u9009\u9879 \u2502\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 \u7EF4\u5EA61 \u2502 \u503C1-1 \u2502 \u503C1-2 \u2502\n * \u2502 \u7EF4\u5EA62 \u2502 \u503C2-1 \u2502 \u503C2-2 \u2502\n * \u2502 \u7EF4\u5EA63 \u2502 \u503C3-1 \u2502 \u503C3-2 \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * ```\n */\nexport const ProductComparison: React.FC<ProductComparisonProps> = ({ data, onAddToCart }) => {\n const { products: rawProducts, dimensions } = data\n\n // \u8FC7\u6EE4\u6389 null \u6216\u65E0\u6548\u7684\u4EA7\u54C1\n const allProducts = rawProducts?.filter(p => p && p.shopifyId) || []\n\n // \u5BF9\u6BD4\u5217\u6570\uFF08\u56FA\u5B9A\u4E3A2\u5217\uFF09\n const COMPARISON_COLUMNS = 2\n\n // \u521D\u59CB\u5316\u6BCF\u4E2A\u5BF9\u6BD4\u4F4D\u7F6E\u7684\u9009\u4E2D\u4EA7\u54C1\uFF08\u9ED8\u8BA4\u53D6\u524D\u4E24\u4E2A\u4EA7\u54C1\uFF09\n const initialSelectedProducts = allProducts.slice(0, COMPARISON_COLUMNS)\n const [selectedProducts, setSelectedProducts] = useState<Product[]>(initialSelectedProducts)\n\n // Early return \u5FC5\u987B\u5728\u6240\u6709 hooks \u4E4B\u540E\n if (allProducts.length === 0) {\n return null\n }\n\n // \u5904\u7406\u4EA7\u54C1\u9009\u62E9\u53D8\u66F4\n const handleProductChange = (index: number, productId: string) => {\n const newProduct = allProducts.find(p => p.shopifyId === productId)\n if (newProduct) {\n const newSelectedProducts = [...selectedProducts]\n newSelectedProducts[index] = newProduct\n setSelectedProducts(newSelectedProducts)\n }\n }\n\n // \u5F53\u524D\u663E\u793A\u7684\u4EA7\u54C1\uFF08\u786E\u4FDD\u53EA\u663E\u793A\u6307\u5B9A\u5217\u6570\uFF09\n const products = selectedProducts.slice(0, COMPARISON_COLUMNS)\n\n /**\n * \u83B7\u53D6\u6307\u5B9A\u4EA7\u54C1\u5728\u67D0\u4E2A\u7EF4\u5EA6\u7684\u503C\n */\n const getDimensionValue = (dimension: ComparisonDimension, productId: string): any => {\n if (!dimension || !dimension.values || !Array.isArray(dimension.values)) {\n return null\n }\n return dimension.values.find(v => v && v.product_id === productId)\n }\n\n /**\n * \u6E32\u67D3\u901A\u7528\u5BF9\u6BD4\u884C\n */\n const renderComparisonRow = (label: string, dimension: ComparisonDimension | undefined) => {\n if (!dimension) return null\n\n return (\n <div className=\"border-b border-[#DADCE0] pb-2\">\n {/* \u7EF4\u5EA6\u6807\u7B7E\uFF08\u6807\u9898\uFF09 */}\n <div className=\"mb-3\">\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#86868C]\">{label}</span>\n </div>\n\n {/* \u4EA7\u54C1\u503C\u5217\u8868\uFF08\u6A2A\u5411\u6392\u5217\uFF09 */}\n <div className=\"flex gap-4\" style={{ gap: '36px' }}>\n {products.map((product, index) => {\n if (!product || !product.shopifyId) return null\n const value = getDimensionValue(dimension, product.shopifyId)\n\n return (\n <div key={`comparison-${index}`} className=\"flex-1\">\n {renderDimensionValue(value, dimension.label)}\n </div>\n )\n })}\n </div>\n </div>\n )\n }\n\n /**\n * \u6E32\u67D3\u7EF4\u5EA6\u503C\n */\n const renderDimensionValue = (value: any, dimensionLabel: string) => {\n if (!value) {\n return <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">-</span>\n }\n\n // \u6839\u636E\u4E0D\u540C\u7EF4\u5EA6\u7C7B\u578B\u6E32\u67D3\u4E0D\u540C\u683C\u5F0F\n if (dimensionLabel.toLowerCase().includes('price')) {\n // \u4EF7\u683C\u7EF4\u5EA6\n const priceDisplay =\n value.min === value.max\n ? formatPrice(value.min, value.currency)\n : `${formatPrice(value.min, value.currency)} - ${formatPrice(value.max, value.currency)}`\n return <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">{priceDisplay}</span>\n }\n\n if (dimensionLabel.toLowerCase().includes('variant')) {\n // \u53D8\u4F53\u6570\u91CF\n return (\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n {value.count || 0} {value.count === 1 ? 'variant' : 'variants'}\n </span>\n )\n }\n\n // \u9ED8\u8BA4\u663E\u793A\n return (\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n {value.display || value.value || '-'}\n </span>\n )\n }\n\n return (\n <div className=\"w-full overflow-hidden rounded-2xl bg-[#F5F6F7]\">\n {/* \u9876\u90E8\u4EA7\u54C1\u5C55\u793A\u533A\u57DF */}\n <div className=\"flex p-4\" style={{ gap: '36px', paddingBottom: '0px' }}>\n {products.map((product, index) => {\n if (!product || !product.shopifyId) return null\n\n // \u83B7\u53D6\u4EF7\u683C\u4FE1\u606F\n const priceInfo = dimensions.price ? getDimensionValue(dimensions.price, product.shopifyId) : null\n\n // \u83B7\u53D6\u6298\u6263\u4FE1\u606F\n const firstVariant = product.variants?.[0]\n const hasDiscount = firstVariant?.discount?.has_discount\n const discountPrice = hasDiscount ? firstVariant?.discount?.discount_price : null\n\n // \u5F53\u524D\u663E\u793A\u4EF7\u683C\uFF1A\u6709\u6298\u6263\u65F6\u663E\u793A\u6298\u6263\u4EF7\uFF0C\u5426\u5219\u663E\u793A\u539F\u4EF7\n const currentPrice = discountPrice || priceInfo?.min || product.price.amount\n const originalPrice = product.price.amount\n\n // Add to Cart \u6309\u94AE\u70B9\u51FB\u5904\u7406\n const handleAddToCart = (e: React.MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n if (onAddToCart) {\n onAddToCart(product)\n }\n }\n\n return (\n <div key={`product-column-${index}`} className=\"flex flex-1 flex-col items-center\">\n {/* \u4EA7\u54C1\u9009\u62E9\u4E0B\u62C9\u6846 */}\n <div className=\"mb-4 w-full\">\n <select\n value={product.shopifyId}\n onChange={e => handleProductChange(index, e.target.value)}\n className=\"w-full rounded-lg border border-[#DADCE0] bg-[#F5F6F7] px-3 py-2 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\"\n style={{\n appearance: 'none',\n backgroundImage:\n \"url(\\\"data:image/svg+xml,%3Csvg width='12' height='8' viewBox='0 0 12 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%231D1D1F' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\\\")\",\n backgroundRepeat: 'no-repeat',\n backgroundPosition: 'right 12px center',\n paddingRight: '32px',\n }}\n >\n {allProducts.map(p => (\n <option key={p.shopifyId} value={p.shopifyId}>\n {p.title.length > 30 ? `${p.title.slice(0, 30)}...` : p.title}\n </option>\n ))}\n </select>\n </div>\n\n {/* \u4EA7\u54C1\u56FE\u7247 */}\n <a\n href={product.productUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mb-4 block w-full max-w-[160px]\"\n >\n <div className=\"aspect-square w-full overflow-hidden rounded-lg\">\n {product.imageUrl ? (\n <img\n src={product.imageUrl}\n alt={product.title}\n className=\"size-full object-contain\"\n loading=\"lazy\"\n />\n ) : (\n <div className=\"flex size-full items-center justify-center text-gray-400\">\n <svg className=\"size-12\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\"\n />\n </svg>\n </div>\n )}\n </div>\n </a>\n\n {/* \u4EF7\u683C\u5C55\u793A\uFF08\u5E26\u5212\u7EBF\u4EF7\uFF09 */}\n <div className=\"mb-4 flex flex-col items-center gap-1\">\n <div className=\"flex items-center gap-2\">\n {/* \u5F53\u524D\u4EF7\u683C\uFF08\u6298\u6263\u4EF7\u6216\u539F\u4EF7\uFF09 */}\n <span className=\"text-base font-bold leading-[1.2] tracking-[-0.02em] text-[#1D1D1F]\">\n {formatPrice(currentPrice, priceInfo?.currency || product.price.currency)}\n </span>\n {/* \u5212\u7EBF\u4EF7 - \u4EC5\u5728\u6709\u6298\u6263\u65F6\u663E\u793A */}\n {hasDiscount && discountPrice && (\n <span className=\"text-base font-bold leading-[1.2] tracking-[-0.02em] text-[#4A4C56] line-through\">\n {formatPrice(originalPrice, product.price.currency)}\n </span>\n )}\n </div>\n </div>\n\n {/* Add to Cart \u6309\u94AE */}\n {onAddToCart && (\n <button\n type=\"button\"\n onClick={handleAddToCart}\n className=\"mb-3 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white\"\n style={{ backgroundColor: '#1D1D1F' }}\n >\n Add to Cart\n </button>\n )}\n\n {/* \u989C\u8272\u9009\u9879\uFF08\u5982\u679C\u6709variants\uFF09 */}\n {product.variants && product.variants.length > 1 && (\n <div className=\"flex gap-2\">\n {product.variants.slice(0, 3).map((variant, idx) => (\n <div\n key={variant.id || idx}\n className=\"size-6 rounded-full border-2 border-[#DADCE0]\"\n style={{ backgroundColor: variant.color || '#000' }}\n title={variant.title}\n />\n ))}\n </div>\n )}\n </div>\n )\n })}\n </div>\n\n {/* \u5BF9\u6BD4\u8868\u683C\u533A\u57DF */}\n <div className=\"flex flex-col gap-4 p-4\">\n {/* \u904D\u5386\u6240\u6709\u7EF4\u5EA6\u5E76\u6E32\u67D3 */}\n {Object.entries(dimensions).map(([key, dimension]) => {\n if (!dimension || key === 'price') return null // price \u5DF2\u5728\u9876\u90E8\u663E\u793A\n return <div key={key}>{renderComparisonRow(dimension.label, dimension)}</div>\n })}\n </div>\n </div>\n )\n}\n\n/**\n * \u521B\u5EFA\u4EA7\u54C1\u5BF9\u6BD4\u6E32\u67D3\u5668\n */\nexport const ProductComparisonRenderer: MessageRenderer = {\n render: (content, isUser, isSystem) => {\n if (content.type !== 'product_comparison' || !content.data) {\n return null\n }\n\n const comparisonData = content.data as ProductComparisonData & { onAddToCart?: (product: Product) => void }\n\n return (\n <ProductComparison\n data={comparisonData}\n isUser={isUser}\n isSystem={isSystem}\n onAddToCart={comparisonData.onAddToCart}\n />\n )\n },\n}\n"],
5
- "mappings": "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",
6
- "names": ["jsx", "jsxs", "useState", "formatPrice", "amount", "currency", "ProductComparison", "data", "onAddToCart", "rawProducts", "dimensions", "allProducts", "p", "COMPARISON_COLUMNS", "initialSelectedProducts", "selectedProducts", "setSelectedProducts", "handleProductChange", "index", "productId", "newProduct", "newSelectedProducts", "products", "getDimensionValue", "dimension", "v", "renderComparisonRow", "label", "product", "value", "renderDimensionValue", "dimensionLabel", "priceDisplay", "priceInfo", "firstVariant", "hasDiscount", "discountPrice", "currentPrice", "originalPrice", "handleAddToCart", "e", "variant", "idx", "key", "ProductComparisonRenderer", "content", "isUser", "isSystem", "comparisonData"]
4
+ "sourcesContent": ["/**\n * \u4EA7\u54C1\u5BF9\u6BD4\u7EC4\u4EF6\n * \u663E\u793A\u591A\u4E2A\u4EA7\u54C1\u7684\u5BF9\u6BD4\u4FE1\u606F\uFF0C\u91C7\u7528\u8868\u683C\u5E03\u5C40\u5C55\u793A\u5404\u7EF4\u5EA6\u5DEE\u5F02\n * \u57FA\u4E8E\u53C2\u8003\u8BBE\u8BA1\uFF1A\u9876\u90E8\u4EA7\u54C1\u5C55\u793A + \u5E95\u90E8\u5BF9\u6BD4\u8868\u683C\n */\n\nimport React, { useState } from 'react'\nimport type { Product, MessageRenderer, CommonText } from '../../types'\nimport { DEFAULT_COMMON_TEXT, CURRENCY_SYMBOLS } from '../../constants'\n\n/**\n * \u5BF9\u6BD4\u7EF4\u5EA6\u6570\u636E\u7ED3\u6784\n */\ninterface ComparisonDimension {\n label: string\n values: Array<{\n product_id: string\n [key: string]: any\n }>\n}\n\n/**\n * \u4EA7\u54C1\u5BF9\u6BD4\u6570\u636E\u7ED3\u6784\n */\nexport interface ProductComparisonData {\n products: Product[]\n dimensions: {\n price?: ComparisonDimension\n variants?: ComparisonDimension\n member_price?: ComparisonDimension\n discount?: ComparisonDimension\n reviews?: ComparisonDimension\n [key: string]: ComparisonDimension | undefined\n }\n commonText?: CommonText\n}\n\nexport interface ProductComparisonProps {\n /**\n * \u4EA7\u54C1\u5BF9\u6BD4\u6570\u636E\n */\n data: ProductComparisonData\n\n /**\n * \u662F\u5426\u4E3A\u7528\u6237\u6D88\u606F\n */\n isUser?: boolean\n\n /**\n * \u662F\u5426\u4E3A\u7CFB\u7EDF\u6D88\u606F\n */\n isSystem?: boolean\n\n /**\n * \u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u56DE\u8C03\n */\n onAddToCart?: (product: Product) => void\n\n /**\n * \u901A\u7528\u6587\u6848\u914D\u7F6E\n */\n commonText?: CommonText\n}\n\n/**\n * \u683C\u5F0F\u5316\u4EF7\u683C\u663E\u793A\n */\nconst formatPrice = (amount: number, currency: string = 'USD'): string => {\n const symbol = CURRENCY_SYMBOLS[currency] || currency\n return `${symbol}${amount}`\n}\n\n/**\n * \u4EA7\u54C1\u5BF9\u6BD4\u7EC4\u4EF6\n *\n * \u5E03\u5C40\uFF1A\n * ```\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u4EA7\u54C11\u56FE\u7247] [\u4EA7\u54C12\u56FE\u7247] \u2502\n * \u2502 \u4EF7\u683C1 \u4EF7\u683C2 \u2502\n * \u2502 \u989C\u8272\u9009\u9879 \u989C\u8272\u9009\u9879 \u2502\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 \u7EF4\u5EA61 \u2502 \u503C1-1 \u2502 \u503C1-2 \u2502\n * \u2502 \u7EF4\u5EA62 \u2502 \u503C2-1 \u2502 \u503C2-2 \u2502\n * \u2502 \u7EF4\u5EA63 \u2502 \u503C3-1 \u2502 \u503C3-2 \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * ```\n */\nexport const ProductComparison: React.FC<ProductComparisonProps> = ({ data, onAddToCart, commonText }) => {\n const { products: rawProducts, dimensions } = data\n\n // \u5408\u5E76\u9ED8\u8BA4\u6587\u6848\u548C\u81EA\u5B9A\u4E49\u6587\u6848\n const mergedText = { ...DEFAULT_COMMON_TEXT, ...commonText }\n\n // \u8FC7\u6EE4\u6389 null \u6216\u65E0\u6548\u7684\u4EA7\u54C1\n const allProducts = rawProducts?.filter(p => p && p.shopifyId) || []\n\n // \u5BF9\u6BD4\u5217\u6570\uFF08\u56FA\u5B9A\u4E3A2\u5217\uFF09\n const COMPARISON_COLUMNS = 2\n\n // \u521D\u59CB\u5316\u6BCF\u4E2A\u5BF9\u6BD4\u4F4D\u7F6E\u7684\u9009\u4E2D\u4EA7\u54C1\uFF08\u9ED8\u8BA4\u53D6\u524D\u4E24\u4E2A\u4EA7\u54C1\uFF09\n const initialSelectedProducts = allProducts.slice(0, COMPARISON_COLUMNS)\n const [selectedProducts, setSelectedProducts] = useState<Product[]>(initialSelectedProducts)\n\n // Early return \u5FC5\u987B\u5728\u6240\u6709 hooks \u4E4B\u540E\n if (allProducts.length === 0) {\n return null\n }\n\n // \u5904\u7406\u4EA7\u54C1\u9009\u62E9\u53D8\u66F4\n const handleProductChange = (index: number, productId: string) => {\n const newProduct = allProducts.find(p => p.shopifyId === productId)\n if (newProduct) {\n const newSelectedProducts = [...selectedProducts]\n newSelectedProducts[index] = newProduct\n setSelectedProducts(newSelectedProducts)\n }\n }\n\n // \u5F53\u524D\u663E\u793A\u7684\u4EA7\u54C1\uFF08\u786E\u4FDD\u53EA\u663E\u793A\u6307\u5B9A\u5217\u6570\uFF09\n const products = selectedProducts.slice(0, COMPARISON_COLUMNS)\n\n /**\n * \u83B7\u53D6\u6307\u5B9A\u4EA7\u54C1\u5728\u67D0\u4E2A\u7EF4\u5EA6\u7684\u503C\n */\n const getDimensionValue = (dimension: ComparisonDimension, productId: string): any => {\n if (!dimension || !dimension.values || !Array.isArray(dimension.values)) {\n return null\n }\n return dimension.values.find(v => v && v.product_id === productId)\n }\n\n /**\n * \u6E32\u67D3\u901A\u7528\u5BF9\u6BD4\u884C\n */\n const renderComparisonRow = (label: string, dimension: ComparisonDimension | undefined) => {\n if (!dimension) return null\n\n return (\n <div className=\"border-b border-[#DADCE0] pb-2\">\n {/* \u7EF4\u5EA6\u6807\u7B7E\uFF08\u6807\u9898\uFF09 */}\n <div className=\"mb-1\">\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#86868C]\">{label==='price'?'has member price':label}</span>\n </div>\n\n {/* \u4EA7\u54C1\u503C\u5217\u8868\uFF08\u6A2A\u5411\u6392\u5217\uFF09 */}\n <div className=\"flex gap-4\" style={{ gap: '36px' }}>\n {products.map((product, index) => {\n if (!product || !product.shopifyId) return null\n const value = getDimensionValue(dimension, product.shopifyId)\n\n return (\n <div key={`comparison-${index}`} className=\"flex-1\">\n {renderDimensionValue(value, dimension.label)}\n </div>\n )\n })}\n </div>\n </div>\n )\n }\n\n /**\n * \u6E32\u67D3\u7EF4\u5EA6\u503C\n */\n const renderDimensionValue = (value: any, dimensionLabel: string) => {\n if (!value) {\n return <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">-</span>\n }\n\n // \u6839\u636E\u4E0D\u540C\u7EF4\u5EA6\u7C7B\u578B\u6E32\u67D3\u4E0D\u540C\u683C\u5F0F\n if (dimensionLabel.toLowerCase().includes('price')) {\n const hasMemberPrice = value?.has_member_price\n // \u4EF7\u683C\u7EF4\u5EA6\n const priceDisplay = value?.available?\n value.min === value.max\n ? formatPrice(value.min, value.currency)\n : `${formatPrice(value.min, value.currency)} - ${formatPrice(value.max, value.currency)}`:'-'\n return <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">{hasMemberPrice?'Yes':'No'}</span>\n }\n\n if (dimensionLabel.toLowerCase().includes('variant')) {\n // \u53D8\u4F53\u6570\u91CF\n return (\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n {value.count || 0} {value.count === 1 ? 'variant' : 'variants'}\n </span>\n )\n }\n\n if (dimensionLabel.toLowerCase().includes('review')) {\n // \u8BC4\u8BBA\u7EF4\u5EA6\uFF1A\u663E\u793A\u8BC4\u5206\u548C\u6570\u91CF\n const rating = value.rating || 0\n const count = value.count || 0\n return (\n <div className=\"flex items-center gap-1\">\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n \u2B50 {rating.toFixed(1)}\n </span>\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#86868C]\">\n ({count})\n </span>\n </div>\n )\n }\n\n // \u9ED8\u8BA4\u663E\u793A\n return (\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n {value.display || value.value || '-'}\n </span>\n )\n }\n\n return (\n <div className=\"w-full overflow-hidden rounded-2xl bg-[#F5F6F7]\">\n {/* \u9876\u90E8\u4EA7\u54C1\u5C55\u793A\u533A\u57DF */}\n <div className=\"flex p-4\" style={{ gap: '36px', paddingBottom: '0px' }}>\n {products.map((product, index) => {\n if (!product || !product.shopifyId) return null\n\n // \u83B7\u53D6\u4EF7\u683C\u4FE1\u606F\n const priceInfo = dimensions.price ? getDimensionValue(dimensions.price, product.shopifyId) : null\n\n // \u83B7\u53D6\u6298\u6263\u4FE1\u606F\n const firstVariant = product.variants?.[0]\n const hasDiscount = firstVariant?.discount?.has_discount\n const discountPrice = hasDiscount ? firstVariant?.discount?.discount_price : null\n\n // \u5F53\u524D\u663E\u793A\u4EF7\u683C\uFF1A\u6709\u6298\u6263\u65F6\u663E\u793A\u6298\u6263\u4EF7\uFF0C\u5426\u5219\u663E\u793A\u539F\u4EF7\n const currentPrice = discountPrice || priceInfo?.min || product.price.amount\n const originalPrice = product.price.amount\n\n // Add to Cart \u6309\u94AE\u70B9\u51FB\u5904\u7406\n const handleAddToCart = (e: React.MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n if (onAddToCart) {\n onAddToCart(product)\n }\n }\n\n return (\n <div key={`product-column-${index}`} className=\"flex flex-1 flex-col items-center\">\n {/* \u4EA7\u54C1\u9009\u62E9\u4E0B\u62C9\u6846 */}\n <div className=\"mb-4 w-full\">\n <select\n value={product.shopifyId}\n onChange={e => handleProductChange(index, e.target.value)}\n className=\"w-full rounded-lg border border-[#DADCE0] bg-[#F5F6F7] px-3 py-2 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\"\n style={{\n appearance: 'none',\n backgroundImage:\n \"url(\\\"data:image/svg+xml,%3Csvg width='12' height='8' viewBox='0 0 12 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%231D1D1F' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\\\")\",\n backgroundRepeat: 'no-repeat',\n backgroundPosition: 'right 12px center',\n paddingRight: '32px',\n }}\n >\n {allProducts.map(p => (\n <option key={p.shopifyId} value={p.shopifyId}>\n {p.title.length > 30 ? `${p.title.slice(0, 30)}...` : p.title}\n </option>\n ))}\n </select>\n </div>\n\n {/* \u4EA7\u54C1\u56FE\u7247 */}\n <a\n href={product.productUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mb-4 block w-full max-w-[160px]\"\n >\n <div className=\"aspect-square w-full overflow-hidden rounded-lg\">\n {product.imageUrl ? (\n <img\n src={product.imageUrl}\n alt={product.title}\n className=\"size-full object-contain\"\n loading=\"lazy\"\n />\n ) : (\n <div className=\"flex size-full items-center justify-center text-gray-400\">\n <svg className=\"size-12\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\"\n />\n </svg>\n </div>\n )}\n </div>\n </a>\n\n {/* \u4EF7\u683C\u5C55\u793A\uFF08\u5E26\u5212\u7EBF\u4EF7\uFF09 */}\n <div className=\"mb-4 flex flex-col items-center gap-1\">\n <div className=\"flex items-center gap-2\">\n {/* \u5F53\u524D\u4EF7\u683C\uFF08\u6298\u6263\u4EF7\u6216\u539F\u4EF7\uFF09 */}\n <span className=\"text-base font-bold leading-[1.2] tracking-[-0.02em] text-[#1D1D1F]\">\n {formatPrice(currentPrice, priceInfo?.currency || product.price.currency)}\n </span>\n {/* \u5212\u7EBF\u4EF7 - \u4EC5\u5728\u6709\u6298\u6263\u65F6\u663E\u793A */}\n {hasDiscount && discountPrice && (\n <span className=\"text-base font-bold leading-[1.2] tracking-[-0.02em] text-[#4A4C56] line-through\">\n {formatPrice(originalPrice, product.price.currency)}\n </span>\n )}\n </div>\n </div>\n\n {/* Add to Cart \u6309\u94AE */}\n {onAddToCart && (\n <button\n type=\"button\"\n onClick={handleAddToCart}\n className=\"mb-3 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white\"\n style={{ backgroundColor: '#1D1D1F' }}\n >\n {mergedText.addToCart}\n </button>\n )}\n\n {/* \u989C\u8272\u9009\u9879\uFF08\u5982\u679C\u6709variants\uFF09 */}\n {product.variants && product.variants.length > 1 && (\n <div className=\"flex gap-2\">\n {product.variants.slice(0, 3).map((variant, idx) => (\n <div\n key={variant.id || idx}\n className=\"size-6 rounded-full border-2 border-[#DADCE0]\"\n style={{ backgroundColor: variant.color || '#000' }}\n title={variant.title}\n />\n ))}\n </div>\n )}\n </div>\n )\n })}\n </div>\n\n {/* \u5BF9\u6BD4\u8868\u683C\u533A\u57DF */}\n <div className=\"flex flex-col gap-4 p-4\">\n {/* \u904D\u5386\u6240\u6709\u7EF4\u5EA6\u5E76\u6E32\u67D3 */}\n {Object.entries(dimensions).map(([key, dimension]) => {\n if (!dimension) return null // price \u5DF2\u5728\u9876\u90E8\u663E\u793A\n return <div key={key}>{renderComparisonRow(dimension.label, dimension)}</div>\n })}\n </div>\n </div>\n )\n}\n\n/**\n * \u521B\u5EFA\u4EA7\u54C1\u5BF9\u6BD4\u6E32\u67D3\u5668\n */\nexport const ProductComparisonRenderer: MessageRenderer = {\n render: (content, isUser, isSystem) => {\n if (content.type !== 'product_comparison' || !content.data) {\n return null\n }\n\n const comparisonData = content.data as ProductComparisonData & { onAddToCart?: (product: Product) => void }\n\n return (\n <ProductComparison\n data={comparisonData}\n isUser={isUser}\n isSystem={isSystem}\n onAddToCart={comparisonData.onAddToCart}\n commonText={comparisonData.commonText}\n />\n )\n },\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["jsx", "jsxs", "useState", "DEFAULT_COMMON_TEXT", "CURRENCY_SYMBOLS", "formatPrice", "amount", "currency", "ProductComparison", "data", "onAddToCart", "commonText", "rawProducts", "dimensions", "mergedText", "allProducts", "p", "COMPARISON_COLUMNS", "initialSelectedProducts", "selectedProducts", "setSelectedProducts", "handleProductChange", "index", "productId", "newProduct", "newSelectedProducts", "products", "getDimensionValue", "dimension", "v", "renderComparisonRow", "label", "product", "value", "renderDimensionValue", "dimensionLabel", "hasMemberPrice", "priceDisplay", "rating", "count", "priceInfo", "firstVariant", "hasDiscount", "discountPrice", "currentPrice", "originalPrice", "handleAddToCart", "e", "variant", "idx", "key", "ProductComparisonRenderer", "content", "isUser", "isSystem", "comparisonData"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{jsx as t,jsxs as c}from"react/jsx-runtime";import{useState as C}from"react";import{CURRENCY_SYMBOLS as y}from"../../constants.js";function b(e){const{amount:n,currency:o}=e;return`${y[o]||o}${n.toFixed(2)}`}function P(e,n){if(!e.discount_type||e.discount_value===void 0)return"";const o=typeof e.discount_value=="string"?parseFloat(e.discount_value):e.discount_value;return isNaN(o)?"":e.discount_type==="percentage"?`${Math.round(o)}% OFF`:e.discount_type==="fixed_amount"?`${y[n]||n}${Math.round(o)} OFF`:""}const F=({product:e,onAddToCart:n})=>{const{title:o,description:s,price:r,imageUrl:i,productUrl:d,stockStatus:u,averageRating:l,variants:a}=e,f=u==="out_of_stock",p=a?.[0],m=p?.discount?.has_discount,g=m?p?.discount?.discount_price:null,x=p?.discount,N=g?{amount:g,currency:r.currency}:r,v=x&&m?P(x,r.currency):"",k=h=>{h.preventDefault(),h.stopPropagation(),n&&n(e)};return t("div",{className:"block w-full overflow-hidden rounded-2xl bg-[#F5F6F7] transition-shadow hover:shadow-md",children:t("a",{href:d,target:"_blank",rel:"noopener noreferrer",className:"block",children:c("div",{className:"flex gap-2 p-4",children:[t("div",{className:" flex shrink-0 items-center overflow-hidden rounded-md ",style:{width:"40%"},children:t("img",{src:i,alt:o,className:`h-auto w-full object-cover ${f?"opacity-50":""}`,loading:"lazy"})}),c("div",{className:"flex flex-1 flex-col justify-center gap-0.5",children:[v&&t("div",{className:"mb-1 w-fit rounded-full px-2 text-sm font-bold leading-none tracking-[-0.04em] text-white",style:{backgroundColor:"#005D8E",paddingTop:"6px",paddingBottom:"4px"},children:v}),t("h4",{className:"line-clamp-2 text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]",children:o}),s&&t("p",{className:"line-clamp-2 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:s}),c("div",{className:"mt-4 flex items-center gap-2",children:[c("div",{className:"flex items-center gap-1",children:[t("span",{className:"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:b(N)}),m&&t("span",{className:"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#6D6D6F] line-through",children:b(r)})]}),l!==void 0&&c("div",{className:"flex items-center gap-0.5 text-xs text-gray-600",children:[t("span",{className:"text-yellow-500",children:"\u2B50"}),t("span",{children:l.toFixed(1)})]})]}),t("button",{type:"button",onClick:k,className:"mt-2 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white",style:{backgroundColor:"#1D1D1F"},children:"Add to Cart"})]})]})})})},_=({products:e,title:n,onAddToCart:o})=>{const[s,r]=C(!1),i=e.filter(a=>a&&a.shopifyId),d=3,u=i.length>d,l=s?i:i.slice(0,d);return c("div",{className:"flex w-full flex-col gap-2",children:[n&&t("h3",{className:"text-sm font-semibold text-gray-900",children:n}),t("div",{className:"flex flex-col gap-1.5",children:l.map((a,f)=>!a||!a.shopifyId?null:t(F,{product:a,onAddToCart:o},a.shopifyId))}),u&&c("button",{type:"button",onClick:()=>r(!s),className:"flex items-center justify-center gap-1.5 px-3 py-2 text-[14px] font-bold leading-[1.2] tracking-tighter text-[#080A0F]",children:[t("span",{children:s?"Show Less":"Learn More"}),t("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:`transition-transform ${s?"rotate-180":""}`,children:t("polyline",{points:"6 9 12 15 18 9"})})]})]})},A={render:e=>{const n=e,{products:o,title:s,onAddToCart:r}=n.data,i=o?.filter(d=>d&&d.shopifyId)||[];return i.length===0?null:t(_,{products:i,title:s,onAddToCart:r})}};export{A as ProductList};
1
+ import{jsx as t,jsxs as c}from"react/jsx-runtime";import{useState as P}from"react";import{CURRENCY_SYMBOLS as C,DEFAULT_COMMON_TEXT as p}from"../../constants.js";function N(e){const{amount:o,currency:s}=e;return`${C[s]||s}${o.toFixed(2)}`}function _(e,o,s=p.off){if(!e.discount_type||e.discount_value===void 0)return"";const a=typeof e.discount_value=="string"?parseFloat(e.discount_value):e.discount_value;return isNaN(a)?"":e.discount_type==="percentage"?`${Math.round(a)}% ${s}`:e.discount_type==="fixed_amount"?`${C[o]||o}${Math.round(a)} ${s}`:""}const w=({product:e,onAddToCart:o,addToCartText:s=p.addToCart,offText:a=p.off})=>{const{title:r,description:l,price:n,imageUrl:d,stockStatus:u,averageRating:m,variants:f}=e,i=u==="out_of_stock",x=f?.[0],g=x?.discount?.has_discount,v=g?x?.discount?.discount_price:null,y=x?.discount,T=v?{amount:v,currency:n.currency}:n,h=y&&g?_(y,n.currency,a):"",k=b=>{b.preventDefault(),b.stopPropagation(),o&&o(e)};return t("div",{className:"block w-full overflow-hidden rounded-2xl bg-[#F5F6F7] transition-shadow",children:t("div",{className:"block",children:c("div",{className:"flex gap-2 p-4",children:[t("div",{className:" flex shrink-0 items-center overflow-hidden rounded-md ",style:{width:"40%"},children:t("img",{src:d,alt:r,className:`h-auto w-full object-cover ${i?"opacity-50":""}`,loading:"lazy"})}),c("div",{className:"flex flex-1 flex-col justify-center",children:[h&&t("div",{className:"mb-1 w-fit rounded-full px-2 text-sm font-bold leading-none tracking-[-0.04em] text-white",style:{backgroundColor:"#005D8E",paddingTop:"6px",paddingBottom:"4px"},children:h}),t("h4",{className:"line-clamp-2 text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]",children:r}),l&&t("p",{className:"line-clamp-2 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:l}),c("div",{className:"mt-4 flex items-center gap-2",children:[c("div",{className:"flex items-center gap-1",children:[t("span",{className:"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:N(T)}),g&&t("span",{className:"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#6D6D6F] line-through",children:N(n)})]}),m!==void 0&&c("div",{className:"flex items-center gap-0.5 text-xs text-gray-600",children:[t("span",{className:"text-yellow-500",children:"\u2B50"}),t("span",{children:m.toFixed(1)})]})]}),t("button",{type:"button",onClick:k,className:"mt-2 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white",style:{backgroundColor:"#1D1D1F"},children:s})]})]})})})},F=({products:e,title:o,onAddToCart:s,commonText:a})=>{const[r,l]=P(!1),n={...p,...a},d=e.filter(i=>i&&i.shopifyId),u=3,m=d.length>u,f=r?d:d.slice(0,u);return c("div",{className:"flex w-full flex-col gap-2",children:[o&&t("h3",{className:"text-sm font-semibold text-gray-900",children:o}),t("div",{className:"flex flex-col gap-1.5",children:f.map(i=>!i||!i.shopifyId?null:t(w,{product:i,onAddToCart:s,addToCartText:n.addToCart,offText:n.off},i.shopifyId))}),m&&c("button",{type:"button",onClick:()=>l(!r),className:"flex items-center justify-center gap-1.5 px-3 py-2 text-[14px] font-bold leading-[1.2] tracking-tighter text-[#080A0F]",children:[t("span",{children:r?n.showLess:n.learnMore}),t("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:`transition-transform ${r?"rotate-180":""}`,children:t("polyline",{points:"6 9 12 15 18 9"})})]})]})},M={render:e=>{const o=e,{products:s,title:a,onAddToCart:r,commonText:l}=o.data,n=s?.filter(d=>d&&d.shopifyId)||[];return n.length===0?null:t(F,{products:n,title:a,onAddToCart:r,commonText:l})}};export{M as ProductList};
2
2
  //# sourceMappingURL=ProductList.js.map