@trustless-work/blocks 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -0
- package/bin/index.js +1123 -0
- package/package.json +44 -0
- package/templates/deps.json +29 -0
- package/templates/escrows/details/Actions.tsx +149 -0
- package/templates/escrows/details/Entities.tsx +48 -0
- package/templates/escrows/details/EntityCard.tsx +98 -0
- package/templates/escrows/details/EscrowDetailDialog.tsx +154 -0
- package/templates/escrows/details/GeneralInformation.tsx +329 -0
- package/templates/escrows/details/MilestoneCard.tsx +254 -0
- package/templates/escrows/details/MilestoneDetailDialog.tsx +276 -0
- package/templates/escrows/details/Milestones.tsx +87 -0
- package/templates/escrows/details/ProgressEscrow.tsx +191 -0
- package/templates/escrows/details/StatisticsCard.tsx +79 -0
- package/templates/escrows/details/SuccessReleaseDialog.tsx +101 -0
- package/templates/escrows/details/useDetailsEscrow.ts +126 -0
- package/templates/escrows/escrow-context/EscrowAmountProvider.tsx +86 -0
- package/templates/escrows/escrow-context/EscrowDialogsProvider.tsx +108 -0
- package/templates/escrows/escrow-context/EscrowProvider.tsx +124 -0
- package/templates/escrows/escrows-by-role/cards/EscrowsCards.tsx +503 -0
- package/templates/escrows/escrows-by-role/cards/Filters.tsx +421 -0
- package/templates/escrows/escrows-by-role/table/EscrowsTable.tsx +427 -0
- package/templates/escrows/escrows-by-role/table/Filters.tsx +421 -0
- package/templates/escrows/escrows-by-role/useEscrowsByRole.shared.ts +336 -0
- package/templates/escrows/escrows-by-signer/cards/EscrowsCards.tsx +502 -0
- package/templates/escrows/escrows-by-signer/cards/Filters.tsx +389 -0
- package/templates/escrows/escrows-by-signer/table/EscrowsTable.tsx +422 -0
- package/templates/escrows/escrows-by-signer/table/Filters.tsx +389 -0
- package/templates/escrows/escrows-by-signer/useEscrowsBySigner.shared.ts +320 -0
- package/templates/escrows/single-release/approve-milestone/button/ApproveMilestone.tsx +78 -0
- package/templates/escrows/single-release/approve-milestone/dialog/ApproveMilestone.tsx +102 -0
- package/templates/escrows/single-release/approve-milestone/form/ApproveMilestone.tsx +80 -0
- package/templates/escrows/single-release/approve-milestone/shared/schema.ts +9 -0
- package/templates/escrows/single-release/approve-milestone/shared/useApproveMilestone.ts +67 -0
- package/templates/escrows/single-release/change-milestone-status/button/ChangeMilestoneStatus.tsx +78 -0
- package/templates/escrows/single-release/change-milestone-status/dialog/ChangeMilestoneStatus.tsx +167 -0
- package/templates/escrows/single-release/change-milestone-status/form/ChangeMilestoneStatus.tsx +114 -0
- package/templates/escrows/single-release/change-milestone-status/shared/schema.ts +15 -0
- package/templates/escrows/single-release/change-milestone-status/shared/useChangeMilestoneStatus.ts +77 -0
- package/templates/escrows/single-release/dispute-escrow/button/DisputeEscrow.tsx +68 -0
- package/templates/escrows/single-release/fund-escrow/button/FundEscrow.tsx +84 -0
- package/templates/escrows/single-release/fund-escrow/dialog/FundEscrow.tsx +77 -0
- package/templates/escrows/single-release/fund-escrow/form/FundEscrow.tsx +54 -0
- package/templates/escrows/single-release/fund-escrow/shared/schema.ts +10 -0
- package/templates/escrows/single-release/fund-escrow/shared/useFundEscrow.ts +66 -0
- package/templates/escrows/single-release/initialize-escrow/dialog/InitializeEscrow.tsx +526 -0
- package/templates/escrows/single-release/initialize-escrow/form/InitializeEscrow.tsx +504 -0
- package/templates/escrows/single-release/initialize-escrow/shared/schema.ts +232 -0
- package/templates/escrows/single-release/initialize-escrow/shared/useInitializeEscrow.ts +115 -0
- package/templates/escrows/single-release/release-escrow/button/ReleaseEscrow.tsx +80 -0
- package/templates/escrows/single-release/resolve-dispute/button/ResolveDispute.tsx +94 -0
- package/templates/escrows/single-release/resolve-dispute/dialog/ResolveDispute.tsx +123 -0
- package/templates/escrows/single-release/resolve-dispute/form/ResolveDispute.tsx +82 -0
- package/templates/escrows/single-release/resolve-dispute/shared/schema.ts +82 -0
- package/templates/escrows/single-release/resolve-dispute/shared/useResolveDispute.ts +58 -0
- package/templates/escrows/single-release/update-escrow/dialog/UpdateEscrow.tsx +485 -0
- package/templates/escrows/single-release/update-escrow/form/UpdateEscrow.tsx +463 -0
- package/templates/escrows/single-release/update-escrow/shared/schema.ts +139 -0
- package/templates/escrows/single-release/update-escrow/shared/useUpdateEscrow.ts +211 -0
- package/templates/handle-errors/errors.enum.ts +6 -0
- package/templates/handle-errors/handle.ts +47 -0
- package/templates/helpers/format.helper.ts +27 -0
- package/templates/helpers/useCopy.ts +13 -0
- package/templates/providers/ReactQueryClientProvider.tsx +28 -0
- package/templates/providers/TrustlessWork.tsx +30 -0
- package/templates/tanstak/useEscrowsByRoleQuery.ts +87 -0
- package/templates/tanstak/useEscrowsBySignerQuery.ts +78 -0
- package/templates/tanstak/useEscrowsMutations.ts +411 -0
- package/templates/wallet-kit/WalletButtons.tsx +116 -0
- package/templates/wallet-kit/WalletProvider.tsx +94 -0
- package/templates/wallet-kit/trustlines.ts +40 -0
- package/templates/wallet-kit/useWallet.ts +77 -0
- package/templates/wallet-kit/validators.ts +12 -0
- package/templates/wallet-kit/wallet-kit.ts +30 -0
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { Card } from "__UI_BASE__/card";
|
|
5
|
+
import { Button } from "__UI_BASE__/button";
|
|
6
|
+
import type {
|
|
7
|
+
GetEscrowsFromIndexerResponse as Escrow,
|
|
8
|
+
Role,
|
|
9
|
+
MultiReleaseMilestone,
|
|
10
|
+
} from "@trustless-work/escrow/types";
|
|
11
|
+
import {
|
|
12
|
+
ColumnDef,
|
|
13
|
+
flexRender,
|
|
14
|
+
getCoreRowModel,
|
|
15
|
+
useReactTable,
|
|
16
|
+
} from "@tanstack/react-table";
|
|
17
|
+
import {
|
|
18
|
+
Table,
|
|
19
|
+
TableBody,
|
|
20
|
+
TableCell,
|
|
21
|
+
TableHead,
|
|
22
|
+
TableHeader,
|
|
23
|
+
TableRow,
|
|
24
|
+
} from "__UI_BASE__/table";
|
|
25
|
+
import { FileX, Loader2, Wallet, RefreshCw, AlertTriangle } from "lucide-react";
|
|
26
|
+
import Filters from "./Filters";
|
|
27
|
+
import EscrowDetailDialog from "../details/EscrowDetailDialog";
|
|
28
|
+
import { useEscrowDialogs } from "../../escrow-context/EscrowDialogsProvider";
|
|
29
|
+
import { useEscrowContext } from "../../escrow-context/EscrowProvider";
|
|
30
|
+
import { useEscrowsByRole } from "../useEscrowsByRole.shared";
|
|
31
|
+
import { formatTimestamp } from "../../../helpers/format.helper";
|
|
32
|
+
|
|
33
|
+
export function EscrowsByRoleTable() {
|
|
34
|
+
const {
|
|
35
|
+
walletAddress,
|
|
36
|
+
data,
|
|
37
|
+
isLoading,
|
|
38
|
+
isError,
|
|
39
|
+
refetch,
|
|
40
|
+
isFetching,
|
|
41
|
+
nextData,
|
|
42
|
+
isFetchingNext,
|
|
43
|
+
page,
|
|
44
|
+
setPage,
|
|
45
|
+
orderBy,
|
|
46
|
+
setOrderBy,
|
|
47
|
+
orderDirection,
|
|
48
|
+
setOrderDirection,
|
|
49
|
+
sorting,
|
|
50
|
+
title,
|
|
51
|
+
setTitle,
|
|
52
|
+
engagementId,
|
|
53
|
+
setEngagementId,
|
|
54
|
+
isActive,
|
|
55
|
+
setIsActive,
|
|
56
|
+
validateOnChain,
|
|
57
|
+
setValidateOnChain,
|
|
58
|
+
type,
|
|
59
|
+
setType,
|
|
60
|
+
status,
|
|
61
|
+
setStatus,
|
|
62
|
+
minAmount,
|
|
63
|
+
setMinAmount,
|
|
64
|
+
maxAmount,
|
|
65
|
+
setMaxAmount,
|
|
66
|
+
dateRange,
|
|
67
|
+
setDateRange,
|
|
68
|
+
formattedRangeLabel,
|
|
69
|
+
role,
|
|
70
|
+
setRole,
|
|
71
|
+
onClearFilters,
|
|
72
|
+
handleSortingChange,
|
|
73
|
+
} = useEscrowsByRole();
|
|
74
|
+
|
|
75
|
+
const dialogStates = useEscrowDialogs();
|
|
76
|
+
const { setSelectedEscrow } = useEscrowContext();
|
|
77
|
+
|
|
78
|
+
const columns = React.useMemo<ColumnDef<Escrow>[]>(
|
|
79
|
+
() => [
|
|
80
|
+
{
|
|
81
|
+
header: "Title",
|
|
82
|
+
accessorKey: "title",
|
|
83
|
+
enableSorting: false,
|
|
84
|
+
cell: ({ row }) => (
|
|
85
|
+
<span
|
|
86
|
+
className="max-w-[220px] truncate block"
|
|
87
|
+
title={row.original.title}
|
|
88
|
+
>
|
|
89
|
+
{row.original.title}
|
|
90
|
+
</span>
|
|
91
|
+
),
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
header: "Engagement ID",
|
|
95
|
+
accessorKey: "engagementId",
|
|
96
|
+
enableSorting: false,
|
|
97
|
+
meta: { className: "hidden sm:table-cell" },
|
|
98
|
+
cell: ({ row }) => (
|
|
99
|
+
<span
|
|
100
|
+
className="max-w-[180px] truncate block"
|
|
101
|
+
title={row.original.engagementId}
|
|
102
|
+
>
|
|
103
|
+
{row.original.engagementId}
|
|
104
|
+
</span>
|
|
105
|
+
),
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
header: "Amount",
|
|
109
|
+
accessorKey: "amount",
|
|
110
|
+
enableSorting: true,
|
|
111
|
+
cell: ({ row }) => {
|
|
112
|
+
// single release
|
|
113
|
+
if (row.original.type === "single-release") {
|
|
114
|
+
return row.original.amount;
|
|
115
|
+
}
|
|
116
|
+
// multi release
|
|
117
|
+
return row.original.milestones.reduce(
|
|
118
|
+
(acc, milestone) =>
|
|
119
|
+
acc + (milestone as MultiReleaseMilestone).amount,
|
|
120
|
+
0
|
|
121
|
+
);
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
header: "Balance",
|
|
126
|
+
accessorKey: "balance",
|
|
127
|
+
enableSorting: false,
|
|
128
|
+
meta: { className: "hidden md:table-cell" },
|
|
129
|
+
cell: ({ row }) => row.original.balance ?? 0,
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
header: "Type",
|
|
133
|
+
accessorKey: "type",
|
|
134
|
+
enableSorting: false,
|
|
135
|
+
meta: { className: "hidden lg:table-cell" },
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
header: "Active",
|
|
139
|
+
accessorKey: "isActive",
|
|
140
|
+
enableSorting: false,
|
|
141
|
+
meta: { className: "hidden md:table-cell" },
|
|
142
|
+
cell: ({ row }) => (row.original.isActive ? "Yes" : "No"),
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
header: "Trustline",
|
|
146
|
+
id: "trustline",
|
|
147
|
+
enableSorting: false,
|
|
148
|
+
meta: { className: "hidden lg:table-cell" },
|
|
149
|
+
cell: ({ row }) => (
|
|
150
|
+
<span
|
|
151
|
+
className="max-w-[220px] truncate block"
|
|
152
|
+
title={`${row.original.trustline.name} (${row.original.trustline.address})`}
|
|
153
|
+
>
|
|
154
|
+
{row.original.trustline.name}
|
|
155
|
+
</span>
|
|
156
|
+
),
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
header: "Created",
|
|
160
|
+
accessorKey: "createdAt",
|
|
161
|
+
enableSorting: true,
|
|
162
|
+
meta: { className: "hidden sm:table-cell" },
|
|
163
|
+
cell: ({ row }) => formatTimestamp(row.original.createdAt),
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
header: "Updated",
|
|
167
|
+
accessorKey: "updatedAt",
|
|
168
|
+
enableSorting: true,
|
|
169
|
+
meta: { className: "hidden xl:table-cell" },
|
|
170
|
+
cell: ({ row }) => formatTimestamp(row.original.updatedAt),
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
header: "Actions",
|
|
174
|
+
id: "actions",
|
|
175
|
+
enableSorting: false,
|
|
176
|
+
cell: ({ row }) => (
|
|
177
|
+
<Button
|
|
178
|
+
variant="outline"
|
|
179
|
+
className="cursor-pointer"
|
|
180
|
+
onClick={() => {
|
|
181
|
+
setSelectedEscrow(row.original);
|
|
182
|
+
dialogStates.second.setIsOpen(true);
|
|
183
|
+
}}
|
|
184
|
+
>
|
|
185
|
+
Details
|
|
186
|
+
</Button>
|
|
187
|
+
),
|
|
188
|
+
},
|
|
189
|
+
],
|
|
190
|
+
[]
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
const table = useReactTable({
|
|
194
|
+
data: React.useMemo(() => data ?? [], [data]),
|
|
195
|
+
columns,
|
|
196
|
+
getCoreRowModel: getCoreRowModel(),
|
|
197
|
+
state: {
|
|
198
|
+
sorting,
|
|
199
|
+
},
|
|
200
|
+
onSortingChange: handleSortingChange,
|
|
201
|
+
manualSorting: true,
|
|
202
|
+
enableSortingRemoval: true,
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const activeRole: Role[] = role.split(",") as Role[];
|
|
206
|
+
const escrows = data ?? [];
|
|
207
|
+
|
|
208
|
+
return (
|
|
209
|
+
<>
|
|
210
|
+
<div className="w-full flex flex-col gap-4">
|
|
211
|
+
<Filters
|
|
212
|
+
title={title}
|
|
213
|
+
engagementId={engagementId}
|
|
214
|
+
isActive={isActive}
|
|
215
|
+
validateOnChain={validateOnChain}
|
|
216
|
+
type={type}
|
|
217
|
+
status={status}
|
|
218
|
+
minAmount={minAmount}
|
|
219
|
+
maxAmount={maxAmount}
|
|
220
|
+
dateRange={dateRange}
|
|
221
|
+
formattedRangeLabel={formattedRangeLabel}
|
|
222
|
+
role={role}
|
|
223
|
+
setTitle={setTitle}
|
|
224
|
+
setEngagementId={setEngagementId}
|
|
225
|
+
setIsActive={setIsActive}
|
|
226
|
+
setValidateOnChain={setValidateOnChain}
|
|
227
|
+
setType={(v) => setType(v as typeof type)}
|
|
228
|
+
setStatus={(v) => setStatus(v as typeof status)}
|
|
229
|
+
setMinAmount={setMinAmount}
|
|
230
|
+
setMaxAmount={setMaxAmount}
|
|
231
|
+
setDateRange={setDateRange}
|
|
232
|
+
setRole={(v) => setRole(v as Role)}
|
|
233
|
+
onClearFilters={onClearFilters}
|
|
234
|
+
onRefresh={() => refetch()}
|
|
235
|
+
isRefreshing={isFetching}
|
|
236
|
+
orderBy={orderBy}
|
|
237
|
+
orderDirection={orderDirection}
|
|
238
|
+
setOrderBy={(v) => setOrderBy(v)}
|
|
239
|
+
setOrderDirection={(v) => setOrderDirection(v)}
|
|
240
|
+
/>
|
|
241
|
+
|
|
242
|
+
<Card className="w-full p-2 sm:p-4">
|
|
243
|
+
<div className="mt-2 sm:mt-4 overflow-x-auto">
|
|
244
|
+
<Table>
|
|
245
|
+
<TableHeader>
|
|
246
|
+
{table.getHeaderGroups().map((headerGroup) => (
|
|
247
|
+
<TableRow key={headerGroup.id} className="text-xs sm:text-sm">
|
|
248
|
+
{headerGroup.headers.map((header) => {
|
|
249
|
+
const isSortable = header.column.getCanSort();
|
|
250
|
+
const sorted = header.column.getIsSorted();
|
|
251
|
+
const className =
|
|
252
|
+
typeof header.column.columnDef.meta === "object" &&
|
|
253
|
+
header.column.columnDef.meta &&
|
|
254
|
+
"className" in (header.column.columnDef.meta as any)
|
|
255
|
+
? (header.column.columnDef.meta as any).className
|
|
256
|
+
: "";
|
|
257
|
+
return (
|
|
258
|
+
<TableHead
|
|
259
|
+
key={header.id}
|
|
260
|
+
className={`select-none ${className}`}
|
|
261
|
+
onClick={
|
|
262
|
+
isSortable
|
|
263
|
+
? header.column.getToggleSortingHandler()
|
|
264
|
+
: undefined
|
|
265
|
+
}
|
|
266
|
+
role={isSortable ? "button" : undefined}
|
|
267
|
+
aria-sort={
|
|
268
|
+
sorted
|
|
269
|
+
? sorted === "desc"
|
|
270
|
+
? "descending"
|
|
271
|
+
: "ascending"
|
|
272
|
+
: "none"
|
|
273
|
+
}
|
|
274
|
+
>
|
|
275
|
+
<div className="flex items-center gap-1">
|
|
276
|
+
{flexRender(
|
|
277
|
+
header.column.columnDef.header,
|
|
278
|
+
header.getContext()
|
|
279
|
+
)}
|
|
280
|
+
{isSortable && (
|
|
281
|
+
<span className="text-muted-foreground">
|
|
282
|
+
{sorted === "asc"
|
|
283
|
+
? "▲"
|
|
284
|
+
: sorted === "desc"
|
|
285
|
+
? "▼"
|
|
286
|
+
: ""}
|
|
287
|
+
</span>
|
|
288
|
+
)}
|
|
289
|
+
</div>
|
|
290
|
+
</TableHead>
|
|
291
|
+
);
|
|
292
|
+
})}
|
|
293
|
+
</TableRow>
|
|
294
|
+
))}
|
|
295
|
+
</TableHeader>
|
|
296
|
+
<TableBody>
|
|
297
|
+
{!walletAddress ? (
|
|
298
|
+
<TableRow>
|
|
299
|
+
<TableCell colSpan={table.getAllLeafColumns().length}>
|
|
300
|
+
<div className="p-6 md:p-8 flex flex-col items-center justify-center text-center">
|
|
301
|
+
<Wallet className="h-8 w-8 md:h-12 md:w-12 text-primary mb-3" />
|
|
302
|
+
<h3 className="font-medium text-foreground mb-2">
|
|
303
|
+
Connect your wallet
|
|
304
|
+
</h3>
|
|
305
|
+
<p className="text-sm text-muted-foreground max-w-sm">
|
|
306
|
+
To continue, connect your wallet and authorize the
|
|
307
|
+
application.
|
|
308
|
+
</p>
|
|
309
|
+
</div>
|
|
310
|
+
</TableCell>
|
|
311
|
+
</TableRow>
|
|
312
|
+
) : isLoading ? (
|
|
313
|
+
<TableRow>
|
|
314
|
+
<TableCell colSpan={table.getAllLeafColumns().length}>
|
|
315
|
+
<div className="p-6 md:p-8 flex flex-col items-center justify-center text-center">
|
|
316
|
+
<Loader2 className="h-6 w-6 md:h-8 md:w-8 animate-spin text-primary mb-3" />
|
|
317
|
+
<p className="text-sm text-muted-foreground">
|
|
318
|
+
Loading escrows…
|
|
319
|
+
</p>
|
|
320
|
+
</div>
|
|
321
|
+
</TableCell>
|
|
322
|
+
</TableRow>
|
|
323
|
+
) : isError ? (
|
|
324
|
+
<TableRow>
|
|
325
|
+
<TableCell colSpan={table.getAllLeafColumns().length}>
|
|
326
|
+
<div className="p-6 md:p-8 flex flex-col items-center justify-center text-center">
|
|
327
|
+
<AlertTriangle className="h-8 w-8 md:h-10 md:w-10 text-destructive mb-3" />
|
|
328
|
+
<h3 className="font-medium text-foreground mb-2">
|
|
329
|
+
Error loading data
|
|
330
|
+
</h3>
|
|
331
|
+
<p className="text-sm text-muted-foreground max-w-sm mb-4">
|
|
332
|
+
An error occurred while loading the information.
|
|
333
|
+
Please try again.
|
|
334
|
+
</p>
|
|
335
|
+
<Button
|
|
336
|
+
variant="outline"
|
|
337
|
+
size="sm"
|
|
338
|
+
onClick={() => refetch()}
|
|
339
|
+
>
|
|
340
|
+
<RefreshCw className="h-4 w-4 mr-2" />
|
|
341
|
+
Retry
|
|
342
|
+
</Button>
|
|
343
|
+
</div>
|
|
344
|
+
</TableCell>
|
|
345
|
+
</TableRow>
|
|
346
|
+
) : escrows.length === 0 ? (
|
|
347
|
+
<TableRow>
|
|
348
|
+
<TableCell colSpan={table.getAllLeafColumns().length}>
|
|
349
|
+
<div className="p-6 md:p-8 flex flex-col items-center justify-center text-center">
|
|
350
|
+
<FileX className="h-8 w-8 md:h-10 md:w-10 text-muted-foreground/60 mb-3" />
|
|
351
|
+
<h3 className="font-medium text-foreground mb-2">
|
|
352
|
+
No data available
|
|
353
|
+
</h3>
|
|
354
|
+
<p className="text-sm text-muted-foreground">
|
|
355
|
+
No escrows found for the selected filters.
|
|
356
|
+
</p>
|
|
357
|
+
</div>
|
|
358
|
+
</TableCell>
|
|
359
|
+
</TableRow>
|
|
360
|
+
) : (
|
|
361
|
+
<>
|
|
362
|
+
{table.getRowModel().rows.map((row) => (
|
|
363
|
+
<TableRow key={row.id} className="text-xs sm:text-sm">
|
|
364
|
+
{row.getVisibleCells().map((cell) => {
|
|
365
|
+
const className =
|
|
366
|
+
typeof cell.column.columnDef.meta === "object" &&
|
|
367
|
+
cell.column.columnDef.meta &&
|
|
368
|
+
"className" in (cell.column.columnDef.meta as any)
|
|
369
|
+
? (cell.column.columnDef.meta as any).className
|
|
370
|
+
: "";
|
|
371
|
+
return (
|
|
372
|
+
<TableCell key={cell.id} className={className}>
|
|
373
|
+
{flexRender(
|
|
374
|
+
cell.column.columnDef.cell,
|
|
375
|
+
cell.getContext()
|
|
376
|
+
)}
|
|
377
|
+
</TableCell>
|
|
378
|
+
);
|
|
379
|
+
})}
|
|
380
|
+
</TableRow>
|
|
381
|
+
))}
|
|
382
|
+
</>
|
|
383
|
+
)}
|
|
384
|
+
</TableBody>
|
|
385
|
+
</Table>
|
|
386
|
+
</div>
|
|
387
|
+
|
|
388
|
+
<div className="mt-3 sm:mt-4 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2">
|
|
389
|
+
<div className="text-xs sm:text-sm text-muted-foreground">
|
|
390
|
+
Page {page}
|
|
391
|
+
</div>
|
|
392
|
+
<div className="flex items-center gap-2 self-end sm:self-auto">
|
|
393
|
+
<Button
|
|
394
|
+
variant="outline"
|
|
395
|
+
onClick={() => setPage((p) => Math.max(1, p - 1))}
|
|
396
|
+
disabled={page === 1 || isFetching}
|
|
397
|
+
>
|
|
398
|
+
Previous
|
|
399
|
+
</Button>
|
|
400
|
+
<Button
|
|
401
|
+
variant="outline"
|
|
402
|
+
onClick={() => setPage((p) => p + 1)}
|
|
403
|
+
disabled={
|
|
404
|
+
isFetching ||
|
|
405
|
+
!walletAddress ||
|
|
406
|
+
((nextData?.length ?? 0) === 0 && !isFetchingNext)
|
|
407
|
+
}
|
|
408
|
+
>
|
|
409
|
+
Next
|
|
410
|
+
</Button>
|
|
411
|
+
</div>
|
|
412
|
+
</div>
|
|
413
|
+
</Card>
|
|
414
|
+
</div>
|
|
415
|
+
|
|
416
|
+
{/* Dialog */}
|
|
417
|
+
<EscrowDetailDialog
|
|
418
|
+
activeRole={activeRole}
|
|
419
|
+
isDialogOpen={dialogStates.second.isOpen}
|
|
420
|
+
setIsDialogOpen={dialogStates.second.setIsOpen}
|
|
421
|
+
setSelectedEscrow={setSelectedEscrow}
|
|
422
|
+
/>
|
|
423
|
+
</>
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
export default EscrowsByRoleTable;
|