@trustless-work/blocks 0.0.7 → 0.0.8

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 (66) hide show
  1. package/bin/index.js +485 -17
  2. package/package.json +1 -1
  3. package/templates/escrows/details/Actions.tsx +144 -149
  4. package/templates/escrows/details/Entities.tsx +1 -1
  5. package/templates/escrows/details/EntityCard.tsx +1 -3
  6. package/templates/escrows/details/EscrowDetailDialog.tsx +16 -16
  7. package/templates/escrows/details/GeneralInformation.tsx +19 -22
  8. package/templates/escrows/details/MilestoneCard.tsx +46 -47
  9. package/templates/escrows/details/MilestoneDetailDialog.tsx +1 -2
  10. package/templates/escrows/details/Milestones.tsx +0 -5
  11. package/templates/escrows/details/SuccessReleaseDialog.tsx +4 -6
  12. package/templates/escrows/escrows-by-role/cards/EscrowsCards.tsx +84 -49
  13. package/templates/escrows/escrows-by-role/cards/Filters.tsx +3 -5
  14. package/templates/escrows/escrows-by-role/table/EscrowsTable.tsx +8 -26
  15. package/templates/escrows/escrows-by-role/table/Filters.tsx +3 -5
  16. package/templates/escrows/escrows-by-signer/cards/EscrowsCards.tsx +89 -55
  17. package/templates/escrows/escrows-by-signer/cards/Filters.tsx +3 -5
  18. package/templates/escrows/escrows-by-signer/table/EscrowsTable.tsx +8 -24
  19. package/templates/escrows/escrows-by-signer/table/Filters.tsx +3 -5
  20. package/templates/escrows/multi-release/dispute-milestone/button/DisputeEscrow.tsx +98 -0
  21. package/templates/escrows/multi-release/initialize-escrow/dialog/InitializeEscrow.tsx +528 -0
  22. package/templates/escrows/multi-release/initialize-escrow/form/InitializeEscrow.tsx +506 -0
  23. package/templates/escrows/multi-release/initialize-escrow/shared/schema.ts +179 -0
  24. package/templates/escrows/multi-release/initialize-escrow/shared/useInitializeEscrow.ts +175 -0
  25. package/templates/escrows/multi-release/release-milestone/button/ReleaseEscrow.tsx +116 -0
  26. package/templates/escrows/multi-release/resolve-dispute/button/ResolveDispute.tsx +122 -0
  27. package/templates/escrows/multi-release/resolve-dispute/dialog/ResolveDispute.tsx +178 -0
  28. package/templates/escrows/multi-release/resolve-dispute/form/ResolveDispute.tsx +156 -0
  29. package/templates/escrows/multi-release/resolve-dispute/shared/schema.ts +85 -0
  30. package/templates/escrows/multi-release/resolve-dispute/shared/useResolveDispute.ts +105 -0
  31. package/templates/escrows/multi-release/update-escrow/dialog/UpdateEscrow.tsx +471 -0
  32. package/templates/escrows/multi-release/update-escrow/form/UpdateEscrow.tsx +449 -0
  33. package/templates/escrows/multi-release/update-escrow/shared/schema.ts +152 -0
  34. package/templates/escrows/multi-release/update-escrow/shared/useUpdateEscrow.ts +254 -0
  35. package/templates/escrows/{single-release → single-multi-release}/approve-milestone/button/ApproveMilestone.tsx +20 -7
  36. package/templates/escrows/{single-release → single-multi-release}/approve-milestone/dialog/ApproveMilestone.tsx +3 -3
  37. package/templates/escrows/{single-release → single-multi-release}/approve-milestone/form/ApproveMilestone.tsx +3 -3
  38. package/templates/escrows/{single-release/approve-milestone/shared → single-multi-release/approve-milestone}/useApproveMilestone.ts +16 -16
  39. package/templates/escrows/{single-release → single-multi-release}/change-milestone-status/button/ChangeMilestoneStatus.tsx +4 -4
  40. package/templates/escrows/{single-release → single-multi-release}/change-milestone-status/dialog/ChangeMilestoneStatus.tsx +4 -4
  41. package/templates/escrows/{single-release → single-multi-release}/change-milestone-status/form/ChangeMilestoneStatus.tsx +3 -3
  42. package/templates/escrows/{single-release/change-milestone-status/shared → single-multi-release/change-milestone-status}/useChangeMilestoneStatus.ts +1 -1
  43. package/templates/escrows/{single-release → single-multi-release}/fund-escrow/button/FundEscrow.tsx +3 -3
  44. package/templates/escrows/{single-release → single-multi-release}/fund-escrow/dialog/FundEscrow.tsx +3 -3
  45. package/templates/escrows/{single-release → single-multi-release}/fund-escrow/form/FundEscrow.tsx +3 -3
  46. package/templates/escrows/{single-release/fund-escrow/shared → single-multi-release/fund-escrow}/useFundEscrow.ts +1 -1
  47. package/templates/escrows/single-release/dispute-escrow/button/DisputeEscrow.tsx +2 -2
  48. package/templates/escrows/single-release/initialize-escrow/dialog/InitializeEscrow.tsx +14 -6
  49. package/templates/escrows/single-release/initialize-escrow/form/InitializeEscrow.tsx +14 -6
  50. package/templates/escrows/single-release/initialize-escrow/shared/schema.ts +0 -57
  51. package/templates/escrows/single-release/initialize-escrow/shared/useInitializeEscrow.ts +42 -1
  52. package/templates/escrows/single-release/release-escrow/button/ReleaseEscrow.tsx +2 -2
  53. package/templates/escrows/single-release/resolve-dispute/button/ResolveDispute.tsx +3 -3
  54. package/templates/escrows/single-release/resolve-dispute/dialog/ResolveDispute.tsx +3 -6
  55. package/templates/escrows/single-release/resolve-dispute/form/ResolveDispute.tsx +2 -2
  56. package/templates/escrows/single-release/resolve-dispute/shared/useResolveDispute.ts +14 -1
  57. package/templates/escrows/single-release/update-escrow/dialog/UpdateEscrow.tsx +2 -2
  58. package/templates/escrows/single-release/update-escrow/form/UpdateEscrow.tsx +2 -2
  59. package/templates/escrows/single-release/update-escrow/shared/useUpdateEscrow.ts +12 -7
  60. package/templates/providers/EscrowDialogsProvider.tsx +1 -3
  61. package/templates/providers/EscrowProvider.tsx +27 -4
  62. package/templates/providers/TrustlessWork.tsx +1 -1
  63. package/templates/escrows/details/ProgressEscrow.tsx +0 -191
  64. /package/templates/escrows/{single-release/approve-milestone/shared → single-multi-release/approve-milestone}/schema.ts +0 -0
  65. /package/templates/escrows/{single-release/change-milestone-status/shared → single-multi-release/change-milestone-status}/schema.ts +0 -0
  66. /package/templates/escrows/{single-release/fund-escrow/shared → single-multi-release/fund-escrow}/schema.ts +0 -0
@@ -5,14 +5,14 @@ import { Button } from "__UI_BASE__/button";
5
5
  import type {
6
6
  GetEscrowsFromIndexerResponse as Escrow,
7
7
  MultiReleaseMilestone,
8
- Role,
9
8
  SingleReleaseMilestone,
10
9
  } from "@trustless-work/escrow/types";
11
- import Filters from "./Filters";
10
+ import { Filters } from "./Filters";
12
11
  import { useEscrowsBySigner } from "../useEscrowsBySigner.shared";
13
12
  import { Card, CardContent, CardHeader, CardTitle } from "__UI_BASE__/card";
14
13
  import { Badge } from "__UI_BASE__/badge";
15
14
  import { Separator } from "__UI_BASE__/separator";
15
+ import { Tooltip, TooltipContent, TooltipTrigger } from "__UI_BASE__/tooltip";
16
16
  import {
17
17
  Goal,
18
18
  Wallet,
@@ -23,10 +23,13 @@ import {
23
23
  } from "lucide-react";
24
24
  import { useEscrowContext } from "@/components/tw-blocks/providers/EscrowProvider";
25
25
  import { useEscrowDialogs } from "@/components/tw-blocks/providers/EscrowDialogsProvider";
26
- import EscrowDetailDialog from "../../escrows-by-role/details/EscrowDetailDialog";
27
- import { formatTimestamp } from "../../../helpers/format.helper";
26
+ import { EscrowDetailDialog } from "../details/EscrowDetailDialog";
27
+ import {
28
+ formatCurrency,
29
+ formatTimestamp,
30
+ } from "../../../helpers/format.helper";
28
31
 
29
- export function EscrowsBySignerCards() {
32
+ export const EscrowsBySignerCards = () => {
30
33
  const {
31
34
  walletAddress,
32
35
  data,
@@ -74,10 +77,6 @@ export function EscrowsBySignerCards() {
74
77
  void refetch();
75
78
  }, [refetch]);
76
79
 
77
- const formatCurrency = (value: number, currency: string) => {
78
- return `${currency} ${value.toFixed(2)}`;
79
- };
80
-
81
80
  function allMilestonesReleasedOrResolved(
82
81
  milestones: MultiReleaseMilestone[]
83
82
  ) {
@@ -120,18 +119,6 @@ export function EscrowsBySignerCards() {
120
119
  dialogStates.second.setIsOpen(true);
121
120
  };
122
121
 
123
- /**
124
- * Based on the provided roles -> https://docs.trustlesswork.com/trustless-work/technology-overview/roles-in-trustless-work
125
- *
126
- * You must pass one or more roles according to requirements
127
- *
128
- * For example:
129
- * - If the user is a freelancer, you must pass the "serviceProvider" and "receiver" role
130
- *
131
- * Depending of the role, you'll have different actions buttons
132
- */
133
- const activeRole: Role[] = React.useMemo(() => ["approver"] as Role[], []);
134
-
135
122
  const escrows: Escrow[] = data ?? [];
136
123
 
137
124
  return (
@@ -262,7 +249,7 @@ export function EscrowsBySignerCards() {
262
249
  {escrows.map((escrow) => (
263
250
  <React.Fragment key={escrow.contractId}>
264
251
  <Card
265
- className="w-full max-w-md mx-auto hover:shadow-lg transition-shadow duration-200"
252
+ className="w-full max-w-md mx-auto hover:shadow-lg transition-shadow duration-200 cursor-pointer"
266
253
  onClick={(e) => {
267
254
  e.stopPropagation();
268
255
  onCardClick(escrow);
@@ -347,9 +334,9 @@ export function EscrowsBySignerCards() {
347
334
  <ul className="list-disc list-inside flex flex-col gap-1">
348
335
  {escrow.milestones
349
336
  .slice(0, 3)
350
- .map((milestone) => (
337
+ .map((milestone, index) => (
351
338
  <li
352
- key={milestone.description.slice(0, 5)}
339
+ key={`milestone-${milestone.description}-${milestone.status}-${index}`}
353
340
  className="text-xs flex justify-between"
354
341
  >
355
342
  {milestone.description}
@@ -365,33 +352,83 @@ export function EscrowsBySignerCards() {
365
352
  )}
366
353
  </span>
367
354
 
368
- <span
369
- className={`bg-red-800 rounded-full h-2 w-2 ml-1 ${
370
- milestone.flags?.disputed
371
- ? "block"
372
- : "hidden"
373
- }`}
374
- />
375
-
376
- <span
377
- className={`bg-green-800 rounded-full h-2 w-2 ml-1 ${
378
- milestone.flags?.resolved ||
379
- milestone.flags?.released
380
- ? "block"
381
- : "hidden"
382
- }`}
383
- />
384
-
385
- <span
386
- className={`bg-yellow-800 rounded-full h-2 w-2 ml-1 ${
387
- milestone.flags?.approved &&
388
- !milestone.flags?.disputed &&
389
- !milestone.flags?.resolved &&
390
- !milestone.flags?.released
391
- ? "block"
392
- : "hidden"
393
- }`}
394
- />
355
+ {milestone.flags?.disputed && (
356
+ <Tooltip>
357
+ <TooltipTrigger>
358
+ <span
359
+ className={`bg-red-800 rounded-full h-2 w-2 ml-1 ${
360
+ milestone.flags?.disputed
361
+ ? "block"
362
+ : "hidden"
363
+ }`}
364
+ />
365
+ </TooltipTrigger>
366
+ <TooltipContent>
367
+ Disputed
368
+ </TooltipContent>
369
+ </Tooltip>
370
+ )}
371
+
372
+ {milestone.flags?.resolved && (
373
+ <Tooltip>
374
+ <TooltipTrigger>
375
+ <span
376
+ className={`bg-green-800 rounded-full h-2 w-2 ml-1 ${
377
+ milestone.flags?.resolved
378
+ ? "block"
379
+ : "hidden"
380
+ }`}
381
+ />
382
+ </TooltipTrigger>
383
+ <TooltipContent>
384
+ Resolved
385
+ </TooltipContent>
386
+ </Tooltip>
387
+ )}
388
+
389
+ {milestone.flags?.released && (
390
+ <Tooltip>
391
+ <TooltipTrigger>
392
+ <span
393
+ className={`bg-green-800 rounded-full h-2 w-2 ml-1 ${
394
+ milestone.flags?.released
395
+ ? "block"
396
+ : "hidden"
397
+ }`}
398
+ />
399
+ </TooltipTrigger>
400
+ <TooltipContent>
401
+ Released
402
+ </TooltipContent>
403
+ </Tooltip>
404
+ )}
405
+
406
+ {milestone.flags?.approved &&
407
+ !milestone.flags?.disputed &&
408
+ !milestone.flags?.resolved &&
409
+ !milestone.flags?.released && (
410
+ <Tooltip>
411
+ <TooltipTrigger>
412
+ <span
413
+ className={`bg-yellow-600 rounded-full h-2 w-2 ml-1 ${
414
+ milestone.flags
415
+ ?.approved &&
416
+ !milestone.flags
417
+ ?.disputed &&
418
+ !milestone.flags
419
+ ?.resolved &&
420
+ !milestone.flags
421
+ ?.released
422
+ ? "block"
423
+ : "hidden"
424
+ }`}
425
+ />
426
+ </TooltipTrigger>
427
+ <TooltipContent>
428
+ Pending Release
429
+ </TooltipContent>
430
+ </Tooltip>
431
+ )}
395
432
  </div>
396
433
  </>
397
434
  )}
@@ -508,7 +545,6 @@ export function EscrowsBySignerCards() {
508
545
  {/* Dialog */}
509
546
  {dialogStates.second.isOpen ? (
510
547
  <EscrowDetailDialog
511
- activeRole={activeRole}
512
548
  isDialogOpen={dialogStates.second.isOpen}
513
549
  setIsDialogOpen={dialogStates.second.setIsOpen}
514
550
  setSelectedEscrow={setSelectedEscrow}
@@ -516,6 +552,4 @@ export function EscrowsBySignerCards() {
516
552
  ) : null}
517
553
  </>
518
554
  );
519
- }
520
-
521
- export default React.memo(EscrowsBySignerCards);
555
+ };
@@ -81,7 +81,7 @@ type FiltersProps = {
81
81
  setOrderDirection: (v: "asc" | "desc") => void;
82
82
  };
83
83
 
84
- function Filters({
84
+ export const Filters = ({
85
85
  title,
86
86
  engagementId,
87
87
  isActive,
@@ -108,7 +108,7 @@ function Filters({
108
108
  onRefresh,
109
109
  setOrderBy,
110
110
  setOrderDirection,
111
- }: FiltersProps) {
111
+ }: FiltersProps) => {
112
112
  return (
113
113
  <div className="w-full bg-card/50 backdrop-blur-sm border border-border/50 rounded-lg p-4 shadow-sm">
114
114
  {/* Header Section */}
@@ -384,6 +384,4 @@ function Filters({
384
384
  </div>
385
385
  </div>
386
386
  );
387
- }
388
-
389
- export default React.memo(Filters);
387
+ };
@@ -6,7 +6,6 @@ import { Button } from "__UI_BASE__/button";
6
6
  import type {
7
7
  GetEscrowsFromIndexerResponse as Escrow,
8
8
  MultiReleaseMilestone,
9
- Role,
10
9
  } from "@trustless-work/escrow/types";
11
10
  import {
12
11
  ColumnDef,
@@ -23,14 +22,14 @@ import {
23
22
  TableRow,
24
23
  } from "__UI_BASE__/table";
25
24
  import { FileX, Loader2, Wallet, RefreshCw, AlertTriangle } from "lucide-react";
26
- import Filters from "./Filters";
25
+ import { Filters } from "./Filters";
27
26
  import { useEscrowsBySigner } from "../useEscrowsBySigner.shared";
28
27
  import { useEscrowDialogs } from "@/components/tw-blocks/providers/EscrowDialogsProvider";
29
28
  import { useEscrowContext } from "@/components/tw-blocks/providers/EscrowProvider";
30
- import EscrowDetailDialog from "../../escrows-by-role/details/EscrowDetailDialog";
29
+ import { EscrowDetailDialog } from "../details/EscrowDetailDialog";
31
30
  import { formatTimestamp } from "../../../helpers/format.helper";
32
31
 
33
- export function EscrowsBySignerTable() {
32
+ export const EscrowsBySignerTable = () => {
34
33
  const {
35
34
  walletAddress,
36
35
  data,
@@ -203,18 +202,6 @@ export function EscrowsBySignerTable() {
203
202
  enableSortingRemoval: true,
204
203
  });
205
204
 
206
- /**
207
- * Based on the provided roles -> https://docs.trustlesswork.com/trustless-work/technology-overview/roles-in-trustless-work
208
- *
209
- * You must pass one or more roles according to requirements
210
- *
211
- * For example:
212
- * - If the user is a freelancer, you must pass the "serviceProvider" and "receiver" role
213
- *
214
- * Depending of the role, you'll have different actions buttons
215
- */
216
- const activeRole: Role[] = React.useMemo(() => ["approver"] as Role[], []);
217
-
218
205
  const escrows = data ?? [];
219
206
 
220
207
  return (
@@ -261,8 +248,8 @@ export function EscrowsBySignerTable() {
261
248
  const className =
262
249
  typeof header.column.columnDef.meta === "object" &&
263
250
  header.column.columnDef.meta &&
264
- "className" in (header.column.columnDef.meta as any)
265
- ? (header.column.columnDef.meta as any).className
251
+ "className" in header.column.columnDef.meta
252
+ ? header.column.columnDef.meta.className
266
253
  : "";
267
254
  return (
268
255
  <TableHead
@@ -375,8 +362,8 @@ export function EscrowsBySignerTable() {
375
362
  const className =
376
363
  typeof cell.column.columnDef.meta === "object" &&
377
364
  cell.column.columnDef.meta &&
378
- "className" in (cell.column.columnDef.meta as any)
379
- ? (cell.column.columnDef.meta as any).className
365
+ "className" in cell.column.columnDef.meta
366
+ ? (cell.column.columnDef.meta.className as string)
380
367
  : "";
381
368
  return (
382
369
  <TableCell key={cell.id} className={className}>
@@ -426,7 +413,6 @@ export function EscrowsBySignerTable() {
426
413
  {/* Dialog */}
427
414
  {dialogStates.second.isOpen ? (
428
415
  <EscrowDetailDialog
429
- activeRole={activeRole}
430
416
  isDialogOpen={dialogStates.second.isOpen}
431
417
  setIsDialogOpen={dialogStates.second.setIsOpen}
432
418
  setSelectedEscrow={setSelectedEscrow}
@@ -434,6 +420,4 @@ export function EscrowsBySignerTable() {
434
420
  ) : null}
435
421
  </>
436
422
  );
437
- }
438
-
439
- export default React.memo(EscrowsBySignerTable);
423
+ };
@@ -81,7 +81,7 @@ type FiltersProps = {
81
81
  setOrderDirection: (v: "asc" | "desc") => void;
82
82
  };
83
83
 
84
- function Filters({
84
+ export const Filters = ({
85
85
  title,
86
86
  engagementId,
87
87
  isActive,
@@ -108,7 +108,7 @@ function Filters({
108
108
  onRefresh,
109
109
  setOrderBy,
110
110
  setOrderDirection,
111
- }: FiltersProps) {
111
+ }: FiltersProps) => {
112
112
  return (
113
113
  <div className="w-full bg-card/50 backdrop-blur-sm border border-border/50 rounded-lg p-4 shadow-sm">
114
114
  {/* Header Section */}
@@ -384,6 +384,4 @@ function Filters({
384
384
  </div>
385
385
  </div>
386
386
  );
387
- }
388
-
389
- export default React.memo(Filters);
387
+ };
@@ -0,0 +1,98 @@
1
+ import * as React from "react";
2
+ import { Button } from "__UI_BASE__/button";
3
+ import { useEscrowsMutations } from "@/components/tw-blocks/tanstack/useEscrowsMutations";
4
+ import { useWalletContext } from "@/components/tw-blocks/wallet-kit/WalletProvider";
5
+ import {
6
+ MultiReleaseStartDisputePayload,
7
+ MultiReleaseMilestone,
8
+ } from "@trustless-work/escrow/types";
9
+ import { toast } from "sonner";
10
+ import {
11
+ ErrorResponse,
12
+ handleError,
13
+ } from "@/components/tw-blocks/handle-errors/handle";
14
+ import { useEscrowContext } from "@/components/tw-blocks/providers/EscrowProvider";
15
+ import { Loader2 } from "lucide-react";
16
+
17
+ type DisputeEscrowButtonProps = {
18
+ milestoneIndex: number | string;
19
+ };
20
+
21
+ export const DisputeEscrowButton = ({
22
+ milestoneIndex,
23
+ }: DisputeEscrowButtonProps) => {
24
+ const { startDispute } = useEscrowsMutations();
25
+ const { selectedEscrow, updateEscrow } = useEscrowContext();
26
+ const { walletAddress } = useWalletContext();
27
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
28
+
29
+ async function handleClick() {
30
+ try {
31
+ setIsSubmitting(true);
32
+
33
+ /**
34
+ * Create the payload for the dispute escrow mutation
35
+ *
36
+ * @returns The payload for the dispute escrow mutation
37
+ */
38
+ const payload: MultiReleaseStartDisputePayload = {
39
+ contractId: selectedEscrow?.contractId || "",
40
+ signer: walletAddress || "",
41
+ milestoneIndex: String(milestoneIndex),
42
+ };
43
+
44
+ /**
45
+ * Call the dispute escrow mutation
46
+ *
47
+ * @param payload - The payload for the dispute escrow mutation
48
+ * @param type - The type of the escrow
49
+ * @param address - The address of the escrow
50
+ */
51
+ await startDispute.mutateAsync({
52
+ payload,
53
+ type: "multi-release",
54
+ address: walletAddress || "",
55
+ });
56
+
57
+ toast.success("Escrow disputed successfully");
58
+
59
+ updateEscrow({
60
+ ...selectedEscrow,
61
+ milestones: selectedEscrow?.milestones.map((milestone, index) => {
62
+ if (index === Number(milestoneIndex)) {
63
+ return {
64
+ ...milestone,
65
+ flags: {
66
+ ...(milestone as MultiReleaseMilestone).flags,
67
+ disputed: true,
68
+ },
69
+ };
70
+ }
71
+ return milestone;
72
+ }),
73
+ });
74
+ } catch (error) {
75
+ toast.error(handleError(error as ErrorResponse).message);
76
+ } finally {
77
+ setIsSubmitting(false);
78
+ }
79
+ }
80
+
81
+ return (
82
+ <Button
83
+ type="button"
84
+ disabled={isSubmitting || !selectedEscrow?.balance}
85
+ onClick={handleClick}
86
+ className="cursor-pointer w-full"
87
+ >
88
+ {isSubmitting ? (
89
+ <div className="flex items-center">
90
+ <Loader2 className="h-5 w-5 animate-spin" />
91
+ <span className="ml-2">Disputing...</span>
92
+ </div>
93
+ ) : (
94
+ "Dispute Milestone"
95
+ )}
96
+ </Button>
97
+ );
98
+ };