@trustless-work/blocks 0.0.1 → 0.0.3

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 (3) hide show
  1. package/README.md +220 -9
  2. package/bin/index.js +95 -80
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,8 +1,12 @@
1
1
  <p align="center"> <img src="https://github.com/user-attachments/assets/5b182044-dceb-41f5-acf0-da22dea7c98a" alt="CLR-S (2)"> </p>
2
2
 
3
- # Trustless Work <a href="https://www.npmjs.com/package/@trustless-work/escrow" target="_blank">React Library</a> CHANGE IT!
3
+ # Trustless Work <a href="https://www.npmjs.com/package/@trustless-work/blocks" target="_blank">React Library</a>
4
4
 
5
- A powerful React library for integrating Trustless Work's escrow and dispute resolution system into your applications. This library provides a set of React hooks and utilities to interact with the Trustless Work API.
5
+ A production-ready set of React blocks for integrating Trustless Work's escrow and dispute resolution flows. It ships:
6
+ - UI blocks (cards/tables/dialogs/forms) to list and manage escrows
7
+ - Providers for API config, wallet context, dialogs and amounts
8
+ - TanStack Query hooks for fetching and mutating escrows
9
+ - Wallet-kit helpers and error handling utilities
6
10
 
7
11
  ## Installation
8
12
 
@@ -10,20 +14,144 @@ A powerful React library for integrating Trustless Work's escrow and dispute res
10
14
  npm install @trustless-work/blocks
11
15
  # or
12
16
  yarn add @trustless-work/blocks
17
+
18
+ # Then run the CLI to scaffold UI and providers
19
+ npx trustless-work init
13
20
  ```
14
21
 
22
+ What init does:
23
+ - Installs shadcn/ui components (prompted)
24
+ - Installs required deps: @tanstack/react-query, @trustless-work/escrow, axios, zod, react-hook-form, @creit.tech/stellar-wallets-kit, react-day-picker, etc.
25
+ - Creates .twblocks.json with your UI base alias (default: "@/components/ui")
26
+ - Optionally wires providers into Next.js `app/layout.tsx`
27
+
28
+ Environment:
29
+ - Create `NEXT_PUBLIC_API_KEY` in your env. The library uses `TrustlessWorkProvider` with `development` base URL by default.
30
+
31
+ Tutorial at <a href="https://dapp.trustlesswork.com" target="_blank">backoffice's landing</a>
32
+
15
33
  ## Quick Start
16
34
 
17
- 1.
35
+ 1. Initialize
36
+ ```bash
37
+ npx trustless-work init
38
+ ```
39
+
40
+ 2. Add providers (if you skipped wiring during init)
41
+ ```bash
42
+ npx trustless-work add providers
43
+ ```
44
+
45
+ 3. Wrap your Next.js layout
46
+ ```tsx
47
+ // app/layout.tsx
48
+ import { ReactQueryClientProvider } from "@/components/tw-blocks/providers/ReactQueryClientProvider";
49
+ import { TrustlessWorkProvider } from "@/components/tw-blocks/providers/TrustlessWork";
50
+ import { WalletProvider } from "@/components/tw-blocks/wallet-kit/WalletProvider";
51
+ import { EscrowProvider } from "@/components/tw-blocks/escrows/escrow-context/EscrowProvider";
52
+
53
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
54
+ return (
55
+ <html lang="en">
56
+ <body>
57
+ <ReactQueryClientProvider>
58
+ <TrustlessWorkProvider>
59
+ <WalletProvider>
60
+ <EscrowProvider>
61
+ {children}
62
+ </EscrowProvider>
63
+ </WalletProvider>
64
+ </TrustlessWorkProvider>
65
+ </ReactQueryClientProvider>
66
+ </body>
67
+ </html>
68
+ );
69
+ }
70
+ ```
71
+
72
+ 4. Add a wallet button to your header
73
+ ```bash
74
+ npx trustless-work add wallet-kit
75
+ ```
76
+ ```tsx
77
+ // Example usage
78
+ import { WalletButton } from "@/components/tw-blocks/wallet-kit/WalletButtons";
79
+
80
+ export function Header() {
81
+ return (
82
+ <div className="flex justify-end p-4">
83
+ <WalletButton />
84
+ </div>
85
+ );
86
+ }
87
+ ```
88
+
89
+ 5. List escrows quickly
90
+ ```bash
91
+ # By role
92
+ npx trustless-work add escrows/escrows-by-role/cards
93
+ # Or table view
94
+ npx trustless-work add escrows/escrows-by-role/table
95
+ ```
96
+ ```tsx
97
+ // app/escrows/page.tsx
98
+ import { EscrowsByRoleCards } from "@/components/tw-blocks/escrows/escrows-by-role/cards/EscrowsCards";
99
+ import { EscrowDialogsProvider } from "@/components/tw-blocks/escrows/escrow-context/EscrowDialogsProvider";
100
+
101
+ export default function Page() {
102
+ return (
103
+ <EscrowDialogsProvider>
104
+ <EscrowsByRoleCards />
105
+ </EscrowDialogsProvider>
106
+ );
107
+ }
108
+ ```
18
109
 
19
110
  ## State Management Integration
20
111
 
21
- This library is designed to be flexible and work with any state management solution. The hooks expose functions that you can integrate with your preferred state management library.
112
+ This library works with any state solution. It exposes React Context providers and TanStack Query hooks. You can also integrate the hooks into Redux/Zustand if needed.
22
113
 
23
114
  ### With TanStack Query (Recommended)
24
115
 
25
116
  ```tsx
117
+ // Fetch escrows by role
118
+ import { useEscrowsByRoleQuery } from "@/components/tw-blocks/tanstak/useEscrowsByRoleQuery";
119
+
120
+ export function MyEscrows({ roleAddress }: { roleAddress: string }) {
121
+ const { data, isLoading, isError, refetch } = useEscrowsByRoleQuery({
122
+ role: "approver",
123
+ roleAddress,
124
+ isActive: true,
125
+ validateOnChain: true,
126
+ page: 1,
127
+ orderBy: "createdAt",
128
+ orderDirection: "desc",
129
+ });
130
+
131
+ if (isLoading) return <p>Loading…</p>;
132
+ if (isError) return <button onClick={() => refetch()}>Retry</button>;
133
+ return <pre>{JSON.stringify(data, null, 2)}</pre>;
134
+ }
135
+
136
+ // Mutations (deploy/fund/update/approve/change-status/release/dispute/resolve)
137
+ import { useEscrowsMutations } from "@/components/tw-blocks/tanstak/useEscrowsMutations";
26
138
 
139
+ export function DeployButton({ address }: { address: string }) {
140
+ const { deployEscrow } = useEscrowsMutations();
141
+ return (
142
+ <button
143
+ onClick={() =>
144
+ deployEscrow.mutate({
145
+ payload: { /* InitializeSingleReleaseEscrowPayload */ },
146
+ type: "single-release",
147
+ address,
148
+ })
149
+ }
150
+ >
151
+ Deploy
152
+ </button>
153
+ );
154
+ }
27
155
  ```
28
156
 
29
157
  ## Available Blocks
@@ -31,18 +159,101 @@ This library is designed to be flexible and work with any state management solut
31
159
  In order to see all of them, just run this script:
32
160
 
33
161
  ```shell
34
- NPM LIST SSSSSSSSSSSSSSSSSSSSSS
162
+
163
+ npx trustless-work list
164
+
165
+ # Scaffold top-level groups
166
+ npx trustless-work add providers
167
+ npx trustless-work add wallet-kit
168
+ npx trustless-work add handle-errors
169
+ npx trustless-work add helpers
170
+ npx trustless-work add tanstak
171
+ npx trustless-work add escrows
172
+
173
+ # Escrow context providers
174
+ npx trustless-work add escrows/escrow-context
175
+
176
+ # Escrows by role
177
+ npx trustless-work add escrows/escrows-by-role
178
+ npx trustless-work add escrows/escrows-by-role/table
179
+ npx trustless-work add escrows/escrows-by-role/cards
180
+
181
+ # Escrows by signer
182
+ npx trustless-work add escrows/escrows-by-signer
183
+ npx trustless-work add escrows/escrows-by-signer/table
184
+ npx trustless-work add escrows/escrows-by-signer/cards
185
+
186
+ # Escrow details (optional standalone)
187
+ npx trustless-work add escrows/details
188
+
189
+ # Single-release flows
190
+ npx trustless-work add escrows/single-release
191
+ npx trustless-work add escrows/single-release/initialize-escrow
192
+ npx trustless-work add escrows/single-release/approve-milestone
193
+ npx trustless-work add escrows/single-release/change-milestone-status
194
+ npx trustless-work add escrows/single-release/fund-escrow
195
+ npx trustless-work add escrows/single-release/release-escrow
196
+ npx trustless-work add escrows/single-release/dispute-escrow
197
+ npx trustless-work add escrows/single-release/resolve-dispute
198
+ npx trustless-work add escrows/single-release/update-escrow
35
199
  ```
36
200
 
37
- ### E
38
- - `useInitializeEscrow`: Create a new escrow
201
+ ### Escrows
202
+ - Cards and tables to browse escrows (by role or by signer) with filters, pagination, and sort
203
+ - Detail dialog with actions gated by roles and escrow flags
204
+ - Dialogs/forms for single-release lifecycle (initialize, fund, approve, change status, release, dispute, resolve, update)
205
+
206
+ Using cards (by role):
207
+ ```tsx
208
+ import { EscrowDialogsProvider } from "@/components/tw-blocks/escrows/escrow-context/EscrowDialogsProvider";
209
+ import { EscrowsByRoleCards } from "@/components/tw-blocks/escrows/escrows-by-role/cards/EscrowsCards";
210
+
211
+ export default function Screen() {
212
+ return (
213
+ <EscrowDialogsProvider>
214
+ <EscrowsByRoleCards />
215
+ </EscrowDialogsProvider>
216
+ );
217
+ }
218
+ ```
39
219
 
40
220
  Make sure to:
41
- 1. U
221
+ 1. Set `NEXT_PUBLIC_API_KEY` and run the app against the correct environment (the provider defaults to `development`).
222
+ 2. Configure your UI base imports. CLI uses `.twblocks.json` `uiBase` to replace `__UI_BASE__`. If your UI alias differs, pass `--ui-base`:
223
+ ```bash
224
+ npx trustless-work add escrows/escrows-by-role/cards --ui-base "@/components/ui"
225
+ ```
226
+ 3. Wrap your app with all providers in the order: `ReactQueryClientProvider` → `TrustlessWorkProvider` → `WalletProvider` → `EscrowProvider`.
42
227
 
43
228
  ## Best Practices
44
229
 
45
- 1.
230
+ 1. Providers
231
+ - `ReactQueryClientProvider`: global query cache and devtools.
232
+ - `TrustlessWorkProvider`: sets API `baseURL` and `apiKey` via `TrustlessWorkConfig` from `@trustless-work/escrow`.
233
+ - `WalletProvider`: minimal wallet state (address/name) persisted in localStorage; used by wallet button and mutations.
234
+ - `EscrowProvider`: holds the currently selected escrow and roles; persisted in localStorage.
235
+ - `EscrowDialogsProvider`: centralizes dialog open/close state for escrow UI.
236
+ - `EscrowAmountProvider`: computes receiver/platform/fee splits for releases.
237
+
238
+ 2. Queries and caching
239
+ - Use provided queries: `useEscrowsByRoleQuery`, `useEscrowsBySignerQuery`.
240
+ - All mutations invalidate `['escrows']` automatically.
241
+
242
+ 3. Error handling
243
+ - Use `handleError(error)` from `handle-errors/handle.ts` to map Axios and wallet errors to normalized types (`ApiErrorTypes`).
244
+ ```ts
245
+ import { handleError } from "@/components/tw-blocks/handle-errors/handle";
246
+ try { /* ... */ } catch (e) { const err = handleError(e as any); /* show toast */ }
247
+ ```
248
+
249
+ 4. Wallet-kit
250
+ - `WalletButton` opens a modal using `@creit.tech/stellar-wallets-kit` and stores address/name in `WalletProvider`.
251
+ - `signTransaction({ unsignedTransaction, address })` signs and returns XDR used by mutations.
252
+ - `trustlines` and `trustlineOptions` include common assets for testnet/mainnet.
253
+
254
+ 5. Env and network
255
+ - Use `development` (default) or `mainNet` from `@trustless-work/escrow` in `TrustlessWorkProvider`.
256
+ - Keep your API key in env and never commit it.
46
257
 
47
258
  ## Contributing
48
259
 
package/bin/index.js CHANGED
@@ -682,60 +682,49 @@ function copySharedDetailsInto(targetRelativeDir, { uiBase } = {}) {
682
682
  }
683
683
  }
684
684
 
685
- function copySharedRoleSignerHooks() {
686
- const srcDir = path.join(TEMPLATES_DIR, "tanstak");
685
+ function copySharedRoleSignerHooks(kind = "both") {
687
686
  const outRoot = path.join(PROJECT_ROOT, "src", "components", "tw-blocks");
688
687
 
689
- const files = [
690
- {
691
- shared: "useEscrowsByRole.shared.ts",
692
- targets: [
693
- path.join(
694
- outRoot,
695
- "escrows",
696
- "escrows-by-role",
697
- "cards",
698
- "useEsrowsByRole.ts"
699
- ),
700
- path.join(
701
- outRoot,
702
- "escrows",
703
- "escrows-by-role",
704
- "table",
705
- "useEsrowsByRole.ts"
706
- ),
707
- ],
708
- },
709
- {
710
- shared: "useEscrowsBySigner.shared.ts",
711
- targets: [
712
- path.join(
713
- outRoot,
714
- "escrows",
715
- "escrows-by-signer",
716
- "cards",
717
- "useEsrowsBySigner.ts"
718
- ),
719
- path.join(
720
- outRoot,
721
- "escrows",
722
- "escrows-by-signer",
723
- "table",
724
- "useEsrowsBySigner.ts"
725
- ),
726
- ],
727
- },
728
- ];
688
+ const mappings = [];
689
+ if (kind === "both" || kind === "role") {
690
+ mappings.push({
691
+ src: path.join(
692
+ TEMPLATES_DIR,
693
+ "escrows",
694
+ "escrows-by-role",
695
+ "useEscrowsByRole.shared.ts"
696
+ ),
697
+ dest: path.join(
698
+ outRoot,
699
+ "escrows",
700
+ "escrows-by-role",
701
+ "useEscrowsByRole.shared.ts"
702
+ ),
703
+ });
704
+ }
705
+ if (kind === "both" || kind === "signer") {
706
+ mappings.push({
707
+ src: path.join(
708
+ TEMPLATES_DIR,
709
+ "escrows",
710
+ "escrows-by-signer",
711
+ "useEscrowsBySigner.shared.ts"
712
+ ),
713
+ dest: path.join(
714
+ outRoot,
715
+ "escrows",
716
+ "escrows-by-signer",
717
+ "useEscrowsBySigner.shared.ts"
718
+ ),
719
+ });
720
+ }
729
721
 
730
- for (const group of files) {
731
- const src = path.join(srcDir, group.shared);
722
+ for (const { src, dest } of mappings) {
732
723
  if (!fs.existsSync(src)) continue;
733
724
  const raw = fs.readFileSync(src, "utf8");
734
- for (const dest of group.targets) {
735
- fs.mkdirSync(path.dirname(dest), { recursive: true });
736
- fs.writeFileSync(dest, raw, "utf8");
737
- console.log(`✅ ${path.relative(PROJECT_ROOT, dest)} created`);
738
- }
725
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
726
+ fs.writeFileSync(dest, raw, "utf8");
727
+ console.log(`✅ ${path.relative(PROJECT_ROOT, dest)} created`);
739
728
  }
740
729
  }
741
730
 
@@ -1025,7 +1014,7 @@ if (args[0] === "init") {
1025
1014
  copySharedDetailsInto("escrows/escrows-by-signer/details", {
1026
1015
  uiBase: flags.uiBase,
1027
1016
  });
1028
- copySharedRoleSignerHooks();
1017
+ copySharedRoleSignerHooks("both");
1029
1018
  }
1030
1019
  if (
1031
1020
  args[1] === "escrows/escrows-by-role" ||
@@ -1034,7 +1023,7 @@ if (args[0] === "init") {
1034
1023
  copySharedDetailsInto("escrows/escrows-by-role/details", {
1035
1024
  uiBase: flags.uiBase,
1036
1025
  });
1037
- copySharedRoleSignerHooks();
1026
+ copySharedRoleSignerHooks("role");
1038
1027
  }
1039
1028
  if (
1040
1029
  args[1] === "escrows/escrows-by-signer" ||
@@ -1043,7 +1032,7 @@ if (args[0] === "init") {
1043
1032
  copySharedDetailsInto("escrows/escrows-by-signer/details", {
1044
1033
  uiBase: flags.uiBase,
1045
1034
  });
1046
- copySharedRoleSignerHooks();
1035
+ copySharedRoleSignerHooks("signer");
1047
1036
  }
1048
1037
  } catch (e) {
1049
1038
  console.warn("⚠️ Failed to copy shared details:", e?.message || e);
@@ -1052,72 +1041,98 @@ if (args[0] === "init") {
1052
1041
  console.log(`
1053
1042
 
1054
1043
  Usage:
1055
-
1044
+
1056
1045
  trustless-work init
1057
1046
  trustless-work add <template> [--install]
1058
1047
 
1059
1048
  Options:
1060
-
1049
+
1061
1050
  --ui-base <path> Base import path to your shadcn/ui components (default: "@/components/ui")
1062
1051
  --install, -i Also install dependencies (normally use 'init' once instead)
1063
-
1052
+
1064
1053
  Examples:
1065
-
1054
+
1066
1055
  --- Get started ---
1067
1056
  trustless-work init
1068
-
1057
+
1069
1058
  --- Providers ---
1070
1059
  trustless-work add providers
1071
-
1060
+
1072
1061
  --- Wallet-kit ---
1073
1062
  trustless-work add wallet-kit
1074
-
1063
+
1075
1064
  --- Handle-errors ---
1076
1065
  trustless-work add handle-errors
1077
-
1066
+
1067
+ --- Helpers ---
1068
+ trustless-work add helpers
1069
+
1078
1070
  --- Tanstack ---
1079
1071
  trustless-work add tanstak
1080
-
1072
+
1081
1073
  --- Escrows ---
1082
1074
  trustless-work add escrows
1083
-
1075
+
1084
1076
  --- Escrow context ---
1085
1077
  trustless-work add escrows/escrow-context
1086
-
1078
+
1087
1079
  --- Escrows by role ---
1088
1080
  trustless-work add escrows/escrows-by-role
1089
1081
  trustless-work add escrows/escrows-by-role/table
1090
1082
  trustless-work add escrows/escrows-by-role/cards
1091
-
1083
+
1092
1084
  --- Escrows by signer ---
1093
1085
  trustless-work add escrows/escrows-by-signer
1094
1086
  trustless-work add escrows/escrows-by-signer/table
1095
1087
  trustless-work add escrows/escrows-by-signer/cards
1096
-
1088
+
1089
+ --- Escrow details (optional standalone) ---
1090
+ trustless-work add escrows/details
1091
+
1097
1092
  ----------------------
1098
1093
  --- SINGLE-RELEASE ---
1099
1094
  trustless-work add escrows/single-release
1100
-
1095
+
1101
1096
  --- Initialize escrow ---
1102
1097
  - trustless-work add escrows/single-release/initialize-escrow
1103
-
1098
+ - trustless-work add escrows/single-release/initialize-escrow/form
1099
+ - trustless-work add escrows/single-release/initialize-escrow/dialog
1100
+
1101
+ --- Approve milestone ---
1102
+ - trustless-work add escrows/single-release/approve-milestone
1103
+ - trustless-work add escrows/single-release/approve-milestone/form
1104
+ - trustless-work add escrows/single-release/approve-milestone/button
1105
+ - trustless-work add escrows/single-release/approve-milestone/dialog
1106
+
1107
+ --- Change milestone status ---
1108
+ - trustless-work add escrows/single-release/change-milestone-status
1109
+ - trustless-work add escrows/single-release/change-milestone-status/form
1110
+ - trustless-work add escrows/single-release/change-milestone-status/button
1111
+ - trustless-work add escrows/single-release/change-milestone-status/dialog
1112
+
1104
1113
  --- Fund escrow ---
1105
1114
  - trustless-work add escrows/single-release/fund-escrow
1106
1115
  - trustless-work add escrows/single-release/fund-escrow/form
1107
1116
  - trustless-work add escrows/single-release/fund-escrow/button
1108
1117
  - trustless-work add escrows/single-release/fund-escrow/dialog
1109
-
1110
- ---------------------
1111
- --- MULTI-RELEASE ---
1112
- trustless-work add escrows/multi-release
1113
1118
 
1114
- --- Initialize escrow ---
1115
- - trustless-work add escrows/multi-release/initialize-escrow
1116
-
1117
- --- Fund escrow ---
1118
- - trustless-work add escrows/multi-release/fund-escrow
1119
- - trustless-work add escrows/multi-release/fund-escrow/form
1120
- - trustless-work add escrows/multi-release/fund-escrow/button
1121
- - trustless-work add escrows/multi-release/fund-escrow/dialog
1122
- `);
1119
+ --- Resolve dispute ---
1120
+ - trustless-work add escrows/single-release/resolve-dispute
1121
+ - trustless-work add escrows/single-release/resolve-dispute/form
1122
+ - trustless-work add escrows/single-release/resolve-dispute/button
1123
+ - trustless-work add escrows/single-release/resolve-dispute/dialog
1124
+
1125
+ --- Update escrow ---
1126
+ - trustless-work add escrows/single-release/update-escrow
1127
+ - trustless-work add escrows/single-release/update-escrow/form
1128
+ - trustless-work add escrows/single-release/update-escrow/dialog
1129
+
1130
+ --- Release escrow ---
1131
+ - trustless-work add escrows/single-release/release-escrow
1132
+ - trustless-work add escrows/single-release/release-escrow/button
1133
+
1134
+ --- Dispute escrow ---
1135
+ - trustless-work add escrows/single-release/dispute-escrow
1136
+ - trustless-work add escrows/single-release/dispute-escrow/button
1137
+ `);
1123
1138
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trustless-work/blocks",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "author": "Trustless Work",
5
5
  "keywords": [
6
6
  "react",