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 { useState, useEffect, useRef, useCallback } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
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 { Bell, Plus, Calendar as CalIcon, ListTodo, RefreshCw } from 'lucide-react';
|
||||||
import api from '@/lib/api';
|
import api from '@/lib/api';
|
||||||
import type { DashboardData, UpcomingResponse, WeatherData } from '@/types';
|
import type { DashboardData, UpcomingResponse, WeatherData } from '@/types';
|
||||||
@ -44,10 +44,16 @@ export default function DashboardPage() {
|
|||||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||||
const [clockNow, setClockNow] = useState(() => new Date());
|
const [clockNow, setClockNow] = useState(() => new Date());
|
||||||
|
|
||||||
// Live clock — update every minute
|
// Live clock — synced to the minute boundary
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const interval = setInterval(() => setClockNow(new Date()), 60_000);
|
let intervalId: ReturnType<typeof setInterval>;
|
||||||
return () => clearInterval(interval);
|
// 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
|
// Click outside to close dropdown
|
||||||
@ -167,7 +173,12 @@ export default function DashboardPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const updatedAgo = dataUpdatedAt
|
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;
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user