Body:
Summary
The main dashboard at app/dashboard/ currently has no defined UI states for when events are loading or when no events have been received yet. Users who open the app before any events arrive see a blank or broken layout with no feedback, which is a poor first impression and makes the app feel broken.
Problem
On first load, the event list renders nothing while the WebSocket connection is being established and the first events are fetched from Horizon/RPC
If a user searches for a contract that has emitted no events, the result is an empty list with no messaging
There is no visual distinction between "still loading" and "no results found"
Required work
Skeleton loader (components/dashboard/EventListSkeleton.tsx):
Create a skeleton component that renders 5–8 placeholder event rows matching the shape of a real translated event row
Use Tailwind's animate-pulse utility on placeholder blocks for text, address chips, and timestamp fields
Render the skeleton whenever the WebSocket connection is in a connecting state or the initial event fetch has not yet resolved
Empty state (components/dashboard/EmptyState.tsx):
Design a centred empty state panel with an icon (suggest a magnifying glass or blockchain icon from lucide-react), a heading ("No events found"), and a contextual subline that varies based on cause:
"Waiting for events on the Stellar network…" — when connected but no events received yet
"No events match your search." — when a search filter returns zero results
"Could not connect to Stellar. Retrying…" — on WebSocket error
Include a "Clear search" action button when the empty state is caused by a filter
Integration:
Wire the skeleton and empty states into the existing dashboard layout
Ensure transitions between states are smooth (no flash of empty content)
Acceptance criteria
Skeleton renders on initial load and disappears once the first event batch arrives
Empty state renders with correct contextual message for each cause
No layout shift when transitioning between skeleton → populated → empty states
Components are accessible: skeleton uses aria-busy="true", empty state uses role="status"
Existing dashboard tests continue to pass; new component tests added with at least 80% coverage
Body:
Summary
The main dashboard at app/dashboard/ currently has no defined UI states for when events are loading or when no events have been received yet. Users who open the app before any events arrive see a blank or broken layout with no feedback, which is a poor first impression and makes the app feel broken.
Problem
On first load, the event list renders nothing while the WebSocket connection is being established and the first events are fetched from Horizon/RPC
If a user searches for a contract that has emitted no events, the result is an empty list with no messaging
There is no visual distinction between "still loading" and "no results found"
Required work
Skeleton loader (components/dashboard/EventListSkeleton.tsx):
Create a skeleton component that renders 5–8 placeholder event rows matching the shape of a real translated event row
Use Tailwind's animate-pulse utility on placeholder blocks for text, address chips, and timestamp fields
Render the skeleton whenever the WebSocket connection is in a connecting state or the initial event fetch has not yet resolved
Empty state (components/dashboard/EmptyState.tsx):
Design a centred empty state panel with an icon (suggest a magnifying glass or blockchain icon from lucide-react), a heading ("No events found"), and a contextual subline that varies based on cause:
"Waiting for events on the Stellar network…" — when connected but no events received yet
"No events match your search." — when a search filter returns zero results
"Could not connect to Stellar. Retrying…" — on WebSocket error
Include a "Clear search" action button when the empty state is caused by a filter
Integration:
Wire the skeleton and empty states into the existing dashboard layout
Ensure transitions between states are smooth (no flash of empty content)
Acceptance criteria
Skeleton renders on initial load and disappears once the first event batch arrives
Empty state renders with correct contextual message for each cause
No layout shift when transitioning between skeleton → populated → empty states
Components are accessible: skeleton uses aria-busy="true", empty state uses role="status"
Existing dashboard tests continue to pass; new component tests added with at least 80% coverage