11"use client" ;
22
33import { BoxIcon , CheckCheckIcon , ReceiptTextIcon , UserPenIcon , XIcon } from "lucide-react" ;
4- import React , { useEffect , useState } from "react" ;
4+ import React , { useEffect , useMemo , useState } from "react" ;
55import { useInView } from "react-intersection-observer" ;
66import { ExpandedState , flexRender , getCoreRowModel , getExpandedRowModel , useReactTable } from "@tanstack/react-table" ;
77import { createColumnHelper } from "@tanstack/react-table" ;
88import { Badge } from "../../../../../../components/ui/Badge" ;
9+ import { Input } from "../../../../../../components/ui/Input" ;
910import { Skeleton } from "../../../../../../components/ui/Skeleton" ;
1011import {
1112 Table ,
@@ -121,15 +122,47 @@ export function TransactionsTable() {
121122 const { data : indexedTransactions , fetchNextPage } = useTransactionsQuery ( ) ;
122123 const loadedInitialTransactions = Array . isArray ( indexedTransactions ) && indexedTransactions . length > 0 ;
123124 const [ expanded , setExpanded ] = useState < ExpandedState > ( { } ) ;
125+ const [ filters , setFilters ] = useState ( {
126+ blockNumber : "" ,
127+ from : "" ,
128+ calls : "" ,
129+ hash : "" ,
130+ timestamp : "" ,
131+ } ) ;
124132
125133 useEffect ( ( ) => {
126134 if ( inView ) {
127135 fetchNextPage ( ) ;
128136 }
129137 } , [ fetchNextPage , inView ] ) ;
130138
139+ // Filter transactions based on filter values
140+ const filteredTransactions = useMemo ( ( ) => {
141+ return transactions . filter ( ( transaction ) => {
142+ if ( filters . blockNumber && ! transaction . blockNumber ?. toString ( ) . includes ( filters . blockNumber ) ) {
143+ return false ;
144+ }
145+ if ( filters . from && ! transaction . from ?. toLowerCase ( ) . includes ( filters . from . toLowerCase ( ) ) ) {
146+ return false ;
147+ }
148+ if (
149+ filters . calls &&
150+ ! transaction . calls ?. some ( ( call ) => call . functionName ?. toLowerCase ( ) . includes ( filters . calls . toLowerCase ( ) ) )
151+ ) {
152+ return false ;
153+ }
154+ if ( filters . hash && ! transaction . hash ?. toLowerCase ( ) . includes ( filters . hash . toLowerCase ( ) ) ) {
155+ return false ;
156+ }
157+ if ( filters . timestamp && ! transaction . timestamp ?. toString ( ) . includes ( filters . timestamp ) ) {
158+ return false ;
159+ }
160+ return true ;
161+ } ) ;
162+ } , [ transactions , filters ] ) ;
163+
131164 const table = useReactTable ( {
132- data : transactions ,
165+ data : filteredTransactions ,
133166 columns,
134167 state : {
135168 expanded,
@@ -141,59 +174,110 @@ export function TransactionsTable() {
141174 } ) ;
142175
143176 return (
144- < Table >
145- < TableHeader className = "sticky top-0 z-10 bg-[var(--color-background)]" >
146- { table . getHeaderGroups ( ) . map ( ( headerGroup ) => (
147- < TableRow key = { headerGroup . id } >
148- { headerGroup . headers . map ( ( header ) => {
149- return (
150- < TableHead key = { header . id } className = "text-xs uppercase" >
151- { header . isPlaceholder ? null : flexRender ( header . column . columnDef . header , header . getContext ( ) ) }
152- </ TableHead >
153- ) ;
177+ < div className = "space-y-4" >
178+ { /* Filter Row */ }
179+ < div className = "grid grid-cols-5 gap-4 rounded-md border bg-muted/20 p-4" >
180+ < div className = "space-y-2" >
181+ < label className = "text-xs font-medium uppercase text-muted-foreground" > Block</ label >
182+ < Input
183+ placeholder = "Filter block..."
184+ value = { filters . blockNumber }
185+ onChange = { ( e ) => setFilters ( ( prev ) => ( { ...prev , blockNumber : e . target . value } ) ) }
186+ className = "h-8 text-xs"
187+ />
188+ </ div >
189+ < div className = "space-y-2" >
190+ < label className = "text-xs font-medium uppercase text-muted-foreground" > From</ label >
191+ < Input
192+ placeholder = "Filter address..."
193+ value = { filters . from }
194+ onChange = { ( e ) => setFilters ( ( prev ) => ( { ...prev , from : e . target . value } ) ) }
195+ className = "h-8 text-xs"
196+ />
197+ </ div >
198+ < div className = "space-y-2" >
199+ < label className = "text-xs font-medium uppercase text-muted-foreground" > Functions</ label >
200+ < Input
201+ placeholder = "Filter functions..."
202+ value = { filters . calls }
203+ onChange = { ( e ) => setFilters ( ( prev ) => ( { ...prev , calls : e . target . value } ) ) }
204+ className = "h-8 text-xs"
205+ />
206+ </ div >
207+ < div className = "space-y-2" >
208+ < label className = "text-xs font-medium uppercase text-muted-foreground" > Tx Hash</ label >
209+ < Input
210+ placeholder = "Filter hash..."
211+ value = { filters . hash }
212+ onChange = { ( e ) => setFilters ( ( prev ) => ( { ...prev , hash : e . target . value } ) ) }
213+ className = "h-8 text-xs"
214+ />
215+ </ div >
216+ < div className = "space-y-2" >
217+ < label className = "text-xs font-medium uppercase text-muted-foreground" > Time</ label >
218+ < Input
219+ placeholder = "Filter time..."
220+ value = { filters . timestamp }
221+ onChange = { ( e ) => setFilters ( ( prev ) => ( { ...prev , timestamp : e . target . value } ) ) }
222+ className = "h-8 text-xs"
223+ />
224+ </ div >
225+ </ div >
226+
227+ < Table >
228+ < TableHeader className = "sticky top-0 z-10 bg-[var(--color-background)]" >
229+ { table . getHeaderGroups ( ) . map ( ( headerGroup ) => (
230+ < TableRow key = { headerGroup . id } >
231+ { headerGroup . headers . map ( ( header ) => {
232+ return (
233+ < TableHead key = { header . id } className = "text-xs uppercase" >
234+ { header . isPlaceholder ? null : flexRender ( header . column . columnDef . header , header . getContext ( ) ) }
235+ </ TableHead >
236+ ) ;
237+ } ) }
238+ </ TableRow >
239+ ) ) }
240+ </ TableHeader >
241+ < TableBody >
242+ { table . getRowModel ( ) . rows ?. length ? (
243+ table . getRowModel ( ) . rows . map ( ( row ) => < TransactionTableRow key = { row . id } row = { row } /> )
244+ ) : (
245+ < TableRow >
246+ < TableCell colSpan = { columns . length } >
247+ < p className = "flex items-center justify-center gap-3 py-4 font-mono text-xs font-bold uppercase text-muted-foreground" >
248+ < span className = "inline-block h-1.5 w-1.5 animate-ping rounded-full bg-muted-foreground" /> Waiting
249+ for transactions…
250+ </ p >
251+ </ TableCell >
252+ </ TableRow >
253+ ) }
254+ </ TableBody >
255+
256+ { indexer . type === "hosted" && (
257+ < TableFooter
258+ className = { cn ( "border-t-transparent bg-transparent hover:bg-transparent" , {
259+ "border-t-muted" : loadedInitialTransactions ,
154260 } ) }
155- </ TableRow >
156- ) ) }
157- </ TableHeader >
158- < TableBody >
159- { table . getRowModel ( ) . rows ?. length ? (
160- table . getRowModel ( ) . rows . map ( ( row ) => < TransactionTableRow key = { row . id } row = { row } /> )
161- ) : (
162- < TableRow >
163- < TableCell colSpan = { columns . length } >
164- < p className = "flex items-center justify-center gap-3 py-4 font-mono text-xs font-bold uppercase text-muted-foreground" >
165- < span className = "inline-block h-1.5 w-1.5 animate-ping rounded-full bg-muted-foreground" /> Waiting for
166- transactions…
167- </ p >
168- </ TableCell >
169- </ TableRow >
261+ >
262+ < TableRow >
263+ < TableCell colSpan = { columns . length } >
264+ < div
265+ ref = { ref }
266+ className = { cn (
267+ "hidden items-center justify-center gap-3 py-4 font-mono text-xs font-bold uppercase text-muted-foreground" ,
268+ {
269+ flex : loadedInitialTransactions ,
270+ } ,
271+ ) }
272+ >
273+ < span className = "inline-block h-1.5 w-1.5 animate-ping rounded-full bg-muted-foreground" />
274+ Loading more transactions...
275+ </ div >
276+ </ TableCell >
277+ </ TableRow >
278+ </ TableFooter >
170279 ) }
171- </ TableBody >
172-
173- { indexer . type === "hosted" && (
174- < TableFooter
175- className = { cn ( "border-t-transparent bg-transparent hover:bg-transparent" , {
176- "border-t-muted" : loadedInitialTransactions ,
177- } ) }
178- >
179- < TableRow >
180- < TableCell colSpan = { columns . length } >
181- < div
182- ref = { ref }
183- className = { cn (
184- "hidden items-center justify-center gap-3 py-4 font-mono text-xs font-bold uppercase text-muted-foreground" ,
185- {
186- flex : loadedInitialTransactions ,
187- } ,
188- ) }
189- >
190- < span className = "inline-block h-1.5 w-1.5 animate-ping rounded-full bg-muted-foreground" />
191- Loading more transactions...
192- </ div >
193- </ TableCell >
194- </ TableRow >
195- </ TableFooter >
196- ) }
197- </ Table >
280+ </ Table >
281+ </ div >
198282 ) ;
199283}
0 commit comments