From 39da377065d8d1e9b0b451eed518d5b51f272c1b Mon Sep 17 00:00:00 2001 From: Maciej Pienczyn Date: Fri, 10 Apr 2026 06:09:42 +0200 Subject: [PATCH] fix: UTC timezone correction for all JS date parsing across portal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added global parseUTC() helper in base.html that appends 'Z' to naive ISO dates from server. Applied to: - Notification bell (base.html) — formatTimeAgo - NordaGPT conversation sort (chat.html) - B2B interest dates (classifieds/view.html) - Admin forum moderation dates (admin/forum.html) - Admin AI insights dates (admin/insights.html) Same fix as conversations.js parseUTC, now available globally. Co-Authored-By: Claude Opus 4.6 (1M context) --- templates/admin/forum.html | 4 ++-- templates/admin/insights.html | 2 +- templates/base.html | 12 +++++++++++- templates/chat.html | 2 +- templates/classifieds/view.html | 2 +- 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/templates/admin/forum.html b/templates/admin/forum.html index e5f293b..83eff03 100755 --- a/templates/admin/forum.html +++ b/templates/admin/forum.html @@ -1220,7 +1220,7 @@ ${r.is_deleted ? ' (usunięty)' : ''}
${r.content_preview}
- ${r.author_name} • ${new Date(r.created_at).toLocaleString('pl-PL')} + ${r.author_name} • ${parseUTC(r.created_at).toLocaleString('pl-PL')} ${r.category_label ? ` • ${r.category_label}` : ''}
@@ -1415,7 +1415,7 @@ ${a.title} ${a.is_deleted ? ' (usunięty)' : ''} - ${new Date(a.created_at).toLocaleString('pl-PL')} + ${parseUTC(a.created_at).toLocaleString('pl-PL')} `).join(''); } diff --git a/templates/admin/insights.html b/templates/admin/insights.html index dbe1066..db427dd 100644 --- a/templates/admin/insights.html +++ b/templates/admin/insights.html @@ -312,7 +312,7 @@ async function loadInsights() { - ${insight.source_type} | ${insight.created_at ? new Date(insight.created_at).toLocaleDateString('pl-PL') : ''} + ${insight.source_type} | ${insight.created_at ? parseUTC(insight.created_at).toLocaleDateString('pl-PL') : ''} diff --git a/templates/base.html b/templates/base.html index 50e3322..56fd9cc 100755 --- a/templates/base.html +++ b/templates/base.html @@ -858,7 +858,7 @@ let html = ''; data.notifications.forEach(n => { - const timeAgo = formatTimeAgo(new Date(n.created_at)); + const timeAgo = formatTimeAgo(parseUTC(n.created_at)); const unreadClass = n.is_read ? '' : 'unread'; const dotHtml = n.is_read ? '' : ''; const icon = getNotificationIcon(n.notification_type); @@ -987,6 +987,16 @@ } } + // Parse server UTC datetime — append Z if no timezone info + function parseUTC(dateStr) { + if (!dateStr) return new Date(); + if (typeof dateStr === 'object') return dateStr; + if (dateStr.indexOf('Z') === -1 && dateStr.indexOf('+') === -1 && dateStr.indexOf('T') !== -1) { + return new Date(dateStr + 'Z'); + } + return new Date(dateStr); + } + function formatTimeAgo(date) { const now = new Date(); const diff = now - date; diff --git a/templates/chat.html b/templates/chat.html index 5e1889c..a89d6c3 100755 --- a/templates/chat.html +++ b/templates/chat.html @@ -2265,7 +2265,7 @@ async function togglePin(conversationId) { // Re-sort: pinned first, then by updated_at conversations.sort((a, b) => { if (a.is_pinned !== b.is_pinned) return b.is_pinned ? 1 : -1; - return new Date(b.updated_at) - new Date(a.updated_at); + return parseUTC(b.updated_at) - parseUTC(a.updated_at); }); renderConversationsList(); } diff --git a/templates/classifieds/view.html b/templates/classifieds/view.html index de7f4fe..73f6783 100755 --- a/templates/classifieds/view.html +++ b/templates/classifieds/view.html @@ -1078,7 +1078,7 @@ async function showInterestsModal() { ${i.company_name ? `
${i.company_name}
` : ''} ${i.message ? `
"${i.message}"
` : ''} -
${new Date(i.created_at).toLocaleDateString('pl-PL')}
+
${parseUTC(i.created_at).toLocaleDateString('pl-PL')}
`).join(''); }