@trustless-work/blocks 0.0.1

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 (74) hide show
  1. package/README.md +96 -0
  2. package/bin/index.js +1123 -0
  3. package/package.json +44 -0
  4. package/templates/deps.json +29 -0
  5. package/templates/escrows/details/Actions.tsx +149 -0
  6. package/templates/escrows/details/Entities.tsx +48 -0
  7. package/templates/escrows/details/EntityCard.tsx +98 -0
  8. package/templates/escrows/details/EscrowDetailDialog.tsx +154 -0
  9. package/templates/escrows/details/GeneralInformation.tsx +329 -0
  10. package/templates/escrows/details/MilestoneCard.tsx +254 -0
  11. package/templates/escrows/details/MilestoneDetailDialog.tsx +276 -0
  12. package/templates/escrows/details/Milestones.tsx +87 -0
  13. package/templates/escrows/details/ProgressEscrow.tsx +191 -0
  14. package/templates/escrows/details/StatisticsCard.tsx +79 -0
  15. package/templates/escrows/details/SuccessReleaseDialog.tsx +101 -0
  16. package/templates/escrows/details/useDetailsEscrow.ts +126 -0
  17. package/templates/escrows/escrow-context/EscrowAmountProvider.tsx +86 -0
  18. package/templates/escrows/escrow-context/EscrowDialogsProvider.tsx +108 -0
  19. package/templates/escrows/escrow-context/EscrowProvider.tsx +124 -0
  20. package/templates/escrows/escrows-by-role/cards/EscrowsCards.tsx +503 -0
  21. package/templates/escrows/escrows-by-role/cards/Filters.tsx +421 -0
  22. package/templates/escrows/escrows-by-role/table/EscrowsTable.tsx +427 -0
  23. package/templates/escrows/escrows-by-role/table/Filters.tsx +421 -0
  24. package/templates/escrows/escrows-by-role/useEscrowsByRole.shared.ts +336 -0
  25. package/templates/escrows/escrows-by-signer/cards/EscrowsCards.tsx +502 -0
  26. package/templates/escrows/escrows-by-signer/cards/Filters.tsx +389 -0
  27. package/templates/escrows/escrows-by-signer/table/EscrowsTable.tsx +422 -0
  28. package/templates/escrows/escrows-by-signer/table/Filters.tsx +389 -0
  29. package/templates/escrows/escrows-by-signer/useEscrowsBySigner.shared.ts +320 -0
  30. package/templates/escrows/single-release/approve-milestone/button/ApproveMilestone.tsx +78 -0
  31. package/templates/escrows/single-release/approve-milestone/dialog/ApproveMilestone.tsx +102 -0
  32. package/templates/escrows/single-release/approve-milestone/form/ApproveMilestone.tsx +80 -0
  33. package/templates/escrows/single-release/approve-milestone/shared/schema.ts +9 -0
  34. package/templates/escrows/single-release/approve-milestone/shared/useApproveMilestone.ts +67 -0
  35. package/templates/escrows/single-release/change-milestone-status/button/ChangeMilestoneStatus.tsx +78 -0
  36. package/templates/escrows/single-release/change-milestone-status/dialog/ChangeMilestoneStatus.tsx +167 -0
  37. package/templates/escrows/single-release/change-milestone-status/form/ChangeMilestoneStatus.tsx +114 -0
  38. package/templates/escrows/single-release/change-milestone-status/shared/schema.ts +15 -0
  39. package/templates/escrows/single-release/change-milestone-status/shared/useChangeMilestoneStatus.ts +77 -0
  40. package/templates/escrows/single-release/dispute-escrow/button/DisputeEscrow.tsx +68 -0
  41. package/templates/escrows/single-release/fund-escrow/button/FundEscrow.tsx +84 -0
  42. package/templates/escrows/single-release/fund-escrow/dialog/FundEscrow.tsx +77 -0
  43. package/templates/escrows/single-release/fund-escrow/form/FundEscrow.tsx +54 -0
  44. package/templates/escrows/single-release/fund-escrow/shared/schema.ts +10 -0
  45. package/templates/escrows/single-release/fund-escrow/shared/useFundEscrow.ts +66 -0
  46. package/templates/escrows/single-release/initialize-escrow/dialog/InitializeEscrow.tsx +526 -0
  47. package/templates/escrows/single-release/initialize-escrow/form/InitializeEscrow.tsx +504 -0
  48. package/templates/escrows/single-release/initialize-escrow/shared/schema.ts +232 -0
  49. package/templates/escrows/single-release/initialize-escrow/shared/useInitializeEscrow.ts +115 -0
  50. package/templates/escrows/single-release/release-escrow/button/ReleaseEscrow.tsx +80 -0
  51. package/templates/escrows/single-release/resolve-dispute/button/ResolveDispute.tsx +94 -0
  52. package/templates/escrows/single-release/resolve-dispute/dialog/ResolveDispute.tsx +123 -0
  53. package/templates/escrows/single-release/resolve-dispute/form/ResolveDispute.tsx +82 -0
  54. package/templates/escrows/single-release/resolve-dispute/shared/schema.ts +82 -0
  55. package/templates/escrows/single-release/resolve-dispute/shared/useResolveDispute.ts +58 -0
  56. package/templates/escrows/single-release/update-escrow/dialog/UpdateEscrow.tsx +485 -0
  57. package/templates/escrows/single-release/update-escrow/form/UpdateEscrow.tsx +463 -0
  58. package/templates/escrows/single-release/update-escrow/shared/schema.ts +139 -0
  59. package/templates/escrows/single-release/update-escrow/shared/useUpdateEscrow.ts +211 -0
  60. package/templates/handle-errors/errors.enum.ts +6 -0
  61. package/templates/handle-errors/handle.ts +47 -0
  62. package/templates/helpers/format.helper.ts +27 -0
  63. package/templates/helpers/useCopy.ts +13 -0
  64. package/templates/providers/ReactQueryClientProvider.tsx +28 -0
  65. package/templates/providers/TrustlessWork.tsx +30 -0
  66. package/templates/tanstak/useEscrowsByRoleQuery.ts +87 -0
  67. package/templates/tanstak/useEscrowsBySignerQuery.ts +78 -0
  68. package/templates/tanstak/useEscrowsMutations.ts +411 -0
  69. package/templates/wallet-kit/WalletButtons.tsx +116 -0
  70. package/templates/wallet-kit/WalletProvider.tsx +94 -0
  71. package/templates/wallet-kit/trustlines.ts +40 -0
  72. package/templates/wallet-kit/useWallet.ts +77 -0
  73. package/templates/wallet-kit/validators.ts +12 -0
  74. package/templates/wallet-kit/wallet-kit.ts +30 -0
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@trustless-work/blocks",
3
+ "version": "0.0.1",
4
+ "author": "Trustless Work",
5
+ "keywords": [
6
+ "react",
7
+ "hooks",
8
+ "trustless work",
9
+ "escrow",
10
+ "api",
11
+ "blocks",
12
+ "ui",
13
+ "components",
14
+ "helpers",
15
+ "templates",
16
+ "blockchain"
17
+ ],
18
+ "bin": {
19
+ "trustless-work": "bin/index.js"
20
+ },
21
+ "scripts": {
22
+ "test": "echo \"Error: no test specified\" && exit 1",
23
+ "build": "node -e \"console.log('Skipping build: no src to bundle')\"",
24
+ "prepublishOnly": "npm run build"
25
+ },
26
+ "description": "",
27
+ "type": "module",
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/Trustless-Work/react-library-trustless-work-blocks.git"
34
+ },
35
+ "files": [
36
+ "bin",
37
+ "templates",
38
+ "README.md"
39
+ ],
40
+ "license": "MIT",
41
+ "engines": {
42
+ "node": ">=18.17"
43
+ }
44
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "dependencies": {
3
+ "react": "^18.2.0",
4
+ "react-dom": "^18.2.0",
5
+ "react-hook-form": "^7.53.0",
6
+ "zod": "^3.23.8",
7
+ "@trustless-work/escrow": "^2.0.2",
8
+ "@tanstack/react-query": "^5.75.0",
9
+ "@tanstack/react-query-devtools": "^5.75.0",
10
+ "tailwindcss": "^3.3.3",
11
+ "tsup": "^8.3.5",
12
+ "typescript": "^5.6.3",
13
+ "@hookform/resolvers": "^3.10.0",
14
+ "@creit.tech/stellar-wallets-kit": "^1.8.0",
15
+ "axios": "^1.7.9",
16
+ "@tanstack/react-table": "^8.21.3",
17
+ "react-day-picker": "^9.5.0"
18
+ },
19
+ "devDependencies": {
20
+ "postcss": "^8",
21
+ "prettier": "^3.3.3",
22
+ "tailwindcss": "^3.4.1",
23
+ "typescript": "^5",
24
+ "@types/next": "^8.0.7",
25
+ "@types/node": "^20",
26
+ "@types/react": "^18.3.23",
27
+ "@types/react-dom": "^18"
28
+ }
29
+ }
@@ -0,0 +1,149 @@
1
+ import {
2
+ DollarSign,
3
+ CheckCircle,
4
+ CheckSquare,
5
+ AlertTriangle,
6
+ Edit,
7
+ Scale,
8
+ Unlock,
9
+ Wallet,
10
+ Settings,
11
+ Briefcase,
12
+ } from "lucide-react";
13
+ import {
14
+ GetEscrowsFromIndexerResponse as Escrow,
15
+ Role,
16
+ } from "@trustless-work/escrow/types";
17
+ import DisputeEscrowButton from "../../single-release/dispute-escrow/button/DisputeEscrow";
18
+ import ResolveDisputeDialog from "../../single-release/resolve-dispute/dialog/ResolveDispute";
19
+ import ReleaseEscrowButton from "../../single-release/release-escrow/button/ReleaseEscrow";
20
+ import FundEscrowDialog from "../../single-release/fund-escrow/dialog/FundEscrow";
21
+ import UpdateEscrowDialog from "../../single-release/update-escrow/dialog/UpdateEscrow";
22
+
23
+ interface ActionsProps {
24
+ selectedEscrow: Escrow;
25
+ userRolesInEscrow: string[];
26
+ areAllMilestonesApproved: boolean;
27
+ activeRole: Role[];
28
+ }
29
+
30
+ export const roleActions: {
31
+ role: Role;
32
+ actions: string[];
33
+ icon: React.ReactNode;
34
+ color: string;
35
+ }[] = [
36
+ {
37
+ role: "signer",
38
+ actions: ["fundEscrow"],
39
+ icon: <Wallet className="h-6 w-6 text-primary" />,
40
+ color: "",
41
+ },
42
+ {
43
+ role: "approver",
44
+ actions: ["fundEscrow", "approveMilestone", "startDispute"],
45
+ icon: <CheckCircle className="h-6 w-6 text-primary" />,
46
+ color: "0",
47
+ },
48
+ {
49
+ role: "serviceProvider",
50
+ actions: ["fundEscrow", "completeMilestone", "startDispute"],
51
+ icon: <Briefcase className="h-6 w-6 text-primary" />,
52
+ color: "0",
53
+ },
54
+ {
55
+ role: "disputeResolver",
56
+ actions: ["fundEscrow", "resolveDispute"],
57
+ icon: <Scale className="h-6 w-6 text-primary" />,
58
+ color: "00",
59
+ },
60
+ {
61
+ role: "releaseSigner",
62
+ actions: ["fundEscrow", "releasePayment"],
63
+ icon: <Unlock className="h-6 w-6 text-primary" />,
64
+ color: "",
65
+ },
66
+ {
67
+ role: "platformAddress",
68
+ actions: ["fundEscrow", "editEscrow"],
69
+ icon: <Settings className="h-6 w-6 text-primary" />,
70
+ color: "0",
71
+ },
72
+ {
73
+ role: "receiver",
74
+ actions: ["fundEscrow"],
75
+ icon: <DollarSign className="h-6 w-6 text-primary" />,
76
+ color: "",
77
+ },
78
+ ];
79
+
80
+ export const actionIcons: Record<string, React.ReactNode> = {
81
+ fundEscrow: <DollarSign className="h-6 w-6 text-primary/60" />,
82
+ approveMilestone: <CheckCircle className="h-6 w-6 text-primary/60" />,
83
+ completeMilestone: <CheckSquare className="h-6 w-6 text-primary/60" />,
84
+ startDispute: <AlertTriangle className="h-6 w-6 text-primary/60" />,
85
+ resolveDispute: <Scale className="h-6 w-6 text-primary/60" />,
86
+ releasePayment: <Unlock className="h-6 w-6 text-primary/60" />,
87
+ editEscrow: <Edit className="h-6 w-6 text-primary/60" />,
88
+ };
89
+
90
+ export const Actions = ({
91
+ selectedEscrow,
92
+ userRolesInEscrow,
93
+ areAllMilestonesApproved,
94
+ activeRole,
95
+ }: ActionsProps) => {
96
+ const shouldShowEditButton =
97
+ userRolesInEscrow.includes("platformAddress") &&
98
+ !selectedEscrow?.flags?.disputed &&
99
+ !selectedEscrow?.flags?.resolved &&
100
+ !selectedEscrow?.flags?.released &&
101
+ activeRole.includes("platformAddress");
102
+
103
+ const shouldShowDisputeButton =
104
+ selectedEscrow.type === "single-release" &&
105
+ (userRolesInEscrow.includes("approver") ||
106
+ userRolesInEscrow.includes("serviceProvider")) &&
107
+ (activeRole.includes("approver") ||
108
+ activeRole.includes("serviceProvider")) &&
109
+ !selectedEscrow?.flags?.disputed &&
110
+ !selectedEscrow?.flags?.resolved;
111
+
112
+ const shouldShowResolveButton =
113
+ selectedEscrow.type === "single-release" &&
114
+ userRolesInEscrow.includes("disputeResolver") &&
115
+ activeRole.includes("disputeResolver") &&
116
+ !selectedEscrow?.flags?.resolved &&
117
+ selectedEscrow?.flags?.disputed;
118
+
119
+ const shouldShowReleaseFundsButton =
120
+ selectedEscrow.type === "single-release" &&
121
+ areAllMilestonesApproved &&
122
+ userRolesInEscrow.includes("releaseSigner") &&
123
+ !selectedEscrow.flags?.released &&
124
+ activeRole.includes("releaseSigner");
125
+
126
+ const hasConditionalButtons =
127
+ shouldShowEditButton ||
128
+ shouldShowDisputeButton ||
129
+ shouldShowResolveButton ||
130
+ shouldShowReleaseFundsButton;
131
+
132
+ return (
133
+ <div className="flex items-start justify-start flex-col gap-2 w-full">
134
+ {hasConditionalButtons && (
135
+ <div className="flex flex-col sm:flex-row gap-2 w-full">
136
+ {shouldShowEditButton && <UpdateEscrowDialog />}
137
+
138
+ {shouldShowDisputeButton && <DisputeEscrowButton />}
139
+
140
+ {shouldShowResolveButton && <ResolveDisputeDialog />}
141
+
142
+ {shouldShowReleaseFundsButton && <ReleaseEscrowButton />}
143
+ </div>
144
+ )}
145
+
146
+ <FundEscrowDialog />
147
+ </div>
148
+ );
149
+ };
@@ -0,0 +1,48 @@
1
+ "use client";
2
+
3
+ import { GetEscrowsFromIndexerResponse as Escrow } from "@trustless-work/escrow/types";
4
+ import EntityCard from "./EntityCard";
5
+
6
+ interface EntitiesProps {
7
+ selectedEscrow: Escrow;
8
+ }
9
+
10
+ export const Entities = ({ selectedEscrow }: EntitiesProps) => {
11
+ return (
12
+ <>
13
+ <div className="flex justify-between items-center mb-6">
14
+ <div className="flex items-center gap-2">
15
+ <h3 className="text-lg font-semibold">Entities</h3>
16
+ </div>
17
+ </div>
18
+
19
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
20
+ <EntityCard
21
+ type="approver"
22
+ entity={selectedEscrow.roles?.approver}
23
+ inDispute={selectedEscrow.flags?.disputed}
24
+ />
25
+ <EntityCard
26
+ type="serviceProvider"
27
+ entity={selectedEscrow.roles?.serviceProvider}
28
+ inDispute={selectedEscrow.flags?.disputed}
29
+ />
30
+ <EntityCard
31
+ type="disputeResolver"
32
+ entity={selectedEscrow.roles?.disputeResolver}
33
+ />
34
+ <EntityCard
35
+ type="platformAddress"
36
+ entity={selectedEscrow.roles?.platformAddress}
37
+ hasPercentage
38
+ percentage={selectedEscrow.platformFee}
39
+ />
40
+ <EntityCard
41
+ type="releaseSigner"
42
+ entity={selectedEscrow.roles?.releaseSigner}
43
+ />
44
+ <EntityCard type="receiver" entity={selectedEscrow.roles?.receiver} />
45
+ </div>
46
+ </>
47
+ );
48
+ };
@@ -0,0 +1,98 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { Avatar, AvatarFallback } from "__UI_BASE__/avatar";
5
+ import { Card, CardContent } from "__UI_BASE__/card";
6
+ import { Badge } from "__UI_BASE__/badge";
7
+ import { Separator } from "__UI_BASE__/separator";
8
+ import Link from "next/link";
9
+ import {
10
+ formatAddress,
11
+ formatRole,
12
+ } from "@/components/tw-blocks/helpers/format.helper";
13
+
14
+ interface EntityCardProps {
15
+ entity?: string;
16
+ type: string;
17
+ hasPercentage?: boolean;
18
+ percentage?: number;
19
+ hasAmount?: boolean;
20
+ amount?: number;
21
+ currency?: string;
22
+ inDispute?: boolean;
23
+ }
24
+
25
+ const EntityCard = ({
26
+ entity,
27
+ type,
28
+ hasPercentage,
29
+ percentage,
30
+ hasAmount,
31
+ amount,
32
+ currency,
33
+ inDispute,
34
+ }: EntityCardProps) => {
35
+ return (
36
+ <Card className="w-full overflow-hidden transition-all duration-200 hover:shadow-md py-2">
37
+ <Link href={`/dashboard/public-profile/${entity}`} target="_blank">
38
+ <CardContent className="p-3">
39
+ <div className="flex items-center justify-between mb-2">
40
+ <div className="flex w-2/4 items-center justify-between gap-2">
41
+ <span className="text-xs font-medium text-muted-foreground">
42
+ {formatRole(type)}
43
+ </span>
44
+ {inDispute && <Badge variant="destructive">In Dispute</Badge>}
45
+ </div>
46
+
47
+ <div className="flex w-2/4 items-center justify-end gap-2 text-xs">
48
+ {hasPercentage && (
49
+ <div className="flex items-center">
50
+ <span className="text-muted-foreground mr-1">Fee:</span>
51
+ <span className="font-medium text-emerald-600">
52
+ {percentage}%
53
+ </span>
54
+ </div>
55
+ )}
56
+ {hasAmount && (
57
+ <div className="flex items-center">
58
+ <span className="text-muted-foreground mr-1">Amount:</span>
59
+ <span className="font-medium">
60
+ {currency ? `${currency} ` : ""}
61
+ {typeof amount === "number" ? amount.toFixed(2) : "-"}
62
+ </span>
63
+ </div>
64
+ )}
65
+ </div>
66
+ </div>
67
+
68
+ <Separator className="my-2" />
69
+
70
+ <div className="flex items-center gap-3 py-1">
71
+ <Avatar className="h-9 w-9 rounded-md border">
72
+ <AvatarFallback className="rounded-md bg-background text-foreground">
73
+ {entity?.[0] || "?"}
74
+ </AvatarFallback>
75
+ </Avatar>
76
+
77
+ <div className="flex flex-col">
78
+ {entity && (
79
+ <span className="text-sm font-medium leading-tight">
80
+ {formatAddress(entity)}
81
+ </span>
82
+ )}
83
+ {entity && (
84
+ <span className="text-xs text-muted-foreground">
85
+ {type === "Trustless Work"
86
+ ? "Private"
87
+ : formatAddress(entity)}
88
+ </span>
89
+ )}
90
+ </div>
91
+ </div>
92
+ </CardContent>
93
+ </Link>
94
+ </Card>
95
+ );
96
+ };
97
+
98
+ export default EntityCard;
@@ -0,0 +1,154 @@
1
+ "use client";
2
+
3
+ import React, { useState } from "react";
4
+ import {
5
+ Dialog,
6
+ DialogContent,
7
+ DialogDescription,
8
+ DialogHeader,
9
+ DialogTitle,
10
+ } from "__UI_BASE__/dialog";
11
+ import useEscrowDetailDialog from "./useDetailsEscrow";
12
+ import Link from "next/link";
13
+ import { Card } from "__UI_BASE__/card";
14
+ import { Info, Users, ListChecks } from "lucide-react";
15
+ import { useEscrowDialogs } from "../../escrow-context/EscrowDialogsProvider";
16
+ import type {
17
+ GetEscrowsFromIndexerResponse as Escrow,
18
+ Role,
19
+ } from "@trustless-work/escrow/types";
20
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "__UI_BASE__/tabs";
21
+ import { Milestones } from "./Milestones";
22
+ import { Entities } from "./Entities";
23
+ import { GeneralInformation } from "./GeneralInformation";
24
+ import { useEscrowContext } from "../../escrow-context/EscrowProvider";
25
+ import SuccessReleaseDialog from "./SuccessReleaseDialog";
26
+
27
+ interface EscrowDetailDialogProps {
28
+ isDialogOpen: boolean;
29
+ activeRole: Role[];
30
+ setIsDialogOpen: (value: boolean) => void;
31
+ setSelectedEscrow: (selectedEscrow?: Escrow) => void;
32
+ }
33
+
34
+ const EscrowDetailDialog = ({
35
+ isDialogOpen,
36
+ setIsDialogOpen,
37
+ setSelectedEscrow,
38
+ activeRole,
39
+ }: EscrowDetailDialogProps) => {
40
+ const { selectedEscrow } = useEscrowContext();
41
+ const dialogStates = useEscrowDialogs();
42
+ const [activeTab, setActiveTab] = useState("general");
43
+
44
+ const {
45
+ handleClose,
46
+ setEvidenceVisibleMap,
47
+ evidenceVisibleMap,
48
+ areAllMilestonesApproved,
49
+ userRolesInEscrow,
50
+ } = useEscrowDetailDialog({
51
+ setIsDialogOpen,
52
+ setSelectedEscrow,
53
+ selectedEscrow,
54
+ });
55
+
56
+ const stellarExplorerUrl = `https://stellar.expert/explorer/testnet/contract/${selectedEscrow?.contractId}`;
57
+
58
+ if (!isDialogOpen || !selectedEscrow) return null;
59
+ return (
60
+ <>
61
+ <Dialog open={isDialogOpen} onOpenChange={handleClose}>
62
+ <DialogContent className="w-11/12 sm:w-3/4 h-[95vh] overflow-hidden flex flex-col !max-w-none">
63
+ <DialogHeader className="flex-shrink-0">
64
+ <div className="w-full">
65
+ <div className="flex flex-col gap-2">
66
+ <div className="w-full">
67
+ <Link
68
+ href={stellarExplorerUrl}
69
+ target="_blank"
70
+ className="hover:underline"
71
+ >
72
+ <DialogTitle className="text-xl">
73
+ {selectedEscrow.title}
74
+ </DialogTitle>
75
+ </Link>
76
+ </div>
77
+
78
+ <DialogDescription>
79
+ {selectedEscrow.description}
80
+ </DialogDescription>
81
+ </div>
82
+ </div>
83
+ </DialogHeader>
84
+
85
+ <Tabs
86
+ defaultValue="general"
87
+ className="w-full"
88
+ value={activeTab}
89
+ onValueChange={setActiveTab}
90
+ >
91
+ <TabsList className="grid w-full grid-cols-3 mb-6 bg-muted/50">
92
+ <TabsTrigger
93
+ value="general"
94
+ className="flex items-center gap-2 data-[state=active]:bg-background"
95
+ >
96
+ <Info className="h-4 w-4 hidden md:block" />
97
+ <span>Information</span>
98
+ </TabsTrigger>
99
+ <TabsTrigger
100
+ value="entities"
101
+ className="flex items-center gap-2 data-[state=active]:bg-background"
102
+ >
103
+ <Users className="h-4 w-4 hidden md:block" />
104
+ <span>Entities</span>
105
+ </TabsTrigger>
106
+ <TabsTrigger
107
+ value="milestones"
108
+ className="flex items-center gap-2 data-[state=active]:bg-background"
109
+ >
110
+ <ListChecks className="h-4 w-4 hidden md:block" />
111
+ <span>Milestones</span>
112
+ </TabsTrigger>
113
+ </TabsList>
114
+
115
+ <div className="flex-1 min-h-0">
116
+ <TabsContent value="general" className="mt-4 h-full">
117
+ <GeneralInformation
118
+ activeRole={activeRole}
119
+ selectedEscrow={selectedEscrow}
120
+ userRolesInEscrow={userRolesInEscrow}
121
+ dialogStates={dialogStates}
122
+ areAllMilestonesApproved={areAllMilestonesApproved}
123
+ />
124
+ </TabsContent>
125
+
126
+ <TabsContent value="entities" className="mt-4 h-full">
127
+ <Entities selectedEscrow={selectedEscrow} />
128
+ </TabsContent>
129
+
130
+ <TabsContent value="milestones" className="mt-4 h-full">
131
+ <Card className="p-4 h-full">
132
+ <Milestones
133
+ activeRole={activeRole}
134
+ selectedEscrow={selectedEscrow}
135
+ userRolesInEscrow={userRolesInEscrow}
136
+ setEvidenceVisibleMap={setEvidenceVisibleMap}
137
+ evidenceVisibleMap={evidenceVisibleMap}
138
+ />
139
+ </Card>
140
+ </TabsContent>
141
+ </div>
142
+ </Tabs>
143
+ </DialogContent>
144
+ </Dialog>
145
+
146
+ <SuccessReleaseDialog
147
+ isOpen={dialogStates.successRelease.isOpen}
148
+ onOpenChange={dialogStates.successRelease.setIsOpen}
149
+ />
150
+ </>
151
+ );
152
+ };
153
+
154
+ export default EscrowDetailDialog;