diff --git a/dashboard/src/components/ActivityFeed.tsx b/dashboard/src/components/ActivityFeed.tsx index 14afb512..146b7c40 100644 --- a/dashboard/src/components/ActivityFeed.tsx +++ b/dashboard/src/components/ActivityFeed.tsx @@ -1,7 +1,7 @@ import { useState, useEffect, useCallback } from 'react'; import { fetchActivityFeed, generateMockActivityEvents } from '../services/activityApi'; import type { ActivityEvent, ActivityType } from '../types/activity'; -import { formatTimestamp } from '../utils/formatTime'; +import { formatRelativeTimestamp, formatTimestamp, parseToDate } from '../utils/formatTime'; import { PaginationControls } from './PaginationControls'; import { useWalletAccountSync } from '../hooks/useWalletAccountSync'; import { EmptyState } from './EmptyState'; @@ -9,14 +9,14 @@ import { EmptyState } from './EmptyState'; // Helper to get icon/color based on activity type const getActivityTypeStyle = (type: ActivityType) => { const styles: Record = { - 'notification_sent': { color: '#34d399', icon: '✓', bg: 'rgba(52, 211, 153, 0.12)' }, - 'notification_failed': { color: '#f87171', icon: '✕', bg: 'rgba(248, 113, 113, 0.12)' }, - 'notification_retried': { color: '#f4b400', icon: '↻', bg: 'rgba(244, 180, 0, 0.12)' }, - 'contract_event_received': { color: '#60a5fa', icon: '📡', bg: 'rgba(96, 165, 250, 0.12)' }, - 'preference_updated': { color: '#a78bfa', icon: '⚙', bg: 'rgba(167, 139, 250, 0.12)' }, - 'template_created': { color: '#38bdf8', icon: '📄', bg: 'rgba(56, 189, 248, 0.12)' }, - 'template_updated': { color: '#22d3ee', icon: '📝', bg: 'rgba(34, 211, 238, 0.12)' }, - 'webhook_received': { color: '#fb923c', icon: '🔗', bg: 'rgba(251, 146, 60, 0.12)' }, + notification_sent: { color: '#34d399', icon: '✓', bg: 'rgba(52, 211, 153, 0.12)' }, + notification_failed: { color: '#f87171', icon: '✕', bg: 'rgba(248, 113, 113, 0.12)' }, + notification_retried: { color: '#f4b400', icon: '↻', bg: 'rgba(244, 180, 0, 0.12)' }, + contract_event_received: { color: '#60a5fa', icon: '📡', bg: 'rgba(96, 165, 250, 0.12)' }, + preference_updated: { color: '#a78bfa', icon: '⚙', bg: 'rgba(167, 139, 250, 0.12)' }, + template_created: { color: '#38bdf8', icon: '📄', bg: 'rgba(56, 189, 248, 0.12)' }, + template_updated: { color: '#22d3ee', icon: '📝', bg: 'rgba(34, 211, 238, 0.12)' }, + webhook_received: { color: '#fb923c', icon: '🔗', bg: 'rgba(251, 146, 60, 0.12)' }, }; return styles[type] || styles['contract_event_received']; }; @@ -24,6 +24,7 @@ const getActivityTypeStyle = (type: ActivityType) => { // Individual activity event card const ActivityEventCard = ({ event }: { event: ActivityEvent }) => { const style = getActivityTypeStyle(event.type); + const timestamp = parseToDate(event.timestamp); return (
{ {event.type.replace(/_/g, ' ')} -

{event.message}

{Object.keys(event.metadata).length > 0 && (
- {Object.entries(event.metadata).map(([key, value]) => ( - value !== undefined && value !== null && ( - - {key}: - {String(value)} - - ) - ))} + {Object.entries(event.metadata).map( + ([key, value]) => + value !== undefined && + value !== null && ( + + {key}: + {String(value)} + + ), + )}
)} @@ -131,8 +138,8 @@ export function ActivityFeed() { const interval = setInterval(() => { const [newEvent] = generateMockActivityEvents(1); - setLiveEvents(prev => [newEvent, ...prev]); - setTotal(prev => prev + 1); + setLiveEvents((prev) => [newEvent, ...prev]); + setTotal((prev) => prev + 1); }, 15000); return () => clearInterval(interval); @@ -211,9 +218,7 @@ export function ActivityFeed() { description="System events, notification deliveries, and contract activity will appear here as they occur." /> ) : ( - displayedEvents.map(event => ( - - )) + displayedEvents.map((event) => ) )} diff --git a/dashboard/src/components/EventCard.tsx b/dashboard/src/components/EventCard.tsx index c48a6138..e2ec0ca2 100644 --- a/dashboard/src/components/EventCard.tsx +++ b/dashboard/src/components/EventCard.tsx @@ -1,6 +1,6 @@ import { memo, type KeyboardEvent } from 'react'; import type { BlockchainEvent } from '../types/event'; -import { formatTimestamp, formatTimestampShort } from '../utils/formatTime'; +import { formatRelativeTimestamp, formatTimestamp } from '../utils/formatTime'; import { CopyButton } from './CopyButton'; export type EventCardVariant = 'compact' | 'expanded'; @@ -34,13 +34,7 @@ function getEventBadgeClass(name: string | null): string { } function SkeletonLine({ width = '100%', height = '14px' }: { width?: string; height?: string }) { - return ( -