diff --git a/config.php b/config.php index 7b5d141..9946605 100644 --- a/config.php +++ b/config.php @@ -1,7 +1,7 @@ true]; $sch = curl_init(rtrim($relayUrl, '/') . '/api/sync-events'); curl_setopt_array($sch, [ CURLOPT_RETURNTRANSFER => true, @@ -970,14 +971,20 @@ if (str_starts_with($route, '/api/')) { $sResp = curl_exec($sch); $sStatus = curl_getinfo($sch, CURLINFO_HTTP_CODE); curl_close($sch); + $syncDebug['status'] = $sStatus; if ($sStatus === 200) { $decoded = json_decode($sResp, true); if (is_array($decoded) && isset($decoded['events'])) { $syncEvents = $decoded['events']; + $syncDebug['count'] = count($syncEvents); + } else { + $syncDebug['parse_error'] = substr((string)$sResp, 0, 200); } + } else { + $syncDebug['body'] = substr((string)$sResp, 0, 200); } - echo json_encode(['ok' => true, 'pulled' => $pulled, 'sync_events' => $syncEvents]); exit; + echo json_encode(['ok' => true, 'pulled' => $pulled, 'sync_events' => $syncEvents, 'sync_debug' => $syncDebug]); exit; } // List relay tenants (for the recipient picker) diff --git a/public/js/modules/caldav.js b/public/js/modules/caldav.js index 829de4a..4a0337d 100644 --- a/public/js/modules/caldav.js +++ b/public/js/modules/caldav.js @@ -340,6 +340,9 @@ function showSyncEventToast(ev) { } function drainSyncEvents(relayRes) { + if (relayRes?.sync_debug) { + console.debug('[sync-events]', relayRes.sync_debug); + } const events = Array.isArray(relayRes?.sync_events) ? relayRes.sync_events : []; for (const ev of events) showSyncEventToast(ev); } diff --git a/public/js/modules/detail.js b/public/js/modules/detail.js index 10bb60c..995cbcc 100644 --- a/public/js/modules/detail.js +++ b/public/js/modules/detail.js @@ -116,6 +116,10 @@ function showStaleBanner(fresh) { state.viewingCard = current; renderSidebar(current); showContent(current); + // Treat the reload as an explicit "I've now seen the new version" + // — re-fire detail.opened so collab-buckets clears the red dot + // on the board card and persists mark-card-seen to the backend. + window.hyprcrd?.hooks?.emit?.('detail.opened', { id: current.id }); } dismissStaleBanner(); }); @@ -123,7 +127,15 @@ function showStaleBanner(fresh) { } function timeAgo(iso) { - const t = new Date(iso).getTime(); + if (!iso) return ''; + // SQLite stores CURRENT_TIMESTAMP as UTC without a tz marker + // ("2026-04-14 12:34:56"). Without an explicit Z, JS parses it as + // local time — off by the tz offset (2h on CEST, hence "2h ago" + // for a 30-second-old update). + const normalized = String(iso).includes('T') || /[Zz]|[+-]\d\d:?\d\d$/.test(iso) + ? iso + : iso.replace(' ', 'T') + 'Z'; + const t = new Date(normalized).getTime(); if (!isFinite(t)) return ''; const s = Math.max(0, (Date.now() - t) / 1000); if (s < 60) return `${Math.floor(s)}s ago`;