Skip to content

Commit 3e42f39

Browse files
committed
add basic filters
1 parent c30a61c commit 3e42f39

1 file changed

Lines changed: 138 additions & 54 deletions

File tree

packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/observe/TransactionsTable.tsx

Lines changed: 138 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
"use client";
22

33
import { BoxIcon, CheckCheckIcon, ReceiptTextIcon, UserPenIcon, XIcon } from "lucide-react";
4-
import React, { useEffect, useState } from "react";
4+
import React, { useEffect, useMemo, useState } from "react";
55
import { useInView } from "react-intersection-observer";
66
import { ExpandedState, flexRender, getCoreRowModel, getExpandedRowModel, useReactTable } from "@tanstack/react-table";
77
import { createColumnHelper } from "@tanstack/react-table";
88
import { Badge } from "../../../../../../components/ui/Badge";
9+
import { Input } from "../../../../../../components/ui/Input";
910
import { Skeleton } from "../../../../../../components/ui/Skeleton";
1011
import {
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

Comments
 (0)