fix(messages): tempId-based dedup (not content) + clickable profile in chat header
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
Dedup: sendContent passes tempId through queue to _doSend, which replaces optimistic msg by matching tempId (not content). Eliminates false negatives from HTML sanitization differences. Profile: clicking avatar or name in chat header opens /profil/<user_id>. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3931b1466c
commit
a52c52863e
@ -388,6 +388,21 @@
|
|||||||
var other = details.members.find(function (m) {
|
var other = details.members.find(function (m) {
|
||||||
return m.user_id !== window.__CURRENT_USER__.id;
|
return m.user_id !== window.__CURRENT_USER__.id;
|
||||||
});
|
});
|
||||||
|
if (other) {
|
||||||
|
// Make avatar and name clickable to profile
|
||||||
|
var headerAvatar = document.getElementById('headerAvatar');
|
||||||
|
var headerName = document.getElementById('headerName');
|
||||||
|
var profileUrl = '/profil/' + other.user_id;
|
||||||
|
if (headerAvatar) {
|
||||||
|
headerAvatar.style.cursor = 'pointer';
|
||||||
|
headerAvatar.onclick = function() { window.location.href = profileUrl; };
|
||||||
|
}
|
||||||
|
if (headerName) {
|
||||||
|
headerName.style.cursor = 'pointer';
|
||||||
|
headerName.onclick = function() { window.location.href = profileUrl; };
|
||||||
|
headerName.title = 'Otwórz profil';
|
||||||
|
}
|
||||||
|
}
|
||||||
if (other && other.is_online) {
|
if (other && other.is_online) {
|
||||||
subtitle.innerHTML = '<span class="online-status-dot"></span> online';
|
subtitle.innerHTML = '<span class="online-status-dot"></span> online';
|
||||||
subtitle.classList.add('is-online');
|
subtitle.classList.add('is-online');
|
||||||
@ -1295,12 +1310,14 @@
|
|||||||
sendContent: function (html, text) {
|
sendContent: function (html, text) {
|
||||||
if (!state.currentConversationId) return;
|
if (!state.currentConversationId) return;
|
||||||
// Add to queue with current state snapshot
|
// Add to queue with current state snapshot
|
||||||
|
var tempId = 'temp-' + Date.now() + '-' + Math.random();
|
||||||
Composer._sendQueue.push({
|
Composer._sendQueue.push({
|
||||||
convId: state.currentConversationId,
|
convId: state.currentConversationId,
|
||||||
html: html,
|
html: html,
|
||||||
text: text,
|
text: text,
|
||||||
replyTo: state.replyToMessage,
|
replyTo: state.replyToMessage,
|
||||||
files: state.attachedFiles.slice()
|
files: state.attachedFiles.slice(),
|
||||||
|
tempId: tempId
|
||||||
});
|
});
|
||||||
state.attachedFiles = [];
|
state.attachedFiles = [];
|
||||||
state.replyToMessage = null;
|
state.replyToMessage = null;
|
||||||
@ -1308,7 +1325,6 @@
|
|||||||
if (replyPreview) replyPreview.style.display = 'none';
|
if (replyPreview) replyPreview.style.display = 'none';
|
||||||
Composer.renderAttachments();
|
Composer.renderAttachments();
|
||||||
// Show optimistic message immediately
|
// Show optimistic message immediately
|
||||||
var tempId = 'temp-' + Date.now() + '-' + Math.random();
|
|
||||||
ChatView.appendMessage({
|
ChatView.appendMessage({
|
||||||
id: tempId,
|
id: tempId,
|
||||||
conversation_id: state.currentConversationId,
|
conversation_id: state.currentConversationId,
|
||||||
@ -1327,7 +1343,7 @@
|
|||||||
Composer._queueProcessing = true;
|
Composer._queueProcessing = true;
|
||||||
while (Composer._sendQueue.length > 0) {
|
while (Composer._sendQueue.length > 0) {
|
||||||
var item = Composer._sendQueue.shift();
|
var item = Composer._sendQueue.shift();
|
||||||
await Composer._doSend(item.convId, item.html, item.text, item.replyTo, item.files);
|
await Composer._doSend(item.convId, item.html, item.text, item.replyTo, item.files, item.tempId);
|
||||||
}
|
}
|
||||||
Composer._queueProcessing = false;
|
Composer._queueProcessing = false;
|
||||||
},
|
},
|
||||||
@ -1355,7 +1371,7 @@
|
|||||||
return Composer._doSend(convId, html, text, savedReplyTo, savedFiles);
|
return Composer._doSend(convId, html, text, savedReplyTo, savedFiles);
|
||||||
},
|
},
|
||||||
|
|
||||||
_doSend: async function (convId, html, text, savedReplyTo, savedFiles) {
|
_doSend: async function (convId, html, text, savedReplyTo, savedFiles, tempId) {
|
||||||
// Optimistic message already shown by sendContent() — just do the API call
|
// Optimistic message already shown by sendContent() — just do the API call
|
||||||
try {
|
try {
|
||||||
var fd = new FormData();
|
var fd = new FormData();
|
||||||
@ -1368,18 +1384,15 @@
|
|||||||
|
|
||||||
var result = await api('/api/conversations/' + convId + '/messages', 'POST', fd);
|
var result = await api('/api/conversations/' + convId + '/messages', 'POST', fd);
|
||||||
|
|
||||||
// Update optimistic message in state with real data (for dedup)
|
// Replace optimistic message with real data (match by tempId)
|
||||||
var msgs = state.messages[convId];
|
var msgs = state.messages[convId];
|
||||||
if (msgs) {
|
if (msgs && tempId) {
|
||||||
var stripped = (html || '').replace(/<[^>]*>/g, '').trim();
|
|
||||||
for (var i = msgs.length - 1; i >= 0; i--) {
|
for (var i = msgs.length - 1; i >= 0; i--) {
|
||||||
if (msgs[i]._optimistic && msgs[i].sender_id === result.sender_id) {
|
if (msgs[i].id === tempId) {
|
||||||
var mc = (msgs[i].content || '').replace(/<[^>]*>/g, '').trim();
|
msgs[i].id = result.id;
|
||||||
if (mc === stripped) {
|
msgs[i]._optimistic = false;
|
||||||
msgs[i].id = result.id;
|
msgs[i].content = result.content;
|
||||||
msgs[i]._optimistic = false;
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user