Sync clock to minute boundary and stabilize "Updated" text
Clock: Instead of starting a 60s interval from mount time (which drifts from the system clock), calculate ms until the next :00 second mark, setTimeout to that point, then setInterval every 60s from there. Updated text: Replaced formatDistanceToNow (which flickered between "less than a minute ago" / "a minute ago" / "2 minutes ago" on each render) with a stable minute-based calculation derived from clockNow: "just now" / "1 min ago" / "N min ago". Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
3afa894e1b
commit
b663455c26
@ -1,7 +1,7 @@
|
||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { format, formatDistanceToNow } from 'date-fns';
|
||||
import { format } from 'date-fns';
|
||||
import { Bell, Plus, Calendar as CalIcon, ListTodo, RefreshCw } from 'lucide-react';
|
||||
import api from '@/lib/api';
|
||||
import type { DashboardData, UpcomingResponse, WeatherData } from '@/types';
|
||||
@ -44,10 +44,16 @@ export default function DashboardPage() {
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
const [clockNow, setClockNow] = useState(() => new Date());
|
||||
|
||||
// Live clock — update every minute
|
||||
// Live clock — synced to the minute boundary
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => setClockNow(new Date()), 60_000);
|
||||
return () => clearInterval(interval);
|
||||
let intervalId: ReturnType<typeof setInterval>;
|
||||
// Wait until the next :00 second mark, then tick every 60s
|
||||
const msUntilNextMinute = (60 - new Date().getSeconds()) * 1000 - new Date().getMilliseconds();
|
||||
const timeoutId = setTimeout(() => {
|
||||
setClockNow(new Date());
|
||||
intervalId = setInterval(() => setClockNow(new Date()), 60_000);
|
||||
}, msUntilNextMinute);
|
||||
return () => { clearTimeout(timeoutId); clearInterval(intervalId); };
|
||||
}, []);
|
||||
|
||||
// Click outside to close dropdown
|
||||
@ -167,7 +173,12 @@ export default function DashboardPage() {
|
||||
}
|
||||
|
||||
const updatedAgo = dataUpdatedAt
|
||||
? formatDistanceToNow(new Date(dataUpdatedAt), { addSuffix: true })
|
||||
? (() => {
|
||||
const mins = Math.floor((clockNow.getTime() - dataUpdatedAt) / 60_000);
|
||||
if (mins < 1) return 'just now';
|
||||
if (mins === 1) return '1 min ago';
|
||||
return `${mins} min ago`;
|
||||
})()
|
||||
: null;
|
||||
|
||||
return (
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user