55} from 'lucide-react' ;
66import { useAuth } from '../../lib/AuthContext' ;
77import { getActivityLog , type ActivityLog , type ActivityAction } from '../../lib/structuresService' ;
8+ import { useTimezone , formatTime } from '../../lib/timezoneUtils' ;
89
910// ─── Helpers ──────────────────────────────────────────────────────
1011
@@ -27,19 +28,22 @@ const ACTION_CONFIG: Record<ActivityAction, { label: string; icon: React.Element
2728 duplicate : { label : 'Duplicated' , icon : Copy , color : 'text-pink-400' , bg : 'bg-pink-500/10 border-pink-500/20' } ,
2829} ;
2930
30- // Group consecutive logs by date
31- function groupByDate ( logs : ActivityLog [ ] ) {
31+ // Group consecutive logs by date (timezone-aware)
32+ function groupByDate ( logs : ActivityLog [ ] , timezone : string ) {
3233 const groups : { date : string ; items : ActivityLog [ ] } [ ] = [ ] ;
34+
35+ const todayLabel = new Date ( ) . toLocaleDateString ( undefined , { timeZone : timezone , year : 'numeric' , month : '2-digit' , day : '2-digit' } ) ;
36+ const yesterdayDate = new Date ( Date . now ( ) - 86400000 ) ;
37+ const yesterdayLabel = yesterdayDate . toLocaleDateString ( undefined , { timeZone : timezone , year : 'numeric' , month : '2-digit' , day : '2-digit' } ) ;
38+
3339 for ( const log of logs ) {
3440 const d = new Date ( log . created_at ) ;
35- const today = new Date ( ) ;
36- const yesterday = new Date ( today ) ;
37- yesterday . setDate ( today . getDate ( ) - 1 ) ;
41+ const dLabel = d . toLocaleDateString ( undefined , { timeZone : timezone , year : 'numeric' , month : '2-digit' , day : '2-digit' } ) ;
3842
3943 let label : string ;
40- if ( d . toDateString ( ) === today . toDateString ( ) ) label = 'Today' ;
41- else if ( d . toDateString ( ) === yesterday . toDateString ( ) ) label = 'Yesterday' ;
42- else label = d . toLocaleDateString ( undefined , { weekday : 'short' , month : 'short' , day : 'numeric' } ) ;
44+ if ( dLabel === todayLabel ) label = 'Today' ;
45+ else if ( dLabel === yesterdayLabel ) label = 'Yesterday' ;
46+ else label = d . toLocaleDateString ( undefined , { timeZone : timezone , weekday : 'short' , month : 'short' , day : 'numeric' } ) ;
4347
4448 const last = groups [ groups . length - 1 ] ;
4549 if ( last && last . date === label ) last . items . push ( log ) ;
@@ -84,6 +88,7 @@ function StatsBar({ logs }: { logs: ActivityLog[] }) {
8488
8589export const ActivityTimeline = ( ) => {
8690 const { user } = useAuth ( ) ;
91+ const timezone = useTimezone ( ) ;
8792 const [ logs , setLogs ] = useState < ActivityLog [ ] > ( [ ] ) ;
8893 const [ loading , setLoading ] = useState ( true ) ;
8994 const [ error , setError ] = useState < string | null > ( null ) ;
@@ -105,7 +110,7 @@ export const ActivityTimeline = () => {
105110 useEffect ( ( ) => { load ( ) ; } , [ load ] ) ;
106111
107112 const visible = filter === 'all' ? logs : logs . filter ( l => l . action === filter ) ;
108- const grouped = groupByDate ( visible ) ;
113+ const grouped = groupByDate ( visible , timezone ) ;
109114
110115 const FILTERS : { key : ActivityAction | 'all' ; label : string } [ ] = [
111116 { key : 'all' , label : 'All' } ,
@@ -212,7 +217,10 @@ export const ActivityTimeline = () => {
212217 </ div >
213218
214219 { /* Time */ }
215- < span className = "text-xs text-[var(--text-muted)] group-hover:text-[var(--text-muted)] transition-colors whitespace-nowrap shrink-0" >
220+ < span
221+ className = "text-xs text-[var(--text-muted)] group-hover:text-[var(--text-muted)] transition-colors whitespace-nowrap shrink-0"
222+ title = { formatTime ( log . created_at , timezone ) }
223+ >
216224 { timeAgo ( log . created_at ) }
217225 </ span >
218226 </ div >
0 commit comments