@product7/feedback-sdk 1.4.7 → 1.4.9
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/feedback-sdk.js +159 -36
- package/dist/feedback-sdk.js.map +1 -1
- package/dist/feedback-sdk.min.js +1 -1
- package/dist/feedback-sdk.min.js.map +1 -1
- package/package.json +1 -1
- package/src/styles/feedback.js +11 -25
- package/src/widgets/ButtonWidget.js +23 -0
- package/src/widgets/MessengerWidget.js +4 -1
- package/src/widgets/messenger/MessengerState.js +120 -10
- package/src/widgets/messenger/views/ChatView.js +1 -0
package/dist/feedback-sdk.js
CHANGED
|
@@ -2165,6 +2165,7 @@
|
|
|
2165
2165
|
constructor(options) {
|
|
2166
2166
|
super({ ...options, type: 'button' });
|
|
2167
2167
|
this.isMinimized = false;
|
|
2168
|
+
this._hiddenForOpenPanel = false;
|
|
2168
2169
|
}
|
|
2169
2170
|
|
|
2170
2171
|
_render() {
|
|
@@ -2251,6 +2252,28 @@
|
|
|
2251
2252
|
this.element.classList.remove('minimized');
|
|
2252
2253
|
}
|
|
2253
2254
|
|
|
2255
|
+
openPanel() {
|
|
2256
|
+
if (!this.state.isOpen) {
|
|
2257
|
+
this._hiddenForOpenPanel = true;
|
|
2258
|
+
this.hide();
|
|
2259
|
+
}
|
|
2260
|
+
super.openPanel();
|
|
2261
|
+
}
|
|
2262
|
+
|
|
2263
|
+
closePanel() {
|
|
2264
|
+
const shouldRestoreButton = this._hiddenForOpenPanel;
|
|
2265
|
+
super.closePanel();
|
|
2266
|
+
|
|
2267
|
+
if (shouldRestoreButton) {
|
|
2268
|
+
setTimeout(() => {
|
|
2269
|
+
if (!this.destroyed) {
|
|
2270
|
+
this.show();
|
|
2271
|
+
}
|
|
2272
|
+
this._hiddenForOpenPanel = false;
|
|
2273
|
+
}, 320);
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
|
|
2254
2277
|
mount(container) {
|
|
2255
2278
|
super.mount(container);
|
|
2256
2279
|
}
|
|
@@ -3475,23 +3498,133 @@
|
|
|
3475
3498
|
this._notify('messagesUpdate', { conversationId, messages });
|
|
3476
3499
|
}
|
|
3477
3500
|
|
|
3478
|
-
|
|
3501
|
+
_getMessageAttachmentsSignature(message) {
|
|
3502
|
+
if (!Array.isArray(message?.attachments) || message.attachments.length === 0) {
|
|
3503
|
+
return '';
|
|
3504
|
+
}
|
|
3505
|
+
|
|
3506
|
+
return message.attachments
|
|
3507
|
+
.map((att) => `${att?.type || ''}:${att?.name || ''}`)
|
|
3508
|
+
.join('|');
|
|
3509
|
+
}
|
|
3510
|
+
|
|
3511
|
+
_findOptimisticMatchIndex(conversationId, incomingMessage, matchWindowMs) {
|
|
3512
|
+
const messages = this.messages[conversationId] || [];
|
|
3513
|
+
const incomingTimestamp = Date.parse(incomingMessage.timestamp);
|
|
3514
|
+
const incomingSignature =
|
|
3515
|
+
this._getMessageAttachmentsSignature(incomingMessage);
|
|
3516
|
+
|
|
3517
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
3518
|
+
const candidate = messages[i];
|
|
3519
|
+
if (!candidate?.isOptimistic || !candidate?.isOwn) {
|
|
3520
|
+
continue;
|
|
3521
|
+
}
|
|
3522
|
+
if ((candidate.content || '') !== (incomingMessage.content || '')) {
|
|
3523
|
+
continue;
|
|
3524
|
+
}
|
|
3525
|
+
|
|
3526
|
+
const candidateSignature =
|
|
3527
|
+
this._getMessageAttachmentsSignature(candidate);
|
|
3528
|
+
if (candidateSignature !== incomingSignature) {
|
|
3529
|
+
continue;
|
|
3530
|
+
}
|
|
3531
|
+
|
|
3532
|
+
const candidateTimestamp = Date.parse(candidate.timestamp);
|
|
3533
|
+
if (
|
|
3534
|
+
Number.isNaN(incomingTimestamp) ||
|
|
3535
|
+
Number.isNaN(candidateTimestamp) ||
|
|
3536
|
+
Math.abs(incomingTimestamp - candidateTimestamp) <= matchWindowMs
|
|
3537
|
+
) {
|
|
3538
|
+
return i;
|
|
3539
|
+
}
|
|
3540
|
+
}
|
|
3541
|
+
|
|
3542
|
+
return -1;
|
|
3543
|
+
}
|
|
3544
|
+
|
|
3545
|
+
_updateConversationFromMessage(conversationId, message, countUnread) {
|
|
3546
|
+
const conv = this.conversations.find((c) => c.id === conversationId);
|
|
3547
|
+
if (!conv) {
|
|
3548
|
+
return;
|
|
3549
|
+
}
|
|
3550
|
+
|
|
3551
|
+
conv.lastMessage = message.content;
|
|
3552
|
+
conv.lastMessageTime = message.timestamp;
|
|
3553
|
+
|
|
3554
|
+
if (countUnread && !message.isOwn) {
|
|
3555
|
+
conv.unread = (conv.unread || 0) + 1;
|
|
3556
|
+
this._updateUnreadCount();
|
|
3557
|
+
}
|
|
3558
|
+
}
|
|
3559
|
+
|
|
3560
|
+
upsertMessage(conversationId, message, options = {}) {
|
|
3479
3561
|
if (!this.messages[conversationId]) {
|
|
3480
3562
|
this.messages[conversationId] = [];
|
|
3481
3563
|
}
|
|
3482
|
-
this.messages[conversationId].push(message);
|
|
3483
3564
|
|
|
3484
|
-
const
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3565
|
+
const reconcileOwnOptimistic = options.reconcileOwnOptimistic === true;
|
|
3566
|
+
const optimisticMatchWindowMs = options.optimisticMatchWindowMs || 30000;
|
|
3567
|
+
const messages = this.messages[conversationId];
|
|
3568
|
+
const existingIndex =
|
|
3569
|
+
message?.id != null
|
|
3570
|
+
? messages.findIndex((msg) => msg?.id === message.id)
|
|
3571
|
+
: -1;
|
|
3572
|
+
|
|
3573
|
+
if (existingIndex !== -1) {
|
|
3574
|
+
messages[existingIndex] = {
|
|
3575
|
+
...messages[existingIndex],
|
|
3576
|
+
...message,
|
|
3577
|
+
isOptimistic: false,
|
|
3578
|
+
};
|
|
3579
|
+
this._updateConversationFromMessage(
|
|
3580
|
+
conversationId,
|
|
3581
|
+
messages[existingIndex],
|
|
3582
|
+
false
|
|
3583
|
+
);
|
|
3584
|
+
this._notify('messagesUpdate', {
|
|
3585
|
+
conversationId,
|
|
3586
|
+
messages: [...messages],
|
|
3587
|
+
});
|
|
3588
|
+
return messages[existingIndex];
|
|
3589
|
+
}
|
|
3590
|
+
|
|
3591
|
+
if (reconcileOwnOptimistic && message?.isOwn) {
|
|
3592
|
+
const optimisticIndex = this._findOptimisticMatchIndex(
|
|
3593
|
+
conversationId,
|
|
3594
|
+
message,
|
|
3595
|
+
optimisticMatchWindowMs
|
|
3596
|
+
);
|
|
3597
|
+
if (optimisticIndex !== -1) {
|
|
3598
|
+
messages[optimisticIndex] = {
|
|
3599
|
+
...messages[optimisticIndex],
|
|
3600
|
+
...message,
|
|
3601
|
+
isOptimistic: false,
|
|
3602
|
+
};
|
|
3603
|
+
this._updateConversationFromMessage(
|
|
3604
|
+
conversationId,
|
|
3605
|
+
messages[optimisticIndex],
|
|
3606
|
+
false
|
|
3607
|
+
);
|
|
3608
|
+
this._notify('messagesUpdate', {
|
|
3609
|
+
conversationId,
|
|
3610
|
+
messages: [...messages],
|
|
3611
|
+
});
|
|
3612
|
+
return messages[optimisticIndex];
|
|
3491
3613
|
}
|
|
3492
3614
|
}
|
|
3493
3615
|
|
|
3494
|
-
|
|
3616
|
+
const storedMessage = {
|
|
3617
|
+
...message,
|
|
3618
|
+
isOptimistic: Boolean(message?.isOptimistic),
|
|
3619
|
+
};
|
|
3620
|
+
messages.push(storedMessage);
|
|
3621
|
+
this._updateConversationFromMessage(conversationId, storedMessage, true);
|
|
3622
|
+
this._notify('messageAdded', { conversationId, message: storedMessage });
|
|
3623
|
+
return storedMessage;
|
|
3624
|
+
}
|
|
3625
|
+
|
|
3626
|
+
addMessage(conversationId, message) {
|
|
3627
|
+
return this.upsertMessage(conversationId, message);
|
|
3495
3628
|
}
|
|
3496
3629
|
|
|
3497
3630
|
updateConversation(conversationId, updates) {
|
|
@@ -4637,6 +4770,7 @@
|
|
|
4637
4770
|
id: 'msg_' + Date.now(),
|
|
4638
4771
|
content: content,
|
|
4639
4772
|
isOwn: true,
|
|
4773
|
+
isOptimistic: true,
|
|
4640
4774
|
timestamp: new Date().toISOString(),
|
|
4641
4775
|
attachments: attachmentsToSend.map((a) => ({
|
|
4642
4776
|
url: a.preview,
|
|
@@ -6039,7 +6173,10 @@
|
|
|
6039
6173
|
},
|
|
6040
6174
|
};
|
|
6041
6175
|
|
|
6042
|
-
this.messengerState.
|
|
6176
|
+
this.messengerState.upsertMessage(conversation_id, localMessage, {
|
|
6177
|
+
reconcileOwnOptimistic: true,
|
|
6178
|
+
optimisticMatchWindowMs: 30000,
|
|
6179
|
+
});
|
|
6043
6180
|
|
|
6044
6181
|
if (
|
|
6045
6182
|
!this.messengerState.isOpen ||
|
|
@@ -9094,44 +9231,30 @@
|
|
|
9094
9231
|
}
|
|
9095
9232
|
|
|
9096
9233
|
.feedback-panel {
|
|
9097
|
-
width:
|
|
9234
|
+
width: min(420px, calc(100vw - (var(--spacing-4) * 2)));
|
|
9235
|
+
max-height: min(500px, calc(100vh - 88px));
|
|
9098
9236
|
top: auto;
|
|
9099
|
-
bottom:
|
|
9100
|
-
right:
|
|
9101
|
-
left:
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
transform: translateY(100%);
|
|
9105
|
-
border-radius: var(--radius-3xl) var(--radius-3xl) 0 0;
|
|
9237
|
+
bottom: 72px;
|
|
9238
|
+
right: var(--spacing-4);
|
|
9239
|
+
left: auto;
|
|
9240
|
+
transform: translateX(calc(100% + 24px));
|
|
9241
|
+
border-radius: var(--radius-2xl);
|
|
9106
9242
|
}
|
|
9107
9243
|
|
|
9108
9244
|
.feedback-panel.open {
|
|
9109
|
-
transform:
|
|
9245
|
+
transform: translateX(0);
|
|
9110
9246
|
}
|
|
9111
9247
|
|
|
9112
9248
|
.feedback-panel-header {
|
|
9113
|
-
padding: var(--spacing-
|
|
9114
|
-
position: relative;
|
|
9115
|
-
}
|
|
9116
|
-
|
|
9117
|
-
.feedback-panel-header::before {
|
|
9118
|
-
content: '';
|
|
9119
|
-
position: absolute;
|
|
9120
|
-
top: var(--spacing-2);
|
|
9121
|
-
left: 50%;
|
|
9122
|
-
transform: translateX(-50%);
|
|
9123
|
-
width: 40px;
|
|
9124
|
-
height: 4px;
|
|
9125
|
-
background: var(--color-neutral-300);
|
|
9126
|
-
border-radius: 2px;
|
|
9249
|
+
padding: var(--spacing-4) var(--spacing-6);
|
|
9127
9250
|
}
|
|
9128
9251
|
|
|
9129
9252
|
.feedback-panel-body {
|
|
9130
|
-
padding: var(--spacing-
|
|
9253
|
+
padding: var(--spacing-6);
|
|
9131
9254
|
}
|
|
9132
9255
|
|
|
9133
9256
|
.feedback-form-group textarea {
|
|
9134
|
-
min-height:
|
|
9257
|
+
min-height: 120px;
|
|
9135
9258
|
}
|
|
9136
9259
|
}
|
|
9137
9260
|
`;
|