@product7/product7-js 0.2.7 → 0.3.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/README.md +40 -39
- package/dist/README.md +40 -39
- package/dist/product7-js.js +183 -41
- package/dist/product7-js.js.map +1 -1
- package/dist/product7-js.min.js +1 -1
- package/dist/product7-js.min.js.map +1 -1
- package/package.json +1 -1
- package/src/styles/design-tokens.js +3 -3
- package/src/styles/messenger-components.js +85 -4
- package/src/styles/messenger-core.js +2 -2
- package/src/widgets/MessengerWidget.js +25 -4
- package/src/widgets/messenger/MessengerState.js +3 -1
- package/src/widgets/messenger/views/ChatView.js +61 -17
- package/src/widgets/messenger/views/HomeView.js +4 -10
package/package.json
CHANGED
|
@@ -47,8 +47,8 @@ export const designTokens = `
|
|
|
47
47
|
--msg-bg-elevated: #FFFFFF;
|
|
48
48
|
--msg-bg-hover: #F9FAFB;
|
|
49
49
|
--msg-bg-input: rgba(255, 255, 255, 0.7);
|
|
50
|
-
--msg-bg-bubble-own: #
|
|
51
|
-
--msg-bg-bubble-received:
|
|
50
|
+
--msg-bg-bubble-own: #F3F4F6;
|
|
51
|
+
--msg-bg-bubble-received: rgba(21, 94, 239, 0.06);
|
|
52
52
|
--msg-bg-header-gradient: linear-gradient(180deg, #e0e7ff 0%, #f0f4ff 35%, #FFFFFF 65%);
|
|
53
53
|
--msg-bg-header-glow1: radial-gradient(circle, rgba(21, 94, 239, 0.08) 0%, transparent 70%);
|
|
54
54
|
--msg-bg-header-glow2: radial-gradient(circle, rgba(139, 92, 246, 0.05) 0%, transparent 70%);
|
|
@@ -57,7 +57,7 @@ export const designTokens = `
|
|
|
57
57
|
--msg-text-tertiary: #6B7280;
|
|
58
58
|
--msg-text-muted: #9CA3AF;
|
|
59
59
|
--msg-border: #E5E7EB;
|
|
60
|
-
--msg-border-bubble:
|
|
60
|
+
--msg-border-bubble: transparent;
|
|
61
61
|
--msg-shadow-card: rgba(9, 30, 66, 0.25) 0px 1px 1px, rgba(9, 30, 66, 0.13) 0px 0px 1px 1px;
|
|
62
62
|
--msg-shadow-card-hover: rgba(9, 30, 66, 0.3) 0px 2px 2px, rgba(9, 30, 66, 0.18) 0px 0px 1px 1px;
|
|
63
63
|
|
|
@@ -10,6 +10,84 @@ export const messengerComponentsStyles = `
|
|
|
10
10
|
max-width: 85%;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
.messenger-message-system {
|
|
14
|
+
align-self: center;
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
gap: var(--spacing-2);
|
|
18
|
+
padding: var(--spacing-2) 0;
|
|
19
|
+
width: 100%;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.messenger-message-system::before,
|
|
23
|
+
.messenger-message-system::after {
|
|
24
|
+
content: '';
|
|
25
|
+
flex: 1;
|
|
26
|
+
height: 1px;
|
|
27
|
+
background: var(--msg-border);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.messenger-message-system-text {
|
|
31
|
+
font-size: 0.6875rem;
|
|
32
|
+
color: var(--msg-text-tertiary);
|
|
33
|
+
white-space: nowrap;
|
|
34
|
+
padding: 0 var(--spacing-2);
|
|
35
|
+
letter-spacing: 0.01em;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Rich join/leave system event */
|
|
39
|
+
.messenger-message-system-event {
|
|
40
|
+
align-self: center;
|
|
41
|
+
display: flex;
|
|
42
|
+
flex-direction: column;
|
|
43
|
+
align-items: center;
|
|
44
|
+
gap: var(--spacing-2);
|
|
45
|
+
padding: var(--spacing-4) 0;
|
|
46
|
+
width: 100%;
|
|
47
|
+
text-align: center;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.messenger-message-system-event-avatar {
|
|
51
|
+
width: 3rem;
|
|
52
|
+
height: 3rem;
|
|
53
|
+
border-radius: var(--radius-full);
|
|
54
|
+
border: 2px solid var(--msg-border);
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
justify-content: center;
|
|
58
|
+
font-size: 1.125rem;
|
|
59
|
+
font-weight: var(--font-weight-semibold);
|
|
60
|
+
color: #ffffff;
|
|
61
|
+
overflow: hidden;
|
|
62
|
+
flex-shrink: 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.messenger-message-system-event-avatar img {
|
|
66
|
+
width: 100%;
|
|
67
|
+
height: 100%;
|
|
68
|
+
object-fit: cover;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.messenger-message-system-event-name {
|
|
72
|
+
font-size: 0.875rem;
|
|
73
|
+
font-weight: var(--font-weight-semibold);
|
|
74
|
+
color: var(--msg-text);
|
|
75
|
+
line-height: 1.3;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.messenger-message-system-event-action {
|
|
79
|
+
font-size: 0.875rem;
|
|
80
|
+
font-weight: 500;
|
|
81
|
+
color: var(--msg-text-secondary);
|
|
82
|
+
margin-top: -2px;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.messenger-message-system-event-time {
|
|
86
|
+
font-size: 0.875rem;
|
|
87
|
+
font-weight: 500;
|
|
88
|
+
color: var(--msg-text-tertiary);
|
|
89
|
+
}
|
|
90
|
+
|
|
13
91
|
.messenger-message-own {
|
|
14
92
|
align-self: flex-end;
|
|
15
93
|
flex-direction: column;
|
|
@@ -50,7 +128,6 @@ export const messengerComponentsStyles = `
|
|
|
50
128
|
.messenger-message-own .messenger-message-bubble {
|
|
51
129
|
background: var(--msg-bg-bubble-own);
|
|
52
130
|
color: var(--msg-text);
|
|
53
|
-
border: 1px solid var(--msg-border-bubble);
|
|
54
131
|
border-bottom-right-radius: 0.25rem;
|
|
55
132
|
}
|
|
56
133
|
|
|
@@ -61,8 +138,8 @@ export const messengerComponentsStyles = `
|
|
|
61
138
|
}
|
|
62
139
|
|
|
63
140
|
.messenger-message-content {
|
|
64
|
-
font-size:
|
|
65
|
-
font-weight:
|
|
141
|
+
font-size: 0.875rem;
|
|
142
|
+
font-weight: 500;
|
|
66
143
|
line-height: var(--line-height-relaxed);
|
|
67
144
|
}
|
|
68
145
|
|
|
@@ -87,10 +164,14 @@ export const messengerComponentsStyles = `
|
|
|
87
164
|
gap: 0.375rem;
|
|
88
165
|
font-size: var(--font-size-xs);
|
|
89
166
|
color: var(--msg-text-tertiary);
|
|
90
|
-
margin-top: 0.
|
|
167
|
+
margin-top: 0.25rem;
|
|
91
168
|
padding: 0 var(--spacing-1);
|
|
92
169
|
}
|
|
93
170
|
|
|
171
|
+
.messenger-message-meta-own {
|
|
172
|
+
justify-content: flex-end;
|
|
173
|
+
}
|
|
174
|
+
|
|
94
175
|
.messenger-message-image {
|
|
95
176
|
max-width: 220px;
|
|
96
177
|
max-height: 200px;
|
|
@@ -203,8 +203,8 @@ export const messengerCoreStyles = `
|
|
|
203
203
|
--msg-bg-elevated: #232930;
|
|
204
204
|
--msg-bg-hover: #232930;
|
|
205
205
|
--msg-bg-input: #1a1e24;
|
|
206
|
-
--msg-bg-bubble-own: #
|
|
207
|
-
--msg-bg-bubble-received:
|
|
206
|
+
--msg-bg-bubble-own: #1e2330;
|
|
207
|
+
--msg-bg-bubble-received: rgba(21, 94, 239, 0.12);
|
|
208
208
|
--msg-bg-header-gradient: linear-gradient(180deg, #1a1e2e 0%, #141720 50%, #0f1317 100%);
|
|
209
209
|
--msg-bg-header-glow1: radial-gradient(circle, rgba(21, 94, 239, 0.07) 0%, transparent 70%);
|
|
210
210
|
--msg-bg-header-glow2: radial-gradient(circle, rgba(139, 92, 246, 0.05) 0%, transparent 70%);
|
|
@@ -48,6 +48,9 @@ export class MessengerWidget extends BaseWidget {
|
|
|
48
48
|
teamAvatars: options.teamAvatars || [],
|
|
49
49
|
greetingMessage: options.greetingMessage || 'Hi there 👋',
|
|
50
50
|
welcomeMessage: options.welcomeMessage || 'How can we help?',
|
|
51
|
+
onlineMessage: options.onlineMessage || "We're online now",
|
|
52
|
+
responseTime:
|
|
53
|
+
options.responseTime || 'We typically reply within a few minutes',
|
|
51
54
|
enableHelp: options.enableHelp !== false,
|
|
52
55
|
enableChangelog: resolvedEnableChangelog,
|
|
53
56
|
autoLoadData: options.autoLoadData !== false,
|
|
@@ -69,6 +72,8 @@ export class MessengerWidget extends BaseWidget {
|
|
|
69
72
|
teamAvatars: this.messengerOptions.teamAvatars,
|
|
70
73
|
greetingMessage: this.messengerOptions.greetingMessage,
|
|
71
74
|
welcomeMessage: this.messengerOptions.welcomeMessage,
|
|
75
|
+
onlineMessage: this.messengerOptions.onlineMessage,
|
|
76
|
+
responseTime: this.messengerOptions.responseTime,
|
|
72
77
|
enableHelp: this.messengerOptions.enableHelp,
|
|
73
78
|
enableChangelog: this.messengerOptions.enableChangelog,
|
|
74
79
|
metadata: this.sdk?.apiService?.getMetadata() || null,
|
|
@@ -390,6 +395,7 @@ export class MessengerWidget extends BaseWidget {
|
|
|
390
395
|
id: message.id,
|
|
391
396
|
content: message.content,
|
|
392
397
|
isOwn: message.sender_type === 'customer',
|
|
398
|
+
isSystem: message.sender_type === 'system',
|
|
393
399
|
timestamp: message.created_at,
|
|
394
400
|
attachments: attachments.length > 0 ? attachments : undefined,
|
|
395
401
|
sender: {
|
|
@@ -575,7 +581,9 @@ export class MessengerWidget extends BaseWidget {
|
|
|
575
581
|
if (data.availability && typeof data.availability === 'object') {
|
|
576
582
|
const availability = data.availability;
|
|
577
583
|
this.messengerState.agentsOnline = Boolean(
|
|
578
|
-
availability.agentsOnline ??
|
|
584
|
+
availability.agentsOnline ??
|
|
585
|
+
availability.agents_online ??
|
|
586
|
+
availability.is_online
|
|
579
587
|
);
|
|
580
588
|
this.messengerState.onlineCount =
|
|
581
589
|
availability.onlineCount ?? availability.online_count ?? 0;
|
|
@@ -703,6 +711,7 @@ export class MessengerWidget extends BaseWidget {
|
|
|
703
711
|
id: msg.id,
|
|
704
712
|
content: msg.content,
|
|
705
713
|
isOwn: msg.sender_type === 'customer',
|
|
714
|
+
isSystem: msg.sender_type === 'system',
|
|
706
715
|
timestamp: msg.created_at,
|
|
707
716
|
attachments:
|
|
708
717
|
attachments && attachments.length > 0 ? attachments : undefined,
|
|
@@ -753,14 +762,25 @@ export class MessengerWidget extends BaseWidget {
|
|
|
753
762
|
|
|
754
763
|
this.messengerState.addConversation(newConversation);
|
|
755
764
|
|
|
756
|
-
|
|
765
|
+
const initialMessages = [
|
|
757
766
|
{
|
|
758
767
|
id: 'msg_' + Date.now(),
|
|
759
768
|
content: message,
|
|
760
769
|
isOwn: true,
|
|
761
770
|
timestamp: new Date().toISOString(),
|
|
762
771
|
},
|
|
763
|
-
]
|
|
772
|
+
];
|
|
773
|
+
|
|
774
|
+
initialMessages.push({
|
|
775
|
+
id: 'system_rt_' + Date.now(),
|
|
776
|
+
content: this.messengerState.agentsOnline
|
|
777
|
+
? 'One of our customer support agents will be with you shortly.'
|
|
778
|
+
: this.messengerState.responseTime,
|
|
779
|
+
isSystem: true,
|
|
780
|
+
timestamp: new Date().toISOString(),
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
this.messengerState.setMessages(conv.id, initialMessages);
|
|
764
784
|
|
|
765
785
|
this.messengerState.setActiveConversation(conv.id);
|
|
766
786
|
this.messengerState.setView('chat');
|
|
@@ -786,7 +806,8 @@ export class MessengerWidget extends BaseWidget {
|
|
|
786
806
|
try {
|
|
787
807
|
const response = await this.apiService.checkAgentsOnline();
|
|
788
808
|
if (response.status && response.data) {
|
|
789
|
-
this.messengerState.agentsOnline =
|
|
809
|
+
this.messengerState.agentsOnline =
|
|
810
|
+
response.data.agents_online ?? response.data.is_online ?? false;
|
|
790
811
|
this.messengerState.onlineCount = response.data.online_count || 0;
|
|
791
812
|
this.messengerState.responseTime = response.data.response_time || '';
|
|
792
813
|
|
|
@@ -28,7 +28,9 @@ export class MessengerState {
|
|
|
28
28
|
|
|
29
29
|
this.agentsOnline = false;
|
|
30
30
|
this.onlineCount = 0;
|
|
31
|
-
this.
|
|
31
|
+
this.onlineMessage = options.onlineMessage || "We're online now";
|
|
32
|
+
this.responseTime =
|
|
33
|
+
options.responseTime || 'We typically reply within a few minutes';
|
|
32
34
|
|
|
33
35
|
this.typingUsers = {};
|
|
34
36
|
|
|
@@ -186,6 +186,10 @@ export class ChatView {
|
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
_renderMessage(message) {
|
|
189
|
+
if (message.isSystem) {
|
|
190
|
+
return this._renderSystemMessage(message);
|
|
191
|
+
}
|
|
192
|
+
|
|
189
193
|
const isOwn = message.isOwn;
|
|
190
194
|
const messageClass = isOwn
|
|
191
195
|
? 'messenger-message-own'
|
|
@@ -205,12 +209,11 @@ export class ChatView {
|
|
|
205
209
|
<div class="messenger-message ${messageClass}">
|
|
206
210
|
${bubbleHtml}
|
|
207
211
|
${attachmentsHtml}
|
|
212
|
+
${timeStr ? `<div class="messenger-message-meta messenger-message-meta-own"><span>${timeStr}</span></div>` : ''}
|
|
208
213
|
</div>
|
|
209
214
|
`;
|
|
210
215
|
}
|
|
211
216
|
|
|
212
|
-
const senderName = message.sender?.name || 'Support';
|
|
213
|
-
const senderRole = message.sender?.role || 'Agent';
|
|
214
217
|
const avatarHtml = this._renderSenderAvatar(message.sender);
|
|
215
218
|
return `
|
|
216
219
|
<div class="messenger-message ${messageClass}">
|
|
@@ -221,13 +224,53 @@ export class ChatView {
|
|
|
221
224
|
${attachmentsHtml}
|
|
222
225
|
</div>
|
|
223
226
|
</div>
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
227
|
+
${timeStr ? `<div class="messenger-message-meta"><span>${timeStr}</span></div>` : ''}
|
|
228
|
+
</div>
|
|
229
|
+
`;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
_renderSystemMessage(message) {
|
|
233
|
+
const content = message.content || '';
|
|
234
|
+
const isJoinLeave =
|
|
235
|
+
content.includes('joined the chat') ||
|
|
236
|
+
content.includes('left the chat') ||
|
|
237
|
+
content.includes('joined the conversation') ||
|
|
238
|
+
content.includes('left the conversation');
|
|
239
|
+
|
|
240
|
+
if (isJoinLeave && message.sender) {
|
|
241
|
+
const rawName = message.sender.name || '';
|
|
242
|
+
const name = rawName
|
|
243
|
+
.split(' ')
|
|
244
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
245
|
+
.join(' ');
|
|
246
|
+
const avatarUrl = message.sender.avatarUrl;
|
|
247
|
+
const initial = name.charAt(0).toUpperCase() || '?';
|
|
248
|
+
const colors = ['#5856d6', '#007aff', '#34c759', '#ff9500'];
|
|
249
|
+
const colorIndex = rawName.charCodeAt(0) % colors.length;
|
|
250
|
+
const avatarHtml = avatarUrl
|
|
251
|
+
? `<img src="${this._escapeHtml(avatarUrl)}" alt="${this._escapeHtml(name)}" />`
|
|
252
|
+
: initial;
|
|
253
|
+
const avatarStyle = avatarUrl
|
|
254
|
+
? ''
|
|
255
|
+
: `style="background: ${colors[colorIndex]};"`;
|
|
256
|
+
const timeStr = this._formatMessageTime(message.timestamp);
|
|
257
|
+
|
|
258
|
+
const rawAction = content.replace(rawName, '').trim();
|
|
259
|
+
const action = rawAction.charAt(0).toUpperCase() + rawAction.slice(1);
|
|
260
|
+
|
|
261
|
+
return `
|
|
262
|
+
<div class="messenger-message-system-event">
|
|
263
|
+
<div class="messenger-message-system-event-avatar" ${avatarStyle}>${avatarHtml}</div>
|
|
264
|
+
<span class="messenger-message-system-event-name">${this._escapeHtml(name)}</span>
|
|
265
|
+
<span class="messenger-message-system-event-action">${this._escapeHtml(action)}</span>
|
|
266
|
+
${timeStr ? `<span class="messenger-message-system-event-time">${timeStr}</span>` : ''}
|
|
230
267
|
</div>
|
|
268
|
+
`;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return `
|
|
272
|
+
<div class="messenger-message-system">
|
|
273
|
+
<span class="messenger-message-system-text">${this._escapeHtml(content)}</span>
|
|
231
274
|
</div>
|
|
232
275
|
`;
|
|
233
276
|
}
|
|
@@ -243,12 +286,7 @@ export class ChatView {
|
|
|
243
286
|
_renderTeamAvatars() {
|
|
244
287
|
const avatars = this.state.teamAvatars;
|
|
245
288
|
if (!avatars || avatars.length === 0) {
|
|
246
|
-
return
|
|
247
|
-
<div class="messenger-avatar-stack">
|
|
248
|
-
<div class="sdk-avatar sdk-avatar-md">S</div>
|
|
249
|
-
<div class="sdk-avatar sdk-avatar-md">T</div>
|
|
250
|
-
</div>
|
|
251
|
-
`;
|
|
289
|
+
return '';
|
|
252
290
|
}
|
|
253
291
|
|
|
254
292
|
const avatarItems = avatars
|
|
@@ -267,11 +305,17 @@ export class ChatView {
|
|
|
267
305
|
_formatMessageTime(timestamp) {
|
|
268
306
|
if (!timestamp) return '';
|
|
269
307
|
const date = new Date(timestamp);
|
|
270
|
-
|
|
271
|
-
|
|
308
|
+
const datePart = date.toLocaleDateString('en-GB', {
|
|
309
|
+
day: '2-digit',
|
|
310
|
+
month: 'short',
|
|
311
|
+
year: 'numeric',
|
|
312
|
+
});
|
|
313
|
+
const timePart = date.toLocaleTimeString('en-GB', {
|
|
314
|
+
hour: '2-digit',
|
|
272
315
|
minute: '2-digit',
|
|
273
|
-
hour12:
|
|
316
|
+
hour12: false,
|
|
274
317
|
});
|
|
318
|
+
return `${datePart}, ${timePart}`;
|
|
275
319
|
}
|
|
276
320
|
|
|
277
321
|
_formatMessageContent(content) {
|
|
@@ -41,6 +41,7 @@ export class HomeView {
|
|
|
41
41
|
<div class="messenger-home-welcome">
|
|
42
42
|
<span class="messenger-home-greeting">${this.state.greetingMessage}</span>
|
|
43
43
|
<span class="messenger-home-question">${this.state.welcomeMessage}</span>
|
|
44
|
+
${this._renderAvailabilityStatus()}
|
|
44
45
|
</div>
|
|
45
46
|
</div>
|
|
46
47
|
|
|
@@ -60,12 +61,7 @@ export class HomeView {
|
|
|
60
61
|
const colors = ['#5856d6', '#007aff', '#34c759', '#ff9500'];
|
|
61
62
|
|
|
62
63
|
if (!avatars || avatars.length === 0) {
|
|
63
|
-
return
|
|
64
|
-
<div class="messenger-avatar-stack">
|
|
65
|
-
<div class="sdk-avatar sdk-avatar-lg" style="background: ${colors[0]};">S</div>
|
|
66
|
-
<div class="sdk-avatar sdk-avatar-lg" style="background: ${colors[1]};">T</div>
|
|
67
|
-
</div>
|
|
68
|
-
`;
|
|
64
|
+
return '';
|
|
69
65
|
}
|
|
70
66
|
|
|
71
67
|
const avatarItems = avatars
|
|
@@ -83,14 +79,12 @@ export class HomeView {
|
|
|
83
79
|
|
|
84
80
|
_renderAvailabilityStatus() {
|
|
85
81
|
const isOnline = this.state.agentsOnline;
|
|
86
|
-
const responseTime =
|
|
87
|
-
this.state.responseTime || 'We typically reply within a few minutes';
|
|
88
82
|
|
|
89
83
|
if (isOnline) {
|
|
90
84
|
return `
|
|
91
85
|
<div class="messenger-home-availability">
|
|
92
86
|
<span class="messenger-availability-dot messenger-availability-online"></span>
|
|
93
|
-
<span class="messenger-availability-text"
|
|
87
|
+
<span class="messenger-availability-text">${this.state.onlineMessage}</span>
|
|
94
88
|
</div>
|
|
95
89
|
`;
|
|
96
90
|
}
|
|
@@ -98,7 +92,7 @@ export class HomeView {
|
|
|
98
92
|
return `
|
|
99
93
|
<div class="messenger-home-availability">
|
|
100
94
|
<span class="messenger-availability-dot messenger-availability-away"></span>
|
|
101
|
-
<span class="messenger-availability-text">${responseTime}</span>
|
|
95
|
+
<span class="messenger-availability-text">${this.state.responseTime}</span>
|
|
102
96
|
</div>
|
|
103
97
|
`;
|
|
104
98
|
}
|