@anker-in/campaign-ui 0.4.2 → 0.4.3-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/LiveChatWidget/components/ChatInput.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/ChatInput.js.map +2 -2
- package/dist/cjs/components/LiveChatWidget/components/ChatMessage.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/ChatMessage.js.map +2 -2
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/CartCard.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/CartCard.js.map +2 -2
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductCard.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductCard.js.map +2 -2
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductComparison.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductComparison.js.map +2 -2
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductList.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductList.js.map +2 -2
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/TextBlock.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/TextBlock.js.map +2 -2
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js.map +2 -2
- package/dist/cjs/components/LiveChatWidget/utils/fetcher.js +1 -1
- package/dist/cjs/components/LiveChatWidget/utils/fetcher.js.map +3 -3
- package/dist/cjs/components/credits/modal/SubscribeModal.js +1 -1
- package/dist/cjs/components/credits/modal/SubscribeModal.js.map +3 -3
- package/dist/cjs/stories/LiveChatWidget.stories.js +2 -2
- package/dist/cjs/stories/LiveChatWidget.stories.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/components/ChatInput.js +1 -1
- package/dist/esm/components/LiveChatWidget/components/ChatInput.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/components/ChatMessage.js +2 -2
- package/dist/esm/components/LiveChatWidget/components/ChatMessage.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/components/MessageContent/CartCard.js +1 -1
- package/dist/esm/components/LiveChatWidget/components/MessageContent/CartCard.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductCard.js +1 -1
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductCard.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductComparison.js +1 -1
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductComparison.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductList.js +1 -1
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductList.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/components/MessageContent/TextBlock.js +1 -1
- package/dist/esm/components/LiveChatWidget/components/MessageContent/TextBlock.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js +1 -1
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/utils/fetcher.js +1 -1
- package/dist/esm/components/LiveChatWidget/utils/fetcher.js.map +3 -3
- package/dist/esm/components/credits/modal/SubscribeModal.js +1 -1
- package/dist/esm/components/credits/modal/SubscribeModal.js.map +3 -3
- package/dist/esm/stories/LiveChatWidget.stories.js +1 -1
- package/dist/esm/stories/LiveChatWidget.stories.js.map +2 -2
- package/package.json +19 -19
- package/src/components/LiveChatWidget/components/ChatInput.tsx +2 -2
- package/src/components/LiveChatWidget/components/ChatMessage.tsx +1 -1
- package/src/components/LiveChatWidget/components/MessageContent/CartCard.tsx +7 -7
- package/src/components/LiveChatWidget/components/MessageContent/ProductCard.tsx +2 -2
- package/src/components/LiveChatWidget/components/MessageContent/ProductComparison.tsx +1 -1
- package/src/components/LiveChatWidget/components/MessageContent/ProductList.tsx +2 -2
- package/src/components/LiveChatWidget/components/MessageContent/TextBlock.tsx +2 -2
- package/src/components/LiveChatWidget/components/MessageContent/ThinkingBlock.tsx +3 -3
- package/src/components/LiveChatWidget/utils/fetcher.ts +3 -12
- package/src/components/credits/modal/SubscribeModal.tsx +1 -3
- package/src/stories/LiveChatWidget.stories.tsx +2 -2
- package/dist/cjs/stories/CartCard.stories.d.ts +0 -33
- package/dist/cjs/stories/CartCard.stories.js +0 -21
- package/dist/cjs/stories/CartCard.stories.js.map +0 -7
- package/dist/esm/stories/CartCard.stories.d.ts +0 -33
- package/dist/esm/stories/CartCard.stories.js +0 -21
- package/dist/esm/stories/CartCard.stories.js.map +0 -7
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/components/LiveChatWidget/components/MessageContent/ProductList.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * \u5546\u54C1\u5217\u8868\u6E32\u67D3\u5668\n * \u663E\u793A\u591A\u4E2A\u5546\u54C1\u7684\u7EB5\u5411\u5217\u8868\uFF0C\u652F\u6301\u5C55\u5F00/\u6536\u8D77\n * \u57FA\u4E8E specs/livechat-widget/data-model.md \u7684\u5546\u54C1\u6570\u636E\u6A21\u578B\n */\n\nimport React, { useState } from 'react'\nimport type { MessageRenderer, ProductListContent, 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\uFF08\u7528\u4E8E\u7EB5\u5411\u5217\u8868\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\">\n <div className=\"block\">\n <div className=\"flex gap-2 p-4\">\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=\"livechat-tag-product 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=\"livechat-btn-primary 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\u5217\u8868\u5185\u90E8\u7EC4\u4EF6\uFF08\u652F\u6301\u5C55\u5F00/\u6536\u8D77\uFF09\n */\nconst ProductListComponent: React.FC<{\n products: Product[]\n title?: string\n onAddToCart?: (product: Product) => void\n commonText?: CommonText\n}> = ({ products, title, onAddToCart, commonText }) => {\n const [isExpanded, setIsExpanded] = useState(false)\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 validProducts = products.filter(p => p && p.shopifyId)\n\n // \u9ED8\u8BA4\u663E\u793A\u524D3\u4E2A\u4EA7\u54C1\n const INITIAL_DISPLAY_COUNT = 3\n const hasMore = validProducts.length > INITIAL_DISPLAY_COUNT\n const displayedProducts = isExpanded ? validProducts : validProducts.slice(0, INITIAL_DISPLAY_COUNT)\n\n return (\n <div className=\"flex w-full flex-col gap-2\">\n {/* \u5217\u8868\u6807\u9898\uFF08\u53EF\u9009\uFF09 */}\n {title && <h3 className=\"text-sm font-semibold text-gray-900\">{title}</h3>}\n\n {/* \u7EB5\u5411\u6392\u5217\u7684\u5546\u54C1\u5217\u8868 */}\n <div className=\"flex flex-col gap-1.5\">\n {displayedProducts.map(product => {\n if (!product || !product.shopifyId) return null\n return (\n <CompactProductCard\n key={product.shopifyId}\n product={product}\n onAddToCart={onAddToCart}\n addToCartText={mergedText.addToCart}\n offText={mergedText.off}\n />\n )\n })}\n </div>\n\n {/* Learn More \u6309\u94AE */}\n {hasMore && (\n <button\n type=\"button\"\n onClick={() => setIsExpanded(!isExpanded)}\n className=\"flex items-center justify-center gap-1.5 px-3 py-2 text-[14px] font-bold leading-[1.2] tracking-tighter text-[#080A0F]\"\n >\n <span>{isExpanded ? mergedText.showLess : mergedText.learnMore}</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 )\n}\n\n/**\n * \u5546\u54C1\u5217\u8868\u6E32\u67D3\u5668\n *\n * \u529F\u80FD\uFF1A\n * - \u7EB5\u5411\u5C55\u793A\u591A\u4E2A\u5546\u54C1\n * - \u9ED8\u8BA4\u663E\u793A\u524D3\u4E2A\u4EA7\u54C1\n * - \u652F\u6301\u5C55\u5F00/\u6536\u8D77\u67E5\u770B\u5168\u90E8\n * - \u7D27\u51D1\u578B\u5361\u7247\u8BBE\u8BA1\n * - \u53EF\u9009\u6807\u9898\n *\n * \u5E03\u5C40\uFF1A\n * ```\n * \u6807\u9898\uFF08\u53EF\u9009\uFF09\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u56FE] \u5546\u54C1\u6807\u9898 \u2502\n * \u2502 $29.99 \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u56FE] \u5546\u54C1\u6807\u9898 \u2502\n * \u2502 $39.99 \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u56FE] \u5546\u54C1\u6807\u9898 \u2502\n * \u2502 $49.99 \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * [ Learn More \u2193 ]\n * ```\n *\n * @example\n * ```tsx\n * const content: ProductListContent = {\n * type: 'product_list',\n * data: {\n * title: '\u76F8\u5173\u5546\u54C1\u63A8\u8350',\n * products: [product1, product2, product3, product4, product5]\n * }\n * }\n * <ProductList.render(content, false, false) />\n * ```\n */\nexport const ProductList: MessageRenderer = {\n render: content => {\n const productListContent = content as ProductListContent\n const { products, title, onAddToCart, commonText } = productListContent.data\n\n // \u8FC7\u6EE4\u6389 null \u6216\u65E0\u6548\u7684\u4EA7\u54C1\n const validProducts = products?.filter(p => p && p.shopifyId) || []\n\n if (validProducts.length === 0) {\n return null\n }\n\n return (\n <ProductListComponent products={validProducts} title={title} onAddToCart={onAddToCart} commonText={commonText} />\n )\n },\n}\n"],
|
|
5
|
-
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,iBAAAE,IAAA,eAAAC,EAAAH,GA+FY,IAAAI,EAAA,6BAzFZC,EAAgC,iBAEhCC,EAAsD,8BAKtD,SAASC,EAAYC,EAAiC,CACpD,KAAM,CAAE,OAAAC,EAAQ,SAAAC,CAAS,EAAIF,EAG7B,MAAO,GADQ,mBAAiBE,CAAQ,GAAKA,CAC7B,GAAGD,EAAO,QAAQ,CAAC,CAAC,EACtC,CASA,SAASE,EACPC,EACAF,EACAG,EAAkB,sBAAoB,IAC9B,CACR,GAAI,CAACD,EAAS,eAAiBA,EAAS,iBAAmB,OACzD,MAAO,GAIT,MAAME,EACJ,OAAOF,EAAS,gBAAmB,SAAW,WAAWA,EAAS,cAAc,EAAIA,EAAS,eAE/F,OAAI,MAAME,CAAK,EACN,GAGLF,EAAS,gBAAkB,aACtB,GAAG,KAAK,MAAME,CAAK,CAAC,KAAKD,CAAO,GAGrCD,EAAS,gBAAkB,eAEtB,GADQ,mBAAiBF,CAAQ,GAAKA,CAC7B,GAAG,KAAK,MAAMI,CAAK,CAAC,IAAID,CAAO,GAG1C,EACT,CAKA,MAAME,EAKD,CAAC,CAAE,QAAAC,EAAS,YAAAC,EAAa,cAAAC,EAAgB,sBAAoB,UAAW,QAAAL,EAAU,sBAAoB,GAAI,IAAM,CACnH,KAAM,CAAE,MAAAM,EAAO,YAAAC,EAAa,MAAAZ,EAAO,SAAAa,EAAU,YAAAC,EAAa,cAAAC,EAAe,SAAAC,CAAS,EAAIR,EAEhFS,EAAeH,IAAgB,eAG/BI,EAAeF,IAAW,CAAC,EAC3BG,EAAcD,GAAc,UAAU,aACtCE,EAAgBD,EAAcD,GAAc,UAAU,eAAiB,KACvEd,EAAWc,GAAc,SAGzBG,EAAeD,EAAgB,CAAE,OAAQA,EAAe,SAAUpB,EAAM,QAAS,EAAIA,EAGrFsB,EAAgBlB,GAAYe,EAAchB,EAAoBC,EAAUJ,EAAM,SAAUK,CAAO,EAAI,GAEnGkB,EAAmBC,GAAwB,CAC/CA,EAAE,eAAe,EACjBA,EAAE,gBAAgB,EACdf,GACFA,EAAYD,CAAO,CAEvB,EAEA,SACE,OAAC,OAAI,UAAU,0EACb,mBAAC,OAAI,UAAU,QACb,oBAAC,OAAI,UAAU,iBAEb,oBAAC,OAAI,UAAU,0DAA0D,MAAO,CAAE,MAAO,KAAM,EAC7F,mBAAC,OACC,IAAKK,EACL,IAAKF,EACL,UAAW,8BAA8BM,EAAe,aAAe,EAAE,GACzE,QAAQ,OACV,EACF,KAGA,QAAC,OAAI,UAAU,sCAEZ,UAAAK,MACC,OAAC,OACC,UAAU,
|
|
4
|
+
"sourcesContent": ["/**\n * \u5546\u54C1\u5217\u8868\u6E32\u67D3\u5668\n * \u663E\u793A\u591A\u4E2A\u5546\u54C1\u7684\u7EB5\u5411\u5217\u8868\uFF0C\u652F\u6301\u5C55\u5F00/\u6536\u8D77\n * \u57FA\u4E8E specs/livechat-widget/data-model.md \u7684\u5546\u54C1\u6570\u636E\u6A21\u578B\n */\n\nimport React, { useState } from 'react'\nimport type { MessageRenderer, ProductListContent, 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\uFF08\u7528\u4E8E\u7EB5\u5411\u5217\u8868\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\">\n <div className=\"block\">\n <div className=\"flex gap-2 p-4\">\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\u5217\u8868\u5185\u90E8\u7EC4\u4EF6\uFF08\u652F\u6301\u5C55\u5F00/\u6536\u8D77\uFF09\n */\nconst ProductListComponent: React.FC<{\n products: Product[]\n title?: string\n onAddToCart?: (product: Product) => void\n commonText?: CommonText\n}> = ({ products, title, onAddToCart, commonText }) => {\n const [isExpanded, setIsExpanded] = useState(false)\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 validProducts = products.filter(p => p && p.shopifyId)\n\n // \u9ED8\u8BA4\u663E\u793A\u524D3\u4E2A\u4EA7\u54C1\n const INITIAL_DISPLAY_COUNT = 3\n const hasMore = validProducts.length > INITIAL_DISPLAY_COUNT\n const displayedProducts = isExpanded ? validProducts : validProducts.slice(0, INITIAL_DISPLAY_COUNT)\n\n return (\n <div className=\"flex w-full flex-col gap-2\">\n {/* \u5217\u8868\u6807\u9898\uFF08\u53EF\u9009\uFF09 */}\n {title && <h3 className=\"text-sm font-semibold text-gray-900\">{title}</h3>}\n\n {/* \u7EB5\u5411\u6392\u5217\u7684\u5546\u54C1\u5217\u8868 */}\n <div className=\"flex flex-col gap-1.5\">\n {displayedProducts.map(product => {\n if (!product || !product.shopifyId) return null\n return (\n <CompactProductCard\n key={product.shopifyId}\n product={product}\n onAddToCart={onAddToCart}\n addToCartText={mergedText.addToCart}\n offText={mergedText.off}\n />\n )\n })}\n </div>\n\n {/* Learn More \u6309\u94AE */}\n {hasMore && (\n <button\n type=\"button\"\n onClick={() => setIsExpanded(!isExpanded)}\n className=\"flex items-center justify-center gap-1.5 px-3 py-2 text-[14px] font-bold leading-[1.2] tracking-tighter text-[#080A0F]\"\n >\n <span>{isExpanded ? mergedText.showLess : mergedText.learnMore}</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 )\n}\n\n/**\n * \u5546\u54C1\u5217\u8868\u6E32\u67D3\u5668\n *\n * \u529F\u80FD\uFF1A\n * - \u7EB5\u5411\u5C55\u793A\u591A\u4E2A\u5546\u54C1\n * - \u9ED8\u8BA4\u663E\u793A\u524D3\u4E2A\u4EA7\u54C1\n * - \u652F\u6301\u5C55\u5F00/\u6536\u8D77\u67E5\u770B\u5168\u90E8\n * - \u7D27\u51D1\u578B\u5361\u7247\u8BBE\u8BA1\n * - \u53EF\u9009\u6807\u9898\n *\n * \u5E03\u5C40\uFF1A\n * ```\n * \u6807\u9898\uFF08\u53EF\u9009\uFF09\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u56FE] \u5546\u54C1\u6807\u9898 \u2502\n * \u2502 $29.99 \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u56FE] \u5546\u54C1\u6807\u9898 \u2502\n * \u2502 $39.99 \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u56FE] \u5546\u54C1\u6807\u9898 \u2502\n * \u2502 $49.99 \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * [ Learn More \u2193 ]\n * ```\n *\n * @example\n * ```tsx\n * const content: ProductListContent = {\n * type: 'product_list',\n * data: {\n * title: '\u76F8\u5173\u5546\u54C1\u63A8\u8350',\n * products: [product1, product2, product3, product4, product5]\n * }\n * }\n * <ProductList.render(content, false, false) />\n * ```\n */\nexport const ProductList: MessageRenderer = {\n render: content => {\n const productListContent = content as ProductListContent\n const { products, title, onAddToCart, commonText } = productListContent.data\n\n // \u8FC7\u6EE4\u6389 null \u6216\u65E0\u6548\u7684\u4EA7\u54C1\n const validProducts = products?.filter(p => p && p.shopifyId) || []\n\n if (validProducts.length === 0) {\n return null\n }\n\n return (\n <ProductListComponent products={validProducts} title={title} onAddToCart={onAddToCart} commonText={commonText} />\n )\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["ProductList_exports", "__export", "ProductList", "__toCommonJS", "import_jsx_runtime", "import_react", "import_constants", "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", "ProductListComponent", "products", "commonText", "isExpanded", "setIsExpanded", "mergedText", "validProducts", "p", "INITIAL_DISPLAY_COUNT", "hasMore", "displayedProducts", "content", "productListContent"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var x=Object.create;var n=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var y=Object.getPrototypeOf,N=Object.prototype.hasOwnProperty;var f=(a,r)=>{for(var l in r)n(a,l,{get:r[l],enumerable:!0})},s=(a,r,l,d)=>{if(r&&typeof r=="object"||typeof r=="function")for(let t of g(r))!N.call(a,t)&&t!==l&&n(a,t,{get:()=>r[t],enumerable:!(d=i(r,t))||d.enumerable});return a};var m=(a,r,l)=>(l=a!=null?x(y(a)):{},s(r||!a||!a.__esModule?n(l,"default",{value:a,enumerable:!0}):l,a)),
|
|
1
|
+
"use strict";var x=Object.create;var n=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var y=Object.getPrototypeOf,N=Object.prototype.hasOwnProperty;var f=(a,r)=>{for(var l in r)n(a,l,{get:r[l],enumerable:!0})},s=(a,r,l,d)=>{if(r&&typeof r=="object"||typeof r=="function")for(let t of g(r))!N.call(a,t)&&t!==l&&n(a,t,{get:()=>r[t],enumerable:!(d=i(r,t))||d.enumerable});return a};var m=(a,r,l)=>(l=a!=null?x(y(a)):{},s(r||!a||!a.__esModule?n(l,"default",{value:a,enumerable:!0}):l,a)),p=a=>s(n({},"__esModule",{value:!0}),a);var u={};f(u,{TextBlock:()=>h});module.exports=p(u);var o=require("react/jsx-runtime"),b=m(require("react-markdown")),c=m(require("remark-gfm"));const h={render:(a,r,l)=>{const d=a;return d.text?(0,o.jsx)("div",{className:"livechat-markdown text-base md:text-sm",children:(0,o.jsx)(b.default,{remarkPlugins:[c.default],components:{a:({node:t,...e})=>(0,o.jsx)("a",{...e,className:`underline ${r?"text-blue-200 hover:text-blue-100":"text-blue-600 hover:text-blue-700"}`,target:"_blank",rel:"noopener noreferrer"}),code:({node:t,...e})=>e.inline?(0,o.jsx)("code",{...e,className:`rounded px-1.5 py-0.5 font-mono text-xs ${r?"bg-[#004A6E] text-white":"bg-gray-200 text-gray-800"}`}):(0,o.jsx)("code",{...e,className:`block overflow-x-auto rounded px-3 py-2 font-mono text-xs ${r?"bg-[#004A6E] text-white":"bg-gray-200 text-gray-800"}`}),p:({node:t,...e})=>(0,o.jsx)("p",{...e,className:"last:mb-0"}),ul:({node:t,...e})=>(0,o.jsx)("ul",{...e,className:"ml-4 list-disc"}),ol:({node:t,...e})=>(0,o.jsx)("ol",{...e,className:"mb-2 ml-4 list-decimal"}),li:({node:t,...e})=>(0,o.jsx)("li",{...e,className:"mb-1"}),h1:({node:t,...e})=>(0,o.jsx)("h1",{...e,className:"mb-2 font-bold"}),h2:({node:t,...e})=>(0,o.jsx)("h2",{...e,className:"mb-2 font-bold"}),h3:({node:t,...e})=>(0,o.jsx)("h3",{...e,className:"mb-1 font-bold"}),strong:({node:t,...e})=>(0,o.jsx)("strong",{...e,className:"font-bold"}),em:({node:t,...e})=>(0,o.jsx)("em",{...e,className:"italic"}),table:({node:t,...e})=>(0,o.jsx)("div",{className:"my-2 overflow-x-auto",children:(0,o.jsx)("table",{...e,className:"min-w-full border-collapse border border-gray-300 text-base md:text-sm"})}),thead:({node:t,...e})=>(0,o.jsx)("thead",{...e,className:"bg-gray-100"}),tbody:({node:t,...e})=>(0,o.jsx)("tbody",{...e}),tr:({node:t,...e})=>(0,o.jsx)("tr",{...e,className:"border-b border-gray-300"}),th:({node:t,...e})=>(0,o.jsx)("th",{...e,className:"border border-gray-300 px-3 py-2 text-left font-semibold"}),td:({node:t,...e})=>(0,o.jsx)("td",{...e,className:"border border-gray-300 px-3 py-2"})},children:d.text})}):null}};
|
|
2
2
|
//# sourceMappingURL=TextBlock.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/components/LiveChatWidget/components/MessageContent/TextBlock.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * \u6587\u672C\u6D88\u606F\u5185\u5BB9\u6E32\u67D3\u5668\n * \u652F\u6301 Markdown \u683C\u5F0F\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u6587\u672C\u6D88\u606F\u8BBE\u8BA1\n */\n\nimport React from 'react'\nimport ReactMarkdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\nimport type { MessageRenderer, TextContent } from '../../types'\n\n/**\n * \u6587\u672C\u6D88\u606F\u6E32\u67D3\u5668\n *\n * \u529F\u80FD\uFF1A\n * - \u652F\u6301 Markdown \u8BED\u6CD5\uFF08\u7C97\u4F53\u3001\u659C\u4F53\u3001\u94FE\u63A5\u3001\u5217\u8868\u7B49\uFF09\n * - \u5B89\u5168\u6E32\u67D3\uFF08React Markdown \u81EA\u52A8\u9632\u62A4 XSS\uFF09\n * - \u54CD\u5E94\u5F0F\u6587\u672C\u6837\u5F0F\n *\n * Markdown \u652F\u6301\uFF1A\n * - \u7C97\u4F53\uFF1A**text** \u6216 __text__\n * - \u659C\u4F53\uFF1A*text* \u6216 _text_\n * - \u94FE\u63A5\uFF1A[text](url)\n * - \u5217\u8868\uFF1A- item \u6216 1. item\n * - \u4EE3\u7801\uFF1A`code` \u6216 ```code block```\n *\n * @example\n * ```tsx\n * const content: TextContent = {\n * type: 'text',\n * text: '\u60A8\u597D\uFF01**\u8FD9\u662F\u7C97\u4F53**\uFF0C*\u8FD9\u662F\u659C\u4F53*\u3002'\n * }\n * <TextBlock.render(content, false, false) />\n * ```\n */\nexport const TextBlock: MessageRenderer = {\n render: (content, isUser, isSystem) => {\n const textContent = content as TextContent\n\n if (!textContent.text) {\n return null\n }\n\n return (\n <div className=\"livechat-markdown text-base md:text-sm\">\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n components={{\n // \u81EA\u5B9A\u4E49\u94FE\u63A5\u6837\u5F0F\n a: ({ node, ...props }) => (\n <a\n {...props}\n className={`underline ${isUser ? 'text-blue-200 hover:text-blue-100' : 'text-blue-600 hover:text-blue-700'}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n />\n ),\n // \u81EA\u5B9A\u4E49\u4EE3\u7801\u5757\u6837\u5F0F\n code: ({ node, ...props }: any) =>\n props.inline ? (\n <code\n {...props}\n className={`rounded px-1.5 py-0.5 font-mono text-xs ${isUser ? '
|
|
5
|
-
"mappings": "0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,eAAAE,IAAA,eAAAC,EAAAH,GAkDc,IAAAI,EAAA,6BA3CdC,EAA0B,6BAC1BC,EAAsB,yBA2Bf,MAAMJ,EAA6B,CACxC,OAAQ,CAACK,EAASC,EAAQC,IAAa,CACrC,MAAMC,EAAcH,EAEpB,OAAKG,EAAY,QAKf,OAAC,OAAI,UAAU,yCACb,mBAAC,EAAAC,QAAA,CACC,cAAe,CAAC,EAAAC,OAAS,EACzB,WAAY,CAEV,EAAG,CAAC,CAAE,KAAAC,EAAM,GAAGC,CAAM,OACnB,OAAC,KACE,GAAGA,EACJ,UAAW,aAAaN,EAAS,oCAAsC,mCAAmC,GAC1G,OAAO,SACP,IAAI,sBACN,EAGF,KAAM,CAAC,CAAE,KAAAK,EAAM,GAAGC,CAAM,IACtBA,EAAM,UACJ,OAAC,QACE,GAAGA,EACJ,UAAW,2CAA2CN,EAAS,
|
|
4
|
+
"sourcesContent": ["/**\n * \u6587\u672C\u6D88\u606F\u5185\u5BB9\u6E32\u67D3\u5668\n * \u652F\u6301 Markdown \u683C\u5F0F\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u6587\u672C\u6D88\u606F\u8BBE\u8BA1\n */\n\nimport React from 'react'\nimport ReactMarkdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\nimport type { MessageRenderer, TextContent } from '../../types'\n\n/**\n * \u6587\u672C\u6D88\u606F\u6E32\u67D3\u5668\n *\n * \u529F\u80FD\uFF1A\n * - \u652F\u6301 Markdown \u8BED\u6CD5\uFF08\u7C97\u4F53\u3001\u659C\u4F53\u3001\u94FE\u63A5\u3001\u5217\u8868\u7B49\uFF09\n * - \u5B89\u5168\u6E32\u67D3\uFF08React Markdown \u81EA\u52A8\u9632\u62A4 XSS\uFF09\n * - \u54CD\u5E94\u5F0F\u6587\u672C\u6837\u5F0F\n *\n * Markdown \u652F\u6301\uFF1A\n * - \u7C97\u4F53\uFF1A**text** \u6216 __text__\n * - \u659C\u4F53\uFF1A*text* \u6216 _text_\n * - \u94FE\u63A5\uFF1A[text](url)\n * - \u5217\u8868\uFF1A- item \u6216 1. item\n * - \u4EE3\u7801\uFF1A`code` \u6216 ```code block```\n *\n * @example\n * ```tsx\n * const content: TextContent = {\n * type: 'text',\n * text: '\u60A8\u597D\uFF01**\u8FD9\u662F\u7C97\u4F53**\uFF0C*\u8FD9\u662F\u659C\u4F53*\u3002'\n * }\n * <TextBlock.render(content, false, false) />\n * ```\n */\nexport const TextBlock: MessageRenderer = {\n render: (content, isUser, isSystem) => {\n const textContent = content as TextContent\n\n if (!textContent.text) {\n return null\n }\n\n return (\n <div className=\"livechat-markdown text-base md:text-sm\">\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n components={{\n // \u81EA\u5B9A\u4E49\u94FE\u63A5\u6837\u5F0F\n a: ({ node, ...props }) => (\n <a\n {...props}\n className={`underline ${isUser ? 'text-blue-200 hover:text-blue-100' : 'text-blue-600 hover:text-blue-700'}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n />\n ),\n // \u81EA\u5B9A\u4E49\u4EE3\u7801\u5757\u6837\u5F0F\n code: ({ node, ...props }: any) =>\n props.inline ? (\n <code\n {...props}\n className={`rounded px-1.5 py-0.5 font-mono text-xs ${isUser ? 'bg-[#004A6E] text-white' : 'bg-gray-200 text-gray-800'}`}\n />\n ) : (\n <code\n {...props}\n className={`block overflow-x-auto rounded px-3 py-2 font-mono text-xs ${isUser ? 'bg-[#004A6E] text-white' : 'bg-gray-200 text-gray-800'}`}\n />\n ),\n // \u81EA\u5B9A\u4E49\u6BB5\u843D\u6837\u5F0F\n p: ({ node, ...props }) => <p {...props} className=\"last:mb-0\" />,\n // \u81EA\u5B9A\u4E49\u5217\u8868\u6837\u5F0F\n ul: ({ node, ...props }) => <ul {...props} className=\"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 // \u81EA\u5B9A\u4E49\u6807\u9898\u6837\u5F0F\n h1: ({ node, ...props }) => <h1 {...props} className=\"mb-2 font-bold\" />,\n h2: ({ node, ...props }) => <h2 {...props} className=\"mb-2 font-bold\" />,\n h3: ({ node, ...props }) => <h3 {...props} className=\"mb-1 font-bold\" />,\n // \u81EA\u5B9A\u4E49\u5F3A\u8C03\u6837\u5F0F\n strong: ({ node, ...props }) => <strong {...props} className=\"font-bold\" />,\n em: ({ node, ...props }) => <em {...props} className=\"italic\" />,\n // \u8868\u683C\u6837\u5F0F\n table: ({ node, ...props }) => (\n <div className=\"my-2 overflow-x-auto\">\n <table {...props} className=\"min-w-full border-collapse border border-gray-300 text-base md:text-sm\" />\n </div>\n ),\n thead: ({ node, ...props }) => (\n <thead {...props} className=\"bg-gray-100\" />\n ),\n tbody: ({ node, ...props }) => <tbody {...props} />,\n tr: ({ node, ...props }) => (\n <tr {...props} className=\"border-b border-gray-300\" />\n ),\n th: ({ node, ...props }) => (\n <th {...props} className=\"border border-gray-300 px-3 py-2 text-left font-semibold\" />\n ),\n td: ({ node, ...props }) => (\n <td {...props} className=\"border border-gray-300 px-3 py-2\" />\n ),\n }}\n >\n {textContent.text}\n </ReactMarkdown>\n </div>\n )\n },\n}\n"],
|
|
5
|
+
"mappings": "0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,eAAAE,IAAA,eAAAC,EAAAH,GAkDc,IAAAI,EAAA,6BA3CdC,EAA0B,6BAC1BC,EAAsB,yBA2Bf,MAAMJ,EAA6B,CACxC,OAAQ,CAACK,EAASC,EAAQC,IAAa,CACrC,MAAMC,EAAcH,EAEpB,OAAKG,EAAY,QAKf,OAAC,OAAI,UAAU,yCACb,mBAAC,EAAAC,QAAA,CACC,cAAe,CAAC,EAAAC,OAAS,EACzB,WAAY,CAEV,EAAG,CAAC,CAAE,KAAAC,EAAM,GAAGC,CAAM,OACnB,OAAC,KACE,GAAGA,EACJ,UAAW,aAAaN,EAAS,oCAAsC,mCAAmC,GAC1G,OAAO,SACP,IAAI,sBACN,EAGF,KAAM,CAAC,CAAE,KAAAK,EAAM,GAAGC,CAAM,IACtBA,EAAM,UACJ,OAAC,QACE,GAAGA,EACJ,UAAW,2CAA2CN,EAAS,0BAA4B,2BAA2B,GACxH,KAEA,OAAC,QACE,GAAGM,EACJ,UAAW,6DAA6DN,EAAS,0BAA4B,2BAA2B,GAC1I,EAGJ,EAAG,CAAC,CAAE,KAAAK,EAAM,GAAGC,CAAM,OAAM,OAAC,KAAG,GAAGA,EAAO,UAAU,YAAY,EAE/D,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OAAM,OAAC,MAAI,GAAGA,EAAO,UAAU,iBAAiB,EACtE,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OAAM,OAAC,MAAI,GAAGA,EAAO,UAAU,yBAAyB,EAC9E,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OAAM,OAAC,MAAI,GAAGA,EAAO,UAAU,OAAO,EAE5D,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OAAM,OAAC,MAAI,GAAGA,EAAO,UAAU,iBAAiB,EACtE,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OAAM,OAAC,MAAI,GAAGA,EAAO,UAAU,iBAAiB,EACtE,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OAAM,OAAC,MAAI,GAAGA,EAAO,UAAU,iBAAiB,EAEtE,OAAQ,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OAAM,OAAC,UAAQ,GAAGA,EAAO,UAAU,YAAY,EACzE,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OAAM,OAAC,MAAI,GAAGA,EAAO,UAAU,SAAS,EAE9D,MAAO,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OACvB,OAAC,OAAI,UAAU,uBACb,mBAAC,SAAO,GAAGA,EAAO,UAAU,yEAAyE,EACvG,EAEF,MAAO,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OACvB,OAAC,SAAO,GAAGA,EAAO,UAAU,cAAc,EAE5C,MAAO,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OAAM,OAAC,SAAO,GAAGA,EAAO,EACjD,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OACpB,OAAC,MAAI,GAAGA,EAAO,UAAU,2BAA2B,EAEtD,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OACpB,OAAC,MAAI,GAAGA,EAAO,UAAU,2DAA2D,EAEtF,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OACpB,OAAC,MAAI,GAAGA,EAAO,UAAU,mCAAmC,CAEhE,EAEC,SAAAJ,EAAY,KACf,EACF,EAlEO,IAoEX,CACF",
|
|
6
6
|
"names": ["TextBlock_exports", "__export", "TextBlock", "__toCommonJS", "import_jsx_runtime", "import_react_markdown", "import_remark_gfm", "content", "isUser", "isSystem", "textContent", "ReactMarkdown", "remarkGfm", "node", "props"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var r=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var d=Object.prototype.hasOwnProperty;var g=(s,e)=>{for(var a in e)r(s,a,{get:e[a],enumerable:!0})},c=(s,e,a,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of l(e))!d.call(s,t)&&t!==a&&r(s,t,{get:()=>e[t],enumerable:!(o=i(e,t))||o.enumerable});return s};var p=s=>c(r({},"__esModule",{value:!0}),s);var k={};g(k,{ThinkingBlock:()=>u});module.exports=p(k);var n=require("react/jsx-runtime");const u={render:(s,e,a)=>{const t=s.data.status||"";return(0,n.jsx)("div",{className:"flex items-center gap-2 py-1",children:(0,n.jsxs)("div",{className:"livechat-thinking-dots flex gap-1",children:[(0,n.jsx)("span",{className:"size-2 rounded-full",style:{backgroundColor:"rgba(0, 93, 142, 1)"}}),(0,n.jsx)("span",{className:"size-2 rounded-full",style:{backgroundColor:"rgba(0, 93, 142, 0.6)"}}),(0,n.jsx)("span",{className:"size-2 rounded-full",style:{backgroundColor:"rgba(0, 93, 142, 0.2)"}})]})})}};
|
|
2
2
|
//# sourceMappingURL=ThinkingBlock.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/components/LiveChatWidget/components/MessageContent/ThinkingBlock.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * \u601D\u8003\u72B6\u6001\u6D88\u606F\u6E32\u67D3\u5668\n * \u663E\u793A AI \u52A9\u624B\u6B63\u5728\u601D\u8003\u7684\u52A8\u753B\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u601D\u8003\u72B6\u6001\u8BBE\u8BA1\n */\n\nimport React from 'react'\nimport type { MessageRenderer, ThinkingContent } from '../../types'\n\n/**\n * \u601D\u8003\u72B6\u6001\u6E32\u67D3\u5668\n *\n * \u529F\u80FD\uFF1A\n * - \u663E\u793A\"\u6B63\u5728\u601D\u8003...\"\u52A8\u753B\n * - \u4E09\u4E2A\u8DF3\u52A8\u7684\u5706\u70B9\n * - \u9EC4\u8272\u80CC\u666F\u63D0\u793A\n *\n * \u52A8\u753B\u6548\u679C\uFF1A\n * - \u4F7F\u7528 CSS \u52A8\u753B\uFF08livechat.css \u4E2D\u5B9A\u4E49\uFF09\n * - \u4E09\u4E2A\u5706\u70B9\u4F9D\u6B21\u8DF3\u52A8\n * - \u5FAA\u73AF\u64AD\u653E\n *\n * @example\n * ```tsx\n * const content: ThinkingContent = {\n * type: 'thinking',\n * data: {\n * status: '\u6B63\u5728\u67E5\u8BE2\u5546\u54C1\u4FE1\u606F...'\n * }\n * }\n * <ThinkingBlock.render(content, false, false) />\n * ```\n */\nexport const ThinkingBlock: MessageRenderer = {\n render: (content, isUser, isSystem) => {\n const thinkingContent = content as ThinkingContent\n const status = thinkingContent.data.status || ''\n\n return (\n <div className=\"flex items-center gap-2 py-1\">\n {/* \u601D\u8003\u52A8\u753B - \u4E09\u4E2A\u8DF3\u52A8\u7684\u70B9 */}\n <div className=\"livechat-thinking-dots flex gap-1\">\n <span className=\"
|
|
5
|
-
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,mBAAAE,IAAA,eAAAC,EAAAH,GAyCQ,IAAAI,EAAA,6BARD,MAAMF,EAAiC,CAC5C,OAAQ,CAACG,EAASC,EAAQC,IAAa,CAErC,MAAMC,EADkBH,EACO,KAAK,QAAU,GAE9C,SACE,OAAC,OAAI,UAAU,+BAEb,oBAAC,OAAI,UAAU,oCACb,oBAAC,QAAK,UAAU,
|
|
4
|
+
"sourcesContent": ["/**\n * \u601D\u8003\u72B6\u6001\u6D88\u606F\u6E32\u67D3\u5668\n * \u663E\u793A AI \u52A9\u624B\u6B63\u5728\u601D\u8003\u7684\u52A8\u753B\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u601D\u8003\u72B6\u6001\u8BBE\u8BA1\n */\n\nimport React from 'react'\nimport type { MessageRenderer, ThinkingContent } from '../../types'\n\n/**\n * \u601D\u8003\u72B6\u6001\u6E32\u67D3\u5668\n *\n * \u529F\u80FD\uFF1A\n * - \u663E\u793A\"\u6B63\u5728\u601D\u8003...\"\u52A8\u753B\n * - \u4E09\u4E2A\u8DF3\u52A8\u7684\u5706\u70B9\n * - \u9EC4\u8272\u80CC\u666F\u63D0\u793A\n *\n * \u52A8\u753B\u6548\u679C\uFF1A\n * - \u4F7F\u7528 CSS \u52A8\u753B\uFF08livechat.css \u4E2D\u5B9A\u4E49\uFF09\n * - \u4E09\u4E2A\u5706\u70B9\u4F9D\u6B21\u8DF3\u52A8\n * - \u5FAA\u73AF\u64AD\u653E\n *\n * @example\n * ```tsx\n * const content: ThinkingContent = {\n * type: 'thinking',\n * data: {\n * status: '\u6B63\u5728\u67E5\u8BE2\u5546\u54C1\u4FE1\u606F...'\n * }\n * }\n * <ThinkingBlock.render(content, false, false) />\n * ```\n */\nexport const ThinkingBlock: MessageRenderer = {\n render: (content, isUser, isSystem) => {\n const thinkingContent = content as ThinkingContent\n const status = thinkingContent.data.status || ''\n\n return (\n <div className=\"flex items-center gap-2 py-1\">\n {/* \u601D\u8003\u52A8\u753B - \u4E09\u4E2A\u8DF3\u52A8\u7684\u70B9 */}\n <div className=\"livechat-thinking-dots flex gap-1\">\n <span className=\"size-2 rounded-full\" style={{ backgroundColor: 'rgba(0, 93, 142, 1)' }} />\n <span className=\"size-2 rounded-full\" style={{ backgroundColor: 'rgba(0, 93, 142, 0.6)' }} />\n <span className=\"size-2 rounded-full\" style={{ backgroundColor: 'rgba(0, 93, 142, 0.2)' }} />\n </div>\n\n {/* \u72B6\u6001\u6587\u672C\uFF08\u53EF\u9009\uFF09 */}\n {/* {status && <span className=\"text-sm text-gray-500\">{status}</span>} */}\n </div>\n )\n },\n}\n"],
|
|
5
|
+
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,mBAAAE,IAAA,eAAAC,EAAAH,GAyCQ,IAAAI,EAAA,6BARD,MAAMF,EAAiC,CAC5C,OAAQ,CAACG,EAASC,EAAQC,IAAa,CAErC,MAAMC,EADkBH,EACO,KAAK,QAAU,GAE9C,SACE,OAAC,OAAI,UAAU,+BAEb,oBAAC,OAAI,UAAU,oCACb,oBAAC,QAAK,UAAU,sBAAsB,MAAO,CAAE,gBAAiB,qBAAsB,EAAG,KACzF,OAAC,QAAK,UAAU,sBAAsB,MAAO,CAAE,gBAAiB,uBAAwB,EAAG,KAC3F,OAAC,QAAK,UAAU,sBAAsB,MAAO,CAAE,gBAAiB,uBAAwB,EAAG,GAC7F,EAIF,CAEJ,CACF",
|
|
6
6
|
"names": ["ThinkingBlock_exports", "__export", "ThinkingBlock", "__toCommonJS", "import_jsx_runtime", "content", "isUser", "isSystem", "status"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var c=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var
|
|
1
|
+
"use strict";var c=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var w=(t,e)=>{for(var r in e)c(t,r,{get:e[r],enumerable:!0})},m=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of T(e))!y.call(t,i)&&i!==r&&c(t,i,{get:()=>e[i],enumerable:!(n=f(e,i))||n.enumerable});return t};var P=t=>m(c({},"__esModule",{value:!0}),t);var R={};w(R,{fetcher:()=>C});module.exports=P(R);const b=async(t,e)=>{if(typeof window>"u"||!window.grecaptcha?.enterprise?.execute)return console.warn("[LiveChat Fetcher] reCAPTCHA not loaded"),!1;try{return await window.grecaptcha.enterprise.execute(e,{action:t})}catch(r){return console.error("[LiveChat Fetcher] reCAPTCHA execution failed:",r),!1}};async function k(t,e,r="X-Recaptcha-Token"){const n=await b(t,e);return n?{[r]:n}:{}}const C=async({url:t,method:e="POST",headers:r={},body:n,timeout:i=9e4,needRecaptcha:h=!1,recaptchaSitekey:s,recaptchaAction:p="",recaptchaHeaderKey:u="X-Recaptcha-Token"})=>{let d={};h&&(s?d=await k(p,s,u):console.warn("[LiveChat Fetcher] needRecaptcha=true but recaptchaSitekey is missing"));const g=n?JSON.stringify(n):void 0,l=new AbortController;let a;i&&(a=setTimeout(()=>l.abort(),i));try{const o=await fetch(t,{method:e,mode:"cors",headers:{"Content-Type":"application/json",...r,...d},signal:l.signal,...e!=="GET"&&g&&{body:g}});return a&&clearTimeout(a),o}catch(o){throw a&&clearTimeout(a),o}};
|
|
2
2
|
//# sourceMappingURL=fetcher.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/components/LiveChatWidget/utils/fetcher.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * LiveChat Fetcher\n * \u53C2\u7167 storefront \u7684\u5B9E\u73B0\uFF0C\u652F\u6301 reCAPTCHA\n */\n\n/**\n * \u6267\u884C Google reCAPTCHA \u9A8C\u8BC1\n
|
|
5
|
-
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,IAAA,eAAAC,EAAAH,
|
|
6
|
-
"names": ["fetcher_exports", "__export", "fetcher", "__toCommonJS", "executeRecaptcha", "action", "sitekey", "
|
|
4
|
+
"sourcesContent": ["/**\n * LiveChat Fetcher\n * \u53C2\u7167 storefront \u7684\u5B9E\u73B0\uFF0C\u652F\u6301 reCAPTCHA\n */\n\n/**\n * \u6267\u884C Google reCAPTCHA \u9A8C\u8BC1\n */\nconst executeRecaptcha = async (action: string, sitekey: string): Promise<string | false> => {\n if (typeof window === 'undefined' || !window.grecaptcha?.enterprise?.execute) {\n console.warn('[LiveChat Fetcher] reCAPTCHA not loaded')\n return false\n }\n\n try {\n const token = await window.grecaptcha.enterprise.execute(sitekey, { action })\n return token\n } catch (error) {\n console.error('[LiveChat Fetcher] reCAPTCHA execution failed:', error)\n return false\n }\n}\n\n/**\n * \u83B7\u53D6 reCAPTCHA headers\n */\nasync function getRecaptchaHeaders(\n action: string,\n sitekey: string,\n headerKey = 'X-Recaptcha-Token'\n): Promise<Record<string, string>> {\n const recaptchaToken = await executeRecaptcha(action, sitekey)\n if (!recaptchaToken) {\n return {}\n }\n return {\n [headerKey]: recaptchaToken,\n }\n}\n\n/**\n * Fetcher \u53C2\u6570\n */\nexport interface FetcherOptions {\n url: string\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'\n headers?: Record<string, string>\n body?: any\n timeout?: number\n needRecaptcha?: boolean\n recaptchaSitekey?: string\n recaptchaAction?: string\n recaptchaHeaderKey?: string\n}\n\n/**\n * Fetcher \u51FD\u6570\n * \u652F\u6301 reCAPTCHA \u548C\u81EA\u5B9A\u4E49 headers\n */\nexport const fetcher = async ({\n url,\n method = 'POST',\n headers = {},\n body,\n timeout = 90000,\n needRecaptcha = false,\n recaptchaSitekey,\n recaptchaAction = '',\n recaptchaHeaderKey = 'X-Recaptcha-Token',\n}: FetcherOptions): Promise<Response> => {\n // \u83B7\u53D6 reCAPTCHA headers\uFF08\u5982\u679C\u9700\u8981\uFF09\n let recaptchaHeaders: Record<string, string> = {}\n if (needRecaptcha) {\n if (!recaptchaSitekey) {\n console.warn('[LiveChat Fetcher] needRecaptcha=true but recaptchaSitekey is missing')\n } else {\n recaptchaHeaders = await getRecaptchaHeaders(recaptchaAction, recaptchaSitekey, recaptchaHeaderKey)\n }\n }\n\n // \u51C6\u5907\u8BF7\u6C42\u4F53\n const bodyData = body ? JSON.stringify(body) : undefined\n\n const controller = new AbortController()\n let timeoutTimer: NodeJS.Timeout | undefined\n if (timeout) {\n timeoutTimer = setTimeout(() => controller.abort(), timeout)\n }\n\n try {\n const response = await fetch(url, {\n method,\n mode: 'cors',\n headers: {\n 'Content-Type': 'application/json',\n ...headers,\n ...recaptchaHeaders,\n },\n signal: controller.signal,\n ...(method !== 'GET' && bodyData && { body: bodyData }),\n })\n\n if (timeoutTimer) {\n clearTimeout(timeoutTimer)\n }\n\n return response\n } catch (error) {\n if (timeoutTimer) {\n clearTimeout(timeoutTimer)\n }\n throw error\n }\n}\n\n/**\n * \u6269\u5C55 Window \u63A5\u53E3\u4EE5\u652F\u6301 grecaptcha\n */\n declare global {\n interface Window {\n grecaptcha?: {\n execute: (sitekey: string, options: { action: string }) => Promise<string>\n ready: (callback: () => void) => void\n enterprise?: {\n execute: (sitekey: string, options: { action: string }) =>\n Promise<string>\n ready: (callback: () => void) => void\n }\n }\n }\n }\n"],
|
|
5
|
+
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,IAAA,eAAAC,EAAAH,GAQA,MAAMI,EAAmB,MAAOC,EAAgBC,IAA6C,CAC3F,GAAI,OAAO,OAAW,KAAe,CAAC,OAAO,YAAY,YAAY,QACnE,eAAQ,KAAK,yCAAyC,EAC/C,GAGT,GAAI,CAEF,OADc,MAAM,OAAO,WAAW,WAAW,QAAQA,EAAS,CAAE,OAAAD,CAAO,CAAC,CAE9E,OAASE,EAAO,CACd,eAAQ,MAAM,iDAAkDA,CAAK,EAC9D,EACT,CACF,EAKA,eAAeC,EACbH,EACAC,EACAG,EAAY,oBACqB,CACjC,MAAMC,EAAiB,MAAMN,EAAiBC,EAAQC,CAAO,EAC7D,OAAKI,EAGE,CACL,CAACD,CAAS,EAAGC,CACf,EAJS,CAAC,CAKZ,CAqBO,MAAMR,EAAU,MAAO,CAC5B,IAAAS,EACA,OAAAC,EAAS,OACT,QAAAC,EAAU,CAAC,EACX,KAAAC,EACA,QAAAC,EAAU,IACV,cAAAC,EAAgB,GAChB,iBAAAC,EACA,gBAAAC,EAAkB,GAClB,mBAAAC,EAAqB,mBACvB,IAAyC,CAEvC,IAAIC,EAA2C,CAAC,EAC5CJ,IACGC,EAGHG,EAAmB,MAAMZ,EAAoBU,EAAiBD,EAAkBE,CAAkB,EAFlG,QAAQ,KAAK,uEAAuE,GAOxF,MAAME,EAAWP,EAAO,KAAK,UAAUA,CAAI,EAAI,OAEzCQ,EAAa,IAAI,gBACvB,IAAIC,EACAR,IACFQ,EAAe,WAAW,IAAMD,EAAW,MAAM,EAAGP,CAAO,GAG7D,GAAI,CACF,MAAMS,EAAW,MAAM,MAAMb,EAAK,CAChC,OAAAC,EACA,KAAM,OACN,QAAS,CACP,eAAgB,mBAChB,GAAGC,EACH,GAAGO,CACL,EACA,OAAQE,EAAW,OACnB,GAAIV,IAAW,OAASS,GAAY,CAAE,KAAMA,CAAS,CACvD,CAAC,EAED,OAAIE,GACF,aAAaA,CAAY,EAGpBC,CACT,OAASjB,EAAO,CACd,MAAIgB,GACF,aAAaA,CAAY,EAErBhB,CACR,CACF",
|
|
6
|
+
"names": ["fetcher_exports", "__export", "fetcher", "__toCommonJS", "executeRecaptcha", "action", "sitekey", "error", "getRecaptchaHeaders", "headerKey", "recaptchaToken", "url", "method", "headers", "body", "timeout", "needRecaptcha", "recaptchaSitekey", "recaptchaAction", "recaptchaHeaderKey", "recaptchaHeaders", "bodyData", "controller", "timeoutTimer", "response"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var B=Object.create;var f=Object.defineProperty;var F=Object.getOwnPropertyDescriptor;var H=Object.getOwnPropertyNames;var
|
|
1
|
+
"use strict";var B=Object.create;var f=Object.defineProperty;var F=Object.getOwnPropertyDescriptor;var H=Object.getOwnPropertyNames;var R=Object.getPrototypeOf,q=Object.prototype.hasOwnProperty;var O=(e,t)=>{for(var r in t)f(e,r,{get:t[r],enumerable:!0})},N=(e,t,r,c)=>{if(t&&typeof t=="object"||typeof t=="function")for(let l of H(t))!q.call(e,l)&&l!==r&&f(e,l,{get:()=>t[l],enumerable:!(c=F(t,l))||c.enumerable});return e};var T=(e,t,r)=>(r=e!=null?B(R(e)):{},N(t||!e||!e.__esModule?f(r,"default",{value:e,enumerable:!0}):r,e)),U=e=>N(f({},"__esModule",{value:!0}),e);var G={};O(G,{CreditsSubscribeModal:()=>z});module.exports=U(G);var s=require("react/jsx-runtime"),a=require("react"),o=require("@anker-in/headless-ui"),i=require("@anker-in/lib"),n=T(require("js-cookie")),M=require("query-string"),w=T(require("crypto-js/sha256")),S=require("../context/provider"),E=require("../../../constants"),P=require("../context/utils"),k=require("./ModalContainer");const V=()=>{if(typeof window>"u")return{register_source:""};const{search:e,href:t}=window.location||{},r=(0,M.parse)(e);return{fbuy_ref_code:n.default.get("fbuy_ref_code"),affiliate:n.default.get("affiliate"),ref:n.default.get("ref_ads"),inviter_code:r.ic||r.inviter_code||n.default.get("inviter_code"),register_source:r.redirect||n.default.get("reg_source")||t,deals_type:n.default.get("deal"),transfer_id:n.default.get("transfer_id")}};function z({copy:e,onSuccess:t,...r}){const{brand:c,locale:l}=(0,i.useHeadlessContext)(),x=E.ROUNDED_BRANDS.includes(c),[m,A]=(0,a.useState)(!1),[d,h]=(0,a.useState)(""),[v,p]=(0,a.useState)(""),[_,C]=(0,a.useState)(""),[D,y]=(0,a.useState)(!1),{profile:u}=(0,S.useCreditsContext)(),I=(0,a.useCallback)(b=>{p(""),h(b.target?.value?.trim())},[]),L=(0,a.useCallback)(async()=>{if(p(""),!d)return p("Please fill in your email");if(!(0,P.emailValidate)(d))return p("Invalid email address");if(!m)return p("Please agree to the policy");y(!0);const{register_source:b}=V(),g=await(0,i.fetcher)({locale:l,action:"subscribe",url:"/api/multipass/subscribe/subscribe_emails",method:"POST",body:{email:d,register_source:b,brand:c,deals_type:e.dealsType||"vip_subscribe"},headers:{},type:""});y(!1),g.errors?p(g.errors||g.statusText):(C(e.successTips||"Subscribed successfully!"),t&&t(),setTimeout(()=>{C("")},3e3),(0,i.gaTrack)({subscribe_hashed_email:d?(0,w.default)(d):""}),(0,i.gaTrack)({event:"ga4Event",event_name:"subscribe",event_parameters:{page_group:e.dealsType||"vip_subscribe",position:"pop_up"}}),(0,i.gaTrack)({event:"uaEvent",eventCategory:"subscribe",eventAction:e.dealsType||"vip_subscribe",eventLabel:"pop_up",nonInteraction:!1}))},[d,m,l,c,e.dealsType,e.successTips,t]);return(0,a.useEffect)(()=>{u&&u?.email&&h(u?.email)},[u]),(0,s.jsx)(k.CreditsModalContainer,{className:"w-[540px] md:h-auto",scrollClassName:"mb-[40px] min-l:px-[48px] md:mb-[24px]",titleClassName:"h-[56px]",useAnimation:!0,animationClassName:"md:translate-y-[100vh]",...r,children:(0,s.jsxs)("div",{className:"flex flex-col gap-[16px] text-center min-l:px-[16px]",children:[(0,s.jsx)("div",{children:(0,s.jsx)(o.Text,{className:(0,i.classNames)("mb-[24px] text-[22px] font-bold"),html:e.title})}),e.desc&&(0,s.jsx)(o.Text,{className:"mb-[8px] text-left text-[16px] font-semibold leading-[1.4] text-[#1F2021]",html:e.desc}),(0,s.jsxs)("div",{className:(0,i.classNames)("relative flex h-[52px] w-full overflow-hidden rounded-[2px] md:grid md:h-auto md:grid-rows-1 md:gap-[16px]",!x&&"rounded-none"),children:[(0,s.jsx)("input",{className:(0,i.classNames)("h-full flex-1 rounded-l-[2px] border-[1px] border-[#d8d8d8] px-[14px] py-[17px] text-[16px] font-semibold leading-[1] outline-none placeholder:text-[#999] md:h-[52px] md:rounded-[2px]",!x&&"rounded-none"),placeholder:e.placeholder,value:d,onChange:I}),(0,s.jsx)(o.Button,{variant:"primary",onClick:L,loading:D,className:(0,i.classNames)("legacy-headless-ui-primary-button !h-full !min-w-0 !rounded-l-none !rounded-r-[2px] !px-[40px] !py-[13px]",!x&&"rounded-none"),children:(0,s.jsx)(o.Picture,{source:"https://cdn.shopify.com/s/files/1/0512/8568/8505/files/icon_email.png?v=1697527383",className:"h-[24px] w-[24px]",alt:"email"})})]}),(0,s.jsxs)("div",{className:"flex w-full",children:[(0,s.jsx)(o.Checkbox,{checked:m,onCheckedChange:()=>A(!m),required:!0,className:"border-[#1d1d1f]"}),(0,s.jsx)("label",{className:"text-left ml-2 text-[14px] font-semibold text-[#777] [&_a]:underline",dangerouslySetInnerHTML:{__html:e?.policy||""}})]}),(0,s.jsx)("div",{className:(0,i.classNames)("w-full text-left text-[16px] font-semibold",v&&"text-[#F84D4F]",_&&"text-[#52C41A]"),children:(0,s.jsx)(o.Text,{html:_||v||""})})]})})}
|
|
2
2
|
//# sourceMappingURL=SubscribeModal.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/components/credits/modal/SubscribeModal.tsx"],
|
|
4
|
-
"sourcesContent": ["import { useCallback, useEffect, useState } from 'react'\nimport {
|
|
5
|
-
"mappings": "0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,2BAAAE,IAAA,eAAAC,EAAAH,
|
|
6
|
-
"names": ["SubscribeModal_exports", "__export", "CreditsSubscribeModal", "__toCommonJS", "import_jsx_runtime", "import_react", "
|
|
4
|
+
"sourcesContent": ["import { useCallback, useEffect, useState } from 'react'\nimport { Button, Checkbox, Picture, Text } from '@anker-in/headless-ui'\nimport { classNames, fetcher, gaTrack, useHeadlessContext } from '@anker-in/lib'\nimport Cookies from 'js-cookie'\nimport { parse } from 'query-string'\nimport sha256 from 'crypto-js/sha256'\nimport { useCreditsContext } from '../context/provider'\nimport { ROUNDED_BRANDS } from '../../../constants'\nimport { emailValidate } from '../context/utils'\nimport { CreditsModalContainer, type ModalContainerProps } from './ModalContainer'\n\nexport type CreditsSubscribeModalCopy = {\n title: string\n desc?: string\n placeholder: string\n policy?: string\n successTips?: string\n dealsType?: string\n}\n\ninterface CreditsSubscribeModalProps extends ModalContainerProps {\n copy: CreditsSubscribeModalCopy\n onSuccess?: () => void\n}\n\nconst getAdCookie = () => {\n if (typeof window === 'undefined') {\n return { register_source: '' }\n }\n const { search, href } = window.location || {}\n const query = parse(search)\n\n return {\n fbuy_ref_code: Cookies.get('fbuy_ref_code'),\n affiliate: Cookies.get('affiliate'),\n ref: Cookies.get('ref_ads'),\n inviter_code: query.ic || query.inviter_code || Cookies.get('inviter_code'),\n register_source: query.redirect || Cookies.get('reg_source') || href,\n deals_type: Cookies.get('deal'),\n transfer_id: Cookies.get('transfer_id'),\n }\n}\n\nexport function CreditsSubscribeModal({ copy, onSuccess, ...props }: CreditsSubscribeModalProps) {\n const { brand, locale } = useHeadlessContext()\n const rounded = ROUNDED_BRANDS.includes(brand)\n const [policy, setPolicy] = useState(false)\n const [email, setEmail] = useState('')\n const [errorMessage, setErrorMessage] = useState('')\n const [successMessage, setSuccessMessage] = useState('')\n const [loading, setLoading] = useState(false)\n const { profile } = useCreditsContext()\n\n const handleEmailChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {\n setErrorMessage('')\n setEmail(event.target?.value?.trim())\n }, [])\n\n const handleSubmit = useCallback(async () => {\n setErrorMessage('')\n if (!email) {\n return setErrorMessage('Please fill in your email')\n }\n\n if (!emailValidate(email)) {\n return setErrorMessage('Invalid email address')\n }\n\n if (!policy) {\n return setErrorMessage('Please agree to the policy')\n }\n\n setLoading(true)\n const { register_source } = getAdCookie()\n\n const result = await fetcher({\n locale,\n action: 'subscribe',\n url: '/api/multipass/subscribe/subscribe_emails',\n method: 'POST',\n body: {\n email,\n register_source,\n brand,\n deals_type: copy.dealsType || 'vip_subscribe',\n },\n headers: {},\n type: '',\n })\n setLoading(false)\n\n if (!result.errors) {\n setSuccessMessage(copy.successTips || 'Subscribed successfully!')\n if (onSuccess) {\n onSuccess()\n }\n setTimeout(() => {\n setSuccessMessage('')\n }, 3000)\n gaTrack({\n subscribe_hashed_email: email ? sha256(email) : '',\n })\n gaTrack({\n event: 'ga4Event',\n event_name: 'subscribe',\n event_parameters: {\n page_group: copy.dealsType || 'vip_subscribe',\n position: 'pop_up',\n },\n })\n gaTrack({\n event: 'uaEvent',\n eventCategory: 'subscribe',\n eventAction: copy.dealsType || 'vip_subscribe',\n eventLabel: 'pop_up',\n nonInteraction: false,\n })\n } else {\n setErrorMessage(result.errors || result.statusText)\n }\n }, [email, policy, locale, brand, copy.dealsType, copy.successTips, onSuccess])\n\n useEffect(() => {\n if (profile && profile?.email) {\n setEmail(profile?.email)\n }\n }, [profile])\n\n return (\n <CreditsModalContainer\n className=\"w-[540px] md:h-auto\"\n scrollClassName=\"mb-[40px] min-l:px-[48px] md:mb-[24px]\"\n titleClassName=\"h-[56px]\"\n useAnimation\n animationClassName=\"md:translate-y-[100vh]\"\n {...props}\n >\n <div className=\"flex flex-col gap-[16px] text-center min-l:px-[16px]\">\n <div>\n <Text className={classNames('mb-[24px] text-[22px] font-bold')} html={copy.title}></Text>\n </div>\n {copy.desc && (\n <Text\n className=\"mb-[8px] text-left text-[16px] font-semibold leading-[1.4] text-[#1F2021]\"\n html={copy.desc}\n ></Text>\n )}\n <div\n className={classNames(\n 'relative flex h-[52px] w-full overflow-hidden rounded-[2px] md:grid md:h-auto md:grid-rows-1 md:gap-[16px]',\n !rounded && 'rounded-none'\n )}\n >\n <input\n className={classNames(\n 'h-full flex-1 rounded-l-[2px] border-[1px] border-[#d8d8d8] px-[14px] py-[17px] text-[16px] font-semibold leading-[1] outline-none placeholder:text-[#999] md:h-[52px] md:rounded-[2px]',\n !rounded && 'rounded-none'\n )}\n placeholder={copy.placeholder}\n value={email}\n onChange={handleEmailChange}\n />\n <Button\n variant=\"primary\"\n onClick={handleSubmit}\n loading={loading}\n className={classNames(\n 'legacy-headless-ui-primary-button !h-full !min-w-0 !rounded-l-none !rounded-r-[2px] !px-[40px] !py-[13px]',\n !rounded && 'rounded-none'\n )}\n >\n <Picture\n source=\"https://cdn.shopify.com/s/files/1/0512/8568/8505/files/icon_email.png?v=1697527383\"\n className=\"h-[24px] w-[24px]\"\n alt=\"email\"\n />\n </Button>\n </div>\n <div className=\"flex w-full\">\n <Checkbox checked={policy} onCheckedChange={() => setPolicy(!policy)} required className=\"border-[#1d1d1f]\" />\n <label\n className=\"text-left ml-2 text-[14px] font-semibold text-[#777] [&_a]:underline\"\n dangerouslySetInnerHTML={{\n __html: copy?.policy || '',\n }}\n />\n </div>\n <div\n className={classNames(\n 'w-full text-left text-[16px] font-semibold',\n errorMessage && 'text-[#F84D4F]',\n successMessage && 'text-[#52C41A]'\n )}\n >\n <Text html={successMessage || errorMessage || ''} />\n </div>\n </div>\n </CreditsModalContainer>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["SubscribeModal_exports", "__export", "CreditsSubscribeModal", "__toCommonJS", "import_jsx_runtime", "import_react", "import_headless_ui", "import_lib", "import_js_cookie", "import_query_string", "import_sha256", "import_provider", "import_constants", "import_utils", "import_ModalContainer", "getAdCookie", "search", "href", "query", "Cookies", "copy", "onSuccess", "props", "brand", "locale", "rounded", "policy", "setPolicy", "email", "setEmail", "errorMessage", "setErrorMessage", "successMessage", "setSuccessMessage", "loading", "setLoading", "profile", "handleEmailChange", "event", "handleSubmit", "register_source", "result", "sha256"]
|
|
7
7
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var n=Object.defineProperty;var c=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var p=Object.prototype.hasOwnProperty;var g=(t,e)=>{for(var a in e)n(t,a,{get:e[a],enumerable:!0})},m=(t,e,a,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of d(e))!p.call(t,r)&&r!==a&&n(t,r,{get:()=>e[r],enumerable:!(i=c(e,r))||i.enumerable});return t};var u=t=>m(n({},"__esModule",{value:!0}),t);var f={};g(f,{Default:()=>
|
|
1
|
+
"use strict";var n=Object.defineProperty;var c=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var p=Object.prototype.hasOwnProperty;var g=(t,e)=>{for(var a in e)n(t,a,{get:e[a],enumerable:!0})},m=(t,e,a,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of d(e))!p.call(t,r)&&r!==a&&n(t,r,{get:()=>e[r],enumerable:!(i=c(e,r))||i.enumerable});return t};var u=t=>m(n({},"__esModule",{value:!0}),t);var f={};g(f,{Default:()=>y,default:()=>h});module.exports=u(f);var o=require("react/jsx-runtime"),s=require("../components/LiveChatWidget"),b=require("../styles/livechat.css");const v={title:"Campaign/LiveChatWidget",component:s.LiveChatWidget,parameters:{layout:"fullscreen",docs:{story:{inline:!1,iframeHeight:500},description:{component:`
|
|
2
2
|
# LiveChat \u804A\u5929\u7EC4\u4EF6
|
|
3
3
|
|
|
4
4
|
\u53EF\u590D\u7528\u7684\u6C14\u6CE1\u5F39\u7A97\u804A\u5929\u7EC4\u4EF6\uFF0C\u652F\u6301 SSE \u6D41\u5F0F\u6D88\u606F\u3001\u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\u548C\u591A\u79CD\u6D88\u606F\u7C7B\u578B\u3002
|
|
@@ -48,5 +48,5 @@ const customRenderers = {
|
|
|
48
48
|
customRenderers={customRenderers}
|
|
49
49
|
/>
|
|
50
50
|
\`\`\`
|
|
51
|
-
`}}},tags:["autodocs"],argTypes:{apiBaseUrl:{control:"text",description:"API \u57FA\u7840 URL"},headers:{control:"object",description:"\u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\uFF0C\u5C06\u5728\u6240\u6709 API \u8BF7\u6C42\u4E2D\u6DFB\u52A0",table:{defaultValue:{summary:"undefined"}}},recaptchaSitekey:{control:"text",description:"Google reCAPTCHA v3 site key\uFF0C\u63D0\u4F9B\u6B64\u53C2\u6570\u5C06\u81EA\u52A8\u542F\u7528 reCAPTCHA v3 \u9A8C\u8BC1",table:{defaultValue:{summary:"undefined"}}},recaptchaAction:{control:"text",description:"reCAPTCHA action \u540D\u79F0\uFF0C\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7684\u9A8C\u8BC1\u573A\u666F",table:{defaultValue:{summary:'"activity"'}}},site:{control:"text",description:"Shopify \u5E97\u94FA URL"},channelCode:{control:"text",description:"\u6E20\u9053\u7F16\u7801\uFF0C\u7528\u4E8E\u6807\u8BC6\u6765\u6E90\u6E20\u9053",table:{defaultValue:{summary:"undefined"}}},welcomeMessage:{control:"text",description:"\u6B22\u8FCE\u6D88\u606F",table:{defaultValue:{summary:"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F"}}},logoUrl:{control:"text",description:"Logo URL"},position:{control:"object",description:"\u6C14\u6CE1\u6309\u94AE\u4F4D\u7F6E\u5BF9\u8C61",table:{defaultValue:{summary:'{ bottom: "1.5rem", right: "1.5rem" }'}}}},args:{apiBaseUrl:"http://172.16.38.183:3003",site:"www.eufy.com",loginUserId:"test_test",welcomeMessage:"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F"}};var
|
|
51
|
+
`}}},tags:["autodocs"],argTypes:{apiBaseUrl:{control:"text",description:"API \u57FA\u7840 URL"},headers:{control:"object",description:"\u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\uFF0C\u5C06\u5728\u6240\u6709 API \u8BF7\u6C42\u4E2D\u6DFB\u52A0",table:{defaultValue:{summary:"undefined"}}},recaptchaSitekey:{control:"text",description:"Google reCAPTCHA v3 site key\uFF0C\u63D0\u4F9B\u6B64\u53C2\u6570\u5C06\u81EA\u52A8\u542F\u7528 reCAPTCHA v3 \u9A8C\u8BC1",table:{defaultValue:{summary:"undefined"}}},recaptchaAction:{control:"text",description:"reCAPTCHA action \u540D\u79F0\uFF0C\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7684\u9A8C\u8BC1\u573A\u666F",table:{defaultValue:{summary:'"activity"'}}},site:{control:"text",description:"Shopify \u5E97\u94FA URL"},channelCode:{control:"text",description:"\u6E20\u9053\u7F16\u7801\uFF0C\u7528\u4E8E\u6807\u8BC6\u6765\u6E90\u6E20\u9053",table:{defaultValue:{summary:"undefined"}}},welcomeMessage:{control:"text",description:"\u6B22\u8FCE\u6D88\u606F",table:{defaultValue:{summary:"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F"}}},logoUrl:{control:"text",description:"Logo URL"},position:{control:"object",description:"\u6C14\u6CE1\u6309\u94AE\u4F4D\u7F6E\u5BF9\u8C61",table:{defaultValue:{summary:'{ bottom: "1.5rem", right: "1.5rem" }'}}}},args:{apiBaseUrl:"http://172.16.38.183:3003",site:"www.eufy.com",loginUserId:"test_test",welcomeMessage:"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F"}};var h=v;const y={args:{loginUserId:"test_test1",apiBaseUrl:"https://beta-api-v2-livechat.anker.com",site:"beta.eufy.com",channelCode:"dtc",title:"eufy AI Assistant",cartId:"gid://shopify/Cart/hWN7wB3Pa12gh78d8hPOAUBI?key=0e73db1d3fb5ac21da19099c45033253",accessToken:"47b1aa2c0797043f9baba39388029d70",position:{bottom:"24px",right:"30px"},welcomeMessage:"",quickReplies:[{id:"1",label:"Product Info",value:"Tell me about your products",icon:"\u{1F4E6}"},{id:"2",label:"Track Order",value:"I want to track my order",icon:"\u{1F69A}"},{id:"3",label:"Support",value:"I need help with my device",icon:"\u{1F527}"},{id:"4",label:"Recommendations",value:"Recommend products for me",icon:"\u2B50"}],complianceConfig:{title:"Hi! I'm your eufy AI assistant.",content:"AI-generated responses can be inaccurate. Please verify important info. Do not input sensitive personal data.",checkboxText:`By starting to use "Live Chat", you agree to Anker's <a href="https://www.anker.com/pages/privacy-policy" target="_blank" rel="noopener noreferrer" style="text-decoration: underline;">LIVE CHAT PRIVACY NOTICE</a>.`,agreeButtonText:"Agree"},recaptchaAction:"livechat",showNewSessionButton:!0,commonText:{learnMore:"Learn More",total:"Total"},customRenderers:{video:{render:t=>{const e=t;return(0,o.jsxs)("div",{className:"w-full",children:[(0,o.jsx)("video",{src:e.url,controls:!0,className:"w-full rounded-lg",poster:e.poster,children:"Your browser does not support video playback"}),e.title&&(0,o.jsx)("p",{className:"mt-2 text-sm text-gray-600",children:e.title})]})}},image_gallery:{render:t=>{const a=t.images||[];return(0,o.jsx)("div",{className:"grid grid-cols-2 gap-2",children:a.map((i,r)=>(0,o.jsx)("div",{className:"relative aspect-square",children:(0,o.jsx)("img",{src:i.url,alt:i.alt||`Image ${r+1}`,className:"size-full rounded-lg object-cover"})},r))})}}},productCardRender:(t,e)=>{if(!t)return(0,o.jsx)("div",{style:{padding:"16px",border:"1px dashed #ccc",borderRadius:"8px",textAlign:"center"},children:(0,o.jsxs)("p",{children:["Product loading... (handle: ",e,")"]})});const a=t?.featured_image||"",i=t?.title||"",r=t?.description||"",l=t?.average_rating;return(0,o.jsx)("div",{style:{border:"2px solid #4CAF50",borderRadius:"16px",padding:"16px",margin:"12px 0",backgroundColor:"#f0f9ff",boxShadow:"0 4px 12px rgba(76, 175, 80, 0.15)"},children:(0,o.jsxs)("div",{style:{display:"flex",gap:"12px",alignItems:"center"},children:[a&&(0,o.jsx)("img",{src:a,alt:i,style:{width:"60px",height:"60px",borderRadius:"8px",objectFit:"cover"}}),(0,o.jsxs)("div",{style:{flex:1},children:[(0,o.jsx)("h4",{style:{margin:"0 0 4px 0",fontSize:"16px",fontWeight:"bold"},children:i}),r&&(0,o.jsxs)("p",{style:{margin:0,fontSize:"12px",color:"#666",lineHeight:1.4},children:[r.slice(0,80),"..."]}),l&&(0,o.jsxs)("span",{style:{fontSize:"12px",color:"#FFB800"},children:["Rating: ",l.toFixed(1)]})]}),(0,o.jsx)("button",{style:{padding:"8px 16px",backgroundColor:"#4CAF50",color:"white",borderRadius:"8px",border:"none",cursor:"pointer"},onClick:()=>console.log("View product:",e,t),children:"View"})]})})}},render:t=>(0,o.jsx)(s.LiveChatWidget,{...t,onOpen:()=>console.log("[LiveChat] Chat opened"),onClose:()=>console.log("[LiveChat] Chat closed"),onMessageSend:e=>console.log("[LiveChat] Message sent:",e),onError:e=>console.error("[LiveChat] Error:",e),onTextMessage:()=>console.log("[LiveChat] AI text message received"),onProductList:()=>console.log("[LiveChat] Product list received"),onPromotionList:()=>console.log("[LiveChat] Promotion list received"),onAddToCart:e=>{console.log("[LiveChat] Add to cart:",e),alert(`Added "${e.title}" to cart!`)},onCart:(e,a)=>{console.log("[LiveChat] Cart clicked:",{cartId:e,checkoutUrl:a}),alert(`Cart ID: ${e}`)}})};
|
|
52
52
|
//# sourceMappingURL=LiveChatWidget.stories.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/stories/LiveChatWidget.stories.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * LiveChatWidget Storybook Stories\n * \u5C55\u793A LiveChat \u7EC4\u4EF6\u7684\u5404\u79CD\u4F7F\u7528\u573A\u666F\u548C\u914D\u7F6E\n */\n\nimport type { Meta, StoryObj } from '@storybook/react'\nimport { LiveChatWidget } from '../components/LiveChatWidget'\nimport type { MessageRenderer, MessageContent } from '../components/LiveChatWidget'\nimport '../styles/livechat.css'\n\nconst meta: Meta<typeof LiveChatWidget> = {\n title: 'Campaign/LiveChatWidget',\n component: LiveChatWidget,\n parameters: {\n layout: 'fullscreen',\n docs: {\n story: {\n inline: false,\n iframeHeight: 500,\n },\n description: {\n component: `\n# LiveChat \u804A\u5929\u7EC4\u4EF6\n\n\u53EF\u590D\u7528\u7684\u6C14\u6CE1\u5F39\u7A97\u804A\u5929\u7EC4\u4EF6\uFF0C\u652F\u6301 SSE \u6D41\u5F0F\u6D88\u606F\u3001\u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\u548C\u591A\u79CD\u6D88\u606F\u7C7B\u578B\u3002\n\n## \u529F\u80FD\u7279\u6027\n\n- \uD83C\uDF88 **\u6C14\u6CE1\u5F39\u7A97**: \u53EF\u81EA\u5B9A\u4E49\u4F4D\u7F6E\u7684\u60AC\u6D6E\u6C14\u6CE1\u6309\u94AE\n- \uD83D\uDCAC **\u6D41\u5F0F\u6D88\u606F**: \u57FA\u4E8E SSE \u7684\u5B9E\u65F6\u6D41\u5F0F\u54CD\u5E94\n- \uD83D\uDCE6 **\u591A\u79CD\u6D88\u606F\u7C7B\u578B**: \u6587\u672C\u3001\u5546\u54C1\u5361\u7247\u3001\u5546\u54C1\u5217\u8868\u3001\u653F\u7B56\u3001\u5FEB\u6377\u56DE\u590D\u7B49\n- \uD83C\uDFA8 **\u53EF\u5B9A\u5236**: \u652F\u6301\u81EA\u5B9A\u4E49\u54C1\u724C\u989C\u8272\u3001Logo\u3001\u6E32\u67D3\u5668\n- \uD83D\uDCF1 **\u54CD\u5E94\u5F0F**: \u79FB\u52A8\u7AEF\u5168\u5C4F\uFF0C\u684C\u9762\u7AEF\u56FA\u5B9A\u5C3A\u5BF8\n- \uD83D\uDCBE **\u4F1A\u8BDD\u7BA1\u7406**: \u81EA\u52A8\u7BA1\u7406 userId \u548C sessionId\n- \uD83D\uDD12 **\u5B89\u5168\u9632\u62A4**: \u5185\u7F6E XSS \u9632\u62A4\u548C\u8F93\u5165\u9A8C\u8BC1\n\n## \u57FA\u7840\u7528\u6CD5\n\n\\`\\`\\`tsx\nimport { LiveChatWidget } from '@anker-in/campaign-ui'\nimport '@anker-in/campaign-ui/livechat.css'\n\nfunction App() {\n return (\n <LiveChatWidget\n apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n site=\"www.eufy.com\"\n channel_code=\"web_homepage\"\n welcomeMessage=\"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\"\n />\n )\n}\n\\`\\`\\`\n\n## \u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\n\n\\`\\`\\`tsx\nconst customRenderers = {\n video: {\n render: (content) => (\n <video src={content.url} controls className=\"w-full rounded\" />\n )\n }\n}\n\n<LiveChatWidget\n apiBaseUrl=\"...\"\n site=\"...\"\n customRenderers={customRenderers}\n/>\n\\`\\`\\`\n `,\n },\n },\n },\n tags: ['autodocs'],\n argTypes: {\n apiBaseUrl: {\n control: 'text',\n description: 'API \u57FA\u7840 URL',\n },\n headers: {\n control: 'object',\n description: '\u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\uFF0C\u5C06\u5728\u6240\u6709 API \u8BF7\u6C42\u4E2D\u6DFB\u52A0',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n recaptchaSitekey: {\n control: 'text',\n description: 'Google reCAPTCHA v3 site key\uFF0C\u63D0\u4F9B\u6B64\u53C2\u6570\u5C06\u81EA\u52A8\u542F\u7528 reCAPTCHA v3 \u9A8C\u8BC1',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n recaptchaAction: {\n control: 'text',\n description: 'reCAPTCHA action \u540D\u79F0\uFF0C\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7684\u9A8C\u8BC1\u573A\u666F',\n table: {\n defaultValue: { summary: '\"activity\"' },\n },\n },\n site: {\n control: 'text',\n description: 'Shopify \u5E97\u94FA URL',\n },\n channelCode: {\n control: 'text',\n description: '\u6E20\u9053\u7F16\u7801\uFF0C\u7528\u4E8E\u6807\u8BC6\u6765\u6E90\u6E20\u9053',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n welcomeMessage: {\n control: 'text',\n description: '\u6B22\u8FCE\u6D88\u606F',\n table: {\n defaultValue: { summary: '\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F' },\n },\n },\n logoUrl: {\n control: 'text',\n description: 'Logo URL',\n },\n position: {\n control: 'object',\n description: '\u6C14\u6CE1\u6309\u94AE\u4F4D\u7F6E\u5BF9\u8C61',\n table: {\n defaultValue: { summary: '{ bottom: \"1.5rem\", right: \"1.5rem\" }' },\n },\n },\n },\n args: {\n apiBaseUrl: 'http://172.16.38.183:3003',\n site: 'www.eufy.com',\n loginUserId: 'test_test',\n welcomeMessage: '\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F',\n },\n}\n\nexport default meta\ntype Story = StoryObj<typeof LiveChatWidget>\n\n/**\n * \u9ED8\u8BA4\u914D\u7F6E - \u5C55\u793A\u6240\u6709\u529F\u80FD\n */\nexport const Default: Story = {\n args: {\n // \u57FA\u7840\u914D\u7F6E\n loginUserId: 'test_test1',\n apiBaseUrl: 'https://beta-api-v2-livechat.anker.com',\n site: 'beta.soundcore.com',\n channelCode: 'dtc',\n title: 'eufy AI Assistant',\n cartId: 'gid://shopify/Cart/hWNAAJweS9IkeRKib4LRy9PY?key=ff1f9b24e74b3f11f5574539e7cbbb2f',\n accessToken: '47b1aa2c0797043f9baba39388029d70',\n\n // \u81EA\u5B9A\u4E49\u4F4D\u7F6E\n position: { bottom: '24px', right: '30px' },\n\n // \u6B22\u8FCE\u6D88\u606F\n welcomeMessage: '',\n\n // \u5FEB\u6377\u56DE\u590D\n quickReplies: [\n { id: '1', label: 'Product Info', value: 'Tell me about your products', icon: '\uD83D\uDCE6' },\n { id: '2', label: 'Track Order', value: 'I want to track my order', icon: '\uD83D\uDE9A' },\n { id: '3', label: 'Support', value: 'I need help with my device', icon: '\uD83D\uDD27' },\n { id: '4', label: 'Recommendations', value: 'Recommend products for me', icon: '\u2B50' },\n ],\n\n // \u6CD5\u89C4\u534F\u8BAE\u5F39\u7A97\n complianceConfig: {\n title: \"Hi! I'm your eufy AI assistant.\",\n content:\n 'AI-generated responses can be inaccurate. Please verify important info. Do not input sensitive personal data.',\n checkboxText:\n 'By starting to use \"Live Chat\", you agree to Anker\\'s <a href=\"https://www.anker.com/pages/privacy-policy\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"text-decoration: underline;\">LIVE CHAT PRIVACY NOTICE</a>.',\n agreeButtonText: 'Agree',\n },\n\n // reCAPTCHA \u914D\u7F6E\uFF08\u53D6\u6D88\u6CE8\u91CA\u4EE5\u542F\u7528\uFF09\n // recaptchaSitekey: '6LfS4J4pAAAAACX1e_WrxutmxxzCK7FU4WzVqL14',\n recaptchaAction: 'livechat',\n\n // \u663E\u793A\u65B0\u4F1A\u8BDD\u6309\u94AE\n showNewSessionButton: true,\n\n // \u81EA\u5B9A\u4E49\u6587\u6848\n commonText: {\n learnMore: 'Learn More',\n total: 'Total',\n },\n\n // \u81EA\u5B9A\u4E49\u6D88\u606F\u6E32\u67D3\u5668\n customRenderers: {\n video: {\n render: (content: MessageContent) => {\n const videoContent = content as any\n return (\n <div className=\"w-full\">\n <video src={videoContent.url} controls className=\"w-full rounded-lg\" poster={videoContent.poster}>\n Your browser does not support video playback\n </video>\n {videoContent.title && <p className=\"mt-2 text-sm text-gray-600\">{videoContent.title}</p>}\n </div>\n )\n },\n } as MessageRenderer,\n image_gallery: {\n render: (content: MessageContent) => {\n const galleryContent = content as any\n const images = galleryContent.images || []\n return (\n <div className=\"grid grid-cols-2 gap-2\">\n {images.map((image: any, index: number) => (\n <div key={index} className=\"relative aspect-square\">\n <img\n src={image.url}\n alt={image.alt || `Image ${index + 1}`}\n className=\"size-full rounded-lg object-cover\"\n />\n </div>\n ))}\n </div>\n )\n },\n } as MessageRenderer,\n },\n\n // \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5361\u7247\u6E32\u67D3\n productCardRender: (product, productHandle) => {\n // product \u53EF\u80FD\u4E3A undefined\uFF0C\u6B64\u65F6\u53EF\u7528 productHandle \u67E5\u8BE2\n if (!product) {\n return (\n <div style={{ padding: '16px', border: '1px dashed #ccc', borderRadius: '8px', textAlign: 'center' }}>\n <p>Product loading... (handle: {productHandle})</p>\n </div>\n )\n }\n\n const imageUrl = product?.featured_image || ''\n const title = product?.title || ''\n const description = product?.description || ''\n const averageRating = product?.average_rating\n\n return (\n <div\n style={{\n border: '2px solid #4CAF50',\n borderRadius: '16px',\n padding: '16px',\n margin: '12px 0',\n backgroundColor: '#f0f9ff',\n boxShadow: '0 4px 12px rgba(76, 175, 80, 0.15)',\n }}\n >\n <div style={{ display: 'flex', gap: '12px', alignItems: 'center' }}>\n {imageUrl && (\n <img\n src={imageUrl}\n alt={title}\n style={{ width: '60px', height: '60px', borderRadius: '8px', objectFit: 'cover' }}\n />\n )}\n <div style={{ flex: 1 }}>\n <h4 style={{ margin: '0 0 4px 0', fontSize: '16px', fontWeight: 'bold' }}>{title}</h4>\n {description && (\n <p style={{ margin: 0, fontSize: '12px', color: '#666', lineHeight: 1.4 }}>\n {description.slice(0, 80)}...\n </p>\n )}\n {averageRating && (\n <span style={{ fontSize: '12px', color: '#FFB800' }}>Rating: {averageRating.toFixed(1)}</span>\n )}\n </div>\n <button\n style={{\n padding: '8px 16px',\n backgroundColor: '#4CAF50',\n color: 'white',\n borderRadius: '8px',\n border: 'none',\n cursor: 'pointer',\n }}\n onClick={() => console.log('View product:', productHandle, product)}\n >\n View\n </button>\n </div>\n </div>\n )\n },\n },\n\n render: args => (\n <LiveChatWidget\n {...args}\n // \u6240\u6709\u4E8B\u4EF6\u56DE\u8C03\n onOpen={() => console.log('[LiveChat] Chat opened')}\n onClose={() => console.log('[LiveChat] Chat closed')}\n onMessageSend={(message: string) => console.log('[LiveChat] Message sent:', message)}\n onError={(error: Error) => console.error('[LiveChat] Error:', error)}\n onTextMessage={() => console.log('[LiveChat] AI text message received')}\n onProductList={() => console.log('[LiveChat] Product list received')}\n onPromotionList={() => console.log('[LiveChat] Promotion list received')}\n onAddToCart={(product: any) => {\n console.log('[LiveChat] Add to cart:', product)\n alert(`Added \"${product.title}\" to cart!`)\n }}\n onCart={(cartId: string, checkoutUrl?: string) => {\n console.log('[LiveChat] Cart clicked:', { cartId, checkoutUrl })\n alert(`Cart ID: ${cartId}`)\n }}\n />\n ),\n}\n"],
|
|
5
|
-
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,EAAA,YAAAC,IAAA,eAAAC,EAAAJ,GAwMY,IAAAK,EAAA,6BAlMZC,EAA+B,wCAE/BC,EAAO,kCAEP,MAAMC,EAAoC,CACxC,MAAO,0BACP,UAAW,iBACX,WAAY,CACV,OAAQ,aACR,KAAM,CACJ,MAAO,CACL,OAAQ,GACR,aAAc,GAChB,EACA,YAAa,CACX,UAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAmDb,CACF,CACF,EACA,KAAM,CAAC,UAAU,EACjB,SAAU,CACR,WAAY,CACV,QAAS,OACT,YAAa,sBACf,EACA,QAAS,CACP,QAAS,SACT,YAAa,wGACb,MAAO,CACL,aAAc,CAAE,QAAS,WAAY,CACvC,CACF,EACA,iBAAkB,CAChB,QAAS,OACT,YAAa,2HACb,MAAO,CACL,aAAc,CAAE,QAAS,WAAY,CACvC,CACF,EACA,gBAAiB,CACf,QAAS,OACT,YAAa,wGACb,MAAO,CACL,aAAc,CAAE,QAAS,YAAa,CACxC,CACF,EACA,KAAM,CACJ,QAAS,OACT,YAAa,0BACf,EACA,YAAa,CACX,QAAS,OACT,YAAa,iFACb,MAAO,CACL,aAAc,CAAE,QAAS,WAAY,CACvC,CACF,EACA,eAAgB,CACd,QAAS,OACT,YAAa,2BACb,MAAO,CACL,aAAc,CAAE,QAAS,wHAA0B,CACrD,CACF,EACA,QAAS,CACP,QAAS,OACT,YAAa,UACf,EACA,SAAU,CACR,QAAS,SACT,YAAa,mDACb,MAAO,CACL,aAAc,CAAE,QAAS,uCAAwC,CACnE,CACF,CACF,EACA,KAAM,CACJ,WAAY,4BACZ,KAAM,eACN,YAAa,YACb,eAAgB,wHAClB,CACF,EAEA,IAAOL,EAAQK,EAMR,MAAMN,EAAiB,CAC5B,KAAM,CAEJ,YAAa,aACb,WAAY,yCACZ,KAAM,
|
|
4
|
+
"sourcesContent": ["/**\n * LiveChatWidget Storybook Stories\n * \u5C55\u793A LiveChat \u7EC4\u4EF6\u7684\u5404\u79CD\u4F7F\u7528\u573A\u666F\u548C\u914D\u7F6E\n */\n\nimport type { Meta, StoryObj } from '@storybook/react'\nimport { LiveChatWidget } from '../components/LiveChatWidget'\nimport type { MessageRenderer, MessageContent } from '../components/LiveChatWidget'\nimport '../styles/livechat.css'\n\nconst meta: Meta<typeof LiveChatWidget> = {\n title: 'Campaign/LiveChatWidget',\n component: LiveChatWidget,\n parameters: {\n layout: 'fullscreen',\n docs: {\n story: {\n inline: false,\n iframeHeight: 500,\n },\n description: {\n component: `\n# LiveChat \u804A\u5929\u7EC4\u4EF6\n\n\u53EF\u590D\u7528\u7684\u6C14\u6CE1\u5F39\u7A97\u804A\u5929\u7EC4\u4EF6\uFF0C\u652F\u6301 SSE \u6D41\u5F0F\u6D88\u606F\u3001\u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\u548C\u591A\u79CD\u6D88\u606F\u7C7B\u578B\u3002\n\n## \u529F\u80FD\u7279\u6027\n\n- \uD83C\uDF88 **\u6C14\u6CE1\u5F39\u7A97**: \u53EF\u81EA\u5B9A\u4E49\u4F4D\u7F6E\u7684\u60AC\u6D6E\u6C14\u6CE1\u6309\u94AE\n- \uD83D\uDCAC **\u6D41\u5F0F\u6D88\u606F**: \u57FA\u4E8E SSE \u7684\u5B9E\u65F6\u6D41\u5F0F\u54CD\u5E94\n- \uD83D\uDCE6 **\u591A\u79CD\u6D88\u606F\u7C7B\u578B**: \u6587\u672C\u3001\u5546\u54C1\u5361\u7247\u3001\u5546\u54C1\u5217\u8868\u3001\u653F\u7B56\u3001\u5FEB\u6377\u56DE\u590D\u7B49\n- \uD83C\uDFA8 **\u53EF\u5B9A\u5236**: \u652F\u6301\u81EA\u5B9A\u4E49\u54C1\u724C\u989C\u8272\u3001Logo\u3001\u6E32\u67D3\u5668\n- \uD83D\uDCF1 **\u54CD\u5E94\u5F0F**: \u79FB\u52A8\u7AEF\u5168\u5C4F\uFF0C\u684C\u9762\u7AEF\u56FA\u5B9A\u5C3A\u5BF8\n- \uD83D\uDCBE **\u4F1A\u8BDD\u7BA1\u7406**: \u81EA\u52A8\u7BA1\u7406 userId \u548C sessionId\n- \uD83D\uDD12 **\u5B89\u5168\u9632\u62A4**: \u5185\u7F6E XSS \u9632\u62A4\u548C\u8F93\u5165\u9A8C\u8BC1\n\n## \u57FA\u7840\u7528\u6CD5\n\n\\`\\`\\`tsx\nimport { LiveChatWidget } from '@anker-in/campaign-ui'\nimport '@anker-in/campaign-ui/livechat.css'\n\nfunction App() {\n return (\n <LiveChatWidget\n apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n site=\"www.eufy.com\"\n channel_code=\"web_homepage\"\n welcomeMessage=\"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\"\n />\n )\n}\n\\`\\`\\`\n\n## \u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\n\n\\`\\`\\`tsx\nconst customRenderers = {\n video: {\n render: (content) => (\n <video src={content.url} controls className=\"w-full rounded\" />\n )\n }\n}\n\n<LiveChatWidget\n apiBaseUrl=\"...\"\n site=\"...\"\n customRenderers={customRenderers}\n/>\n\\`\\`\\`\n `,\n },\n },\n },\n tags: ['autodocs'],\n argTypes: {\n apiBaseUrl: {\n control: 'text',\n description: 'API \u57FA\u7840 URL',\n },\n headers: {\n control: 'object',\n description: '\u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\uFF0C\u5C06\u5728\u6240\u6709 API \u8BF7\u6C42\u4E2D\u6DFB\u52A0',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n recaptchaSitekey: {\n control: 'text',\n description: 'Google reCAPTCHA v3 site key\uFF0C\u63D0\u4F9B\u6B64\u53C2\u6570\u5C06\u81EA\u52A8\u542F\u7528 reCAPTCHA v3 \u9A8C\u8BC1',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n recaptchaAction: {\n control: 'text',\n description: 'reCAPTCHA action \u540D\u79F0\uFF0C\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7684\u9A8C\u8BC1\u573A\u666F',\n table: {\n defaultValue: { summary: '\"activity\"' },\n },\n },\n site: {\n control: 'text',\n description: 'Shopify \u5E97\u94FA URL',\n },\n channelCode: {\n control: 'text',\n description: '\u6E20\u9053\u7F16\u7801\uFF0C\u7528\u4E8E\u6807\u8BC6\u6765\u6E90\u6E20\u9053',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n welcomeMessage: {\n control: 'text',\n description: '\u6B22\u8FCE\u6D88\u606F',\n table: {\n defaultValue: { summary: '\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F' },\n },\n },\n logoUrl: {\n control: 'text',\n description: 'Logo URL',\n },\n position: {\n control: 'object',\n description: '\u6C14\u6CE1\u6309\u94AE\u4F4D\u7F6E\u5BF9\u8C61',\n table: {\n defaultValue: { summary: '{ bottom: \"1.5rem\", right: \"1.5rem\" }' },\n },\n },\n },\n args: {\n apiBaseUrl: 'http://172.16.38.183:3003',\n site: 'www.eufy.com',\n loginUserId: 'test_test',\n welcomeMessage: '\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F',\n },\n}\n\nexport default meta\ntype Story = StoryObj<typeof LiveChatWidget>\n\n/**\n * \u9ED8\u8BA4\u914D\u7F6E - \u5C55\u793A\u6240\u6709\u529F\u80FD\n */\nexport const Default: Story = {\n args: {\n // \u57FA\u7840\u914D\u7F6E\n loginUserId: 'test_test1',\n apiBaseUrl: 'https://beta-api-v2-livechat.anker.com',\n site: 'beta.eufy.com',\n channelCode: 'dtc',\n title: 'eufy AI Assistant',\n cartId: 'gid://shopify/Cart/hWN7wB3Pa12gh78d8hPOAUBI?key=0e73db1d3fb5ac21da19099c45033253',\n accessToken: '47b1aa2c0797043f9baba39388029d70',\n\n // \u81EA\u5B9A\u4E49\u4F4D\u7F6E\n position: { bottom: '24px', right: '30px' },\n\n // \u6B22\u8FCE\u6D88\u606F\n welcomeMessage: '',\n\n // \u5FEB\u6377\u56DE\u590D\n quickReplies: [\n { id: '1', label: 'Product Info', value: 'Tell me about your products', icon: '\uD83D\uDCE6' },\n { id: '2', label: 'Track Order', value: 'I want to track my order', icon: '\uD83D\uDE9A' },\n { id: '3', label: 'Support', value: 'I need help with my device', icon: '\uD83D\uDD27' },\n { id: '4', label: 'Recommendations', value: 'Recommend products for me', icon: '\u2B50' },\n ],\n\n // \u6CD5\u89C4\u534F\u8BAE\u5F39\u7A97\n complianceConfig: {\n title: \"Hi! I'm your eufy AI assistant.\",\n content:\n 'AI-generated responses can be inaccurate. Please verify important info. Do not input sensitive personal data.',\n checkboxText:\n 'By starting to use \"Live Chat\", you agree to Anker\\'s <a href=\"https://www.anker.com/pages/privacy-policy\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"text-decoration: underline;\">LIVE CHAT PRIVACY NOTICE</a>.',\n agreeButtonText: 'Agree',\n },\n\n // reCAPTCHA \u914D\u7F6E\uFF08\u53D6\u6D88\u6CE8\u91CA\u4EE5\u542F\u7528\uFF09\n // recaptchaSitekey: '6LfS4J4pAAAAACX1e_WrxutmxxzCK7FU4WzVqL14',\n recaptchaAction: 'livechat',\n\n // \u663E\u793A\u65B0\u4F1A\u8BDD\u6309\u94AE\n showNewSessionButton: true,\n\n // \u81EA\u5B9A\u4E49\u6587\u6848\n commonText: {\n learnMore: 'Learn More',\n total: 'Total',\n },\n\n // \u81EA\u5B9A\u4E49\u6D88\u606F\u6E32\u67D3\u5668\n customRenderers: {\n video: {\n render: (content: MessageContent) => {\n const videoContent = content as any\n return (\n <div className=\"w-full\">\n <video src={videoContent.url} controls className=\"w-full rounded-lg\" poster={videoContent.poster}>\n Your browser does not support video playback\n </video>\n {videoContent.title && <p className=\"mt-2 text-sm text-gray-600\">{videoContent.title}</p>}\n </div>\n )\n },\n } as MessageRenderer,\n image_gallery: {\n render: (content: MessageContent) => {\n const galleryContent = content as any\n const images = galleryContent.images || []\n return (\n <div className=\"grid grid-cols-2 gap-2\">\n {images.map((image: any, index: number) => (\n <div key={index} className=\"relative aspect-square\">\n <img\n src={image.url}\n alt={image.alt || `Image ${index + 1}`}\n className=\"size-full rounded-lg object-cover\"\n />\n </div>\n ))}\n </div>\n )\n },\n } as MessageRenderer,\n },\n\n // \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5361\u7247\u6E32\u67D3\n productCardRender: (product, productHandle) => {\n // product \u53EF\u80FD\u4E3A undefined\uFF0C\u6B64\u65F6\u53EF\u7528 productHandle \u67E5\u8BE2\n if (!product) {\n return (\n <div style={{ padding: '16px', border: '1px dashed #ccc', borderRadius: '8px', textAlign: 'center' }}>\n <p>Product loading... (handle: {productHandle})</p>\n </div>\n )\n }\n\n const imageUrl = product?.featured_image || ''\n const title = product?.title || ''\n const description = product?.description || ''\n const averageRating = product?.average_rating\n\n return (\n <div\n style={{\n border: '2px solid #4CAF50',\n borderRadius: '16px',\n padding: '16px',\n margin: '12px 0',\n backgroundColor: '#f0f9ff',\n boxShadow: '0 4px 12px rgba(76, 175, 80, 0.15)',\n }}\n >\n <div style={{ display: 'flex', gap: '12px', alignItems: 'center' }}>\n {imageUrl && (\n <img\n src={imageUrl}\n alt={title}\n style={{ width: '60px', height: '60px', borderRadius: '8px', objectFit: 'cover' }}\n />\n )}\n <div style={{ flex: 1 }}>\n <h4 style={{ margin: '0 0 4px 0', fontSize: '16px', fontWeight: 'bold' }}>{title}</h4>\n {description && (\n <p style={{ margin: 0, fontSize: '12px', color: '#666', lineHeight: 1.4 }}>\n {description.slice(0, 80)}...\n </p>\n )}\n {averageRating && (\n <span style={{ fontSize: '12px', color: '#FFB800' }}>Rating: {averageRating.toFixed(1)}</span>\n )}\n </div>\n <button\n style={{\n padding: '8px 16px',\n backgroundColor: '#4CAF50',\n color: 'white',\n borderRadius: '8px',\n border: 'none',\n cursor: 'pointer',\n }}\n onClick={() => console.log('View product:', productHandle, product)}\n >\n View\n </button>\n </div>\n </div>\n )\n },\n },\n\n render: args => (\n <LiveChatWidget\n {...args}\n // \u6240\u6709\u4E8B\u4EF6\u56DE\u8C03\n onOpen={() => console.log('[LiveChat] Chat opened')}\n onClose={() => console.log('[LiveChat] Chat closed')}\n onMessageSend={(message: string) => console.log('[LiveChat] Message sent:', message)}\n onError={(error: Error) => console.error('[LiveChat] Error:', error)}\n onTextMessage={() => console.log('[LiveChat] AI text message received')}\n onProductList={() => console.log('[LiveChat] Product list received')}\n onPromotionList={() => console.log('[LiveChat] Promotion list received')}\n onAddToCart={(product: any) => {\n console.log('[LiveChat] Add to cart:', product)\n alert(`Added \"${product.title}\" to cart!`)\n }}\n onCart={(cartId: string, checkoutUrl?: string) => {\n console.log('[LiveChat] Cart clicked:', { cartId, checkoutUrl })\n alert(`Cart ID: ${cartId}`)\n }}\n />\n ),\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["LiveChatWidget_stories_exports", "__export", "Default", "LiveChatWidget_stories_default", "__toCommonJS", "import_jsx_runtime", "import_LiveChatWidget", "import_livechat", "meta", "content", "videoContent", "images", "image", "index", "product", "productHandle", "imageUrl", "title", "description", "averageRating", "args", "message", "error", "cartId", "checkoutUrl"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsx as n,jsxs as a}from"react/jsx-runtime";import{useRef as
|
|
1
|
+
import{jsx as n,jsxs as a}from"react/jsx-runtime";import{useRef as h,useEffect as E}from"react";const v=()=>a("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[n("path",{d:"M10.2069 15.6997V4.69971",stroke:"white","stroke-width":"2","stroke-linecap":"round"}),n("path",{d:"M15.3995 8.50341L10.9506 4.05446C10.534 3.6379 9.85866 3.63791 9.4421 4.05446L5.00005 8.49651",stroke:"white","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"})]}),N=({value:t,onChange:p,onSend:c,placeholder:u="",disabled:o=!1,autoFocus:x=!1,maxLength:s=5e3,bottomTips:d,className:f=""})=>{const g=h(null),r=h(!1);E(()=>{const e=g.current;if(!e)return;e.style.height="auto";const k=Math.min(e.scrollHeight,120);e.style.height=`${k}px`},[t]);const m=()=>{r.current=!0},b=()=>{r.current=!1},w=e=>{if(e.key==="Enter"&&!e.shiftKey){if(r.current)return;e.preventDefault(),t.trim()&&!o&&c()}},C=e=>{const l=e.target.value;l.length<=s&&p(l)},y=()=>{t.trim()&&!o&&c()},i=t.trim().length>0&&!o;return a("div",{className:`flex flex-col gap-2 bg-white px-4 py-4 ${f}`,children:[n("div",{className:"flex items-center gap-2 rounded-2xl",style:{background:"linear-gradient(to right, #7687F3, #7687F3, #4DA8F5, #A3DFCE)",padding:"2px"},children:a("div",{className:"flex flex-1 items-center gap-2 bg-white px-3 py-2",style:{borderRadius:"14px"},children:[n("textarea",{ref:g,value:t,onChange:C,onKeyDown:w,onCompositionStart:m,onCompositionEnd:b,placeholder:u,disabled:o,autoFocus:x,rows:1,className:"flex-1 resize-none bg-transparent font-bold text-sm text-gray-900 outline-none placeholder:text-gray-400 disabled:cursor-not-allowed disabled:opacity-50",style:{resize:"none"}}),t.length>s*.8&&a("span",{className:"text-xs text-gray-400",children:[t.length,"/",s]}),n("button",{type:"button",onClick:y,disabled:!i,className:`shrink-0 rounded-full p-2 transition-all ${i?" active:scale-95":"cursor-not-allowed "}`,style:i?{background:"linear-gradient(to bottom, #A3DFCE, #4DA8F5, #7687F3)"}:{background:"#BEBEBE"},"aria-label":"Send message",children:n(v,{})})]})}),d&&n("p",{className:"px-3 font-bold text-[12px] text-[#767880] tracking-tight leading-[1.4]",children:d})]})};export{N as ChatInput};
|
|
2
2
|
//# sourceMappingURL=ChatInput.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/components/LiveChatWidget/components/ChatInput.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * \u804A\u5929\u8F93\u5165\u6846\u7EC4\u4EF6\n * \u63D0\u4F9B\u6587\u672C\u8F93\u5165\u548C\u53D1\u9001\u6309\u94AE\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u8F93\u5165\u6846\u8BBE\u8BA1\n */\n\nimport React, { useRef, useEffect } from 'react'\n\nexport interface ChatInputProps {\n /**\n * \u8F93\u5165\u6846\u5F53\u524D\u503C\n */\n value: string\n\n /**\n * \u503C\u53D8\u5316\u56DE\u8C03\n */\n onChange: (value: string) => void\n\n /**\n * \u53D1\u9001\u6D88\u606F\u56DE\u8C03\n */\n onSend: () => void\n\n /**\n * \u5360\u4F4D\u7B26\u6587\u672C\n * @default \"\u8F93\u5165\u6D88\u606F...\"\n */\n placeholder?: string\n\n /**\n * \u662F\u5426\u7981\u7528\u8F93\u5165\n * @default false\n */\n disabled?: boolean\n\n /**\n * \u662F\u5426\u81EA\u52A8\u805A\u7126\n * @default false\n */\n autoFocus?: boolean\n\n /**\n * \u6700\u5927\u5B57\u7B26\u6570\n * @default 5000\n */\n maxLength?: number\n\n /**\n * \u81EA\u5B9A\u4E49\u6837\u5F0F\u7C7B\u540D\n */\n className?: string\n\n /**\n * \u5E95\u90E8\u63D0\u793A\u6587\u672C\n * \u4E0D\u4F20\u5165\u5219\u4E0D\u663E\u793A\n */\n bottomTips?: string\n}\n\n/**\n * \u53D1\u9001\u56FE\u6807 (\u5411\u4E0A\u7BAD\u5934)\n */\nconst SendIcon: React.FC = () => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M10.2069 15.6997V4.69971\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" />\n <path\n d=\"M15.3995 8.50341L10.9506 4.05446C10.534 3.6379 9.85866 3.63791 9.4421 4.05446L5.00005 8.49651\"\n stroke=\"white\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n)\n\n/**\n * \u804A\u5929\u8F93\u5165\u6846\u7EC4\u4EF6\n *\n * \u529F\u80FD\uFF1A\n * - \u591A\u884C\u6587\u672C\u8F93\u5165\uFF08\u81EA\u52A8\u589E\u957F\uFF09\n * - Enter \u53D1\u9001\uFF0CShift+Enter \u6362\u884C\n * - \u5B57\u7B26\u6570\u9650\u5236\uFF085000\uFF09\n * - \u7981\u7528\u72B6\u6001\uFF08\u53D1\u9001\u4E2D\uFF09\n * - \u53D1\u9001\u6309\u94AE\uFF08\u7A7A\u5185\u5BB9\u65F6\u7981\u7528\uFF09\n *\n * \u6837\u5F0F\uFF1A\n * - \u56FA\u5B9A\u5E95\u90E8\n * - \u8FB9\u6846\u5206\u9694\u4E0A\u65B9\u5185\u5BB9\n * - \u81EA\u9002\u5E94\u9AD8\u5EA6\uFF081-5 \u884C\uFF09\n *\n * @example\n * ```tsx\n * <ChatInput\n * value={inputValue}\n * onChange={setInputValue}\n * onSend={handleSend}\n * disabled={isStreaming}\n * />\n * ```\n */\nexport const ChatInput: React.FC<ChatInputProps> = ({\n value,\n onChange,\n onSend,\n placeholder = '',\n disabled = false,\n autoFocus = false,\n maxLength = 5000,\n bottomTips,\n className = '',\n}) => {\n const textareaRef = useRef<HTMLTextAreaElement>(null)\n // \u8DDF\u8E2A\u8F93\u5165\u6CD5\u72B6\u6001\uFF08\u662F\u5426\u6B63\u5728\u4F7F\u7528\u62FC\u97F3\u8F93\u5165\u7B49\uFF09\n const isComposingRef = useRef(false)\n\n /**\n * \u81EA\u52A8\u8C03\u6574 textarea \u9AD8\u5EA6\n */\n useEffect(() => {\n const textarea = textareaRef.current\n if (!textarea) return\n\n // \u91CD\u7F6E\u9AD8\u5EA6\u4EE5\u83B7\u53D6\u6B63\u786E\u7684 scrollHeight\n textarea.style.height = 'auto'\n\n // \u8BBE\u7F6E\u9AD8\u5EA6\uFF0C\u6700\u5927 5 \u884C\uFF08\u7EA6 120px\uFF09\n const maxHeight = 120\n const newHeight = Math.min(textarea.scrollHeight, maxHeight)\n textarea.style.height = `${newHeight}px`\n }, [value])\n\n /**\n * \u5904\u7406\u8F93\u5165\u6CD5\u5F00\u59CB\n */\n const handleCompositionStart = () => {\n isComposingRef.current = true\n }\n\n /**\n * \u5904\u7406\u8F93\u5165\u6CD5\u7ED3\u675F\n */\n const handleCompositionEnd = () => {\n isComposingRef.current = false\n }\n\n /**\n * \u5904\u7406\u952E\u76D8\u4E8B\u4EF6\n * Enter \u53D1\u9001\uFF0CShift+Enter \u6362\u884C\n * \u6CE8\u610F\uFF1A\u8F93\u5165\u6CD5\u6FC0\u6D3B\u65F6\uFF08\u5982\u62FC\u97F3\u8F93\u5165\u4E2D\uFF09\uFF0C\u56DE\u8F66\u952E\u4E0D\u5E94\u53D1\u9001\u6D88\u606F\n */\n const handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (event.key === 'Enter' && !event.shiftKey) {\n // \u5982\u679C\u6B63\u5728\u4F7F\u7528\u8F93\u5165\u6CD5\uFF08\u5982\u62FC\u97F3\u8F93\u5165\uFF09\uFF0C\u5219\u4E0D\u53D1\u9001\u6D88\u606F\n // \u8BA9\u8F93\u5165\u6CD5\u5148\u5B8C\u6210\u5B57\u7B26\u9009\u62E9\n if (isComposingRef.current) {\n return\n }\n\n event.preventDefault()\n if (value.trim() && !disabled) {\n onSend()\n }\n }\n }\n\n /**\n * \u5904\u7406\u8F93\u5165\u53D8\u5316\n */\n const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {\n const newValue = event.target.value\n\n // \u5B57\u7B26\u6570\u9650\u5236\n if (newValue.length <= maxLength) {\n onChange(newValue)\n }\n }\n\n /**\n * \u5904\u7406\u53D1\u9001\u6309\u94AE\u70B9\u51FB\n */\n const handleSendClick = () => {\n if (value.trim() && !disabled) {\n onSend()\n }\n }\n\n const canSend = value.trim().length > 0 && !disabled\n\n return (\n <div className={`flex flex-col gap-2 bg-white px-4 py-4 ${className}`}>\n {/* \u8F93\u5165\u6846\u5BB9\u5668 - \u5E26\u6E10\u53D8\u8FB9\u6846 */}\n <div\n className=\"
|
|
5
|
-
"mappings": "AAgEE,OACE,OAAAA,EADF,QAAAC,MAAA,oBA1DF,OAAgB,UAAAC,EAAQ,aAAAC,MAAiB,QAyDzC,MAAMC,EAAqB,IACzBH,EAAC,OAAI,MAAM,KAAK,OAAO,KAAK,QAAQ,YAAY,KAAK,OAAO,MAAM,6BAChE,UAAAD,EAAC,QAAK,EAAE,2BAA2B,OAAO,QAAQ,eAAa,IAAI,iBAAe,QAAQ,EAC1FA,EAAC,QACC,EAAE,gGACF,OAAO,QACP,eAAa,IACb,iBAAe,QACf,kBAAgB,QAClB,GACF,EA4BWK,EAAsC,CAAC,CAClD,MAAAC,EACA,SAAAC,EACA,OAAAC,EACA,YAAAC,EAAc,GACd,SAAAC,EAAW,GACX,UAAAC,EAAY,GACZ,UAAAC,EAAY,IACZ,WAAAC,EACA,UAAAC,EAAY,EACd,IAAM,CACJ,MAAMC,EAAcb,EAA4B,IAAI,EAE9Cc,EAAiBd,EAAO,EAAK,EAKnCC,EAAU,IAAM,CACd,MAAMc,EAAWF,EAAY,QAC7B,GAAI,CAACE,EAAU,OAGfA,EAAS,MAAM,OAAS,OAIxB,MAAMC,EAAY,KAAK,IAAID,EAAS,aADlB,GACyC,EAC3DA,EAAS,MAAM,OAAS,GAAGC,CAAS,IACtC,EAAG,CAACZ,CAAK,CAAC,EAKV,MAAMa,EAAyB,IAAM,CACnCH,EAAe,QAAU,EAC3B,EAKMI,EAAuB,IAAM,CACjCJ,EAAe,QAAU,EAC3B,EAOMK,EAAiBC,GAAoD,CACzE,GAAIA,EAAM,MAAQ,SAAW,CAACA,EAAM,SAAU,CAG5C,GAAIN,EAAe,QACjB,OAGFM,EAAM,eAAe,EACjBhB,EAAM,KAAK,GAAK,CAACI,GACnBF,EAAO,CAEX,CACF,EAKMe,EAAgBD,GAAkD,CACtE,MAAME,EAAWF,EAAM,OAAO,MAG1BE,EAAS,QAAUZ,GACrBL,EAASiB,CAAQ,CAErB,EAKMC,EAAkB,IAAM,CACxBnB,EAAM,KAAK,GAAK,CAACI,GACnBF,EAAO,CAEX,EAEMkB,EAAUpB,EAAM,KAAK,EAAE,OAAS,GAAK,CAACI,EAE5C,OACET,EAAC,OAAI,UAAW,0CAA0Ca,CAAS,GAEjE,UAAAd,EAAC,OACC,UAAU,
|
|
4
|
+
"sourcesContent": ["/**\n * \u804A\u5929\u8F93\u5165\u6846\u7EC4\u4EF6\n * \u63D0\u4F9B\u6587\u672C\u8F93\u5165\u548C\u53D1\u9001\u6309\u94AE\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u8F93\u5165\u6846\u8BBE\u8BA1\n */\n\nimport React, { useRef, useEffect } from 'react'\n\nexport interface ChatInputProps {\n /**\n * \u8F93\u5165\u6846\u5F53\u524D\u503C\n */\n value: string\n\n /**\n * \u503C\u53D8\u5316\u56DE\u8C03\n */\n onChange: (value: string) => void\n\n /**\n * \u53D1\u9001\u6D88\u606F\u56DE\u8C03\n */\n onSend: () => void\n\n /**\n * \u5360\u4F4D\u7B26\u6587\u672C\n * @default \"\u8F93\u5165\u6D88\u606F...\"\n */\n placeholder?: string\n\n /**\n * \u662F\u5426\u7981\u7528\u8F93\u5165\n * @default false\n */\n disabled?: boolean\n\n /**\n * \u662F\u5426\u81EA\u52A8\u805A\u7126\n * @default false\n */\n autoFocus?: boolean\n\n /**\n * \u6700\u5927\u5B57\u7B26\u6570\n * @default 5000\n */\n maxLength?: number\n\n /**\n * \u81EA\u5B9A\u4E49\u6837\u5F0F\u7C7B\u540D\n */\n className?: string\n\n /**\n * \u5E95\u90E8\u63D0\u793A\u6587\u672C\n * \u4E0D\u4F20\u5165\u5219\u4E0D\u663E\u793A\n */\n bottomTips?: string\n}\n\n/**\n * \u53D1\u9001\u56FE\u6807 (\u5411\u4E0A\u7BAD\u5934)\n */\nconst SendIcon: React.FC = () => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M10.2069 15.6997V4.69971\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" />\n <path\n d=\"M15.3995 8.50341L10.9506 4.05446C10.534 3.6379 9.85866 3.63791 9.4421 4.05446L5.00005 8.49651\"\n stroke=\"white\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n)\n\n/**\n * \u804A\u5929\u8F93\u5165\u6846\u7EC4\u4EF6\n *\n * \u529F\u80FD\uFF1A\n * - \u591A\u884C\u6587\u672C\u8F93\u5165\uFF08\u81EA\u52A8\u589E\u957F\uFF09\n * - Enter \u53D1\u9001\uFF0CShift+Enter \u6362\u884C\n * - \u5B57\u7B26\u6570\u9650\u5236\uFF085000\uFF09\n * - \u7981\u7528\u72B6\u6001\uFF08\u53D1\u9001\u4E2D\uFF09\n * - \u53D1\u9001\u6309\u94AE\uFF08\u7A7A\u5185\u5BB9\u65F6\u7981\u7528\uFF09\n *\n * \u6837\u5F0F\uFF1A\n * - \u56FA\u5B9A\u5E95\u90E8\n * - \u8FB9\u6846\u5206\u9694\u4E0A\u65B9\u5185\u5BB9\n * - \u81EA\u9002\u5E94\u9AD8\u5EA6\uFF081-5 \u884C\uFF09\n *\n * @example\n * ```tsx\n * <ChatInput\n * value={inputValue}\n * onChange={setInputValue}\n * onSend={handleSend}\n * disabled={isStreaming}\n * />\n * ```\n */\nexport const ChatInput: React.FC<ChatInputProps> = ({\n value,\n onChange,\n onSend,\n placeholder = '',\n disabled = false,\n autoFocus = false,\n maxLength = 5000,\n bottomTips,\n className = '',\n}) => {\n const textareaRef = useRef<HTMLTextAreaElement>(null)\n // \u8DDF\u8E2A\u8F93\u5165\u6CD5\u72B6\u6001\uFF08\u662F\u5426\u6B63\u5728\u4F7F\u7528\u62FC\u97F3\u8F93\u5165\u7B49\uFF09\n const isComposingRef = useRef(false)\n\n /**\n * \u81EA\u52A8\u8C03\u6574 textarea \u9AD8\u5EA6\n */\n useEffect(() => {\n const textarea = textareaRef.current\n if (!textarea) return\n\n // \u91CD\u7F6E\u9AD8\u5EA6\u4EE5\u83B7\u53D6\u6B63\u786E\u7684 scrollHeight\n textarea.style.height = 'auto'\n\n // \u8BBE\u7F6E\u9AD8\u5EA6\uFF0C\u6700\u5927 5 \u884C\uFF08\u7EA6 120px\uFF09\n const maxHeight = 120\n const newHeight = Math.min(textarea.scrollHeight, maxHeight)\n textarea.style.height = `${newHeight}px`\n }, [value])\n\n /**\n * \u5904\u7406\u8F93\u5165\u6CD5\u5F00\u59CB\n */\n const handleCompositionStart = () => {\n isComposingRef.current = true\n }\n\n /**\n * \u5904\u7406\u8F93\u5165\u6CD5\u7ED3\u675F\n */\n const handleCompositionEnd = () => {\n isComposingRef.current = false\n }\n\n /**\n * \u5904\u7406\u952E\u76D8\u4E8B\u4EF6\n * Enter \u53D1\u9001\uFF0CShift+Enter \u6362\u884C\n * \u6CE8\u610F\uFF1A\u8F93\u5165\u6CD5\u6FC0\u6D3B\u65F6\uFF08\u5982\u62FC\u97F3\u8F93\u5165\u4E2D\uFF09\uFF0C\u56DE\u8F66\u952E\u4E0D\u5E94\u53D1\u9001\u6D88\u606F\n */\n const handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (event.key === 'Enter' && !event.shiftKey) {\n // \u5982\u679C\u6B63\u5728\u4F7F\u7528\u8F93\u5165\u6CD5\uFF08\u5982\u62FC\u97F3\u8F93\u5165\uFF09\uFF0C\u5219\u4E0D\u53D1\u9001\u6D88\u606F\n // \u8BA9\u8F93\u5165\u6CD5\u5148\u5B8C\u6210\u5B57\u7B26\u9009\u62E9\n if (isComposingRef.current) {\n return\n }\n\n event.preventDefault()\n if (value.trim() && !disabled) {\n onSend()\n }\n }\n }\n\n /**\n * \u5904\u7406\u8F93\u5165\u53D8\u5316\n */\n const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {\n const newValue = event.target.value\n\n // \u5B57\u7B26\u6570\u9650\u5236\n if (newValue.length <= maxLength) {\n onChange(newValue)\n }\n }\n\n /**\n * \u5904\u7406\u53D1\u9001\u6309\u94AE\u70B9\u51FB\n */\n const handleSendClick = () => {\n if (value.trim() && !disabled) {\n onSend()\n }\n }\n\n const canSend = value.trim().length > 0 && !disabled\n\n return (\n <div className={`flex flex-col gap-2 bg-white px-4 py-4 ${className}`}>\n {/* \u8F93\u5165\u6846\u5BB9\u5668 - \u5E26\u6E10\u53D8\u8FB9\u6846 */}\n <div\n className=\"flex items-center gap-2 rounded-2xl\"\n style={{\n background: 'linear-gradient(to right, #7687F3, #7687F3, #4DA8F5, #A3DFCE)',\n padding: '2px',\n }}\n >\n {/* \u5185\u90E8\u767D\u8272\u80CC\u666F */}\n <div className=\"flex flex-1 items-center gap-2 bg-white px-3 py-2\" style={{ borderRadius: '14px' }}>\n {/* \u6587\u672C\u8F93\u5165\u6846 */}\n <textarea\n ref={textareaRef}\n value={value}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n onCompositionStart={handleCompositionStart}\n onCompositionEnd={handleCompositionEnd}\n placeholder={placeholder}\n disabled={disabled}\n autoFocus={autoFocus}\n rows={1}\n className=\"flex-1 resize-none bg-transparent font-bold text-sm text-gray-900 outline-none placeholder:text-gray-400 disabled:cursor-not-allowed disabled:opacity-50\"\n style={{\n resize: 'none',\n }}\n />\n\n {/* \u5B57\u7B26\u6570\u63D0\u793A (\u63A5\u8FD1\u4E0A\u9650\u65F6\u663E\u793A) */}\n {value.length > maxLength * 0.8 && (\n <span className=\"text-xs text-gray-400\">\n {value.length}/{maxLength}\n </span>\n )}\n\n {/* \u53D1\u9001\u6309\u94AE */}\n <button\n type=\"button\"\n onClick={handleSendClick}\n disabled={!canSend}\n className={`shrink-0 rounded-full p-2 transition-all ${canSend ? ' active:scale-95' : 'cursor-not-allowed '}`}\n style={\n canSend\n ? {\n background: 'linear-gradient(to bottom, #A3DFCE, #4DA8F5, #7687F3)',\n }\n : { background: '#BEBEBE' }\n }\n aria-label=\"Send message\"\n >\n <SendIcon />\n </button>\n </div>\n </div>\n {bottomTips && (\n <p className=\"px-3 font-bold text-[12px] text-[#767880] tracking-tight leading-[1.4]\">\n {bottomTips}\n </p>\n )}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "AAgEE,OACE,OAAAA,EADF,QAAAC,MAAA,oBA1DF,OAAgB,UAAAC,EAAQ,aAAAC,MAAiB,QAyDzC,MAAMC,EAAqB,IACzBH,EAAC,OAAI,MAAM,KAAK,OAAO,KAAK,QAAQ,YAAY,KAAK,OAAO,MAAM,6BAChE,UAAAD,EAAC,QAAK,EAAE,2BAA2B,OAAO,QAAQ,eAAa,IAAI,iBAAe,QAAQ,EAC1FA,EAAC,QACC,EAAE,gGACF,OAAO,QACP,eAAa,IACb,iBAAe,QACf,kBAAgB,QAClB,GACF,EA4BWK,EAAsC,CAAC,CAClD,MAAAC,EACA,SAAAC,EACA,OAAAC,EACA,YAAAC,EAAc,GACd,SAAAC,EAAW,GACX,UAAAC,EAAY,GACZ,UAAAC,EAAY,IACZ,WAAAC,EACA,UAAAC,EAAY,EACd,IAAM,CACJ,MAAMC,EAAcb,EAA4B,IAAI,EAE9Cc,EAAiBd,EAAO,EAAK,EAKnCC,EAAU,IAAM,CACd,MAAMc,EAAWF,EAAY,QAC7B,GAAI,CAACE,EAAU,OAGfA,EAAS,MAAM,OAAS,OAIxB,MAAMC,EAAY,KAAK,IAAID,EAAS,aADlB,GACyC,EAC3DA,EAAS,MAAM,OAAS,GAAGC,CAAS,IACtC,EAAG,CAACZ,CAAK,CAAC,EAKV,MAAMa,EAAyB,IAAM,CACnCH,EAAe,QAAU,EAC3B,EAKMI,EAAuB,IAAM,CACjCJ,EAAe,QAAU,EAC3B,EAOMK,EAAiBC,GAAoD,CACzE,GAAIA,EAAM,MAAQ,SAAW,CAACA,EAAM,SAAU,CAG5C,GAAIN,EAAe,QACjB,OAGFM,EAAM,eAAe,EACjBhB,EAAM,KAAK,GAAK,CAACI,GACnBF,EAAO,CAEX,CACF,EAKMe,EAAgBD,GAAkD,CACtE,MAAME,EAAWF,EAAM,OAAO,MAG1BE,EAAS,QAAUZ,GACrBL,EAASiB,CAAQ,CAErB,EAKMC,EAAkB,IAAM,CACxBnB,EAAM,KAAK,GAAK,CAACI,GACnBF,EAAO,CAEX,EAEMkB,EAAUpB,EAAM,KAAK,EAAE,OAAS,GAAK,CAACI,EAE5C,OACET,EAAC,OAAI,UAAW,0CAA0Ca,CAAS,GAEjE,UAAAd,EAAC,OACC,UAAU,sCACV,MAAO,CACL,WAAY,gEACZ,QAAS,KACX,EAGA,SAAAC,EAAC,OAAI,UAAU,oDAAoD,MAAO,CAAE,aAAc,MAAO,EAE/F,UAAAD,EAAC,YACC,IAAKe,EACL,MAAOT,EACP,SAAUiB,EACV,UAAWF,EACX,mBAAoBF,EACpB,iBAAkBC,EAClB,YAAaX,EACb,SAAUC,EACV,UAAWC,EACX,KAAM,EACN,UAAU,2JACV,MAAO,CACL,OAAQ,MACV,EACF,EAGCL,EAAM,OAASM,EAAY,IAC1BX,EAAC,QAAK,UAAU,wBACb,UAAAK,EAAM,OAAO,IAAEM,GAClB,EAIFZ,EAAC,UACC,KAAK,SACL,QAASyB,EACT,SAAU,CAACC,EACX,UAAW,4CAA4CA,EAAU,mBAAqB,qBAAqB,GAC3G,MACEA,EACI,CACE,WAAY,uDACd,EACA,CAAE,WAAY,SAAU,EAE9B,aAAW,eAEX,SAAA1B,EAACI,EAAA,EAAS,EACZ,GACF,EACF,EACCS,GACCb,EAAC,KAAE,UAAU,yEACV,SAAAa,EACH,GAEJ,CAEJ",
|
|
6
6
|
"names": ["jsx", "jsxs", "useRef", "useEffect", "SendIcon", "ChatInput", "value", "onChange", "onSend", "placeholder", "disabled", "autoFocus", "maxLength", "bottomTips", "className", "textareaRef", "isComposingRef", "textarea", "newHeight", "handleCompositionStart", "handleCompositionEnd", "handleKeyDown", "event", "handleChange", "newValue", "handleSendClick", "canSend"]
|
|
7
7
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{jsx as s,jsxs as
|
|
1
|
+
import{jsx as s,jsxs as C}from"react/jsx-runtime";import{MessageContent as d}from"./MessageContent";import u from"classnames";function v(t){const r=new Date(t),o=r.getHours().toString().padStart(2,"0"),i=r.getMinutes().toString().padStart(2,"0");return`${o}:${i}`}const $=({message:t,rendererRegistry:r,defaultRenderer:o,showTimestamp:i=!0,className:c="",onAddToCart:p})=>{const n=t.role==="user",R=t.role==="assistant",y=t.role==="system",g=t.role==="tool";if(y)return s("div",{className:`flex justify-center py-2 ${c}`,children:s("div",{className:"",children:t.content.map((e,a)=>s(d,{content:e,isUser:!1,isSystem:!0,rendererRegistry:r,defaultRenderer:o},a))})});if(g)return null;const f=["product_list","product_comparison","faq_list","promotion_list","cart"],l=t.content.filter(e=>!f.includes(e.type)),x=t.content.filter(e=>f.includes(e.type)),m=l.some(e=>e.type==="product_card");return s("div",{className:`flex ${n?"justify-end":"justify-start"} py-2 ${c}`,children:C("div",{className:"flex w-fit max-w-full flex-col gap-2",children:[l.length>0&&s("div",{className:u("w-fit min-w-0 overflow-hidden rounded-2xl ",n?"text-white":"text-[#1D1D1F]",m?"p-4":"p-3"),style:{backgroundColor:n?"#005D8E":"#F5F6F7"},children:s("div",{className:u("flex w-full min-w-0 flex-col",m?"gap-0":"gap-2"),children:l.map((e,a)=>s(d,{content:e,isUser:n,isSystem:!1,rendererRegistry:r,defaultRenderer:o,onAddToCart:p},a))})}),x.map((e,a)=>s("div",{className:"w-full",children:s(d,{content:e,isUser:n,isSystem:!1,rendererRegistry:r,defaultRenderer:o,onAddToCart:p})},`standalone-${a}`)),i&&s("span",{className:`
|
|
2
2
|
px-2 text-xs text-gray-400
|
|
3
3
|
${n?"text-right":"text-left"}
|
|
4
|
-
`,children:
|
|
4
|
+
`,children:v(t.timestamp)})]})})};export{$ as ChatMessage};
|
|
5
5
|
//# sourceMappingURL=ChatMessage.js.map
|