@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
@@ -0,0 +1,254 @@
1
+ import * as React from "react";
2
+ import { useForm } from "react-hook-form";
3
+ import { zodResolver } from "@hookform/resolvers/zod";
4
+ import { useUpdateEscrowSchema } from "./schema";
5
+ import { z } from "zod";
6
+ import {
7
+ UpdateMultiReleaseEscrowPayload,
8
+ UpdateMultiReleaseEscrowResponse,
9
+ MultiReleaseMilestone,
10
+ } from "@trustless-work/escrow/types";
11
+ import { toast } from "sonner";
12
+ import { useEscrowContext } from "@/components/tw-blocks/providers/EscrowProvider";
13
+ import { useWalletContext } from "@/components/tw-blocks/wallet-kit/WalletProvider";
14
+ import { useEscrowsMutations } from "@/components/tw-blocks/tanstack/useEscrowsMutations";
15
+ import {
16
+ ErrorResponse,
17
+ handleError,
18
+ } from "@/components/tw-blocks/handle-errors/handle";
19
+ import { GetEscrowsFromIndexerResponse } from "@trustless-work/escrow/types";
20
+
21
+ export function useUpdateEscrow() {
22
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
23
+
24
+ const { getMultiReleaseFormSchema } = useUpdateEscrowSchema();
25
+ const formSchema = getMultiReleaseFormSchema();
26
+
27
+ const { walletAddress } = useWalletContext();
28
+ const { selectedEscrow, setSelectedEscrow } = useEscrowContext();
29
+ const { updateEscrow } = useEscrowsMutations();
30
+
31
+ const form = useForm<z.infer<typeof formSchema>>({
32
+ resolver: zodResolver(formSchema),
33
+ defaultValues: {
34
+ engagementId: selectedEscrow?.engagementId || "",
35
+ title: selectedEscrow?.title || "",
36
+ description: selectedEscrow?.description || "",
37
+ platformFee: selectedEscrow?.platformFee as unknown as
38
+ | number
39
+ | string
40
+ | undefined,
41
+ receiverMemo: selectedEscrow?.receiverMemo
42
+ ? String(selectedEscrow.receiverMemo)
43
+ : "",
44
+ trustline: {
45
+ address: selectedEscrow?.trustline?.address || "",
46
+ decimals: 10000000,
47
+ },
48
+ roles: {
49
+ approver: selectedEscrow?.roles?.approver || "",
50
+ serviceProvider: selectedEscrow?.roles?.serviceProvider || "",
51
+ platformAddress: selectedEscrow?.roles?.platformAddress || "",
52
+ receiver: selectedEscrow?.roles?.receiver || "",
53
+ releaseSigner: selectedEscrow?.roles?.releaseSigner || "",
54
+ disputeResolver: selectedEscrow?.roles?.disputeResolver || "",
55
+ },
56
+ milestones: (
57
+ (selectedEscrow?.milestones as MultiReleaseMilestone[]) ?? []
58
+ ).map((m) => ({
59
+ description: m?.description || "",
60
+ amount: m?.amount ?? 0,
61
+ })) || [
62
+ {
63
+ description: "",
64
+ amount: 0,
65
+ },
66
+ ],
67
+ },
68
+ mode: "onChange",
69
+ });
70
+
71
+ React.useEffect(() => {
72
+ if (!selectedEscrow) return;
73
+ form.reset({
74
+ engagementId: selectedEscrow?.engagementId || "",
75
+ title: selectedEscrow?.title || "",
76
+ description: selectedEscrow?.description || "",
77
+ platformFee:
78
+ (selectedEscrow?.platformFee as unknown as
79
+ | number
80
+ | string
81
+ | undefined) || "",
82
+ receiverMemo: selectedEscrow?.receiverMemo
83
+ ? String(selectedEscrow.receiverMemo)
84
+ : "",
85
+ trustline: {
86
+ address: selectedEscrow?.trustline?.address || "",
87
+ decimals: 10000000,
88
+ },
89
+ roles: {
90
+ approver: selectedEscrow?.roles?.approver || "",
91
+ serviceProvider: selectedEscrow?.roles?.serviceProvider || "",
92
+ platformAddress: selectedEscrow?.roles?.platformAddress || "",
93
+ receiver: selectedEscrow?.roles?.receiver || "",
94
+ releaseSigner: selectedEscrow?.roles?.releaseSigner || "",
95
+ disputeResolver: selectedEscrow?.roles?.disputeResolver || "",
96
+ },
97
+ milestones: (
98
+ (selectedEscrow?.milestones as MultiReleaseMilestone[]) ?? []
99
+ ).map((m) => ({
100
+ description: m?.description || "",
101
+ amount: m?.amount ?? "",
102
+ })) || [
103
+ {
104
+ description: "",
105
+ amount: "",
106
+ },
107
+ ],
108
+ });
109
+ }, [selectedEscrow, form]);
110
+
111
+ const milestones = form.watch("milestones");
112
+ const isAnyMilestoneEmpty = milestones.some((m) => m.description === "");
113
+
114
+ const handleAddMilestone = () => {
115
+ const current = form.getValues("milestones");
116
+ const updated = [...current, { description: "", amount: "" }];
117
+ form.setValue("milestones", updated);
118
+ };
119
+
120
+ const handleRemoveMilestone = (index: number) => {
121
+ const current = form.getValues("milestones");
122
+ const updated = current.filter((_, i) => i !== index);
123
+ form.setValue("milestones", updated);
124
+ };
125
+
126
+ const handleMilestoneAmountChange = (
127
+ index: number,
128
+ e: React.ChangeEvent<HTMLInputElement>
129
+ ) => {
130
+ let rawValue = e.target.value;
131
+ rawValue = rawValue.replace(/[^0-9.]/g, "");
132
+
133
+ if (rawValue.split(".").length > 2) {
134
+ rawValue = rawValue.slice(0, -1);
135
+ }
136
+
137
+ // Limit to 2 decimal places
138
+ if (rawValue.includes(".")) {
139
+ const parts = rawValue.split(".");
140
+ if (parts[1] && parts[1].length > 2) {
141
+ rawValue = parts[0] + "." + parts[1].slice(0, 2);
142
+ }
143
+ }
144
+
145
+ // Always keep as string to allow partial input like "0." or "0.5"
146
+ const updatedMilestones = [...milestones];
147
+ updatedMilestones[index] = {
148
+ ...updatedMilestones[index],
149
+ amount: rawValue,
150
+ };
151
+ form.setValue("milestones", updatedMilestones);
152
+ };
153
+
154
+ const handlePlatformFeeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
155
+ let rawValue = e.target.value;
156
+ rawValue = rawValue.replace(/[^0-9.]/g, "");
157
+ if (rawValue.split(".").length > 2) rawValue = rawValue.slice(0, -1);
158
+ if (rawValue.includes(".")) {
159
+ const parts = rawValue.split(".");
160
+ if (parts[1] && parts[1].length > 2) {
161
+ rawValue = parts[0] + "." + parts[1].slice(0, 2);
162
+ }
163
+ }
164
+ form.setValue("platformFee", rawValue);
165
+ };
166
+
167
+ const handleSubmit = form.handleSubmit(async (payload) => {
168
+ try {
169
+ setIsSubmitting(true);
170
+
171
+ /**
172
+ * Create the final payload for the update escrow mutation
173
+ *
174
+ * @param payload - The payload from the form
175
+ * @returns The final payload for the update escrow mutation
176
+ */
177
+ const finalPayload: UpdateMultiReleaseEscrowPayload = {
178
+ contractId: selectedEscrow?.contractId || "",
179
+ signer: walletAddress || "",
180
+ escrow: {
181
+ engagementId: payload.engagementId,
182
+ title: payload.title,
183
+ description: payload.description,
184
+ platformFee:
185
+ typeof payload.platformFee === "string"
186
+ ? Number(payload.platformFee)
187
+ : payload.platformFee,
188
+ receiverMemo: payload.receiverMemo
189
+ ? Number(payload.receiverMemo)
190
+ : undefined,
191
+ trustline: {
192
+ address: payload.trustline.address,
193
+ decimals: 10000000,
194
+ },
195
+ roles: payload.roles,
196
+ milestones: payload.milestones.map((milestone) => ({
197
+ ...milestone,
198
+ amount:
199
+ typeof milestone.amount === "string"
200
+ ? Number(milestone.amount)
201
+ : milestone.amount,
202
+ })),
203
+ },
204
+ };
205
+
206
+ /**
207
+ * Call the update escrow mutation
208
+ *
209
+ * @param payload - The final payload for the update escrow mutation
210
+ * @param type - The type of the escrow
211
+ * @param address - The address of the escrow
212
+ */
213
+ (await updateEscrow.mutateAsync({
214
+ payload: finalPayload,
215
+ type: "multi-release",
216
+ address: walletAddress || "",
217
+ })) as UpdateMultiReleaseEscrowResponse;
218
+
219
+ if (!selectedEscrow) return;
220
+
221
+ const nextSelectedEscrow: GetEscrowsFromIndexerResponse = {
222
+ ...selectedEscrow,
223
+ ...finalPayload.escrow,
224
+ trustline: {
225
+ name:
226
+ selectedEscrow.trustline?.name ||
227
+ (selectedEscrow.trustline?.address as string) ||
228
+ "",
229
+ address: finalPayload.escrow.trustline.address,
230
+ decimals: finalPayload.escrow.trustline.decimals,
231
+ },
232
+ };
233
+
234
+ setSelectedEscrow(nextSelectedEscrow);
235
+ toast.success("Escrow updated successfully");
236
+ } catch (error) {
237
+ toast.error(handleError(error as ErrorResponse).message);
238
+ } finally {
239
+ setIsSubmitting(false);
240
+ }
241
+ });
242
+
243
+ return {
244
+ form,
245
+ isSubmitting,
246
+ milestones,
247
+ isAnyMilestoneEmpty,
248
+ handleSubmit,
249
+ handleAddMilestone,
250
+ handleRemoveMilestone,
251
+ handleMilestoneAmountChange,
252
+ handlePlatformFeeChange,
253
+ };
254
+ }
@@ -2,7 +2,10 @@ import * as React from "react";
2
2
  import { Button } from "__UI_BASE__/button";
3
3
  import { useEscrowsMutations } from "@/components/tw-blocks/tanstack/useEscrowsMutations";
4
4
  import { useWalletContext } from "@/components/tw-blocks/wallet-kit/WalletProvider";
5
- import { ApproveMilestonePayload } from "@trustless-work/escrow/types";
5
+ import {
6
+ ApproveMilestonePayload,
7
+ MultiReleaseMilestone,
8
+ } from "@trustless-work/escrow/types";
6
9
  import { toast } from "sonner";
7
10
  import {
8
11
  ErrorResponse,
@@ -15,9 +18,9 @@ type ApproveMilestoneButtonProps = {
15
18
  milestoneIndex: number | string;
16
19
  };
17
20
 
18
- export default function ApproveMilestoneButton({
21
+ export const ApproveMilestoneButton = ({
19
22
  milestoneIndex,
20
- }: ApproveMilestoneButtonProps) {
23
+ }: ApproveMilestoneButtonProps) => {
21
24
  const { approveMilestone } = useEscrowsMutations();
22
25
  const { selectedEscrow, updateEscrow } = useEscrowContext();
23
26
  const { walletAddress } = useWalletContext();
@@ -49,7 +52,7 @@ export default function ApproveMilestoneButton({
49
52
  */
50
53
  await approveMilestone.mutateAsync({
51
54
  payload,
52
- type: "single-release",
55
+ type: selectedEscrow?.type || "multi-release",
53
56
  address: walletAddress || "",
54
57
  });
55
58
 
@@ -58,8 +61,18 @@ export default function ApproveMilestoneButton({
58
61
  updateEscrow({
59
62
  ...selectedEscrow,
60
63
  milestones: selectedEscrow?.milestones.map((milestone, index) => {
61
- if (index === Number(milestoneIndex)) {
62
- return { ...milestone, approved: true };
64
+ if (index === Number(payload.milestoneIndex)) {
65
+ if (selectedEscrow?.type === "single-release") {
66
+ return { ...milestone, approved: true };
67
+ } else {
68
+ return {
69
+ ...milestone,
70
+ flags: {
71
+ ...(milestone as MultiReleaseMilestone).flags,
72
+ approved: true,
73
+ },
74
+ };
75
+ }
63
76
  }
64
77
  return milestone;
65
78
  }),
@@ -88,4 +101,4 @@ export default function ApproveMilestoneButton({
88
101
  )}
89
102
  </Button>
90
103
  );
91
- }
104
+ };
@@ -16,7 +16,7 @@ import {
16
16
  DialogTrigger,
17
17
  } from "__UI_BASE__/dialog";
18
18
  import { Loader2 } from "lucide-react";
19
- import { useApproveMilestone } from "./useApproveMilestone";
19
+ import { useApproveMilestone } from "../useApproveMilestone";
20
20
  import { useEscrowContext } from "@/components/tw-blocks/providers/EscrowProvider";
21
21
  import {
22
22
  Select,
@@ -26,7 +26,7 @@ import {
26
26
  SelectValue,
27
27
  } from "__UI_BASE__/select";
28
28
 
29
- export default function ApproveMilestoneDialog() {
29
+ export const ApproveMilestoneDialog = () => {
30
30
  const { form, handleSubmit, isSubmitting } = useApproveMilestone();
31
31
  const { selectedEscrow } = useEscrowContext();
32
32
 
@@ -99,4 +99,4 @@ export default function ApproveMilestoneDialog() {
99
99
  </DialogContent>
100
100
  </Dialog>
101
101
  );
102
- }
102
+ };
@@ -8,7 +8,7 @@ import {
8
8
  FormMessage,
9
9
  } from "__UI_BASE__/form";
10
10
  import { Button } from "__UI_BASE__/button";
11
- import { useApproveMilestone } from "./useApproveMilestone";
11
+ import { useApproveMilestone } from "../useApproveMilestone";
12
12
  import { Loader2 } from "lucide-react";
13
13
  import { useEscrowContext } from "@/components/tw-blocks/providers/EscrowProvider";
14
14
  import {
@@ -19,7 +19,7 @@ import {
19
19
  SelectValue,
20
20
  } from "__UI_BASE__/select";
21
21
 
22
- export default function ApproveMilestoneForm() {
22
+ export const ApproveMilestoneForm = () => {
23
23
  const { form, handleSubmit, isSubmitting } = useApproveMilestone();
24
24
  const { selectedEscrow } = useEscrowContext();
25
25
 
@@ -77,4 +77,4 @@ export default function ApproveMilestoneForm() {
77
77
  </form>
78
78
  </Form>
79
79
  );
80
- }
80
+ };
@@ -3,7 +3,10 @@ import { useForm } from "react-hook-form";
3
3
  import { zodResolver } from "@hookform/resolvers/zod";
4
4
  import { approveMilestoneSchema, type ApproveMilestoneValues } from "./schema";
5
5
  import { toast } from "sonner";
6
- import { ApproveMilestonePayload } from "@trustless-work/escrow";
6
+ import {
7
+ ApproveMilestonePayload,
8
+ MultiReleaseMilestone,
9
+ } from "@trustless-work/escrow";
7
10
  import { useEscrowContext } from "@/components/tw-blocks/providers/EscrowProvider";
8
11
  import { useEscrowsMutations } from "@/components/tw-blocks/tanstack/useEscrowsMutations";
9
12
  import {
@@ -31,12 +34,6 @@ export function useApproveMilestone() {
31
34
  try {
32
35
  setIsSubmitting(true);
33
36
 
34
- /**
35
- * Create the final payload for the approve milestone mutation
36
- *
37
- * @param payload - The payload from the form
38
- * @returns The final payload for the approve milestone mutation
39
- */
40
37
  const finalPayload: ApproveMilestonePayload = {
41
38
  contractId: selectedEscrow?.contractId || "",
42
39
  milestoneIndex: payload.milestoneIndex,
@@ -44,16 +41,9 @@ export function useApproveMilestone() {
44
41
  newFlag: true,
45
42
  };
46
43
 
47
- /**
48
- * Call the approve milestone mutation
49
- *
50
- * @param payload - The final payload for the approve milestone mutation
51
- * @param type - The type of the escrow
52
- * @param address - The address of the escrow
53
- */
54
44
  await approveMilestone.mutateAsync({
55
45
  payload: finalPayload,
56
- type: "single-release",
46
+ type: selectedEscrow?.type || "multi-release",
57
47
  address: walletAddress || "",
58
48
  });
59
49
 
@@ -63,7 +53,17 @@ export function useApproveMilestone() {
63
53
  ...selectedEscrow,
64
54
  milestones: selectedEscrow?.milestones.map((milestone, index) => {
65
55
  if (index === Number(payload.milestoneIndex)) {
66
- return { ...milestone, approved: true };
56
+ if (selectedEscrow?.type === "single-release") {
57
+ return { ...milestone, approved: true };
58
+ } else {
59
+ return {
60
+ ...milestone,
61
+ flags: {
62
+ ...(milestone as MultiReleaseMilestone).flags,
63
+ approved: true,
64
+ },
65
+ };
66
+ }
67
67
  }
68
68
  return milestone;
69
69
  }),
@@ -17,11 +17,11 @@ type ChangeMilestoneStatusButtonProps = {
17
17
  milestoneIndex: number | string;
18
18
  };
19
19
 
20
- export default function ChangeMilestoneStatusButton({
20
+ export const ChangeMilestoneStatusButton = ({
21
21
  status,
22
22
  evidence,
23
23
  milestoneIndex,
24
- }: ChangeMilestoneStatusButtonProps) {
24
+ }: ChangeMilestoneStatusButtonProps) => {
25
25
  const { changeMilestoneStatus } = useEscrowsMutations();
26
26
  const { selectedEscrow } = useEscrowContext();
27
27
  const { walletAddress } = useWalletContext();
@@ -61,7 +61,7 @@ export default function ChangeMilestoneStatusButton({
61
61
  */
62
62
  await changeMilestoneStatus.mutateAsync({
63
63
  payload,
64
- type: "single-release",
64
+ type: selectedEscrow?.type || "multi-release",
65
65
  address: walletAddress || "",
66
66
  });
67
67
 
@@ -90,4 +90,4 @@ export default function ChangeMilestoneStatusButton({
90
90
  )}
91
91
  </Button>
92
92
  );
93
- }
93
+ };
@@ -18,7 +18,7 @@ import {
18
18
  DialogTrigger,
19
19
  } from "__UI_BASE__/dialog";
20
20
  import { Loader2 } from "lucide-react";
21
- import { useChangeMilestoneStatus } from "./useChangeMilestoneStatus";
21
+ import { useChangeMilestoneStatus } from "../useChangeMilestoneStatus";
22
22
  import { useEscrowContext } from "@/components/tw-blocks/providers/EscrowProvider";
23
23
  import {
24
24
  Select,
@@ -28,13 +28,13 @@ import {
28
28
  SelectValue,
29
29
  } from "__UI_BASE__/select";
30
30
 
31
- export default function ChangeMilestoneStatusDialog({
31
+ export const ChangeMilestoneStatusDialog = ({
32
32
  showSelectMilestone = false,
33
33
  milestoneIndex,
34
34
  }: {
35
35
  showSelectMilestone?: boolean;
36
36
  milestoneIndex?: number | string;
37
- }) {
37
+ }) => {
38
38
  const { form, handleSubmit, isSubmitting } = useChangeMilestoneStatus();
39
39
  const { selectedEscrow } = useEscrowContext();
40
40
 
@@ -164,4 +164,4 @@ export default function ChangeMilestoneStatusDialog({
164
164
  </DialogContent>
165
165
  </Dialog>
166
166
  );
167
- }
167
+ };
@@ -10,7 +10,7 @@ import {
10
10
  import { Input } from "__UI_BASE__/input";
11
11
  import { Textarea } from "__UI_BASE__/textarea";
12
12
  import { Button } from "__UI_BASE__/button";
13
- import { useChangeMilestoneStatus } from "./useChangeMilestoneStatus";
13
+ import { useChangeMilestoneStatus } from "../useChangeMilestoneStatus";
14
14
  import { Loader2 } from "lucide-react";
15
15
  import { useEscrowContext } from "@/components/tw-blocks/providers/EscrowProvider";
16
16
  import {
@@ -21,7 +21,7 @@ import {
21
21
  SelectValue,
22
22
  } from "__UI_BASE__/select";
23
23
 
24
- export default function ChangeMilestoneStatusForm() {
24
+ export const ChangeMilestoneStatusForm = () => {
25
25
  const { form, handleSubmit, isSubmitting } = useChangeMilestoneStatus();
26
26
  const { selectedEscrow } = useEscrowContext();
27
27
 
@@ -111,4 +111,4 @@ export default function ChangeMilestoneStatusForm() {
111
111
  </form>
112
112
  </Form>
113
113
  );
114
- }
114
+ };
@@ -59,7 +59,7 @@ export function useChangeMilestoneStatus() {
59
59
  */
60
60
  await changeMilestoneStatus.mutateAsync({
61
61
  payload: finalPayload,
62
- type: "single-release",
62
+ type: selectedEscrow?.type || "multi-release",
63
63
  address: walletAddress || "",
64
64
  });
65
65
 
@@ -15,7 +15,7 @@ type FundEscrowButtonProps = {
15
15
  amount: number;
16
16
  };
17
17
 
18
- export default function FundEscrowButton({ amount }: FundEscrowButtonProps) {
18
+ export const FundEscrowButton = ({ amount }: FundEscrowButtonProps) => {
19
19
  const { fundEscrow } = useEscrowsMutations();
20
20
  const { selectedEscrow, updateEscrow } = useEscrowContext();
21
21
  const { walletAddress } = useWalletContext();
@@ -55,7 +55,7 @@ export default function FundEscrowButton({ amount }: FundEscrowButtonProps) {
55
55
  */
56
56
  await fundEscrow.mutateAsync({
57
57
  payload,
58
- type: "single-release",
58
+ type: selectedEscrow?.type || "multi-release",
59
59
  address: walletAddress || "",
60
60
  });
61
61
 
@@ -88,4 +88,4 @@ export default function FundEscrowButton({ amount }: FundEscrowButtonProps) {
88
88
  )}
89
89
  </Button>
90
90
  );
91
- }
91
+ };
@@ -17,9 +17,9 @@ import {
17
17
  DialogTrigger,
18
18
  } from "__UI_BASE__/dialog";
19
19
  import { Loader2 } from "lucide-react";
20
- import { useFundEscrow } from "./useFundEscrow";
20
+ import { useFundEscrow } from "../useFundEscrow";
21
21
 
22
- export default function FundEscrowDialog() {
22
+ export const FundEscrowDialog = () => {
23
23
  const { form, handleSubmit, isSubmitting } = useFundEscrow();
24
24
 
25
25
  return (
@@ -74,4 +74,4 @@ export default function FundEscrowDialog() {
74
74
  </DialogContent>
75
75
  </Dialog>
76
76
  );
77
- }
77
+ };
@@ -9,10 +9,10 @@ import {
9
9
  } from "__UI_BASE__/form";
10
10
  import { Input } from "__UI_BASE__/input";
11
11
  import { Button } from "__UI_BASE__/button";
12
- import { useFundEscrow } from "./useFundEscrow";
12
+ import { useFundEscrow } from "../useFundEscrow";
13
13
  import { Loader2 } from "lucide-react";
14
14
 
15
- export default function FundEscrowForm() {
15
+ export const FundEscrowForm = () => {
16
16
  const { form, handleSubmit, isSubmitting } = useFundEscrow();
17
17
 
18
18
  return (
@@ -51,4 +51,4 @@ export default function FundEscrowForm() {
51
51
  </form>
52
52
  </Form>
53
53
  );
54
- }
54
+ };
@@ -55,7 +55,7 @@ export function useFundEscrow() {
55
55
  */
56
56
  await fundEscrow.mutateAsync({
57
57
  payload: finalPayload,
58
- type: "single-release",
58
+ type: selectedEscrow?.type || "multi-release",
59
59
  address: walletAddress || "",
60
60
  });
61
61
 
@@ -11,7 +11,7 @@ import {
11
11
  import { useEscrowContext } from "@/components/tw-blocks/providers/EscrowProvider";
12
12
  import { Loader2 } from "lucide-react";
13
13
 
14
- export default function DisputeEscrowButton() {
14
+ export const DisputeEscrowButton = () => {
15
15
  const { startDispute } = useEscrowsMutations();
16
16
  const { selectedEscrow, updateEscrow } = useEscrowContext();
17
17
  const { walletAddress } = useWalletContext();
@@ -77,4 +77,4 @@ export default function DisputeEscrowButton() {
77
77
  )}
78
78
  </Button>
79
79
  );
80
- }
80
+ };
@@ -30,7 +30,7 @@ import {
30
30
  DialogTrigger,
31
31
  } from "__UI_BASE__/dialog";
32
32
 
33
- export function InitializeEscrowDialog() {
33
+ export const InitializeEscrowDialog = () => {
34
34
  const {
35
35
  form,
36
36
  isSubmitting,
@@ -39,6 +39,7 @@ export function InitializeEscrowDialog() {
39
39
  handleSubmit,
40
40
  handleAddMilestone,
41
41
  handleRemoveMilestone,
42
+ fillTemplateForm,
42
43
  } = useInitializeEscrow();
43
44
 
44
45
  const handleAmountChange = (e: React.ChangeEvent<HTMLInputElement>) => {
@@ -107,10 +108,19 @@ export function InitializeEscrowDialog() {
107
108
  </h2>
108
109
  </div>
109
110
  <p className="text-muted-foreground mt-1">
110
- A single payment will be released upon completion of all
111
- milestones
111
+ Fill out the form to initialize a single release escrow
112
112
  </p>
113
113
  </Link>
114
+ {process.env.NODE_ENV !== "production" && (
115
+ <Button
116
+ type="button"
117
+ variant="outline"
118
+ onClick={fillTemplateForm}
119
+ className="cursor-pointer"
120
+ >
121
+ Autofill
122
+ </Button>
123
+ )}
114
124
  </Card>
115
125
  <div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
116
126
  <FormField
@@ -521,6 +531,4 @@ export function InitializeEscrowDialog() {
521
531
  </DialogContent>
522
532
  </Dialog>
523
533
  );
524
- }
525
-
526
- export default InitializeEscrowDialog;
534
+ };