@anker-in/campaign-ui 0.5.22 → 0.5.24
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/README.md +21 -1
- package/dist/cjs/components/credits/creditsWaysToGetCredits/useActions.js +1 -1
- package/dist/cjs/components/credits/creditsWaysToGetCredits/useActions.js.map +2 -2
- package/dist/cjs/components/credits/modal/SubscribeModal.d.ts +1 -0
- package/dist/cjs/components/credits/modal/SubscribeModal.js +1 -1
- package/dist/cjs/components/credits/modal/SubscribeModal.js.map +3 -3
- package/dist/esm/components/credits/creditsWaysToGetCredits/useActions.js +1 -1
- package/dist/esm/components/credits/creditsWaysToGetCredits/useActions.js.map +2 -2
- package/dist/esm/components/credits/modal/SubscribeModal.d.ts +1 -0
- package/dist/esm/components/credits/modal/SubscribeModal.js +1 -1
- package/dist/esm/components/credits/modal/SubscribeModal.js.map +3 -3
- package/package.json +1 -1
- package/src/components/credits/creditsWaysToGetCredits/useActions.ts +1 -1
- package/src/components/credits/modal/SubscribeModal.tsx +75 -63
- package/dist/cjs/stories/LiveChatWidget.stories.d.ts +0 -14
- package/dist/cjs/stories/LiveChatWidget.stories.js +0 -52
- package/dist/cjs/stories/LiveChatWidget.stories.js.map +0 -7
- package/dist/cjs/stories/chat.stories.d.ts +0 -7
- package/dist/cjs/stories/chat.stories.js +0 -2
- package/dist/cjs/stories/chat.stories.js.map +0 -7
- package/dist/esm/stories/LiveChatWidget.stories.d.ts +0 -14
- package/dist/esm/stories/LiveChatWidget.stories.js +0 -52
- package/dist/esm/stories/LiveChatWidget.stories.js.map +0 -7
- package/dist/esm/stories/chat.stories.d.ts +0 -7
- package/dist/esm/stories/chat.stories.js +0 -2
- package/dist/esm/stories/chat.stories.js.map +0 -7
- package/src/stories/LiveChatWidget.stories.tsx +0 -317
- package/src/stories/chat.stories.tsx +0 -41
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* LiveChatWidget Storybook Stories
|
|
3
|
-
* 展示 LiveChat 组件的各种使用场景和配置
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { Meta, StoryObj } from '@storybook/react'
|
|
7
|
-
import { LiveChatWidget } from '../components/LiveChatWidget'
|
|
8
|
-
import type { MessageRenderer, MessageContent } from '../components/LiveChatWidget'
|
|
9
|
-
import '../styles/livechat.css'
|
|
10
|
-
|
|
11
|
-
const meta: Meta<typeof LiveChatWidget> = {
|
|
12
|
-
title: 'Campaign/LiveChatWidget',
|
|
13
|
-
component: LiveChatWidget,
|
|
14
|
-
parameters: {
|
|
15
|
-
layout: 'fullscreen',
|
|
16
|
-
docs: {
|
|
17
|
-
story: {
|
|
18
|
-
inline: false,
|
|
19
|
-
iframeHeight: 500,
|
|
20
|
-
},
|
|
21
|
-
description: {
|
|
22
|
-
component: `
|
|
23
|
-
# LiveChat 聊天组件
|
|
24
|
-
|
|
25
|
-
可复用的气泡弹窗聊天组件,支持 SSE 流式消息、自定义渲染器和多种消息类型。
|
|
26
|
-
|
|
27
|
-
## 功能特性
|
|
28
|
-
|
|
29
|
-
- 🎈 **气泡弹窗**: 可自定义位置的悬浮气泡按钮
|
|
30
|
-
- 💬 **流式消息**: 基于 SSE 的实时流式响应
|
|
31
|
-
- 📦 **多种消息类型**: 文本、商品卡片、商品列表、政策、快捷回复等
|
|
32
|
-
- 🎨 **可定制**: 支持自定义品牌颜色、Logo、渲染器
|
|
33
|
-
- 📱 **响应式**: 移动端全屏,桌面端固定尺寸
|
|
34
|
-
- 💾 **会话管理**: 自动管理 userId 和 sessionId
|
|
35
|
-
- 🔒 **安全防护**: 内置 XSS 防护和输入验证
|
|
36
|
-
|
|
37
|
-
## 基础用法
|
|
38
|
-
|
|
39
|
-
\`\`\`tsx
|
|
40
|
-
import { LiveChatWidget } from '@anker-in/campaign-ui'
|
|
41
|
-
import '@anker-in/campaign-ui/livechat.css'
|
|
42
|
-
|
|
43
|
-
function App() {
|
|
44
|
-
return (
|
|
45
|
-
<LiveChatWidget
|
|
46
|
-
apiBaseUrl="https://beta-api-livechat.anker.com"
|
|
47
|
-
site="www.eufy.com"
|
|
48
|
-
channel_code="web_homepage"
|
|
49
|
-
welcomeMessage="你好!我是 AI 助手"
|
|
50
|
-
/>
|
|
51
|
-
)
|
|
52
|
-
}
|
|
53
|
-
\`\`\`
|
|
54
|
-
|
|
55
|
-
## 自定义渲染器
|
|
56
|
-
|
|
57
|
-
\`\`\`tsx
|
|
58
|
-
const customRenderers = {
|
|
59
|
-
video: {
|
|
60
|
-
render: (content) => (
|
|
61
|
-
<video src={content.url} controls className="w-full rounded" />
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
<LiveChatWidget
|
|
67
|
-
apiBaseUrl="..."
|
|
68
|
-
site="..."
|
|
69
|
-
customRenderers={customRenderers}
|
|
70
|
-
/>
|
|
71
|
-
\`\`\`
|
|
72
|
-
`,
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
tags: ['autodocs'],
|
|
77
|
-
argTypes: {
|
|
78
|
-
apiBaseUrl: {
|
|
79
|
-
control: 'text',
|
|
80
|
-
description: 'API 基础 URL',
|
|
81
|
-
},
|
|
82
|
-
headers: {
|
|
83
|
-
control: 'object',
|
|
84
|
-
description: '自定义请求头,将在所有 API 请求中添加',
|
|
85
|
-
table: {
|
|
86
|
-
defaultValue: { summary: 'undefined' },
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
recaptchaSitekey: {
|
|
90
|
-
control: 'text',
|
|
91
|
-
description: 'Google reCAPTCHA v3 site key,提供此参数将自动启用 reCAPTCHA v3 验证',
|
|
92
|
-
table: {
|
|
93
|
-
defaultValue: { summary: 'undefined' },
|
|
94
|
-
},
|
|
95
|
-
},
|
|
96
|
-
recaptchaAction: {
|
|
97
|
-
control: 'text',
|
|
98
|
-
description: 'reCAPTCHA action 名称,用于区分不同的验证场景',
|
|
99
|
-
table: {
|
|
100
|
-
defaultValue: { summary: '"activity"' },
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
site: {
|
|
104
|
-
control: 'text',
|
|
105
|
-
description: 'Shopify 店铺 URL',
|
|
106
|
-
},
|
|
107
|
-
channelCode: {
|
|
108
|
-
control: 'text',
|
|
109
|
-
description: '渠道编码,用于标识来源渠道',
|
|
110
|
-
table: {
|
|
111
|
-
defaultValue: { summary: 'undefined' },
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
welcomeMessage: {
|
|
115
|
-
control: 'text',
|
|
116
|
-
description: '欢迎消息',
|
|
117
|
-
table: {
|
|
118
|
-
defaultValue: { summary: '你好!我是 AI 助手,有什么可以帮助你的吗?' },
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
logoUrl: {
|
|
122
|
-
control: 'text',
|
|
123
|
-
description: 'Logo URL',
|
|
124
|
-
},
|
|
125
|
-
position: {
|
|
126
|
-
control: 'object',
|
|
127
|
-
description: '气泡按钮位置对象',
|
|
128
|
-
table: {
|
|
129
|
-
defaultValue: { summary: '{ bottom: "1.5rem", right: "1.5rem" }' },
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
},
|
|
133
|
-
args: {
|
|
134
|
-
apiBaseUrl: 'http://172.16.38.183:3003',
|
|
135
|
-
site: 'www.eufy.com',
|
|
136
|
-
loginUserId: 'test_test',
|
|
137
|
-
welcomeMessage: '你好!我是 AI 助手,有什么可以帮助你的吗?',
|
|
138
|
-
},
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export default meta
|
|
142
|
-
type Story = StoryObj<typeof LiveChatWidget>
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* 默认配置 - 展示所有功能
|
|
146
|
-
*/
|
|
147
|
-
export const Default: Story = {
|
|
148
|
-
args: {
|
|
149
|
-
// 基础配置
|
|
150
|
-
loginUserId: 'test_test1',
|
|
151
|
-
apiBaseUrl: 'https://beta-api-v2-livechat.anker.com',
|
|
152
|
-
site: 'beta.soundcore.com',
|
|
153
|
-
channelCode: 'dtc',
|
|
154
|
-
title: 'eufy AI Assistant',
|
|
155
|
-
cartId: 'gid://shopify/Cart/hWNAAJweS9IkeRKib4LRy9PY?key=ff1f9b24e74b3f11f5574539e7cbbb2f',
|
|
156
|
-
accessToken: '47b1aa2c0797043f9baba39388029d70',
|
|
157
|
-
|
|
158
|
-
// 自定义位置
|
|
159
|
-
position: { bottom: '24px', right: '30px' },
|
|
160
|
-
|
|
161
|
-
// 欢迎消息
|
|
162
|
-
welcomeMessage: '',
|
|
163
|
-
|
|
164
|
-
// 快捷回复
|
|
165
|
-
quickReplies: [
|
|
166
|
-
{ id: '1', label: 'Product Info', value: 'Tell me about your products', icon: '📦' },
|
|
167
|
-
{ id: '2', label: 'Track Order', value: 'I want to track my order', icon: '🚚' },
|
|
168
|
-
{ id: '3', label: 'Support', value: 'I need help with my device', icon: '🔧' },
|
|
169
|
-
{ id: '4', label: 'Recommendations', value: 'Recommend products for me', icon: '⭐' },
|
|
170
|
-
],
|
|
171
|
-
|
|
172
|
-
// 法规协议弹窗
|
|
173
|
-
complianceConfig: {
|
|
174
|
-
title: "Hi! I'm your eufy AI assistant.",
|
|
175
|
-
content:
|
|
176
|
-
'AI-generated responses can be inaccurate. Please verify important info. Do not input sensitive personal data.',
|
|
177
|
-
checkboxText:
|
|
178
|
-
'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>.',
|
|
179
|
-
agreeButtonText: 'Agree',
|
|
180
|
-
},
|
|
181
|
-
|
|
182
|
-
// reCAPTCHA 配置(取消注释以启用)
|
|
183
|
-
// recaptchaSitekey: '6LfS4J4pAAAAACX1e_WrxutmxxzCK7FU4WzVqL14',
|
|
184
|
-
recaptchaAction: 'livechat',
|
|
185
|
-
|
|
186
|
-
// 显示新会话按钮
|
|
187
|
-
showNewSessionButton: true,
|
|
188
|
-
|
|
189
|
-
// 自定义文案
|
|
190
|
-
commonText: {
|
|
191
|
-
learnMore: 'Learn More',
|
|
192
|
-
total: 'Total',
|
|
193
|
-
},
|
|
194
|
-
|
|
195
|
-
// 自定义消息渲染器
|
|
196
|
-
customRenderers: {
|
|
197
|
-
video: {
|
|
198
|
-
render: (content: MessageContent) => {
|
|
199
|
-
const videoContent = content as any
|
|
200
|
-
return (
|
|
201
|
-
<div className="w-full">
|
|
202
|
-
<video src={videoContent.url} controls className="w-full rounded-lg" poster={videoContent.poster}>
|
|
203
|
-
Your browser does not support video playback
|
|
204
|
-
</video>
|
|
205
|
-
{videoContent.title && <p className="mt-2 text-sm text-gray-600">{videoContent.title}</p>}
|
|
206
|
-
</div>
|
|
207
|
-
)
|
|
208
|
-
},
|
|
209
|
-
} as MessageRenderer,
|
|
210
|
-
image_gallery: {
|
|
211
|
-
render: (content: MessageContent) => {
|
|
212
|
-
const galleryContent = content as any
|
|
213
|
-
const images = galleryContent.images || []
|
|
214
|
-
return (
|
|
215
|
-
<div className="grid grid-cols-2 gap-2">
|
|
216
|
-
{images.map((image: any, index: number) => (
|
|
217
|
-
<div key={index} className="relative aspect-square">
|
|
218
|
-
<img
|
|
219
|
-
src={image.url}
|
|
220
|
-
alt={image.alt || `Image ${index + 1}`}
|
|
221
|
-
className="size-full rounded-lg object-cover"
|
|
222
|
-
/>
|
|
223
|
-
</div>
|
|
224
|
-
))}
|
|
225
|
-
</div>
|
|
226
|
-
)
|
|
227
|
-
},
|
|
228
|
-
} as MessageRenderer,
|
|
229
|
-
},
|
|
230
|
-
|
|
231
|
-
// 自定义产品卡片渲染
|
|
232
|
-
productCardRender: (product, productHandle) => {
|
|
233
|
-
// product 可能为 undefined,此时可用 productHandle 查询
|
|
234
|
-
if (!product) {
|
|
235
|
-
return (
|
|
236
|
-
<div style={{ padding: '16px', border: '1px dashed #ccc', borderRadius: '8px', textAlign: 'center' }}>
|
|
237
|
-
<p>Product loading... (handle: {productHandle})</p>
|
|
238
|
-
</div>
|
|
239
|
-
)
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const imageUrl = product?.featured_image || ''
|
|
243
|
-
const title = product?.title || ''
|
|
244
|
-
const description = product?.description || ''
|
|
245
|
-
const averageRating = product?.average_rating
|
|
246
|
-
|
|
247
|
-
return (
|
|
248
|
-
<div
|
|
249
|
-
style={{
|
|
250
|
-
border: '2px solid #4CAF50',
|
|
251
|
-
borderRadius: '16px',
|
|
252
|
-
padding: '16px',
|
|
253
|
-
margin: '12px 0',
|
|
254
|
-
backgroundColor: '#f0f9ff',
|
|
255
|
-
boxShadow: '0 4px 12px rgba(76, 175, 80, 0.15)',
|
|
256
|
-
}}
|
|
257
|
-
>
|
|
258
|
-
<div style={{ display: 'flex', gap: '12px', alignItems: 'center' }}>
|
|
259
|
-
{imageUrl && (
|
|
260
|
-
<img
|
|
261
|
-
src={imageUrl}
|
|
262
|
-
alt={title}
|
|
263
|
-
style={{ width: '60px', height: '60px', borderRadius: '8px', objectFit: 'cover' }}
|
|
264
|
-
/>
|
|
265
|
-
)}
|
|
266
|
-
<div style={{ flex: 1 }}>
|
|
267
|
-
<h4 style={{ margin: '0 0 4px 0', fontSize: '16px', fontWeight: 'bold' }}>{title}</h4>
|
|
268
|
-
{description && (
|
|
269
|
-
<p style={{ margin: 0, fontSize: '12px', color: '#666', lineHeight: 1.4 }}>
|
|
270
|
-
{description.slice(0, 80)}...
|
|
271
|
-
</p>
|
|
272
|
-
)}
|
|
273
|
-
{averageRating && (
|
|
274
|
-
<span style={{ fontSize: '12px', color: '#FFB800' }}>Rating: {averageRating.toFixed(1)}</span>
|
|
275
|
-
)}
|
|
276
|
-
</div>
|
|
277
|
-
<button
|
|
278
|
-
style={{
|
|
279
|
-
padding: '8px 16px',
|
|
280
|
-
backgroundColor: '#4CAF50',
|
|
281
|
-
color: 'white',
|
|
282
|
-
borderRadius: '8px',
|
|
283
|
-
border: 'none',
|
|
284
|
-
cursor: 'pointer',
|
|
285
|
-
}}
|
|
286
|
-
onClick={() => console.log('View product:', productHandle, product)}
|
|
287
|
-
>
|
|
288
|
-
View
|
|
289
|
-
</button>
|
|
290
|
-
</div>
|
|
291
|
-
</div>
|
|
292
|
-
)
|
|
293
|
-
},
|
|
294
|
-
},
|
|
295
|
-
|
|
296
|
-
render: args => (
|
|
297
|
-
<LiveChatWidget
|
|
298
|
-
{...args}
|
|
299
|
-
// 所有事件回调
|
|
300
|
-
onOpen={() => console.log('[LiveChat] Chat opened')}
|
|
301
|
-
onClose={() => console.log('[LiveChat] Chat closed')}
|
|
302
|
-
onMessageSend={(message: string) => console.log('[LiveChat] Message sent:', message)}
|
|
303
|
-
onError={(error: Error) => console.error('[LiveChat] Error:', error)}
|
|
304
|
-
onTextMessage={() => console.log('[LiveChat] AI text message received')}
|
|
305
|
-
onProductList={() => console.log('[LiveChat] Product list received')}
|
|
306
|
-
onPromotionList={() => console.log('[LiveChat] Promotion list received')}
|
|
307
|
-
onAddToCart={(product: any) => {
|
|
308
|
-
console.log('[LiveChat] Add to cart:', product)
|
|
309
|
-
alert(`Added "${product.title}" to cart!`)
|
|
310
|
-
}}
|
|
311
|
-
onCart={(cartId: string, checkoutUrl?: string) => {
|
|
312
|
-
console.log('[LiveChat] Cart clicked:', { cartId, checkoutUrl })
|
|
313
|
-
alert(`Cart ID: ${cartId}`)
|
|
314
|
-
}}
|
|
315
|
-
/>
|
|
316
|
-
),
|
|
317
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import type { Meta, StoryObj } from '@storybook/react'
|
|
3
|
-
import { Chat } from '../components/index'
|
|
4
|
-
import '../styles/chat.css'
|
|
5
|
-
|
|
6
|
-
type Story = StoryObj<typeof meta>
|
|
7
|
-
|
|
8
|
-
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
|
|
9
|
-
const meta: Meta<typeof Chat> = {
|
|
10
|
-
// 同时定义了页面左侧菜单
|
|
11
|
-
title: 'Campaign/Chat',
|
|
12
|
-
component: Chat,
|
|
13
|
-
args: {
|
|
14
|
-
title: 'DTC Live Chat',
|
|
15
|
-
runtimeUrl: 'https://beta-api-livechat.anker.com',
|
|
16
|
-
shopifyDomain: 'soundcoreusa.myshopify.com',
|
|
17
|
-
},
|
|
18
|
-
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
|
|
19
|
-
tags: ['autodocs'],
|
|
20
|
-
// More on argTypes: https://storybook.js.org/docs/api/argtypes
|
|
21
|
-
decorators: [
|
|
22
|
-
Story => (
|
|
23
|
-
<div style={{ height: '700px' }}>
|
|
24
|
-
<Story />
|
|
25
|
-
</div>
|
|
26
|
-
),
|
|
27
|
-
],
|
|
28
|
-
} satisfies Meta<typeof Chat>
|
|
29
|
-
|
|
30
|
-
export default meta
|
|
31
|
-
|
|
32
|
-
export const Default: Story = {
|
|
33
|
-
args: {
|
|
34
|
-
title: 'DTC Live Chat',
|
|
35
|
-
runtimeUrl: 'https://beta-api-livechat.anker.com',
|
|
36
|
-
shopifyDomain: 'soundcoreusa.myshopify.com',
|
|
37
|
-
userId: 'arno7',
|
|
38
|
-
showResponseButton: 'follow',
|
|
39
|
-
lang: { popupTip: 'Hi ! Welcome to soundcore Innovations live chat!', popupTipTimeout: [3000, 6000] },
|
|
40
|
-
},
|
|
41
|
-
}
|