@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.
- package/bin/index.js +485 -17
- package/package.json +1 -1
- package/templates/escrows/details/Actions.tsx +144 -149
- package/templates/escrows/details/Entities.tsx +1 -1
- package/templates/escrows/details/EntityCard.tsx +1 -3
- package/templates/escrows/details/EscrowDetailDialog.tsx +16 -16
- package/templates/escrows/details/GeneralInformation.tsx +19 -22
- package/templates/escrows/details/MilestoneCard.tsx +46 -47
- package/templates/escrows/details/MilestoneDetailDialog.tsx +1 -2
- package/templates/escrows/details/Milestones.tsx +0 -5
- package/templates/escrows/details/SuccessReleaseDialog.tsx +4 -6
- package/templates/escrows/escrows-by-role/cards/EscrowsCards.tsx +84 -49
- package/templates/escrows/escrows-by-role/cards/Filters.tsx +3 -5
- package/templates/escrows/escrows-by-role/table/EscrowsTable.tsx +8 -26
- package/templates/escrows/escrows-by-role/table/Filters.tsx +3 -5
- package/templates/escrows/escrows-by-signer/cards/EscrowsCards.tsx +89 -55
- package/templates/escrows/escrows-by-signer/cards/Filters.tsx +3 -5
- package/templates/escrows/escrows-by-signer/table/EscrowsTable.tsx +8 -24
- package/templates/escrows/escrows-by-signer/table/Filters.tsx +3 -5
- package/templates/escrows/multi-release/dispute-milestone/button/DisputeEscrow.tsx +98 -0
- package/templates/escrows/multi-release/initialize-escrow/dialog/InitializeEscrow.tsx +528 -0
- package/templates/escrows/multi-release/initialize-escrow/form/InitializeEscrow.tsx +506 -0
- package/templates/escrows/multi-release/initialize-escrow/shared/schema.ts +179 -0
- package/templates/escrows/multi-release/initialize-escrow/shared/useInitializeEscrow.ts +175 -0
- package/templates/escrows/multi-release/release-milestone/button/ReleaseEscrow.tsx +116 -0
- package/templates/escrows/multi-release/resolve-dispute/button/ResolveDispute.tsx +122 -0
- package/templates/escrows/multi-release/resolve-dispute/dialog/ResolveDispute.tsx +178 -0
- package/templates/escrows/multi-release/resolve-dispute/form/ResolveDispute.tsx +156 -0
- package/templates/escrows/multi-release/resolve-dispute/shared/schema.ts +85 -0
- package/templates/escrows/multi-release/resolve-dispute/shared/useResolveDispute.ts +105 -0
- package/templates/escrows/multi-release/update-escrow/dialog/UpdateEscrow.tsx +471 -0
- package/templates/escrows/multi-release/update-escrow/form/UpdateEscrow.tsx +449 -0
- package/templates/escrows/multi-release/update-escrow/shared/schema.ts +152 -0
- package/templates/escrows/multi-release/update-escrow/shared/useUpdateEscrow.ts +254 -0
- package/templates/escrows/{single-release → single-multi-release}/approve-milestone/button/ApproveMilestone.tsx +20 -7
- package/templates/escrows/{single-release → single-multi-release}/approve-milestone/dialog/ApproveMilestone.tsx +3 -3
- package/templates/escrows/{single-release → single-multi-release}/approve-milestone/form/ApproveMilestone.tsx +3 -3
- package/templates/escrows/{single-release/approve-milestone/shared → single-multi-release/approve-milestone}/useApproveMilestone.ts +16 -16
- package/templates/escrows/{single-release → single-multi-release}/change-milestone-status/button/ChangeMilestoneStatus.tsx +4 -4
- package/templates/escrows/{single-release → single-multi-release}/change-milestone-status/dialog/ChangeMilestoneStatus.tsx +4 -4
- package/templates/escrows/{single-release → single-multi-release}/change-milestone-status/form/ChangeMilestoneStatus.tsx +3 -3
- package/templates/escrows/{single-release/change-milestone-status/shared → single-multi-release/change-milestone-status}/useChangeMilestoneStatus.ts +1 -1
- package/templates/escrows/{single-release → single-multi-release}/fund-escrow/button/FundEscrow.tsx +3 -3
- package/templates/escrows/{single-release → single-multi-release}/fund-escrow/dialog/FundEscrow.tsx +3 -3
- package/templates/escrows/{single-release → single-multi-release}/fund-escrow/form/FundEscrow.tsx +3 -3
- package/templates/escrows/{single-release/fund-escrow/shared → single-multi-release/fund-escrow}/useFundEscrow.ts +1 -1
- package/templates/escrows/single-release/dispute-escrow/button/DisputeEscrow.tsx +2 -2
- package/templates/escrows/single-release/initialize-escrow/dialog/InitializeEscrow.tsx +14 -6
- package/templates/escrows/single-release/initialize-escrow/form/InitializeEscrow.tsx +14 -6
- package/templates/escrows/single-release/initialize-escrow/shared/schema.ts +0 -57
- package/templates/escrows/single-release/initialize-escrow/shared/useInitializeEscrow.ts +42 -1
- package/templates/escrows/single-release/release-escrow/button/ReleaseEscrow.tsx +2 -2
- package/templates/escrows/single-release/resolve-dispute/button/ResolveDispute.tsx +3 -3
- package/templates/escrows/single-release/resolve-dispute/dialog/ResolveDispute.tsx +3 -6
- package/templates/escrows/single-release/resolve-dispute/form/ResolveDispute.tsx +2 -2
- package/templates/escrows/single-release/resolve-dispute/shared/useResolveDispute.ts +14 -1
- package/templates/escrows/single-release/update-escrow/dialog/UpdateEscrow.tsx +2 -2
- package/templates/escrows/single-release/update-escrow/form/UpdateEscrow.tsx +2 -2
- package/templates/escrows/single-release/update-escrow/shared/useUpdateEscrow.ts +12 -7
- package/templates/providers/EscrowDialogsProvider.tsx +1 -3
- package/templates/providers/EscrowProvider.tsx +27 -4
- package/templates/providers/TrustlessWork.tsx +1 -1
- package/templates/escrows/details/ProgressEscrow.tsx +0 -191
- /package/templates/escrows/{single-release/approve-milestone/shared → single-multi-release/approve-milestone}/schema.ts +0 -0
- /package/templates/escrows/{single-release/change-milestone-status/shared → single-multi-release/change-milestone-status}/schema.ts +0 -0
- /package/templates/escrows/{single-release/fund-escrow/shared → single-multi-release/fund-escrow}/schema.ts +0 -0
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Form,
|
|
4
|
+
FormField,
|
|
5
|
+
FormItem,
|
|
6
|
+
FormLabel,
|
|
7
|
+
FormControl,
|
|
8
|
+
FormMessage,
|
|
9
|
+
} from "__UI_BASE__/form";
|
|
10
|
+
import { Input } from "__UI_BASE__/input";
|
|
11
|
+
import { Button } from "__UI_BASE__/button";
|
|
12
|
+
import { Card } from "__UI_BASE__/card";
|
|
13
|
+
import {
|
|
14
|
+
Select,
|
|
15
|
+
SelectTrigger,
|
|
16
|
+
SelectValue,
|
|
17
|
+
SelectContent,
|
|
18
|
+
SelectItem,
|
|
19
|
+
} from "__UI_BASE__/select";
|
|
20
|
+
import { Textarea } from "__UI_BASE__/textarea";
|
|
21
|
+
import { useInitializeEscrow } from "./useInitializeEscrow";
|
|
22
|
+
import { Trash2, DollarSign, Percent, Loader2 } from "lucide-react";
|
|
23
|
+
import Link from "next/link";
|
|
24
|
+
import { trustlineOptions } from "@/components/tw-blocks/wallet-kit/trustlines";
|
|
25
|
+
import {
|
|
26
|
+
Dialog,
|
|
27
|
+
DialogContent,
|
|
28
|
+
DialogHeader,
|
|
29
|
+
DialogTitle,
|
|
30
|
+
DialogTrigger,
|
|
31
|
+
} from "__UI_BASE__/dialog";
|
|
32
|
+
|
|
33
|
+
export const InitializeEscrowDialog = () => {
|
|
34
|
+
const {
|
|
35
|
+
form,
|
|
36
|
+
isSubmitting,
|
|
37
|
+
milestones,
|
|
38
|
+
isAnyMilestoneEmpty,
|
|
39
|
+
handleSubmit,
|
|
40
|
+
handleAddMilestone,
|
|
41
|
+
handleRemoveMilestone,
|
|
42
|
+
fillTemplateForm,
|
|
43
|
+
} = useInitializeEscrow();
|
|
44
|
+
|
|
45
|
+
const handleMilestoneAmountChange = (
|
|
46
|
+
index: number,
|
|
47
|
+
e: React.ChangeEvent<HTMLInputElement>
|
|
48
|
+
) => {
|
|
49
|
+
let rawValue = e.target.value;
|
|
50
|
+
rawValue = rawValue.replace(/[^0-9.]/g, "");
|
|
51
|
+
|
|
52
|
+
if (rawValue.split(".").length > 2) {
|
|
53
|
+
rawValue = rawValue.slice(0, -1);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Limit to 2 decimal places
|
|
57
|
+
if (rawValue.includes(".")) {
|
|
58
|
+
const parts = rawValue.split(".");
|
|
59
|
+
if (parts[1] && parts[1].length > 2) {
|
|
60
|
+
rawValue = parts[0] + "." + parts[1].slice(0, 2);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Always keep as string to allow partial input like "0." or "0.5"
|
|
65
|
+
const updatedMilestones = [...milestones];
|
|
66
|
+
updatedMilestones[index] = {
|
|
67
|
+
...updatedMilestones[index],
|
|
68
|
+
amount: rawValue,
|
|
69
|
+
};
|
|
70
|
+
form.setValue("milestones", updatedMilestones);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const handlePlatformFeeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
74
|
+
let rawValue = e.target.value;
|
|
75
|
+
rawValue = rawValue.replace(/[^0-9.]/g, "");
|
|
76
|
+
|
|
77
|
+
if (rawValue.split(".").length > 2) {
|
|
78
|
+
rawValue = rawValue.slice(0, -1);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Limit to 2 decimal places
|
|
82
|
+
if (rawValue.includes(".")) {
|
|
83
|
+
const parts = rawValue.split(".");
|
|
84
|
+
if (parts[1] && parts[1].length > 2) {
|
|
85
|
+
rawValue = parts[0] + "." + parts[1].slice(0, 2);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Always keep as string to allow partial input like "0." or "0.5"
|
|
90
|
+
form.setValue("platformFee", rawValue);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<Dialog>
|
|
95
|
+
<DialogTrigger asChild>
|
|
96
|
+
<Button type="button" className="cursor-pointer w-full">
|
|
97
|
+
Initialize
|
|
98
|
+
</Button>
|
|
99
|
+
</DialogTrigger>
|
|
100
|
+
<DialogContent className="!w-full sm:!max-w-4xl max-h-[95vh] overflow-y-auto">
|
|
101
|
+
<DialogHeader>
|
|
102
|
+
<DialogTitle>Initialize Escrow</DialogTitle>
|
|
103
|
+
</DialogHeader>
|
|
104
|
+
<Form {...form}>
|
|
105
|
+
<form onSubmit={handleSubmit} className="flex flex-col space-y-6">
|
|
106
|
+
<Card className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 p-4">
|
|
107
|
+
<Link
|
|
108
|
+
className="flex-1"
|
|
109
|
+
href="https://docs.trustlesswork.com/trustless-work/technology-overview/escrow-types"
|
|
110
|
+
target="_blank"
|
|
111
|
+
>
|
|
112
|
+
<div className="flex items-center gap-2">
|
|
113
|
+
<div className="h-2 w-2 rounded-full bg-primary" />
|
|
114
|
+
<h2 className="text-xl font-semibold">
|
|
115
|
+
Multi Release Escrow
|
|
116
|
+
</h2>
|
|
117
|
+
</div>
|
|
118
|
+
<p className="text-muted-foreground mt-1">
|
|
119
|
+
Fill out the form to initialize a multi release escrow
|
|
120
|
+
</p>
|
|
121
|
+
</Link>
|
|
122
|
+
{process.env.NODE_ENV !== "production" && (
|
|
123
|
+
<Button
|
|
124
|
+
type="button"
|
|
125
|
+
variant="outline"
|
|
126
|
+
onClick={fillTemplateForm}
|
|
127
|
+
className="cursor-pointer"
|
|
128
|
+
>
|
|
129
|
+
Autofill
|
|
130
|
+
</Button>
|
|
131
|
+
)}
|
|
132
|
+
</Card>
|
|
133
|
+
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
|
134
|
+
<FormField
|
|
135
|
+
control={form.control}
|
|
136
|
+
name="title"
|
|
137
|
+
render={({ field }) => (
|
|
138
|
+
<FormItem>
|
|
139
|
+
<FormLabel className="flex items-center">
|
|
140
|
+
Title<span className="text-destructive ml-1">*</span>
|
|
141
|
+
</FormLabel>
|
|
142
|
+
<FormControl>
|
|
143
|
+
<Input
|
|
144
|
+
placeholder="Escrow title"
|
|
145
|
+
{...field}
|
|
146
|
+
onChange={(e) => {
|
|
147
|
+
field.onChange(e);
|
|
148
|
+
}}
|
|
149
|
+
/>
|
|
150
|
+
</FormControl>
|
|
151
|
+
<FormMessage />
|
|
152
|
+
</FormItem>
|
|
153
|
+
)}
|
|
154
|
+
/>
|
|
155
|
+
|
|
156
|
+
<FormField
|
|
157
|
+
control={form.control}
|
|
158
|
+
name="engagementId"
|
|
159
|
+
render={({ field }) => (
|
|
160
|
+
<FormItem>
|
|
161
|
+
<FormLabel className="flex items-center">
|
|
162
|
+
Engagement<span className="text-destructive ml-1">*</span>
|
|
163
|
+
</FormLabel>
|
|
164
|
+
<FormControl>
|
|
165
|
+
<Input
|
|
166
|
+
placeholder="Enter identifier"
|
|
167
|
+
{...field}
|
|
168
|
+
onChange={(e) => {
|
|
169
|
+
field.onChange(e);
|
|
170
|
+
}}
|
|
171
|
+
/>
|
|
172
|
+
</FormControl>
|
|
173
|
+
<FormMessage />
|
|
174
|
+
</FormItem>
|
|
175
|
+
)}
|
|
176
|
+
/>
|
|
177
|
+
|
|
178
|
+
<FormField
|
|
179
|
+
control={form.control}
|
|
180
|
+
name="trustline.address"
|
|
181
|
+
render={({ field }) => (
|
|
182
|
+
<FormItem>
|
|
183
|
+
<FormLabel className="flex items-center">
|
|
184
|
+
Trustline<span className="text-destructive ml-1">*</span>
|
|
185
|
+
</FormLabel>
|
|
186
|
+
<FormControl>
|
|
187
|
+
<Select
|
|
188
|
+
value={field.value}
|
|
189
|
+
onValueChange={(e) => {
|
|
190
|
+
field.onChange(e);
|
|
191
|
+
}}
|
|
192
|
+
>
|
|
193
|
+
<SelectTrigger className="w-full">
|
|
194
|
+
<SelectValue placeholder="Select trustline" />
|
|
195
|
+
</SelectTrigger>
|
|
196
|
+
<SelectContent>
|
|
197
|
+
{trustlineOptions
|
|
198
|
+
.filter((option) => option.value)
|
|
199
|
+
.map((option, index) => (
|
|
200
|
+
<SelectItem
|
|
201
|
+
key={`${option.value}-${index}`}
|
|
202
|
+
value={option.value}
|
|
203
|
+
>
|
|
204
|
+
{option.label}
|
|
205
|
+
</SelectItem>
|
|
206
|
+
))}
|
|
207
|
+
</SelectContent>
|
|
208
|
+
</Select>
|
|
209
|
+
</FormControl>
|
|
210
|
+
<FormMessage />
|
|
211
|
+
</FormItem>
|
|
212
|
+
)}
|
|
213
|
+
/>
|
|
214
|
+
</div>
|
|
215
|
+
|
|
216
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
|
217
|
+
<FormField
|
|
218
|
+
control={form.control}
|
|
219
|
+
name="roles.approver"
|
|
220
|
+
render={({ field }) => (
|
|
221
|
+
<FormItem>
|
|
222
|
+
<FormLabel className="flex items-center justify-between">
|
|
223
|
+
<span className="flex items-center">
|
|
224
|
+
Approver<span className="text-destructive ml-1">*</span>
|
|
225
|
+
</span>
|
|
226
|
+
</FormLabel>
|
|
227
|
+
|
|
228
|
+
<FormControl>
|
|
229
|
+
<Input
|
|
230
|
+
placeholder="Enter approver address"
|
|
231
|
+
{...field}
|
|
232
|
+
onChange={(e) => {
|
|
233
|
+
field.onChange(e);
|
|
234
|
+
}}
|
|
235
|
+
/>
|
|
236
|
+
</FormControl>
|
|
237
|
+
<FormMessage />
|
|
238
|
+
</FormItem>
|
|
239
|
+
)}
|
|
240
|
+
/>
|
|
241
|
+
|
|
242
|
+
<FormField
|
|
243
|
+
control={form.control}
|
|
244
|
+
name="roles.serviceProvider"
|
|
245
|
+
render={({ field }) => (
|
|
246
|
+
<FormItem>
|
|
247
|
+
<FormLabel className="flex items-center justify-between">
|
|
248
|
+
<span className="flex items-center">
|
|
249
|
+
Service Provider
|
|
250
|
+
<span className="text-destructive ml-1">*</span>
|
|
251
|
+
</span>
|
|
252
|
+
</FormLabel>
|
|
253
|
+
|
|
254
|
+
<FormControl>
|
|
255
|
+
<Input
|
|
256
|
+
placeholder="Enter service provider address"
|
|
257
|
+
{...field}
|
|
258
|
+
onChange={(e) => {
|
|
259
|
+
field.onChange(e);
|
|
260
|
+
}}
|
|
261
|
+
/>
|
|
262
|
+
</FormControl>
|
|
263
|
+
<FormMessage />
|
|
264
|
+
</FormItem>
|
|
265
|
+
)}
|
|
266
|
+
/>
|
|
267
|
+
</div>
|
|
268
|
+
|
|
269
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
|
270
|
+
<FormField
|
|
271
|
+
control={form.control}
|
|
272
|
+
name="roles.releaseSigner"
|
|
273
|
+
render={({ field }) => (
|
|
274
|
+
<FormItem>
|
|
275
|
+
<FormLabel className="flex items-center justify-between">
|
|
276
|
+
<span className="flex items-center">
|
|
277
|
+
Release Signer
|
|
278
|
+
<span className="text-destructive ml-1">*</span>
|
|
279
|
+
</span>
|
|
280
|
+
</FormLabel>
|
|
281
|
+
|
|
282
|
+
<FormControl>
|
|
283
|
+
<Input
|
|
284
|
+
placeholder="Enter release signer address"
|
|
285
|
+
{...field}
|
|
286
|
+
onChange={(e) => {
|
|
287
|
+
field.onChange(e);
|
|
288
|
+
}}
|
|
289
|
+
/>
|
|
290
|
+
</FormControl>
|
|
291
|
+
<FormMessage />
|
|
292
|
+
</FormItem>
|
|
293
|
+
)}
|
|
294
|
+
/>
|
|
295
|
+
|
|
296
|
+
<FormField
|
|
297
|
+
control={form.control}
|
|
298
|
+
name="roles.disputeResolver"
|
|
299
|
+
render={({ field }) => (
|
|
300
|
+
<FormItem>
|
|
301
|
+
<FormLabel className="flex items-center justify-between">
|
|
302
|
+
<span className="flex items-center">
|
|
303
|
+
Dispute Resolver
|
|
304
|
+
<span className="text-destructive ml-1">*</span>
|
|
305
|
+
</span>
|
|
306
|
+
</FormLabel>
|
|
307
|
+
|
|
308
|
+
<FormControl>
|
|
309
|
+
<Input
|
|
310
|
+
placeholder="Enter dispute resolver address"
|
|
311
|
+
{...field}
|
|
312
|
+
onChange={(e) => {
|
|
313
|
+
field.onChange(e);
|
|
314
|
+
}}
|
|
315
|
+
/>
|
|
316
|
+
</FormControl>
|
|
317
|
+
<FormMessage />
|
|
318
|
+
</FormItem>
|
|
319
|
+
)}
|
|
320
|
+
/>
|
|
321
|
+
</div>
|
|
322
|
+
|
|
323
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
|
324
|
+
<FormField
|
|
325
|
+
control={form.control}
|
|
326
|
+
name="roles.platformAddress"
|
|
327
|
+
render={({ field }) => (
|
|
328
|
+
<FormItem>
|
|
329
|
+
<FormLabel className="flex items-center justify-between">
|
|
330
|
+
<span className="flex items-center">
|
|
331
|
+
Platform Address
|
|
332
|
+
<span className="text-destructive ml-1">*</span>
|
|
333
|
+
</span>
|
|
334
|
+
</FormLabel>
|
|
335
|
+
|
|
336
|
+
<FormControl>
|
|
337
|
+
<Input
|
|
338
|
+
placeholder="Enter platform address"
|
|
339
|
+
{...field}
|
|
340
|
+
onChange={(e) => {
|
|
341
|
+
field.onChange(e);
|
|
342
|
+
}}
|
|
343
|
+
/>
|
|
344
|
+
</FormControl>
|
|
345
|
+
<FormMessage />
|
|
346
|
+
</FormItem>
|
|
347
|
+
)}
|
|
348
|
+
/>
|
|
349
|
+
<FormField
|
|
350
|
+
control={form.control}
|
|
351
|
+
name="roles.receiver"
|
|
352
|
+
render={({ field }) => (
|
|
353
|
+
<FormItem>
|
|
354
|
+
<FormLabel className="flex items-center justify-between">
|
|
355
|
+
<span className="flex items-center">
|
|
356
|
+
Receiver<span className="text-destructive ml-1">*</span>
|
|
357
|
+
</span>
|
|
358
|
+
</FormLabel>
|
|
359
|
+
|
|
360
|
+
<FormControl>
|
|
361
|
+
<Input
|
|
362
|
+
placeholder="Enter receiver address"
|
|
363
|
+
{...field}
|
|
364
|
+
onChange={(e) => {
|
|
365
|
+
field.onChange(e);
|
|
366
|
+
}}
|
|
367
|
+
/>
|
|
368
|
+
</FormControl>
|
|
369
|
+
<FormMessage />
|
|
370
|
+
</FormItem>
|
|
371
|
+
)}
|
|
372
|
+
/>
|
|
373
|
+
</div>
|
|
374
|
+
|
|
375
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
|
376
|
+
<FormField
|
|
377
|
+
control={form.control}
|
|
378
|
+
name="platformFee"
|
|
379
|
+
render={() => (
|
|
380
|
+
<FormItem>
|
|
381
|
+
<FormLabel className="flex items-center">
|
|
382
|
+
Platform Fee
|
|
383
|
+
<span className="text-destructive ml-1">*</span>
|
|
384
|
+
</FormLabel>
|
|
385
|
+
<FormControl>
|
|
386
|
+
<div className="relative">
|
|
387
|
+
<Percent
|
|
388
|
+
className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-500"
|
|
389
|
+
size={18}
|
|
390
|
+
/>
|
|
391
|
+
<Input
|
|
392
|
+
placeholder="Enter platform fee"
|
|
393
|
+
className="pl-10"
|
|
394
|
+
value={form.watch("platformFee")?.toString() || ""}
|
|
395
|
+
onChange={handlePlatformFeeChange}
|
|
396
|
+
/>
|
|
397
|
+
</div>
|
|
398
|
+
</FormControl>
|
|
399
|
+
<FormMessage />
|
|
400
|
+
</FormItem>
|
|
401
|
+
)}
|
|
402
|
+
/>
|
|
403
|
+
|
|
404
|
+
<FormField
|
|
405
|
+
control={form.control}
|
|
406
|
+
name="receiverMemo"
|
|
407
|
+
render={({ field }) => (
|
|
408
|
+
<FormItem>
|
|
409
|
+
<FormLabel className="flex items-center">
|
|
410
|
+
Receiver Memo (opcional)
|
|
411
|
+
</FormLabel>
|
|
412
|
+
<FormControl>
|
|
413
|
+
<Input
|
|
414
|
+
type="text"
|
|
415
|
+
placeholder="Enter the escrow receiver Memo"
|
|
416
|
+
{...field}
|
|
417
|
+
onChange={(e) => {
|
|
418
|
+
field.onChange(e);
|
|
419
|
+
}}
|
|
420
|
+
/>
|
|
421
|
+
</FormControl>
|
|
422
|
+
<FormMessage />
|
|
423
|
+
</FormItem>
|
|
424
|
+
)}
|
|
425
|
+
/>
|
|
426
|
+
</div>
|
|
427
|
+
|
|
428
|
+
<FormField
|
|
429
|
+
control={form.control}
|
|
430
|
+
name="description"
|
|
431
|
+
render={({ field }) => (
|
|
432
|
+
<FormItem>
|
|
433
|
+
<FormLabel className="flex items-center">
|
|
434
|
+
Description<span className="text-destructive ml-1">*</span>
|
|
435
|
+
</FormLabel>
|
|
436
|
+
<FormControl>
|
|
437
|
+
<Textarea
|
|
438
|
+
placeholder="Escrow description"
|
|
439
|
+
{...field}
|
|
440
|
+
onChange={(e) => {
|
|
441
|
+
field.onChange(e);
|
|
442
|
+
}}
|
|
443
|
+
/>
|
|
444
|
+
</FormControl>
|
|
445
|
+
<FormMessage />
|
|
446
|
+
</FormItem>
|
|
447
|
+
)}
|
|
448
|
+
/>
|
|
449
|
+
|
|
450
|
+
<div className="space-y-4">
|
|
451
|
+
<FormLabel className="flex items-center">
|
|
452
|
+
Milestones<span className="text-destructive ml-1">*</span>
|
|
453
|
+
</FormLabel>
|
|
454
|
+
{milestones.map((milestone, index) => (
|
|
455
|
+
<div key={index} className="space-y-4">
|
|
456
|
+
<div className="flex flex-col sm:flex-row items-start sm:items-center space-y-2 sm:space-y-0 sm:space-x-4">
|
|
457
|
+
<Input
|
|
458
|
+
placeholder="Milestone Description"
|
|
459
|
+
value={milestone.description}
|
|
460
|
+
className="w-full sm:w-3/5"
|
|
461
|
+
onChange={(e) => {
|
|
462
|
+
const updatedMilestones = [...milestones];
|
|
463
|
+
updatedMilestones[index].description = e.target.value;
|
|
464
|
+
form.setValue("milestones", updatedMilestones);
|
|
465
|
+
}}
|
|
466
|
+
/>
|
|
467
|
+
|
|
468
|
+
<div className="relative w-full sm:w-2/5">
|
|
469
|
+
<DollarSign
|
|
470
|
+
className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-500"
|
|
471
|
+
size={18}
|
|
472
|
+
/>
|
|
473
|
+
<Input
|
|
474
|
+
className="pl-10"
|
|
475
|
+
placeholder="Enter amount"
|
|
476
|
+
value={milestone.amount?.toString() || ""}
|
|
477
|
+
onChange={(e) => handleMilestoneAmountChange(index, e)}
|
|
478
|
+
/>
|
|
479
|
+
</div>
|
|
480
|
+
|
|
481
|
+
<Button
|
|
482
|
+
onClick={() => handleRemoveMilestone(index)}
|
|
483
|
+
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"
|
|
484
|
+
disabled={milestones.length === 1}
|
|
485
|
+
>
|
|
486
|
+
<Trash2 className="h-5 w-5" />
|
|
487
|
+
</Button>
|
|
488
|
+
</div>
|
|
489
|
+
|
|
490
|
+
{index === milestones.length - 1 && (
|
|
491
|
+
<div className="flex justify-end mt-4">
|
|
492
|
+
<Button
|
|
493
|
+
disabled={isAnyMilestoneEmpty}
|
|
494
|
+
className="w-full md:w-1/4"
|
|
495
|
+
variant="outline"
|
|
496
|
+
onClick={handleAddMilestone}
|
|
497
|
+
type="button"
|
|
498
|
+
>
|
|
499
|
+
Add Item
|
|
500
|
+
</Button>
|
|
501
|
+
</div>
|
|
502
|
+
)}
|
|
503
|
+
</div>
|
|
504
|
+
))}
|
|
505
|
+
</div>
|
|
506
|
+
|
|
507
|
+
<div className="flex justify-start">
|
|
508
|
+
<Button
|
|
509
|
+
className="w-full md:w-1/4 cursor-pointer"
|
|
510
|
+
type="submit"
|
|
511
|
+
disabled={isAnyMilestoneEmpty || isSubmitting}
|
|
512
|
+
>
|
|
513
|
+
{isSubmitting ? (
|
|
514
|
+
<div className="flex items-center">
|
|
515
|
+
<Loader2 className="h-5 w-5 animate-spin" />
|
|
516
|
+
<span className="ml-2">Deploying...</span>
|
|
517
|
+
</div>
|
|
518
|
+
) : (
|
|
519
|
+
"Deploy"
|
|
520
|
+
)}
|
|
521
|
+
</Button>
|
|
522
|
+
</div>
|
|
523
|
+
</form>
|
|
524
|
+
</Form>
|
|
525
|
+
</DialogContent>
|
|
526
|
+
</Dialog>
|
|
527
|
+
);
|
|
528
|
+
};
|