11import { useEffect , useRef } from 'react' ;
2- import { SequencerAddressLink } from './SequencerAddressLink' ;
2+ import { SequencerAddressControl } from './SequencerAddressControl' ;
3+ import { getEventTitle , getEventVisual } from '@/lib/presentation' ;
34import type { EventL1Context , MonitorEvent } from '@/types/backendApi' ;
45
56interface EventHistoryProps {
67 events : MonitorEvent [ ] ;
78 hasWatchlistCapability : boolean ;
9+ selectedEventId ?: string | null ;
810 selectedEventError ?: string | null ;
911 onSelectSequencer ?: ( sequencer : MonitorEvent [ 'targets' ] [ number ] ) => void ;
1012}
1113
1214export function EventHistory ( {
1315 events,
1416 hasWatchlistCapability,
17+ selectedEventId = null ,
1518 selectedEventError = null ,
1619 onSelectSequencer,
1720} : EventHistoryProps ) {
18- const selectedEventId = new URLSearchParams ( window . location . search ) . get ( 'event' ) ;
1921 const scrolledEventIdRef = useRef < string | null > ( null ) ;
2022
2123 useEffect ( ( ) => {
@@ -36,7 +38,7 @@ export function EventHistory({
3638 < div className = "mb-2 inline-flex border-3 border-brand-black bg-aqua px-3 py-1 text-xs font-black uppercase text-brand-black" >
3739 Pingme Journal
3840 </ div >
39- < h2 className = "text-2xl font-black text-aqua" > Slashing Activity </ h2 >
41+ < h2 className = "text-2xl font-black text-aqua" > Network feed </ h2 >
4042 < p className = "mt-2 text-sm font-bold text-whisper-white" >
4143 { hasWatchlistCapability
4244 ? 'Node signals and confirmed L1 activity for this browser’s watch list.'
@@ -86,17 +88,18 @@ function EventCard({
8688 onSelectSequencer ?: EventHistoryProps [ 'onSelectSequencer' ] ;
8789} ) {
8890 const pending = event . certainty === 'pending' ;
91+ const visual = getEventVisual ( event . type ) ;
8992 return (
9093 < article
9194 id = { `event-${ event . id } ` }
9295 className = { `border-3 bg-brand-black p-4 ${
93- selected ? 'border-chartreuse shadow-brutal-chartreuse' : pending ? ' border-orchid' : 'border-aqua'
96+ selected ? 'border-chartreuse shadow-brutal-chartreuse' : visual . border
9497 } `}
9598 >
9699 < div className = "flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between" >
97100 < div className = "min-w-0" >
98- < h3 className = { `text-base font-black ${ pending ? ' text-orchid' : 'text-aqua' } ` } >
99- { event . title }
101+ < h3 className = { `text-base font-black ${ visual . text } ` } >
102+ { getEventTitle ( event ) }
100103 </ h3 >
101104 < EventTargets event = { event } onSelectSequencer = { onSelectSequencer } />
102105 </ div >
@@ -127,7 +130,11 @@ function EventTargets({
127130 if ( event . targets . length === 0 ) {
128131 return null ;
129132 }
130- const preview = event . targets . slice ( 0 , 3 ) ;
133+ const uniqueTargets = event . targets . filter ( ( target , index , targets ) =>
134+ targets . findIndex ( ( candidate ) =>
135+ candidate . toLowerCase ( ) === target . toLowerCase ( ) ) === index ) ;
136+ const preview = uniqueTargets . slice ( 0 , 3 ) ;
137+ const remaining = uniqueTargets . slice ( 3 ) ;
131138 return (
132139 < div className = "mt-2" >
133140 < div className = "flex flex-wrap items-center gap-x-3 gap-y-1" >
@@ -145,13 +152,13 @@ function EventTargets({
145152 ) ;
146153 } ) }
147154 </ div >
148- { event . targets . length > 3 && (
155+ { remaining . length > 0 && (
149156 < details className = "mt-2 text-xs text-whisper-white/80" >
150157 < summary className = "w-fit cursor-pointer font-black uppercase text-aqua underline underline-offset-4" >
151- Show all { event . targets . length } targets
158+ Show { remaining . length } more target { remaining . length === 1 ? '' : 's' }
152159 </ summary >
153160 < div className = "mt-2 grid gap-2 border-l-3 border-aqua/50 pl-3 sm:grid-cols-2 xl:grid-cols-3" >
154- { event . targets . map ( ( target ) => {
161+ { remaining . map ( ( target ) => {
155162 const amount = event . l1 ?. actions . find ( ( action ) =>
156163 action . sequencer . toLowerCase ( ) === target . toLowerCase ( ) ) ?. amount ;
157164 return (
@@ -189,21 +196,14 @@ function EventTarget({
189196 item . sequencer . toLowerCase ( ) === target . toLowerCase ( ) ) ;
190197 return (
191198 < div className = "min-w-0" >
192- < SequencerAddressLink
199+ < SequencerAddressControl
193200 address = { target }
194201 chars = { full ? undefined : 6 }
195202 full = { full }
203+ showCopy
204+ onOpenRecord = { onSelectSequencer }
196205 className = "font-mono text-xs font-bold text-whisper-white"
197206 />
198- { onSelectSequencer && (
199- < button
200- type = "button"
201- onClick = { ( ) => onSelectSequencer ( target ) }
202- className = "mt-1 block text-[0.65rem] font-black uppercase text-orchid underline underline-offset-4 hover:text-chartreuse"
203- >
204- Open record
205- </ button >
206- ) }
207207 { amount && (
208208 < span className = "text-[0.68rem] font-bold text-whisper-white/55" >
209209 { formatAztec ( amount ) } AZTEC proposed
@@ -234,7 +234,7 @@ function EventFacts({ event }: { event: MonitorEvent }) {
234234 if ( offense . epoch ) facts . push ( `Epoch ${ offense . epoch } ` ) ;
235235 if ( offense . slot ) {
236236 const slotLabel = event . type === 'inactivity_first_miss'
237- ? 'First missed slot'
237+ ? 'Missed slot'
238238 : offense . timeUnit === 'epoch'
239239 ? 'Epoch starts at slot'
240240 : 'Slot' ;
0 commit comments