@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
|
@@ -23,7 +23,7 @@ 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
25
|
|
|
26
|
-
export
|
|
26
|
+
export const InitializeEscrowForm = () => {
|
|
27
27
|
const {
|
|
28
28
|
form,
|
|
29
29
|
isSubmitting,
|
|
@@ -32,6 +32,7 @@ export function InitializeEscrowForm() {
|
|
|
32
32
|
handleSubmit,
|
|
33
33
|
handleAddMilestone,
|
|
34
34
|
handleRemoveMilestone,
|
|
35
|
+
fillTemplateForm,
|
|
35
36
|
} = useInitializeEscrow();
|
|
36
37
|
|
|
37
38
|
const handleAmountChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
@@ -88,10 +89,19 @@ export function InitializeEscrowForm() {
|
|
|
88
89
|
<h2 className="text-xl font-semibold">Single Release Escrow</h2>
|
|
89
90
|
</div>
|
|
90
91
|
<p className="text-muted-foreground mt-1">
|
|
91
|
-
|
|
92
|
-
milestones
|
|
92
|
+
Fill out the form to initialize a single release escrow milestones
|
|
93
93
|
</p>
|
|
94
94
|
</Link>
|
|
95
|
+
{process.env.NODE_ENV !== "production" && (
|
|
96
|
+
<Button
|
|
97
|
+
type="button"
|
|
98
|
+
variant="outline"
|
|
99
|
+
onClick={fillTemplateForm}
|
|
100
|
+
className="cursor-pointer"
|
|
101
|
+
>
|
|
102
|
+
Autofill
|
|
103
|
+
</Button>
|
|
104
|
+
)}
|
|
95
105
|
</Card>
|
|
96
106
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
|
97
107
|
<FormField
|
|
@@ -499,6 +509,4 @@ export function InitializeEscrowForm() {
|
|
|
499
509
|
</form>
|
|
500
510
|
</Form>
|
|
501
511
|
);
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
export default InitializeEscrowForm;
|
|
512
|
+
};
|
|
@@ -169,64 +169,7 @@ export const useInitializeEscrowSchema = () => {
|
|
|
169
169
|
.min(1, { message: "At least one milestone is required." }),
|
|
170
170
|
});
|
|
171
171
|
};
|
|
172
|
-
|
|
173
|
-
const getMultiReleaseFormSchema = () => {
|
|
174
|
-
const baseSchema = getBaseSchema();
|
|
175
|
-
|
|
176
|
-
return baseSchema.extend({
|
|
177
|
-
milestones: z
|
|
178
|
-
.array(
|
|
179
|
-
z.object({
|
|
180
|
-
description: z.string().min(1, {
|
|
181
|
-
message: "Milestone description is required.",
|
|
182
|
-
}),
|
|
183
|
-
amount: z
|
|
184
|
-
.union([z.string(), z.number()])
|
|
185
|
-
.refine(
|
|
186
|
-
(val) => {
|
|
187
|
-
if (typeof val === "string") {
|
|
188
|
-
if (val === "" || val === "." || val.endsWith(".")) {
|
|
189
|
-
return true;
|
|
190
|
-
}
|
|
191
|
-
const numVal = Number(val);
|
|
192
|
-
return !isNaN(numVal) && numVal > 0;
|
|
193
|
-
}
|
|
194
|
-
return val > 0;
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
message: "Milestone amount must be greater than 0.",
|
|
198
|
-
}
|
|
199
|
-
)
|
|
200
|
-
.refine(
|
|
201
|
-
(val) => {
|
|
202
|
-
if (typeof val === "string") {
|
|
203
|
-
if (val === "" || val === "." || val.endsWith(".")) {
|
|
204
|
-
return true;
|
|
205
|
-
}
|
|
206
|
-
const numVal = Number(val);
|
|
207
|
-
if (isNaN(numVal)) return false;
|
|
208
|
-
const decimalPlaces = (
|
|
209
|
-
numVal.toString().split(".")[1] || ""
|
|
210
|
-
).length;
|
|
211
|
-
return decimalPlaces <= 2;
|
|
212
|
-
}
|
|
213
|
-
const decimalPlaces = (val.toString().split(".")[1] || "")
|
|
214
|
-
.length;
|
|
215
|
-
return decimalPlaces <= 2;
|
|
216
|
-
},
|
|
217
|
-
{
|
|
218
|
-
message:
|
|
219
|
-
"Milestone amount can have a maximum of 2 decimal places.",
|
|
220
|
-
}
|
|
221
|
-
),
|
|
222
|
-
})
|
|
223
|
-
)
|
|
224
|
-
.min(1, { message: "At least one milestone is required." }),
|
|
225
|
-
});
|
|
226
|
-
};
|
|
227
|
-
|
|
228
172
|
return {
|
|
229
173
|
getSingleReleaseFormSchema,
|
|
230
|
-
getMultiReleaseFormSchema,
|
|
231
174
|
};
|
|
232
175
|
};
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
handleError,
|
|
16
16
|
} from "@/components/tw-blocks/handle-errors/handle";
|
|
17
17
|
import { useEscrowContext } from "@/components/tw-blocks/providers/EscrowProvider";
|
|
18
|
+
import { trustlineOptions } from "@/components/tw-blocks/wallet-kit/trustlines";
|
|
18
19
|
|
|
19
20
|
export function useInitializeEscrow() {
|
|
20
21
|
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
|
@@ -69,6 +70,45 @@ export function useInitializeEscrow() {
|
|
|
69
70
|
form.setValue("milestones", updatedMilestones);
|
|
70
71
|
};
|
|
71
72
|
|
|
73
|
+
const fillTemplateForm = () => {
|
|
74
|
+
const usdc = trustlineOptions.find((t) => t.label === "USDC");
|
|
75
|
+
|
|
76
|
+
const templateData: z.infer<typeof formSchema> = {
|
|
77
|
+
engagementId: "ENG-001",
|
|
78
|
+
title: "Design Landing Page",
|
|
79
|
+
description: "Landing for the new product of the company.",
|
|
80
|
+
platformFee: 5,
|
|
81
|
+
amount: 5,
|
|
82
|
+
receiverMemo: "123",
|
|
83
|
+
trustline: {
|
|
84
|
+
address: usdc?.value || "",
|
|
85
|
+
decimals: 10000000,
|
|
86
|
+
},
|
|
87
|
+
roles: {
|
|
88
|
+
approver: walletAddress || "",
|
|
89
|
+
serviceProvider: walletAddress || "",
|
|
90
|
+
platformAddress: walletAddress || "",
|
|
91
|
+
receiver: walletAddress || "",
|
|
92
|
+
releaseSigner: walletAddress || "",
|
|
93
|
+
disputeResolver: walletAddress || "",
|
|
94
|
+
},
|
|
95
|
+
milestones: [
|
|
96
|
+
{ description: "Design the wireframe" },
|
|
97
|
+
{ description: "Develop the wireframe" },
|
|
98
|
+
{ description: "Deploy the wireframe" },
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// Set form values
|
|
103
|
+
Object.entries(templateData).forEach(([key, value]) => {
|
|
104
|
+
form.setValue(key as keyof z.infer<typeof formSchema>, value);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Explicitly set the trustline field
|
|
108
|
+
form.setValue("trustline.address", usdc?.value || "");
|
|
109
|
+
form.setValue("trustline.decimals", 10000000);
|
|
110
|
+
};
|
|
111
|
+
|
|
72
112
|
const handleSubmit = form.handleSubmit(async (payload) => {
|
|
73
113
|
try {
|
|
74
114
|
setIsSubmitting(true);
|
|
@@ -110,7 +150,7 @@ export function useInitializeEscrow() {
|
|
|
110
150
|
|
|
111
151
|
toast.success("Escrow initialized successfully");
|
|
112
152
|
|
|
113
|
-
setSelectedEscrow(response);
|
|
153
|
+
setSelectedEscrow({ ...finalPayload, contractId: response.contractId });
|
|
114
154
|
} catch (error) {
|
|
115
155
|
toast.error(handleError(error as ErrorResponse).message);
|
|
116
156
|
} finally {
|
|
@@ -124,6 +164,7 @@ export function useInitializeEscrow() {
|
|
|
124
164
|
isSubmitting,
|
|
125
165
|
milestones,
|
|
126
166
|
isAnyMilestoneEmpty,
|
|
167
|
+
fillTemplateForm,
|
|
127
168
|
handleSubmit,
|
|
128
169
|
handleAddMilestone,
|
|
129
170
|
handleRemoveMilestone,
|
|
@@ -13,7 +13,7 @@ import { useEscrowDialogs } from "@/components/tw-blocks/providers/EscrowDialogs
|
|
|
13
13
|
import { useEscrowAmountContext } from "@/components/tw-blocks/providers/EscrowAmountProvider";
|
|
14
14
|
import { Loader2 } from "lucide-react";
|
|
15
15
|
|
|
16
|
-
export
|
|
16
|
+
export const ReleaseEscrowButton = () => {
|
|
17
17
|
const { releaseFunds } = useEscrowsMutations();
|
|
18
18
|
const { selectedEscrow, updateEscrow } = useEscrowContext();
|
|
19
19
|
const dialogStates = useEscrowDialogs();
|
|
@@ -89,4 +89,4 @@ export default function ReleaseEscrowButton() {
|
|
|
89
89
|
)}
|
|
90
90
|
</Button>
|
|
91
91
|
);
|
|
92
|
-
}
|
|
92
|
+
};
|
|
@@ -16,10 +16,10 @@ type ResolveDisputeButtonProps = {
|
|
|
16
16
|
receiverFunds: number;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
export
|
|
19
|
+
export const ResolveDisputeButton = ({
|
|
20
20
|
approverFunds,
|
|
21
21
|
receiverFunds,
|
|
22
|
-
}: ResolveDisputeButtonProps) {
|
|
22
|
+
}: ResolveDisputeButtonProps) => {
|
|
23
23
|
const { resolveDispute } = useEscrowsMutations();
|
|
24
24
|
const { selectedEscrow, updateEscrow } = useEscrowContext();
|
|
25
25
|
const { walletAddress } = useWalletContext();
|
|
@@ -103,4 +103,4 @@ export default function ResolveDisputeButton({
|
|
|
103
103
|
)}
|
|
104
104
|
</Button>
|
|
105
105
|
);
|
|
106
|
-
}
|
|
106
|
+
};
|
|
@@ -19,15 +19,12 @@ import {
|
|
|
19
19
|
import { Loader2 } from "lucide-react";
|
|
20
20
|
import { useResolveDispute } from "./useResolveDispute";
|
|
21
21
|
import { useEscrowContext } from "@/components/tw-blocks/providers/EscrowProvider";
|
|
22
|
+
import { formatCurrency } from "../../../../helpers/format.helper";
|
|
22
23
|
|
|
23
|
-
export
|
|
24
|
+
export const ResolveDisputeDialog = () => {
|
|
24
25
|
const { form, handleSubmit, isSubmitting } = useResolveDispute();
|
|
25
26
|
const { selectedEscrow } = useEscrowContext();
|
|
26
27
|
|
|
27
|
-
function formatCurrency(amount: number, currency: string) {
|
|
28
|
-
return `${currency} ${amount.toFixed(2)}`;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
28
|
return (
|
|
32
29
|
<Dialog>
|
|
33
30
|
<DialogTrigger asChild>
|
|
@@ -120,4 +117,4 @@ export default function ResolveDisputeDialog() {
|
|
|
120
117
|
</DialogContent>
|
|
121
118
|
</Dialog>
|
|
122
119
|
);
|
|
123
|
-
}
|
|
120
|
+
};
|
|
@@ -12,7 +12,7 @@ import { Button } from "__UI_BASE__/button";
|
|
|
12
12
|
import { useResolveDispute } from "./useResolveDispute";
|
|
13
13
|
import { Loader2 } from "lucide-react";
|
|
14
14
|
|
|
15
|
-
export
|
|
15
|
+
export const ResolveDisputeForm = () => {
|
|
16
16
|
const { form, handleSubmit, isSubmitting } = useResolveDispute();
|
|
17
17
|
|
|
18
18
|
return (
|
|
@@ -79,4 +79,4 @@ export default function ResolveDisputeForm() {
|
|
|
79
79
|
</form>
|
|
80
80
|
</Form>
|
|
81
81
|
);
|
|
82
|
-
}
|
|
82
|
+
};
|
|
@@ -14,7 +14,7 @@ import { useWalletContext } from "@/components/tw-blocks/wallet-kit/WalletProvid
|
|
|
14
14
|
|
|
15
15
|
export function useResolveDispute() {
|
|
16
16
|
const { resolveDispute } = useEscrowsMutations();
|
|
17
|
-
const { selectedEscrow } = useEscrowContext();
|
|
17
|
+
const { selectedEscrow, updateEscrow } = useEscrowContext();
|
|
18
18
|
const { walletAddress } = useWalletContext();
|
|
19
19
|
|
|
20
20
|
const form = useForm<ResolveDisputeValues>({
|
|
@@ -59,6 +59,19 @@ export function useResolveDispute() {
|
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
toast.success("Dispute resolved successfully");
|
|
62
|
+
|
|
63
|
+
updateEscrow({
|
|
64
|
+
...selectedEscrow,
|
|
65
|
+
flags: {
|
|
66
|
+
...selectedEscrow?.flags,
|
|
67
|
+
disputed: false,
|
|
68
|
+
resolved: true,
|
|
69
|
+
},
|
|
70
|
+
balance:
|
|
71
|
+
(selectedEscrow?.balance || 0) -
|
|
72
|
+
(Number(payload.approverFunds) + Number(payload.receiverFunds)) ||
|
|
73
|
+
0,
|
|
74
|
+
});
|
|
62
75
|
} catch (error) {
|
|
63
76
|
toast.error(handleError(error as ErrorResponse).message);
|
|
64
77
|
} finally {
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
DialogTrigger,
|
|
31
31
|
} from "__UI_BASE__/dialog";
|
|
32
32
|
|
|
33
|
-
export
|
|
33
|
+
export const UpdateEscrowDialog = () => {
|
|
34
34
|
const {
|
|
35
35
|
form,
|
|
36
36
|
isSubmitting,
|
|
@@ -482,4 +482,4 @@ export default function UpdateEscrowDialog() {
|
|
|
482
482
|
</DialogContent>
|
|
483
483
|
</Dialog>
|
|
484
484
|
);
|
|
485
|
-
}
|
|
485
|
+
};
|
|
@@ -23,7 +23,7 @@ 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
25
|
|
|
26
|
-
export
|
|
26
|
+
export const UpdateEscrowForm = () => {
|
|
27
27
|
const {
|
|
28
28
|
form,
|
|
29
29
|
isSubmitting,
|
|
@@ -460,4 +460,4 @@ export default function UpdateEscrowForm() {
|
|
|
460
460
|
</form>
|
|
461
461
|
</Form>
|
|
462
462
|
);
|
|
463
|
-
}
|
|
463
|
+
};
|
|
@@ -6,6 +6,7 @@ import { z } from "zod";
|
|
|
6
6
|
import {
|
|
7
7
|
UpdateSingleReleaseEscrowPayload,
|
|
8
8
|
UpdateSingleReleaseEscrowResponse,
|
|
9
|
+
SingleReleaseMilestone,
|
|
9
10
|
} from "@trustless-work/escrow/types";
|
|
10
11
|
import { toast } from "sonner";
|
|
11
12
|
import { useEscrowContext } from "@/components/tw-blocks/providers/EscrowProvider";
|
|
@@ -53,9 +54,11 @@ export function useUpdateEscrow() {
|
|
|
53
54
|
releaseSigner: selectedEscrow?.roles?.releaseSigner || "",
|
|
54
55
|
disputeResolver: selectedEscrow?.roles?.disputeResolver || "",
|
|
55
56
|
},
|
|
56
|
-
milestones: (selectedEscrow?.milestones || []).map(
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
milestones: (selectedEscrow?.milestones || []).map(
|
|
58
|
+
(m: SingleReleaseMilestone) => ({
|
|
59
|
+
description: m?.description || "",
|
|
60
|
+
})
|
|
61
|
+
),
|
|
59
62
|
},
|
|
60
63
|
mode: "onChange",
|
|
61
64
|
});
|
|
@@ -89,9 +92,11 @@ export function useUpdateEscrow() {
|
|
|
89
92
|
releaseSigner: selectedEscrow?.roles?.releaseSigner || "",
|
|
90
93
|
disputeResolver: selectedEscrow?.roles?.disputeResolver || "",
|
|
91
94
|
},
|
|
92
|
-
milestones: (selectedEscrow?.milestones || []).map(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
+
milestones: (selectedEscrow?.milestones || []).map(
|
|
96
|
+
(m: SingleReleaseMilestone) => ({
|
|
97
|
+
description: m?.description || "",
|
|
98
|
+
})
|
|
99
|
+
),
|
|
95
100
|
});
|
|
96
101
|
}, [selectedEscrow, form]);
|
|
97
102
|
|
|
@@ -168,7 +173,7 @@ export function useUpdateEscrow() {
|
|
|
168
173
|
address: payload.trustline.address,
|
|
169
174
|
decimals: 10000000,
|
|
170
175
|
},
|
|
171
|
-
roles: payload.roles
|
|
176
|
+
roles: payload.roles,
|
|
172
177
|
milestones: payload.milestones,
|
|
173
178
|
},
|
|
174
179
|
};
|
|
@@ -13,9 +13,7 @@ export type DialogStates = {
|
|
|
13
13
|
successRelease: DialogState;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
type EscrowDialogsContextType = DialogStates & StatusStates;
|
|
16
|
+
type EscrowDialogsContextType = DialogStates;
|
|
19
17
|
|
|
20
18
|
const EscrowDialogsContext = createContext<
|
|
21
19
|
EscrowDialogsContextType | undefined
|
|
@@ -10,7 +10,28 @@ import {
|
|
|
10
10
|
ReactNode,
|
|
11
11
|
useCallback,
|
|
12
12
|
} from "react";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
GetEscrowsFromIndexerResponse as Escrow,
|
|
15
|
+
Trustline,
|
|
16
|
+
} from "@trustless-work/escrow/types";
|
|
17
|
+
|
|
18
|
+
type SingleEscrowPayload = Omit<
|
|
19
|
+
Escrow,
|
|
20
|
+
"type" | "updatedAt" | "createdAt" | "user" | "trustline"
|
|
21
|
+
> &
|
|
22
|
+
Partial<Pick<Escrow, "type" | "updatedAt" | "createdAt" | "user">> & {
|
|
23
|
+
trustline: Trustline & { name?: string };
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type MultiEscrowPayload = Omit<
|
|
27
|
+
Escrow,
|
|
28
|
+
"type" | "updatedAt" | "createdAt" | "user" | "trustline" | "amount"
|
|
29
|
+
> &
|
|
30
|
+
Partial<
|
|
31
|
+
Pick<Escrow, "type" | "updatedAt" | "createdAt" | "user" | "amount">
|
|
32
|
+
> & {
|
|
33
|
+
trustline: Trustline & { name?: string };
|
|
34
|
+
};
|
|
14
35
|
|
|
15
36
|
type EscrowContextType = {
|
|
16
37
|
selectedEscrow: Escrow | null;
|
|
@@ -21,7 +42,9 @@ type EscrowContextType = {
|
|
|
21
42
|
) => void;
|
|
22
43
|
setEscrowField: <K extends keyof Escrow>(key: K, value: Escrow[K]) => void;
|
|
23
44
|
clearEscrow: () => void;
|
|
24
|
-
setSelectedEscrow: (
|
|
45
|
+
setSelectedEscrow: (
|
|
46
|
+
escrow?: SingleEscrowPayload | MultiEscrowPayload
|
|
47
|
+
) => void;
|
|
25
48
|
setUserRolesInEscrow: (roles: string[]) => void;
|
|
26
49
|
};
|
|
27
50
|
|
|
@@ -134,8 +157,8 @@ export const EscrowProvider = ({ children }: { children: ReactNode }) => {
|
|
|
134
157
|
updateEscrow,
|
|
135
158
|
setEscrowField,
|
|
136
159
|
clearEscrow,
|
|
137
|
-
setSelectedEscrow: (value?:
|
|
138
|
-
setSelectedEscrowState(value ?? null),
|
|
160
|
+
setSelectedEscrow: (value?: SingleEscrowPayload | MultiEscrowPayload) =>
|
|
161
|
+
setSelectedEscrowState((value as unknown as Escrow) ?? null),
|
|
139
162
|
setUserRolesInEscrow,
|
|
140
163
|
userRolesInEscrow,
|
|
141
164
|
}}
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import { GetEscrowsFromIndexerResponse } from "@trustless-work/escrow/types";
|
|
2
|
-
import { cn } from "@/lib/utils";
|
|
3
|
-
import {
|
|
4
|
-
MultiReleaseMilestone,
|
|
5
|
-
SingleReleaseMilestone,
|
|
6
|
-
} from "@trustless-work/escrow";
|
|
7
|
-
|
|
8
|
-
type Escrow = {
|
|
9
|
-
[K in keyof Omit<
|
|
10
|
-
GetEscrowsFromIndexerResponse,
|
|
11
|
-
"type" | "updatedAt" | "createdAt" | "user"
|
|
12
|
-
>]: K extends "trustline"
|
|
13
|
-
? Omit<NonNullable<GetEscrowsFromIndexerResponse["trustline"]>, "name">
|
|
14
|
-
: GetEscrowsFromIndexerResponse[K];
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
interface ProgressEscrowProps {
|
|
18
|
-
escrow: Escrow;
|
|
19
|
-
className?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const ProgressCircle = ({
|
|
23
|
-
percentage,
|
|
24
|
-
color,
|
|
25
|
-
size = 44,
|
|
26
|
-
strokeWidth = 3,
|
|
27
|
-
}: {
|
|
28
|
-
percentage: number;
|
|
29
|
-
color: string;
|
|
30
|
-
size?: number;
|
|
31
|
-
strokeWidth?: number;
|
|
32
|
-
}) => {
|
|
33
|
-
const radius = (size - strokeWidth) / 2;
|
|
34
|
-
const circumference = 2 * Math.PI * radius;
|
|
35
|
-
const strokeDashoffset = circumference - (percentage / 100) * circumference;
|
|
36
|
-
|
|
37
|
-
return (
|
|
38
|
-
<div className="relative inline-flex">
|
|
39
|
-
<svg
|
|
40
|
-
width={size}
|
|
41
|
-
height={size}
|
|
42
|
-
viewBox={`0 0 ${size} ${size}`}
|
|
43
|
-
className="transform -rotate-90"
|
|
44
|
-
>
|
|
45
|
-
<circle
|
|
46
|
-
cx={size / 2}
|
|
47
|
-
cy={size / 2}
|
|
48
|
-
r={radius}
|
|
49
|
-
fill="none"
|
|
50
|
-
stroke="rgba(226, 232, 240, 0.3)"
|
|
51
|
-
strokeWidth={strokeWidth}
|
|
52
|
-
/>
|
|
53
|
-
<circle
|
|
54
|
-
cx={size / 2}
|
|
55
|
-
cy={size / 2}
|
|
56
|
-
r={radius}
|
|
57
|
-
fill="none"
|
|
58
|
-
stroke={color}
|
|
59
|
-
strokeWidth={strokeWidth}
|
|
60
|
-
strokeDasharray={circumference}
|
|
61
|
-
strokeDashoffset={strokeDashoffset}
|
|
62
|
-
strokeLinecap="round"
|
|
63
|
-
/>
|
|
64
|
-
</svg>
|
|
65
|
-
<div className="absolute inset-0 flex items-center justify-center text-xs font-medium">
|
|
66
|
-
{Math.round(percentage)}%
|
|
67
|
-
</div>
|
|
68
|
-
</div>
|
|
69
|
-
);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const ProgressEscrow = ({ escrow, className }: ProgressEscrowProps) => {
|
|
73
|
-
const completedMilestones = escrow.milestones.filter(
|
|
74
|
-
(milestone) => milestone.status === "completed"
|
|
75
|
-
).length;
|
|
76
|
-
const approvedMilestones = escrow.milestones.filter(
|
|
77
|
-
(milestone: SingleReleaseMilestone | MultiReleaseMilestone) =>
|
|
78
|
-
("flags" in milestone && milestone.flags?.approved === true) ||
|
|
79
|
-
(!("flags" in milestone) &&
|
|
80
|
-
(milestone as SingleReleaseMilestone).approved === true)
|
|
81
|
-
).length;
|
|
82
|
-
const disputedMilestones = escrow.milestones.filter(
|
|
83
|
-
(milestone: SingleReleaseMilestone | MultiReleaseMilestone) =>
|
|
84
|
-
"flags" in milestone && milestone.flags?.disputed === true
|
|
85
|
-
).length;
|
|
86
|
-
const resolvedMilestones = escrow.milestones.filter(
|
|
87
|
-
(milestone: SingleReleaseMilestone | MultiReleaseMilestone) =>
|
|
88
|
-
"flags" in milestone && milestone.flags?.resolved === true
|
|
89
|
-
).length;
|
|
90
|
-
const releasedMilestones = escrow.milestones.filter(
|
|
91
|
-
(milestone: SingleReleaseMilestone | MultiReleaseMilestone) =>
|
|
92
|
-
"flags" in milestone && milestone.flags?.released === true
|
|
93
|
-
).length;
|
|
94
|
-
const totalMilestones = escrow.milestones.length;
|
|
95
|
-
|
|
96
|
-
const progressPercentageCompleted =
|
|
97
|
-
totalMilestones > 0 ? (completedMilestones / totalMilestones) * 100 : 0;
|
|
98
|
-
const progressPercentageApproved =
|
|
99
|
-
totalMilestones > 0 ? (approvedMilestones / totalMilestones) * 100 : 0;
|
|
100
|
-
const progressPercentageDisputed =
|
|
101
|
-
totalMilestones > 0 ? (disputedMilestones / totalMilestones) * 100 : 0;
|
|
102
|
-
const progressPercentageResolved =
|
|
103
|
-
totalMilestones > 0 ? (resolvedMilestones / totalMilestones) * 100 : 0;
|
|
104
|
-
const progressPercentageReleased =
|
|
105
|
-
totalMilestones > 0 ? (releasedMilestones / totalMilestones) * 100 : 0;
|
|
106
|
-
|
|
107
|
-
const shouldHideProgress = escrow.flags?.released || escrow.flags?.resolved;
|
|
108
|
-
const isMultiRelease =
|
|
109
|
-
escrow.milestones[0] && "flags" in escrow.milestones[0];
|
|
110
|
-
|
|
111
|
-
if (shouldHideProgress || totalMilestones === 0) {
|
|
112
|
-
return null;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return (
|
|
116
|
-
<div className={cn("space-y-4 px-10 w-full", className)}>
|
|
117
|
-
<div className="flex flex-wrap items-center justify-center gap-6">
|
|
118
|
-
<div className="flex items-center gap-3">
|
|
119
|
-
<ProgressCircle
|
|
120
|
-
percentage={progressPercentageCompleted}
|
|
121
|
-
color="#006be4"
|
|
122
|
-
/>
|
|
123
|
-
<div className="text-xs">
|
|
124
|
-
<div className="font-medium">Completed</div>
|
|
125
|
-
<div className="text-muted-foreground">
|
|
126
|
-
{completedMilestones}/{totalMilestones}
|
|
127
|
-
</div>
|
|
128
|
-
</div>
|
|
129
|
-
</div>
|
|
130
|
-
|
|
131
|
-
<div className="flex items-center gap-3">
|
|
132
|
-
<ProgressCircle
|
|
133
|
-
percentage={progressPercentageApproved}
|
|
134
|
-
color="#15803d"
|
|
135
|
-
/>
|
|
136
|
-
<div className="text-xs">
|
|
137
|
-
<div className="font-medium">Approved</div>
|
|
138
|
-
<div className="text-muted-foreground">
|
|
139
|
-
{approvedMilestones}/{totalMilestones}
|
|
140
|
-
</div>
|
|
141
|
-
</div>
|
|
142
|
-
</div>
|
|
143
|
-
|
|
144
|
-
{isMultiRelease && (
|
|
145
|
-
<>
|
|
146
|
-
<div className="flex items-center gap-3">
|
|
147
|
-
<ProgressCircle
|
|
148
|
-
percentage={progressPercentageDisputed}
|
|
149
|
-
color="#dc2626"
|
|
150
|
-
/>
|
|
151
|
-
<div className="text-xs">
|
|
152
|
-
<div className="font-medium">Disputed</div>
|
|
153
|
-
<div className="text-muted-foreground">
|
|
154
|
-
{disputedMilestones}/{totalMilestones}
|
|
155
|
-
</div>
|
|
156
|
-
</div>
|
|
157
|
-
</div>
|
|
158
|
-
|
|
159
|
-
<div className="flex items-center gap-3">
|
|
160
|
-
<ProgressCircle
|
|
161
|
-
percentage={progressPercentageResolved}
|
|
162
|
-
color="#15803d"
|
|
163
|
-
/>
|
|
164
|
-
<div className="text-xs">
|
|
165
|
-
<div className="font-medium">Resolved</div>
|
|
166
|
-
<div className="text-muted-foreground">
|
|
167
|
-
{resolvedMilestones}/{totalMilestones}
|
|
168
|
-
</div>
|
|
169
|
-
</div>
|
|
170
|
-
</div>
|
|
171
|
-
|
|
172
|
-
<div className="flex items-center gap-3">
|
|
173
|
-
<ProgressCircle
|
|
174
|
-
percentage={progressPercentageReleased}
|
|
175
|
-
color="#15803d"
|
|
176
|
-
/>
|
|
177
|
-
<div className="text-xs">
|
|
178
|
-
<div className="font-medium">Released</div>
|
|
179
|
-
<div className="text-muted-foreground">
|
|
180
|
-
{releasedMilestones}/{totalMilestones}
|
|
181
|
-
</div>
|
|
182
|
-
</div>
|
|
183
|
-
</div>
|
|
184
|
-
</>
|
|
185
|
-
)}
|
|
186
|
-
</div>
|
|
187
|
-
</div>
|
|
188
|
-
);
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
export default ProgressEscrow;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|