fix: correct timezone display in messages — parse server UTC dates properly
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
Server stores timestamps in UTC without timezone suffix. JavaScript new Date() treated them as local time, showing times 2h behind. Added parseUTC() helper that appends 'Z' to naive ISO dates so the browser correctly converts UTC → user's local timezone. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
898c10921d
commit
f0bdfe013b
@ -84,9 +84,18 @@
|
||||
d.getFullYear() === y.getFullYear();
|
||||
}
|
||||
|
||||
// Server stores UTC but isoformat() omits timezone — append Z so JS knows it's UTC
|
||||
function parseUTC(dateStr) {
|
||||
if (!dateStr) return null;
|
||||
if (dateStr.indexOf('Z') === -1 && dateStr.indexOf('+') === -1 && dateStr.indexOf('T') !== -1) {
|
||||
return new Date(dateStr + 'Z');
|
||||
}
|
||||
return new Date(dateStr);
|
||||
}
|
||||
|
||||
function formatTime(dateStr) {
|
||||
if (!dateStr) return '';
|
||||
var d = new Date(dateStr);
|
||||
var d = parseUTC(dateStr);
|
||||
var now = new Date();
|
||||
var diff = (now - d) / 1000;
|
||||
if (diff < 60) return 'teraz';
|
||||
@ -98,12 +107,12 @@
|
||||
|
||||
function formatMessageTime(dateStr) {
|
||||
if (!dateStr) return '';
|
||||
var d = new Date(dateStr);
|
||||
var d = parseUTC(dateStr);
|
||||
return d.toLocaleTimeString('pl', { hour: '2-digit', minute: '2-digit' });
|
||||
}
|
||||
|
||||
function formatDateSeparator(dateStr) {
|
||||
var d = new Date(dateStr);
|
||||
var d = parseUTC(dateStr);
|
||||
if (isToday(d)) return 'Dzisiaj';
|
||||
if (isYesterday(d)) return 'Wczoraj';
|
||||
return d.toLocaleDateString('pl', { day: 'numeric', month: 'long', year: 'numeric' });
|
||||
@ -111,7 +120,7 @@
|
||||
|
||||
function formatPresence(lastSeen) {
|
||||
if (!lastSeen) return '';
|
||||
var d = new Date(lastSeen);
|
||||
var d = parseUTC(lastSeen);
|
||||
return 'ostatnio: ' + d.toLocaleDateString('pl', { day: '2-digit', month: '2-digit' }) +
|
||||
' o ' + d.toLocaleTimeString('pl', { hour: '2-digit', minute: '2-digit' });
|
||||
}
|
||||
@ -329,7 +338,7 @@
|
||||
state.conversations.sort(function (a, b) {
|
||||
var aTime = a.last_message ? a.last_message.created_at : a.updated_at;
|
||||
var bTime = b.last_message ? b.last_message.created_at : b.updated_at;
|
||||
return new Date(bTime || 0) - new Date(aTime || 0);
|
||||
return (parseUTC(bTime) || 0) - (parseUTC(aTime) || 0);
|
||||
});
|
||||
|
||||
ConversationList.renderList();
|
||||
@ -479,7 +488,7 @@
|
||||
messages.forEach(function (msg) {
|
||||
// Date separator
|
||||
if (msg.created_at) {
|
||||
var msgDate = new Date(msg.created_at).toDateString();
|
||||
var msgDate = parseUTC(msg.created_at).toDateString();
|
||||
if (msgDate !== lastDate) {
|
||||
var sep = el('div', 'date-separator');
|
||||
sep.textContent = formatDateSeparator(msg.created_at);
|
||||
@ -641,18 +650,18 @@
|
||||
var readAt = null;
|
||||
|
||||
if (details && details.members) {
|
||||
var msgTime = new Date(msg.created_at);
|
||||
var msgTime = parseUTC(msg.created_at);
|
||||
var otherMembers = details.members.filter(function (m) {
|
||||
return m.user_id !== window.__CURRENT_USER__.id;
|
||||
});
|
||||
isRead = otherMembers.length > 0 && otherMembers.every(function (m) {
|
||||
return m.last_read_at && new Date(m.last_read_at) >= msgTime;
|
||||
return m.last_read_at && parseUTC(m.last_read_at) >= msgTime;
|
||||
});
|
||||
if (isRead) {
|
||||
// Find earliest read time among others
|
||||
var readTimes = otherMembers
|
||||
.filter(function (m) { return m.last_read_at; })
|
||||
.map(function (m) { return new Date(m.last_read_at); });
|
||||
.map(function (m) { return parseUTC(m.last_read_at); });
|
||||
if (readTimes.length) {
|
||||
readAt = new Date(Math.min.apply(null, readTimes));
|
||||
}
|
||||
@ -670,18 +679,18 @@
|
||||
// Group: show per-member read status
|
||||
// Sort: read (earliest first), then unread (alphabetically)
|
||||
otherMembers.sort(function (a, b) {
|
||||
var aRead = a.last_read_at && new Date(a.last_read_at) >= msgTime;
|
||||
var bRead = b.last_read_at && new Date(b.last_read_at) >= msgTime;
|
||||
var aRead = a.last_read_at && parseUTC(a.last_read_at) >= msgTime;
|
||||
var bRead = b.last_read_at && parseUTC(b.last_read_at) >= msgTime;
|
||||
if (aRead && !bRead) return -1;
|
||||
if (!aRead && bRead) return 1;
|
||||
if (aRead && bRead) return new Date(a.last_read_at) - new Date(b.last_read_at);
|
||||
if (aRead && bRead) return parseUTC(a.last_read_at) - parseUTC(b.last_read_at);
|
||||
return (a.name || '').localeCompare(b.name || '', 'pl');
|
||||
});
|
||||
var lines = [];
|
||||
otherMembers.forEach(function (m) {
|
||||
var name = m.name || 'Użytkownik';
|
||||
if (m.last_read_at && new Date(m.last_read_at) >= msgTime) {
|
||||
var d = new Date(m.last_read_at);
|
||||
if (m.last_read_at && parseUTC(m.last_read_at) >= msgTime) {
|
||||
var d = parseUTC(m.last_read_at);
|
||||
var dateStr = d.toLocaleDateString('pl', {day:'2-digit', month:'2-digit'}) + ' o ' + d.toLocaleTimeString('pl', {hour:'2-digit', minute:'2-digit'});
|
||||
lines.push('<span class="read-status-line read">✓ ' + name + ' — ' + dateStr + '</span>');
|
||||
} else {
|
||||
@ -778,11 +787,11 @@
|
||||
if (lastRow) {
|
||||
var lastMsg = state.messages[convId][state.messages[convId].length - 2];
|
||||
if (lastMsg && lastMsg.created_at) {
|
||||
lastDate = new Date(lastMsg.created_at).toDateString();
|
||||
lastDate = parseUTC(lastMsg.created_at).toDateString();
|
||||
}
|
||||
}
|
||||
if (msg.created_at) {
|
||||
var msgDate = new Date(msg.created_at).toDateString();
|
||||
var msgDate = parseUTC(msg.created_at).toDateString();
|
||||
if (msgDate !== lastDate) {
|
||||
var sep = el('div', 'date-separator');
|
||||
sep.textContent = formatDateSeparator(msg.created_at);
|
||||
@ -890,7 +899,7 @@
|
||||
|
||||
var isMine = msg.sender && msg.sender.id === window.__CURRENT_USER__.id;
|
||||
var canEdit = isMine && msg.created_at &&
|
||||
(new Date() - new Date(msg.created_at)) < 24 * 60 * 60 * 1000;
|
||||
(new Date() - parseUTC(msg.created_at)) < 24 * 60 * 60 * 1000;
|
||||
|
||||
// Show/hide owner-only buttons
|
||||
menu.querySelectorAll('.owner-only').forEach(function (btn) {
|
||||
|
||||
@ -326,7 +326,7 @@ window.__CSRF_TOKEN__ = '{{ csrf_token() }}';
|
||||
// Load conversations.js after data is set
|
||||
(function() {
|
||||
var s = document.createElement('script');
|
||||
s.src = '{{ url_for("static", filename="js/conversations.js") }}?v=24';
|
||||
s.src = '{{ url_for("static", filename="js/conversations.js") }}?v=25';
|
||||
document.body.appendChild(s);
|
||||
})();
|
||||
{% endblock %}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user