Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 110 additions & 7 deletions soroscan-frontend/app/dashboard/components/EventExplorerDashboard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { useState, useEffect, useCallback } from "react";
import { useState, useEffect, useCallback, useRef } from "react";
import { EventTable } from "./EventTable";
import { FilterBar } from "./FilterBar";
import { EventDetailModal } from "./EventDetailModal";
Expand All @@ -12,6 +12,8 @@
import { useToast } from "@/context/ToastContext";
import { parseSearchQuery, matchesFilters } from "@/lib/search-parser";
import { NotificationBell } from "@/components/notifications/NotificationBell";
import { useContractEventSubscription } from "@/src/hooks/useContractEventSubscription";
import { SubscriptionStatusBadge } from "@/components/ui/SubscriptionStatusBadge";

const PAGE_SIZE = 20;

Expand Down Expand Up @@ -52,6 +54,9 @@
const [error, setError] = useState<string | null>(null);
const [selectedEvent, setSelectedEvent] = useState<EventRecord | null>(null);
const [totalCount, setTotalCount] = useState(0);
const [isPaused, setIsPaused] = useState(false);
const [newEventsCount, setNewEventsCount] = useState(0);
const previousEventsRef = useRef<EventRecord[]>([]);

useEffect(() => {
try {
Expand Down Expand Up @@ -135,6 +140,74 @@
loadEvents();
}, [filters.contractId, filters.eventType, filters.since, filters.until, currentPage]);

// Subscribe to real-time events
const { events: realTimeEvents, connectionState } = useContractEventSubscription({
contractId: filters.contractId || "",
maxEvents: 10,
});

// Track new events
useEffect(() => {
const previousIds = new Set(previousEventsRef.current.map(e => e.id));
let count = 0;
events.forEach(event => {
if (!previousIds.has(event.id)) {
count++;
}
});

if (count > 0) {
if (isPaused) {
setNewEventsCount(prev => prev + count);
} else {
setNewEventsCount(0);
}
}

previousEventsRef.current = events;
}, [events, isPaused]);

// Show notification toast for matching events
useEffect(() => {
if (realTimeEvents.length > 0 && !isPaused) {
const newEvent = realTimeEvents[0];
// Check if new event matches current filters
const mockEventRecord: EventRecord = {
id: newEvent.id,
contractId: filters.contractId || "",
contractName: "",
eventType: newEvent.eventType,
ledger: newEvent.ledgerSequence,
eventIndex: 0,
timestamp: newEvent.timestamp,
txHash: "",
payload: newEvent.payload,
};

const parsedQuery = parseSearchQuery(filters.searchQuery);
if (matchesFilters(mockEventRecord, parsedQuery)) {
showToast(`New ${newEvent.eventType} event!`, "info", "New Event");
}

// Refresh events when new event comes in
if (currentPage === 1) {
fetchExplorerEvents({
contractId: filters.contractId,
eventType: filters.eventType || null,
limit: PAGE_SIZE + 1,
offset: 0,
since: filters.since || null,
until: filters.until || null,
}).then(result => {
const nextExists = result.length > PAGE_SIZE;
const visibleEvents = nextExists ? result.slice(0, PAGE_SIZE) : result;
setEvents(visibleEvents);
setHasNext(nextExists);
});
}
}
}, [realTimeEvents, isPaused]);

Check warning on line 209 in soroscan-frontend/app/dashboard/components/EventExplorerDashboard.tsx

View workflow job for this annotation

GitHub Actions / lint-and-test

React Hook useEffect has missing dependencies: 'currentPage', 'filters.contractId', 'filters.eventType', 'filters.searchQuery', 'filters.since', 'filters.until', and 'showToast'. Either include them or remove the dependency array

// Apply search filter client-side
useEffect(() => {
const parsed = parseSearchQuery(filters.searchQuery);
Expand Down Expand Up @@ -188,7 +261,7 @@
}

if (!next.length) {
const { [eventId]: _, ...rest } = prev;

Check warning on line 264 in soroscan-frontend/app/dashboard/components/EventExplorerDashboard.tsx

View workflow job for this annotation

GitHub Actions / lint-and-test

'_' is assigned a value but never used
return rest;
}

Expand Down Expand Up @@ -307,12 +380,42 @@

<section className={styles.timelinePanel} aria-label="Events table">
<div className={styles.panelHead}>
<h2 className={styles.sectionTitle}>Contract Events</h2>
<p className={styles.summary}>
{loading
? "Loading..."
: `Showing ${startIndex}-${endIndex} of ${totalCount}+`}
</p>
<div style={{ display: "flex", alignItems: "center", gap: "1rem" }}>
<h2 className={styles.sectionTitle}>Contract Events</h2>
<SubscriptionStatusBadge connectionState={connectionState} />
{newEventsCount > 0 && (
<button
type="button"
className={styles.btn}
style={{
backgroundColor: "rgba(0, 255, 156, 0.2)",
borderColor: "rgba(0, 255, 156, 0.6)",
}}
onClick={() => setNewEventsCount(0)}
>
{newEventsCount} new event{newEventsCount !== 1 ? "s" : ""}
</button>
)}
</div>
<div style={{ display: "flex", alignItems: "center", gap: "1rem" }}>
<p className={styles.summary}>
{loading
? "Loading..."
: `Showing ${startIndex}-${endIndex} of ${totalCount}+`}
</p>
<button
type="button"
className={styles.btn}
onClick={() => {
setIsPaused(prev => !prev);
if (isPaused) {
setNewEventsCount(0);
}
}}
>
{isPaused ? "▶ Resume" : "⏸ Pause"}
</button>
</div>
</div>

{error && (
Expand Down
Loading