@trustless-work/blocks 1.0.6 → 1.0.7

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 (33) hide show
  1. package/bin/index.js +1930 -1921
  2. package/package.json +1 -1
  3. package/templates/deps.json +1 -1
  4. package/templates/escrows/details/Actions.tsx +1 -2
  5. package/templates/escrows/details/Entities.tsx +23 -2
  6. package/templates/escrows/details/GeneralInformation.tsx +1 -13
  7. package/templates/escrows/details/MilestoneCard.tsx +1 -1
  8. package/templates/escrows/details/MilestoneDetailDialog.tsx +38 -19
  9. package/templates/escrows/details/SuccessReleaseDialog.tsx +84 -28
  10. package/templates/escrows/details/useDetailsEscrow.ts +15 -2
  11. package/templates/escrows/multi-release/initialize-escrow/dialog/InitializeEscrow.tsx +76 -101
  12. package/templates/escrows/multi-release/initialize-escrow/form/InitializeEscrow.tsx +78 -102
  13. package/templates/escrows/multi-release/initialize-escrow/shared/schema.ts +8 -18
  14. package/templates/escrows/multi-release/initialize-escrow/shared/useInitializeEscrow.ts +21 -12
  15. package/templates/escrows/multi-release/release-milestone/button/ReleaseMilestone.tsx +5 -1
  16. package/templates/escrows/multi-release/update-escrow/dialog/UpdateEscrow.tsx +112 -101
  17. package/templates/escrows/multi-release/update-escrow/form/UpdateEscrow.tsx +103 -101
  18. package/templates/escrows/multi-release/update-escrow/shared/schema.ts +8 -16
  19. package/templates/escrows/multi-release/update-escrow/shared/useUpdateEscrow.ts +33 -14
  20. package/templates/escrows/multi-release/withdraw-remaining-funds/button/WithdrawRemainingFunds.tsx +0 -1
  21. package/templates/escrows/multi-release/withdraw-remaining-funds/shared/useWithdrawRemainingFunds.ts +0 -1
  22. package/templates/escrows/single-release/initialize-escrow/dialog/InitializeEscrow.tsx +2 -25
  23. package/templates/escrows/single-release/initialize-escrow/form/InitializeEscrow.tsx +3 -26
  24. package/templates/escrows/single-release/initialize-escrow/shared/schema.ts +0 -10
  25. package/templates/escrows/single-release/initialize-escrow/shared/useInitializeEscrow.ts +0 -4
  26. package/templates/escrows/single-release/release-escrow/button/ReleaseEscrow.tsx +5 -1
  27. package/templates/escrows/single-release/update-escrow/dialog/UpdateEscrow.tsx +41 -27
  28. package/templates/escrows/single-release/update-escrow/form/UpdateEscrow.tsx +38 -3
  29. package/templates/escrows/single-release/update-escrow/shared/useUpdateEscrow.ts +28 -14
  30. package/templates/providers/EscrowAmountProvider.tsx +8 -0
  31. package/templates/tanstack/useEscrowsMutations.ts +1 -6
  32. package/templates/wallet-kit/WalletButtons.tsx +2 -2
  33. package/templates/wallet-kit/WalletProvider.tsx +0 -1
@@ -22,6 +22,7 @@ import { useInitializeEscrow } from "./useInitializeEscrow";
22
22
  import { Trash2, DollarSign, Percent, Loader2 } from "lucide-react";
23
23
  import Link from "next/link";
24
24
  import { trustlineOptions } from "@/components/tw-blocks/wallet-kit/trustlines";
25
+ import { Separator } from "__UI_BASE__/separator";
25
26
 
26
27
  export const InitializeEscrowForm = () => {
27
28
  const {
@@ -86,7 +87,7 @@ export const InitializeEscrowForm = () => {
86
87
  return (
87
88
  <Form {...form}>
88
89
  <form onSubmit={handleSubmit} className="flex flex-col space-y-6">
89
- <Card className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 p-4">
90
+ <Card className="flex w-full max-w-3xl flex-col sm:flex-row justify-between items-start sm:items-center gap-4 p-4">
90
91
  <Link
91
92
  className="flex-1"
92
93
  href="https://docs.trustlesswork.com/trustless-work/technology-overview/escrow-types"
@@ -111,7 +112,7 @@ export const InitializeEscrowForm = () => {
111
112
  </Button>
112
113
  )}
113
114
  </Card>
114
- <div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
115
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
115
116
  <FormField
116
117
  control={form.control}
117
118
  name="title"
@@ -155,7 +156,9 @@ export const InitializeEscrowForm = () => {
155
156
  </FormItem>
156
157
  )}
157
158
  />
159
+ </div>
158
160
 
161
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
159
162
  <FormField
160
163
  control={form.control}
161
164
  name="trustline.address"
@@ -192,6 +195,34 @@ export const InitializeEscrowForm = () => {
192
195
  </FormItem>
193
196
  )}
194
197
  />
198
+
199
+ <FormField
200
+ control={form.control}
201
+ name="platformFee"
202
+ render={() => (
203
+ <FormItem>
204
+ <FormLabel className="flex items-center">
205
+ Platform Fee
206
+ <span className="text-destructive ml-1">*</span>
207
+ </FormLabel>
208
+ <FormControl>
209
+ <div className="relative">
210
+ <Percent
211
+ className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-500"
212
+ size={18}
213
+ />
214
+ <Input
215
+ placeholder="Enter platform fee"
216
+ className="pl-10"
217
+ value={form.watch("platformFee")?.toString() || ""}
218
+ onChange={handlePlatformFeeChange}
219
+ />
220
+ </div>
221
+ </FormControl>
222
+ <FormMessage />
223
+ </FormItem>
224
+ )}
225
+ />
195
226
  </div>
196
227
 
197
228
  <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
@@ -301,7 +332,7 @@ export const InitializeEscrowForm = () => {
301
332
  />
302
333
  </div>
303
334
 
304
- <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
335
+ <div className="grid grid-cols-1 gap-4">
305
336
  <FormField
306
337
  control={form.control}
307
338
  name="roles.platformAddress"
@@ -309,7 +340,7 @@ export const InitializeEscrowForm = () => {
309
340
  <FormItem>
310
341
  <FormLabel className="flex items-center justify-between">
311
342
  <span className="flex items-center">
312
- Platform Address
343
+ Platform
313
344
  <span className="text-destructive ml-1">*</span>
314
345
  </span>
315
346
  </FormLabel>
@@ -327,82 +358,6 @@ export const InitializeEscrowForm = () => {
327
358
  </FormItem>
328
359
  )}
329
360
  />
330
- <FormField
331
- control={form.control}
332
- name="roles.receiver"
333
- render={({ field }) => (
334
- <FormItem>
335
- <FormLabel className="flex items-center justify-between">
336
- <span className="flex items-center">
337
- Receiver<span className="text-destructive ml-1">*</span>
338
- </span>
339
- </FormLabel>
340
-
341
- <FormControl>
342
- <Input
343
- placeholder="Enter receiver address"
344
- {...field}
345
- onChange={(e) => {
346
- field.onChange(e);
347
- }}
348
- />
349
- </FormControl>
350
- <FormMessage />
351
- </FormItem>
352
- )}
353
- />
354
- </div>
355
-
356
- <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
357
- <FormField
358
- control={form.control}
359
- name="platformFee"
360
- render={() => (
361
- <FormItem>
362
- <FormLabel className="flex items-center">
363
- Platform Fee<span className="text-destructive ml-1">*</span>
364
- </FormLabel>
365
- <FormControl>
366
- <div className="relative">
367
- <Percent
368
- className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-500"
369
- size={18}
370
- />
371
- <Input
372
- placeholder="Enter platform fee"
373
- className="pl-10"
374
- value={form.watch("platformFee")?.toString() || ""}
375
- onChange={handlePlatformFeeChange}
376
- />
377
- </div>
378
- </FormControl>
379
- <FormMessage />
380
- </FormItem>
381
- )}
382
- />
383
-
384
- <FormField
385
- control={form.control}
386
- name="receiverMemo"
387
- render={({ field }) => (
388
- <FormItem>
389
- <FormLabel className="flex items-center">
390
- Receiver Memo (opcional)
391
- </FormLabel>
392
- <FormControl>
393
- <Input
394
- type="text"
395
- placeholder="Enter the escrow receiver Memo"
396
- {...field}
397
- onChange={(e) => {
398
- field.onChange(e);
399
- }}
400
- />
401
- </FormControl>
402
- <FormMessage />
403
- </FormItem>
404
- )}
405
- />
406
361
  </div>
407
362
 
408
363
  <FormField
@@ -432,20 +387,33 @@ export const InitializeEscrowForm = () => {
432
387
  Milestones<span className="text-destructive ml-1">*</span>
433
388
  </FormLabel>
434
389
  {milestones.map((milestone, index) => (
435
- <div key={index} className="space-y-4">
436
- <div className="flex flex-col sm:flex-row items-start sm:items-center space-y-2 sm:space-y-0 sm:space-x-4">
437
- <Input
438
- placeholder="Milestone Description"
439
- value={milestone.description}
440
- className="w-full sm:w-3/5"
441
- onChange={(e) => {
442
- const updatedMilestones = [...milestones];
443
- updatedMilestones[index].description = e.target.value;
444
- form.setValue("milestones", updatedMilestones);
445
- }}
446
- />
390
+ <div key={index} className="space-y-4 max-w-3xl">
391
+ <div className="grid grid-cols-1 md:grid-cols-12 gap-4 items-center">
392
+ <div className="md:col-span-4">
393
+ <Input
394
+ placeholder="Enter receiver address"
395
+ value={milestone.receiver}
396
+ onChange={(e) => {
397
+ const updatedMilestones = [...milestones];
398
+ updatedMilestones[index].receiver = e.target.value;
399
+ form.setValue("milestones", updatedMilestones);
400
+ }}
401
+ />
402
+ </div>
403
+
404
+ <div className="md:col-span-4">
405
+ <Input
406
+ placeholder="Milestone description"
407
+ value={milestone.description}
408
+ onChange={(e) => {
409
+ const updatedMilestones = [...milestones];
410
+ updatedMilestones[index].description = e.target.value;
411
+ form.setValue("milestones", updatedMilestones);
412
+ }}
413
+ />
414
+ </div>
447
415
 
448
- <div className="relative w-full sm:w-2/5">
416
+ <div className="md:col-span-3 relative">
449
417
  <DollarSign
450
418
  className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-500"
451
419
  size={18}
@@ -458,21 +426,29 @@ export const InitializeEscrowForm = () => {
458
426
  />
459
427
  </div>
460
428
 
461
- <Button
462
- onClick={() => handleRemoveMilestone(index)}
463
- className="p-2 bg-transparent text-red-500 rounded-md border-none shadow-none hover:bg-transparent hover:shadow-none hover:text-red-500 focus:ring-0 active:ring-0 self-start sm:self-center"
464
- disabled={milestones.length === 1}
465
- type="button"
466
- >
467
- <Trash2 className="h-5 w-5" />
468
- </Button>
429
+ <div className="md:col-span-1 flex justify-end">
430
+ <Button
431
+ onClick={() => handleRemoveMilestone(index)}
432
+ className="p-2 bg-transparent text-red-500 hover:text-red-600"
433
+ disabled={milestones.length === 1}
434
+ type="button"
435
+ >
436
+ <Trash2 className="h-5 w-5" />
437
+ </Button>
438
+ </div>
469
439
  </div>
470
440
 
441
+ {/* Separator */}
442
+ {index < milestones.length - 1 && (
443
+ <Separator className="w-full" />
444
+ )}
445
+
446
+ {/* Add button */}
471
447
  {index === milestones.length - 1 && (
472
448
  <div className="flex justify-end mt-4">
473
449
  <Button
474
450
  disabled={isAnyMilestoneEmpty}
475
- className="w-full md:w-1/4"
451
+ className="w-full md:w-fit md:min-w-40 cursor-pointer"
476
452
  variant="outline"
477
453
  onClick={handleAddMilestone}
478
454
  type="button"
@@ -50,14 +50,6 @@ export const useInitializeEscrowSchema = () => {
50
50
  .refine((value) => isValidWallet(value), {
51
51
  message: "Dispute resolver must be a valid wallet.",
52
52
  }),
53
- receiver: z
54
- .string()
55
- .min(1, {
56
- message: "Receiver address is required.",
57
- })
58
- .refine((value) => isValidWallet(value), {
59
- message: "Receiver address must be a valid wallet.",
60
- }),
61
53
  }),
62
54
  engagementId: z.string().min(1, {
63
55
  message: "Engagement is required.",
@@ -104,16 +96,6 @@ export const useInitializeEscrowSchema = () => {
104
96
  message: "Platform fee can have a maximum of 2 decimal places.",
105
97
  }
106
98
  ),
107
- receiverMemo: z
108
- .string()
109
- .optional()
110
- .refine((val) => !val || val.length >= 1, {
111
- message: "Receiver Memo must be at least 1.",
112
- })
113
- .refine((val) => !val || /^[1-9][0-9]*$/.test(val), {
114
- message:
115
- "Receiver Memo must be a whole number greater than 0 (no decimals).",
116
- }),
117
99
  });
118
100
  };
119
101
 
@@ -124,6 +106,14 @@ export const useInitializeEscrowSchema = () => {
124
106
  milestones: z
125
107
  .array(
126
108
  z.object({
109
+ receiver: z
110
+ .string()
111
+ .min(1, {
112
+ message: "Receiver address is required.",
113
+ })
114
+ .refine((value) => isValidWallet(value), {
115
+ message: "Receiver address must be a valid wallet.",
116
+ }),
127
117
  description: z.string().min(1, {
128
118
  message: "Milestone description is required.",
129
119
  }),
@@ -34,7 +34,6 @@ export function useInitializeEscrow() {
34
34
  title: "",
35
35
  description: "",
36
36
  platformFee: undefined,
37
- receiverMemo: "",
38
37
  trustline: {
39
38
  address: "",
40
39
  },
@@ -42,25 +41,27 @@ export function useInitializeEscrow() {
42
41
  approver: "",
43
42
  serviceProvider: "",
44
43
  platformAddress: "",
45
- receiver: "",
46
44
  releaseSigner: "",
47
45
  disputeResolver: "",
48
46
  },
49
- milestones: [{ description: "", amount: "" }],
47
+ milestones: [{ receiver: "", description: "", amount: "" }],
50
48
  },
51
49
  mode: "onChange",
52
50
  });
53
51
 
54
52
  const milestones = form.watch("milestones");
55
53
  const isAnyMilestoneEmpty = milestones.some(
56
- (milestone) => milestone.description === ""
54
+ (milestone) =>
55
+ milestone.description === "" ||
56
+ milestone.receiver === "" ||
57
+ milestone.amount === ""
57
58
  );
58
59
 
59
60
  const handleAddMilestone = () => {
60
61
  const currentMilestones = form.getValues("milestones");
61
62
  const updatedMilestones = [
62
63
  ...currentMilestones,
63
- { description: "", amount: "" },
64
+ { receiver: "", description: "", amount: "" },
64
65
  ];
65
66
  form.setValue("milestones", updatedMilestones);
66
67
  };
@@ -79,7 +80,6 @@ export function useInitializeEscrow() {
79
80
  title: "Design Landing Page",
80
81
  description: "Landing for the new product of the company.",
81
82
  platformFee: 5,
82
- receiverMemo: "123",
83
83
  trustline: {
84
84
  address: usdc?.value || "",
85
85
  },
@@ -87,14 +87,25 @@ export function useInitializeEscrow() {
87
87
  approver: walletAddress || "",
88
88
  serviceProvider: walletAddress || "",
89
89
  platformAddress: walletAddress || "",
90
- receiver: walletAddress || "",
91
90
  releaseSigner: walletAddress || "",
92
91
  disputeResolver: walletAddress || "",
93
92
  },
94
93
  milestones: [
95
- { description: "Design the wireframe", amount: 2 },
96
- { description: "Develop the wireframe", amount: 2 },
97
- { description: "Deploy the wireframe", amount: 2 },
94
+ {
95
+ receiver: walletAddress || "",
96
+ description: "Design the wireframe",
97
+ amount: 2,
98
+ },
99
+ {
100
+ receiver: walletAddress || "",
101
+ description: "Develop the wireframe",
102
+ amount: 2,
103
+ },
104
+ {
105
+ receiver: walletAddress || "",
106
+ description: "Deploy the wireframe",
107
+ amount: 2,
108
+ },
98
109
  ],
99
110
  };
100
111
 
@@ -105,7 +116,6 @@ export function useInitializeEscrow() {
105
116
 
106
117
  // Explicitly set the trustline field
107
118
  form.setValue("trustline.address", usdc?.value || "");
108
- form.setValue("trustline.decimals", 10000000);
109
119
  };
110
120
 
111
121
  const handleSubmit = form.handleSubmit(async (payload) => {
@@ -124,7 +134,6 @@ export function useInitializeEscrow() {
124
134
  typeof payload.platformFee === "string"
125
135
  ? Number(payload.platformFee)
126
136
  : payload.platformFee,
127
- receiverMemo: Number(payload.receiverMemo) ?? 0,
128
137
  signer: walletAddress || "",
129
138
  milestones: payload.milestones.map((milestone) => ({
130
139
  ...milestone,
@@ -26,7 +26,8 @@ export const ReleaseMilestoneButton = ({
26
26
  const { releaseFunds } = useEscrowsMutations();
27
27
  const { selectedEscrow, updateEscrow } = useEscrowContext();
28
28
  const dialogStates = useEscrowDialogs();
29
- const { setAmounts } = useEscrowAmountContext();
29
+ const { setAmounts, setLastReleasedMilestoneIndex } =
30
+ useEscrowAmountContext();
30
31
  const { walletAddress } = useWalletContext();
31
32
  const [isSubmitting, setIsSubmitting] = React.useState(false);
32
33
 
@@ -87,6 +88,9 @@ export const ReleaseMilestoneButton = ({
87
88
  balance: (selectedEscrow?.balance || 0) - (selectedEscrow?.amount || 0),
88
89
  });
89
90
 
91
+ // Remember which milestone was released for the success dialog
92
+ setLastReleasedMilestoneIndex(Number(milestoneIndex));
93
+
90
94
  // Open success dialog
91
95
  dialogStates.successRelease.setIsOpen(true);
92
96
  } catch (error) {