diff --git a/frontend/src/components/dashboard/DashboardPage.tsx b/frontend/src/components/dashboard/DashboardPage.tsx index e987940..00263cc 100644 --- a/frontend/src/components/dashboard/DashboardPage.tsx +++ b/frontend/src/components/dashboard/DashboardPage.tsx @@ -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(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; + // 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 (