Skip to content

Commit 5184d8b

Browse files
committed
Update page.tsx
1 parent c8499d2 commit 5184d8b

File tree

1 file changed

+90
-24
lines changed

1 file changed

+90
-24
lines changed

src/app/reports/page.tsx

Lines changed: 90 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import {
66
TableContainer, TableHead, TableRow, TextField, Button,
77
Select, MenuItem, FormControl, InputLabel, Alert, Chip,
88
LinearProgress, TablePagination, useMediaQuery, useTheme,
9+
InputAdornment,
910
} from "@mui/material";
11+
import { parseUnits } from "viem";
1012
import { CONTRACTS } from "@/config/contracts";
1113
import { useRewardTypes } from "@/hooks/useRewardsProgram";
1214
import { useChunkedEventLogs, type TimeRange } from "@/hooks/useChunkedEventLogs";
@@ -18,12 +20,18 @@ export default function ReportsPage() {
1820
const { data: rewardTypesData } = useRewardTypes();
1921

2022
const [filterProgramId, setFilterProgramId] = useState("");
21-
const [filterRewardType, setFilterRewardType] = useState<number | "">("");
2223
const [timeRange, setTimeRange] = useState<TimeRange>("7d");
2324
const [trigger, setTrigger] = useState(0);
2425
const [page, setPage] = useState(0);
2526
const [rowsPerPage, setRowsPerPage] = useState(25);
2627

28+
// Client-side filters
29+
const [filterEventType, setFilterEventType] = useState<string>("");
30+
const [filterRewardType, setFilterRewardType] = useState<number | "">("");
31+
const [filterWallet, setFilterWallet] = useState("");
32+
const [filterAmountMin, setFilterAmountMin] = useState("");
33+
const [filterAmountMax, setFilterAmountMax] = useState("");
34+
2735
const {
2836
events, loading, progress, totalChunks, completedChunks, error, cancel,
2937
} = useChunkedEventLogs({
@@ -33,10 +41,30 @@ export default function ReportsPage() {
3341
trigger,
3442
});
3543

36-
// Client-side reward type filter
37-
const filteredEvents = filterRewardType !== ""
38-
? events.filter(r => r.type !== "Deposit" || r.rewardType === filterRewardType)
39-
: events;
44+
// Client-side filter chain
45+
let filteredEvents = events;
46+
if (filterEventType) {
47+
filteredEvents = filteredEvents.filter(e => e.type === filterEventType);
48+
}
49+
if (filterRewardType !== "") {
50+
filteredEvents = filteredEvents.filter(r => r.type !== "Deposit" || r.rewardType === filterRewardType);
51+
}
52+
if (filterWallet) {
53+
const w = filterWallet.toLowerCase();
54+
filteredEvents = filteredEvents.filter(e => e.wallet.toLowerCase().includes(w));
55+
}
56+
if (filterAmountMin) {
57+
try {
58+
const min = parseUnits(filterAmountMin, 18);
59+
filteredEvents = filteredEvents.filter(e => e.amount >= min);
60+
} catch { /* invalid input, skip */ }
61+
}
62+
if (filterAmountMax) {
63+
try {
64+
const max = parseUnits(filterAmountMax, 18);
65+
filteredEvents = filteredEvents.filter(e => e.amount <= max);
66+
} catch { /* invalid input, skip */ }
67+
}
4068

4169
// Summary stats
4270
const totalDeposits = filteredEvents.filter(e => e.type === "Deposit").reduce((s, e) => s + e.amount, BigInt(0));
@@ -60,25 +88,26 @@ export default function ReportsPage() {
6088
}
6189
};
6290

63-
// Pagination
91+
// Pagination — clamp page if filters reduce result count
92+
const safePage = page * rowsPerPage >= filteredEvents.length && filteredEvents.length > 0 ? 0 : page;
6493
const paginatedEvents = filteredEvents.slice(
65-
page * rowsPerPage,
66-
page * rowsPerPage + rowsPerPage
94+
safePage * rowsPerPage,
95+
safePage * rowsPerPage + rowsPerPage
6796
);
6897

6998
return (
7099
<Box>
71100
<Typography variant="h4" gutterBottom>Reports</Typography>
72101

73102
<Paper sx={{ p: 3, mb: 3 }}>
74-
<Typography variant="h6" gutterBottom>Filters</Typography>
103+
<Typography variant="h6" gutterBottom>Fetch Settings</Typography>
75104
<Grid container spacing={2} alignItems="center">
76-
<Grid item xs={12} sm={3}>
105+
<Grid item xs={12} sm={4}>
77106
<TextField label="Program ID" value={filterProgramId}
78107
onChange={(e) => setFilterProgramId(e.target.value)}
79108
type="number" fullWidth size="small" placeholder="All programs" />
80109
</Grid>
81-
<Grid item xs={12} sm={3}>
110+
<Grid item xs={12} sm={4}>
82111
<FormControl fullWidth size="small">
83112
<InputLabel>Time Range</InputLabel>
84113
<Select value={timeRange} onChange={(e) => setTimeRange(e.target.value as TimeRange)} label="Time Range">
@@ -89,18 +118,7 @@ export default function ReportsPage() {
89118
</Select>
90119
</FormControl>
91120
</Grid>
92-
<Grid item xs={12} sm={3}>
93-
<FormControl fullWidth size="small">
94-
<InputLabel>Reward Type</InputLabel>
95-
<Select value={filterRewardType} onChange={(e) => setFilterRewardType(e.target.value as number | "")} label="Reward Type">
96-
<MenuItem value="">All</MenuItem>
97-
{Object.entries(rewardTypeNames).map(([k, v]) => (
98-
<MenuItem key={k} value={Number(k)}>{v}</MenuItem>
99-
))}
100-
</Select>
101-
</FormControl>
102-
</Grid>
103-
<Grid item xs={12} sm={3}>
121+
<Grid item xs={12} sm={4}>
104122
<Button
105123
variant="contained"
106124
onClick={handleGenerate}
@@ -113,6 +131,54 @@ export default function ReportsPage() {
113131
</Grid>
114132
</Paper>
115133

134+
{events.length > 0 && (
135+
<Paper sx={{ p: 3, mb: 3 }}>
136+
<Typography variant="h6" gutterBottom>Filter Results</Typography>
137+
<Grid container spacing={2} alignItems="center">
138+
<Grid item xs={12} sm={2}>
139+
<FormControl fullWidth size="small">
140+
<InputLabel>Event Type</InputLabel>
141+
<Select value={filterEventType} onChange={(e) => { setFilterEventType(e.target.value); setPage(0); }} label="Event Type">
142+
<MenuItem value="">All</MenuItem>
143+
<MenuItem value="Deposit">Deposit</MenuItem>
144+
<MenuItem value="Transfer">Transfer</MenuItem>
145+
<MenuItem value="TransferToParent">To Parent</MenuItem>
146+
<MenuItem value="Withdrawal">Withdrawal</MenuItem>
147+
</Select>
148+
</FormControl>
149+
</Grid>
150+
<Grid item xs={12} sm={2}>
151+
<FormControl fullWidth size="small">
152+
<InputLabel>Reward Type</InputLabel>
153+
<Select value={filterRewardType} onChange={(e) => { setFilterRewardType(e.target.value as number | ""); setPage(0); }} label="Reward Type">
154+
<MenuItem value="">All</MenuItem>
155+
{Object.entries(rewardTypeNames).map(([k, v]) => (
156+
<MenuItem key={k} value={Number(k)}>{v}</MenuItem>
157+
))}
158+
</Select>
159+
</FormControl>
160+
</Grid>
161+
<Grid item xs={12} sm={4}>
162+
<TextField label="Wallet Address" value={filterWallet}
163+
onChange={(e) => { setFilterWallet(e.target.value); setPage(0); }}
164+
fullWidth size="small" placeholder="0x..." />
165+
</Grid>
166+
<Grid item xs={6} sm={2}>
167+
<TextField label="Min Amount" value={filterAmountMin}
168+
onChange={(e) => { setFilterAmountMin(e.target.value); setPage(0); }}
169+
type="number" fullWidth size="small"
170+
InputProps={{ endAdornment: <InputAdornment position="end">FULA</InputAdornment> }} />
171+
</Grid>
172+
<Grid item xs={6} sm={2}>
173+
<TextField label="Max Amount" value={filterAmountMax}
174+
onChange={(e) => { setFilterAmountMax(e.target.value); setPage(0); }}
175+
type="number" fullWidth size="small"
176+
InputProps={{ endAdornment: <InputAdornment position="end">FULA</InputAdornment> }} />
177+
</Grid>
178+
</Grid>
179+
</Paper>
180+
)}
181+
116182
{loading && (
117183
<Paper sx={{ p: 2, mb: 3 }}>
118184
<Box sx={{ display: "flex", justifyContent: "space-between", mb: 1 }}>
@@ -203,7 +269,7 @@ export default function ReportsPage() {
203269
<TablePagination
204270
component="div"
205271
count={filteredEvents.length}
206-
page={page}
272+
page={safePage}
207273
onPageChange={(_, p) => setPage(p)}
208274
rowsPerPage={rowsPerPage}
209275
onRowsPerPageChange={(e) => {

0 commit comments

Comments
 (0)