@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.
Files changed (74) hide show
  1. package/README.md +96 -0
  2. package/bin/index.js +1123 -0
  3. package/package.json +44 -0
  4. package/templates/deps.json +29 -0
  5. package/templates/escrows/details/Actions.tsx +149 -0
  6. package/templates/escrows/details/Entities.tsx +48 -0
  7. package/templates/escrows/details/EntityCard.tsx +98 -0
  8. package/templates/escrows/details/EscrowDetailDialog.tsx +154 -0
  9. package/templates/escrows/details/GeneralInformation.tsx +329 -0
  10. package/templates/escrows/details/MilestoneCard.tsx +254 -0
  11. package/templates/escrows/details/MilestoneDetailDialog.tsx +276 -0
  12. package/templates/escrows/details/Milestones.tsx +87 -0
  13. package/templates/escrows/details/ProgressEscrow.tsx +191 -0
  14. package/templates/escrows/details/StatisticsCard.tsx +79 -0
  15. package/templates/escrows/details/SuccessReleaseDialog.tsx +101 -0
  16. package/templates/escrows/details/useDetailsEscrow.ts +126 -0
  17. package/templates/escrows/escrow-context/EscrowAmountProvider.tsx +86 -0
  18. package/templates/escrows/escrow-context/EscrowDialogsProvider.tsx +108 -0
  19. package/templates/escrows/escrow-context/EscrowProvider.tsx +124 -0
  20. package/templates/escrows/escrows-by-role/cards/EscrowsCards.tsx +503 -0
  21. package/templates/escrows/escrows-by-role/cards/Filters.tsx +421 -0
  22. package/templates/escrows/escrows-by-role/table/EscrowsTable.tsx +427 -0
  23. package/templates/escrows/escrows-by-role/table/Filters.tsx +421 -0
  24. package/templates/escrows/escrows-by-role/useEscrowsByRole.shared.ts +336 -0
  25. package/templates/escrows/escrows-by-signer/cards/EscrowsCards.tsx +502 -0
  26. package/templates/escrows/escrows-by-signer/cards/Filters.tsx +389 -0
  27. package/templates/escrows/escrows-by-signer/table/EscrowsTable.tsx +422 -0
  28. package/templates/escrows/escrows-by-signer/table/Filters.tsx +389 -0
  29. package/templates/escrows/escrows-by-signer/useEscrowsBySigner.shared.ts +320 -0
  30. package/templates/escrows/single-release/approve-milestone/button/ApproveMilestone.tsx +78 -0
  31. package/templates/escrows/single-release/approve-milestone/dialog/ApproveMilestone.tsx +102 -0
  32. package/templates/escrows/single-release/approve-milestone/form/ApproveMilestone.tsx +80 -0
  33. package/templates/escrows/single-release/approve-milestone/shared/schema.ts +9 -0
  34. package/templates/escrows/single-release/approve-milestone/shared/useApproveMilestone.ts +67 -0
  35. package/templates/escrows/single-release/change-milestone-status/button/ChangeMilestoneStatus.tsx +78 -0
  36. package/templates/escrows/single-release/change-milestone-status/dialog/ChangeMilestoneStatus.tsx +167 -0
  37. package/templates/escrows/single-release/change-milestone-status/form/ChangeMilestoneStatus.tsx +114 -0
  38. package/templates/escrows/single-release/change-milestone-status/shared/schema.ts +15 -0
  39. package/templates/escrows/single-release/change-milestone-status/shared/useChangeMilestoneStatus.ts +77 -0
  40. package/templates/escrows/single-release/dispute-escrow/button/DisputeEscrow.tsx +68 -0
  41. package/templates/escrows/single-release/fund-escrow/button/FundEscrow.tsx +84 -0
  42. package/templates/escrows/single-release/fund-escrow/dialog/FundEscrow.tsx +77 -0
  43. package/templates/escrows/single-release/fund-escrow/form/FundEscrow.tsx +54 -0
  44. package/templates/escrows/single-release/fund-escrow/shared/schema.ts +10 -0
  45. package/templates/escrows/single-release/fund-escrow/shared/useFundEscrow.ts +66 -0
  46. package/templates/escrows/single-release/initialize-escrow/dialog/InitializeEscrow.tsx +526 -0
  47. package/templates/escrows/single-release/initialize-escrow/form/InitializeEscrow.tsx +504 -0
  48. package/templates/escrows/single-release/initialize-escrow/shared/schema.ts +232 -0
  49. package/templates/escrows/single-release/initialize-escrow/shared/useInitializeEscrow.ts +115 -0
  50. package/templates/escrows/single-release/release-escrow/button/ReleaseEscrow.tsx +80 -0
  51. package/templates/escrows/single-release/resolve-dispute/button/ResolveDispute.tsx +94 -0
  52. package/templates/escrows/single-release/resolve-dispute/dialog/ResolveDispute.tsx +123 -0
  53. package/templates/escrows/single-release/resolve-dispute/form/ResolveDispute.tsx +82 -0
  54. package/templates/escrows/single-release/resolve-dispute/shared/schema.ts +82 -0
  55. package/templates/escrows/single-release/resolve-dispute/shared/useResolveDispute.ts +58 -0
  56. package/templates/escrows/single-release/update-escrow/dialog/UpdateEscrow.tsx +485 -0
  57. package/templates/escrows/single-release/update-escrow/form/UpdateEscrow.tsx +463 -0
  58. package/templates/escrows/single-release/update-escrow/shared/schema.ts +139 -0
  59. package/templates/escrows/single-release/update-escrow/shared/useUpdateEscrow.ts +211 -0
  60. package/templates/handle-errors/errors.enum.ts +6 -0
  61. package/templates/handle-errors/handle.ts +47 -0
  62. package/templates/helpers/format.helper.ts +27 -0
  63. package/templates/helpers/useCopy.ts +13 -0
  64. package/templates/providers/ReactQueryClientProvider.tsx +28 -0
  65. package/templates/providers/TrustlessWork.tsx +30 -0
  66. package/templates/tanstak/useEscrowsByRoleQuery.ts +87 -0
  67. package/templates/tanstak/useEscrowsBySignerQuery.ts +78 -0
  68. package/templates/tanstak/useEscrowsMutations.ts +411 -0
  69. package/templates/wallet-kit/WalletButtons.tsx +116 -0
  70. package/templates/wallet-kit/WalletProvider.tsx +94 -0
  71. package/templates/wallet-kit/trustlines.ts +40 -0
  72. package/templates/wallet-kit/useWallet.ts +77 -0
  73. package/templates/wallet-kit/validators.ts +12 -0
  74. package/templates/wallet-kit/wallet-kit.ts +30 -0
@@ -0,0 +1,421 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { Button } from "__UI_BASE__/button";
5
+ import { Input } from "__UI_BASE__/input";
6
+ import { Checkbox } from "__UI_BASE__/checkbox";
7
+ import {
8
+ Select,
9
+ SelectContent,
10
+ SelectItem,
11
+ SelectTrigger,
12
+ SelectValue,
13
+ } from "__UI_BASE__/select";
14
+ import { Popover, PopoverContent, PopoverTrigger } from "__UI_BASE__/popover";
15
+ import { Calendar } from "__UI_BASE__/calendar";
16
+ import type { DateRange as DayPickerDateRange } from "react-day-picker";
17
+ import {
18
+ RefreshCcw,
19
+ Trash2,
20
+ Search,
21
+ DollarSign,
22
+ Filter as FilterIcon,
23
+ Calendar as CalendarIcon,
24
+ SlidersHorizontal,
25
+ } from "lucide-react";
26
+ import {
27
+ Select as OrderSelect,
28
+ SelectTrigger as OrderSelectTrigger,
29
+ SelectContent as OrderSelectContent,
30
+ SelectItem as OrderSelectItem,
31
+ SelectValue as OrderSelectValue,
32
+ } from "__UI_BASE__/select";
33
+ import type { Role } from "@trustless-work/escrow/types";
34
+
35
+ type FiltersProps = {
36
+ // values
37
+ title: string;
38
+ engagementId: string;
39
+ isActive: boolean;
40
+ validateOnChain: boolean;
41
+ type: "single-release" | "multi-release" | "all";
42
+ status:
43
+ | "working"
44
+ | "pendingRelease"
45
+ | "released"
46
+ | "resolved"
47
+ | "inDispute"
48
+ | "all";
49
+ minAmount: string;
50
+ maxAmount: string;
51
+ dateRange: DayPickerDateRange;
52
+ formattedRangeLabel: string;
53
+ role?: Role;
54
+
55
+ // setters
56
+ setTitle: (v: string) => void;
57
+ setEngagementId: (v: string) => void;
58
+ setIsActive: (v: boolean) => void;
59
+ setValidateOnChain: (v: boolean) => void;
60
+ setType: (v: "single-release" | "multi-release" | "all") => void;
61
+ setStatus: (
62
+ v:
63
+ | "working"
64
+ | "pendingRelease"
65
+ | "released"
66
+ | "resolved"
67
+ | "inDispute"
68
+ | "all"
69
+ ) => void;
70
+ setMinAmount: (v: string) => void;
71
+ setMaxAmount: (v: string) => void;
72
+ setDateRange: (r: DayPickerDateRange) => void;
73
+ setRole: (v: Role | undefined) => void;
74
+
75
+ // actions
76
+ onClearFilters: () => void;
77
+ onRefresh: () => void;
78
+ isRefreshing: boolean;
79
+
80
+ // ordering
81
+ orderBy: "createdAt" | "updatedAt" | "amount";
82
+ orderDirection: "asc" | "desc";
83
+ setOrderBy: (v: "createdAt" | "updatedAt" | "amount") => void;
84
+ setOrderDirection: (v: "asc" | "desc") => void;
85
+ };
86
+
87
+ function Filters({
88
+ title,
89
+ engagementId,
90
+ isActive,
91
+ validateOnChain,
92
+ type,
93
+ status,
94
+ minAmount,
95
+ maxAmount,
96
+ dateRange,
97
+ formattedRangeLabel,
98
+ role,
99
+ isRefreshing,
100
+ orderBy,
101
+ orderDirection,
102
+ setTitle,
103
+ setEngagementId,
104
+ setIsActive,
105
+ setValidateOnChain,
106
+ setType,
107
+ setStatus,
108
+ setMinAmount,
109
+ setMaxAmount,
110
+ setDateRange,
111
+ setRole,
112
+ onClearFilters,
113
+ onRefresh,
114
+ setOrderBy,
115
+ setOrderDirection,
116
+ }: FiltersProps) {
117
+ return (
118
+ <div className="w-full bg-card/50 backdrop-blur-sm border border-border/50 rounded-lg p-4 shadow-sm">
119
+ {/* Header Section */}
120
+ <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 mb-4">
121
+ <div className="flex items-center gap-2">
122
+ <SlidersHorizontal className="w-4 h-4 text-primary" />
123
+ <h3 className="font-semibold text-foreground">Filters</h3>
124
+ </div>
125
+
126
+ <div className="flex items-center gap-2">
127
+ <Button
128
+ variant="outline"
129
+ size="sm"
130
+ className="h-8 px-3 text-xs font-medium border-border/60 bg-background/80 hover:bg-muted/80 transition-colors cursor-pointer"
131
+ onClick={onRefresh}
132
+ disabled={isRefreshing}
133
+ >
134
+ <RefreshCcw
135
+ className={`w-3 h-3 ${isRefreshing ? "animate-spin" : ""}`}
136
+ />
137
+ <span className="hidden xs:inline">Refresh</span>
138
+ </Button>
139
+
140
+ <Button
141
+ variant="ghost"
142
+ size="sm"
143
+ className="h-8 px-3 text-xs font-medium text-destructive hover:text-destructive hover:bg-destructive/10 transition-colors cursor-pointer"
144
+ onClick={onClearFilters}
145
+ >
146
+ <Trash2 className="w-3 h-3" />
147
+ <span className="hidden xs:inline">Clear</span>
148
+ </Button>
149
+ </div>
150
+ </div>
151
+
152
+ {/* Filters Grid */}
153
+ <div className="space-y-4">
154
+ {/* Row 1: Search, ID, Role, Amount Range, and Type */}
155
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-3">
156
+ <div className="space-y-1.5">
157
+ <label className="text-xs font-medium text-muted-foreground">
158
+ Search
159
+ </label>
160
+ <div className="relative">
161
+ <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-muted-foreground" />
162
+ <Input
163
+ placeholder="Search title..."
164
+ value={title}
165
+ onChange={(e) => setTitle(e.target.value)}
166
+ className="h-9 pl-9 text-sm border-border/60 focus:border-primary/60 bg-background/80 transition-colors w-full"
167
+ />
168
+ </div>
169
+ </div>
170
+
171
+ <div className="space-y-1.5">
172
+ <label className="text-xs font-medium text-muted-foreground">
173
+ Engagement ID
174
+ </label>
175
+ <div className="relative">
176
+ <FilterIcon className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-muted-foreground" />
177
+ <Input
178
+ placeholder="Engagement ID"
179
+ value={engagementId}
180
+ onChange={(e) => setEngagementId(e.target.value)}
181
+ className="h-9 pl-9 text-sm border-border/60 focus:border-primary/60 bg-background/80 transition-colors w-full"
182
+ />
183
+ </div>
184
+ </div>
185
+
186
+ <div className="space-y-1.5">
187
+ <label className="text-xs font-medium text-muted-foreground">
188
+ Role
189
+ </label>
190
+ <div className="w-full">
191
+ <Select value={role} onValueChange={(v) => setRole(v as Role)}>
192
+ <SelectTrigger className="h-9 text-sm border-border/60 bg-background/80 w-full">
193
+ <SelectValue placeholder="Select role" />
194
+ </SelectTrigger>
195
+ <SelectContent>
196
+ <SelectItem value="approver">Approver</SelectItem>
197
+ <SelectItem value="serviceProvider">
198
+ Service Provider
199
+ </SelectItem>
200
+ <SelectItem value="platformAddress">
201
+ Platform Address
202
+ </SelectItem>
203
+ <SelectItem value="releaseSigner">Release Signer</SelectItem>
204
+ <SelectItem value="disputeResolver">
205
+ Dispute Resolver
206
+ </SelectItem>
207
+ <SelectItem value="receiver">Receiver</SelectItem>
208
+ </SelectContent>
209
+ </Select>
210
+ </div>
211
+ </div>
212
+
213
+ <div className="space-y-1.5">
214
+ <label className="text-xs font-medium text-muted-foreground">
215
+ Amount Range
216
+ </label>
217
+ <div className="w-full">
218
+ <div className="flex items-center gap-2 w-full">
219
+ <div className="relative flex-1">
220
+ <DollarSign className="absolute left-2 top-1/2 transform -translate-y-1/2 w-3 h-3 text-muted-foreground" />
221
+ <Input
222
+ placeholder="Min"
223
+ type="number"
224
+ min="0"
225
+ value={minAmount}
226
+ onChange={(e) => setMinAmount(e.target.value)}
227
+ className="h-9 pl-7 text-sm border-border/60 focus:border-primary/60 bg-background/80 w-full"
228
+ />
229
+ </div>
230
+ <span className="text-xs text-muted-foreground px-1">-</span>
231
+ <div className="relative flex-1">
232
+ <DollarSign className="absolute left-2 top-1/2 transform -translate-y-1/2 w-3 h-3 text-muted-foreground" />
233
+ <Input
234
+ placeholder="Max"
235
+ type="number"
236
+ min="0"
237
+ value={maxAmount}
238
+ onChange={(e) => setMaxAmount(e.target.value)}
239
+ className="h-9 pl-7 text-sm border-border/60 focus:border-primary/60 bg-background/80 w-full"
240
+ />
241
+ </div>
242
+ </div>
243
+ </div>
244
+ </div>
245
+
246
+ <div className="space-y-1.5">
247
+ <label className="text-xs font-medium text-muted-foreground">
248
+ Type
249
+ </label>
250
+ <div className="w-full">
251
+ <Select
252
+ value={type}
253
+ onValueChange={(v) => setType(v as typeof type)}
254
+ >
255
+ <SelectTrigger className="h-9 text-sm border-border/60 bg-background/80 w-full">
256
+ <SelectValue placeholder="Select type" />
257
+ </SelectTrigger>
258
+ <SelectContent>
259
+ <SelectItem value="all">All types</SelectItem>
260
+ <SelectItem value="single-release">Single release</SelectItem>
261
+ <SelectItem value="multi-release">Multi release</SelectItem>
262
+ </SelectContent>
263
+ </Select>
264
+ </div>
265
+ </div>
266
+ </div>
267
+
268
+ {/* Row 2: Status, Date Range, Active Checkbox, and Ordering */}
269
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-3 items-end">
270
+ <div className="space-y-1.5">
271
+ <label className="text-xs font-medium text-muted-foreground">
272
+ Status
273
+ </label>
274
+ <div className="w-full">
275
+ <Select
276
+ value={status}
277
+ onValueChange={(v) => setStatus(v as typeof status)}
278
+ >
279
+ <SelectTrigger className="h-9 text-sm border-border/60 bg-background/80 w-full">
280
+ <SelectValue placeholder="Select status" />
281
+ </SelectTrigger>
282
+ <SelectContent>
283
+ <SelectItem value="all">All statuses</SelectItem>
284
+ <SelectItem value="working">Working</SelectItem>
285
+ <SelectItem value="pendingRelease">
286
+ Pending release
287
+ </SelectItem>
288
+ <SelectItem value="released">Released</SelectItem>
289
+ <SelectItem value="resolved">Resolved</SelectItem>
290
+ <SelectItem value="inDispute">In dispute</SelectItem>
291
+ </SelectContent>
292
+ </Select>
293
+ </div>
294
+ </div>
295
+
296
+ <div className="space-y-1.5">
297
+ <label className="text-xs font-medium text-muted-foreground">
298
+ Date Range
299
+ </label>
300
+ <div className="w-full">
301
+ <Popover>
302
+ <PopoverTrigger asChild>
303
+ <Button
304
+ variant="outline"
305
+ size="sm"
306
+ className="h-9 text-sm border-border/60 bg-background/80 hover:bg-muted/80 w-full justify-start transition-colors"
307
+ >
308
+ <CalendarIcon className="w-4 h-4 mr-2 flex-shrink-0" />
309
+ <span className="truncate">{formattedRangeLabel}</span>
310
+ </Button>
311
+ </PopoverTrigger>
312
+ <PopoverContent className="w-auto p-0" align="start">
313
+ <div className="p-3">
314
+ <Calendar
315
+ mode="range"
316
+ selected={dateRange}
317
+ onSelect={(range: DayPickerDateRange | undefined) =>
318
+ setDateRange(
319
+ range ?? { from: undefined, to: undefined }
320
+ )
321
+ }
322
+ numberOfMonths={2}
323
+ />
324
+ <div className="mt-3 flex justify-end">
325
+ <Button
326
+ variant="ghost"
327
+ size="sm"
328
+ onClick={() =>
329
+ setDateRange({ from: undefined, to: undefined })
330
+ }
331
+ >
332
+ Clear
333
+ </Button>
334
+ </div>
335
+ </div>
336
+ </PopoverContent>
337
+ </Popover>
338
+ </div>
339
+ </div>
340
+
341
+ <div className="space-y-1.5">
342
+ <label className="text-xs font-medium text-muted-foreground">
343
+ Active / OnChain
344
+ </label>
345
+ <div className="w-full lg:w-auto lg:min-w-fit">
346
+ <div className="grid grid-cols-2 gap-2 w-full lg:w-auto">
347
+ <div className="flex items-center justify-center lg:justify-start gap-2 h-9 px-3 rounded-md border border-border/60 bg-background/80 w-full lg:w-auto">
348
+ <Checkbox
349
+ checked={Boolean(isActive)}
350
+ onCheckedChange={(checked) => setIsActive(Boolean(checked))}
351
+ />
352
+ <span className="text-sm text-foreground font-medium whitespace-nowrap">
353
+ Active
354
+ </span>
355
+ </div>
356
+ <div className="flex items-center justify-center lg:justify-start gap-2 h-9 px-3 rounded-md border border-border/60 bg-background/80 w-full lg:w-auto">
357
+ <Checkbox
358
+ checked={Boolean(validateOnChain)}
359
+ onCheckedChange={(checked) =>
360
+ setValidateOnChain(Boolean(checked))
361
+ }
362
+ />
363
+ <span className="text-sm text-foreground font-medium whitespace-nowrap">
364
+ OnChain
365
+ </span>
366
+ </div>
367
+ </div>
368
+ </div>
369
+ </div>
370
+
371
+ <div className="space-y-1.5 w-full lg:col-span-2">
372
+ <label className="text-xs font-medium text-muted-foreground">
373
+ Sort By
374
+ </label>
375
+ <div className="w-full">
376
+ <div className="flex items-center gap-2 w-full">
377
+ <div className="flex-1">
378
+ <OrderSelect
379
+ value={orderBy}
380
+ onValueChange={(v) => setOrderBy(v as typeof orderBy)}
381
+ >
382
+ <OrderSelectTrigger className="h-9 text-sm border-border/60 bg-background/80 w-full">
383
+ <OrderSelectValue placeholder="Order by" />
384
+ </OrderSelectTrigger>
385
+ <OrderSelectContent>
386
+ <OrderSelectItem value="createdAt">
387
+ Created
388
+ </OrderSelectItem>
389
+ <OrderSelectItem value="updatedAt">
390
+ Updated
391
+ </OrderSelectItem>
392
+ <OrderSelectItem value="amount">Amount</OrderSelectItem>
393
+ </OrderSelectContent>
394
+ </OrderSelect>
395
+ </div>
396
+ <div className="flex-1">
397
+ <OrderSelect
398
+ value={orderDirection}
399
+ onValueChange={(v) =>
400
+ setOrderDirection(v as typeof orderDirection)
401
+ }
402
+ >
403
+ <OrderSelectTrigger className="h-9 text-sm border-border/60 bg-background/80 w-full">
404
+ <OrderSelectValue placeholder="Direction" />
405
+ </OrderSelectTrigger>
406
+ <OrderSelectContent>
407
+ <OrderSelectItem value="desc">Descending</OrderSelectItem>
408
+ <OrderSelectItem value="asc">Ascending</OrderSelectItem>
409
+ </OrderSelectContent>
410
+ </OrderSelect>
411
+ </div>
412
+ </div>
413
+ </div>
414
+ </div>
415
+ </div>
416
+ </div>
417
+ </div>
418
+ );
419
+ }
420
+
421
+ export default React.memo(Filters);