|
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 |
|
9 | 13 | ```bash |
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 | + |
15 | 31 | ## Quick Start |
16 | 32 |
|
17 | | -1. |
| 33 | +1. Initialize |
| 34 | +```bash |
| 35 | +npx trustless-work init |
| 36 | +``` |
| 37 | + |
| 38 | +2. Add providers (if you skipped wiring during init) |
| 39 | +```bash |
| 40 | +npx trustless-work add providers |
| 41 | +``` |
| 42 | + |
| 43 | +3. Wrap your Next.js layout |
| 44 | +```tsx |
| 45 | +// app/layout.tsx |
| 46 | +import { ReactQueryClientProvider } from "@/components/tw-blocks/providers/ReactQueryClientProvider"; |
| 47 | +import { TrustlessWorkProvider } from "@/components/tw-blocks/providers/TrustlessWork"; |
| 48 | +import { WalletProvider } from "@/components/tw-blocks/wallet-kit/WalletProvider"; |
| 49 | +import { EscrowProvider } from "@/components/tw-blocks/escrows/escrow-context/EscrowProvider"; |
| 50 | + |
| 51 | +export default function RootLayout({ children }: { children: React.ReactNode }) { |
| 52 | + return ( |
| 53 | + <html lang="en"> |
| 54 | + <body> |
| 55 | + <ReactQueryClientProvider> |
| 56 | + <TrustlessWorkProvider> |
| 57 | + <WalletProvider> |
| 58 | + <EscrowProvider> |
| 59 | + {children} |
| 60 | + </EscrowProvider> |
| 61 | + </WalletProvider> |
| 62 | + </TrustlessWorkProvider> |
| 63 | + </ReactQueryClientProvider> |
| 64 | + </body> |
| 65 | + </html> |
| 66 | + ); |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +4. Add a wallet button to your header |
| 71 | +```bash |
| 72 | +npx trustless-work add wallet-kit |
| 73 | +``` |
| 74 | +```tsx |
| 75 | +// Example usage |
| 76 | +import { WalletButton } from "@/components/tw-blocks/wallet-kit/WalletButtons"; |
| 77 | + |
| 78 | +export function Header() { |
| 79 | + return ( |
| 80 | + <div className="flex justify-end p-4"> |
| 81 | + <WalletButton /> |
| 82 | + </div> |
| 83 | + ); |
| 84 | +} |
| 85 | +``` |
| 86 | + |
| 87 | +5. List escrows quickly |
| 88 | +```bash |
| 89 | +# By role |
| 90 | +npx trustless-work add escrows/escrows-by-role/cards |
| 91 | +# Or table view |
| 92 | +npx trustless-work add escrows/escrows-by-role/table |
| 93 | +``` |
| 94 | +```tsx |
| 95 | +// app/escrows/page.tsx |
| 96 | +import { EscrowsByRoleCards } from "@/components/tw-blocks/escrows/escrows-by-role/cards/EscrowsCards"; |
| 97 | +import { EscrowDialogsProvider } from "@/components/tw-blocks/escrows/escrow-context/EscrowDialogsProvider"; |
| 98 | + |
| 99 | +export default function Page() { |
| 100 | + return ( |
| 101 | + <EscrowDialogsProvider> |
| 102 | + <EscrowsByRoleCards /> |
| 103 | + </EscrowDialogsProvider> |
| 104 | + ); |
| 105 | +} |
| 106 | +``` |
18 | 107 |
|
19 | 108 | ## State Management Integration |
20 | 109 |
|
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. |
| 110 | +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 | 111 |
|
23 | 112 | ### With TanStack Query (Recommended) |
24 | 113 |
|
25 | 114 | ```tsx |
| 115 | +// Fetch escrows by role |
| 116 | +import { useEscrowsByRoleQuery } from "@/components/tw-blocks/tanstak/useEscrowsByRoleQuery"; |
| 117 | + |
| 118 | +export function MyEscrows({ roleAddress }: { roleAddress: string }) { |
| 119 | + const { data, isLoading, isError, refetch } = useEscrowsByRoleQuery({ |
| 120 | + role: "approver", |
| 121 | + roleAddress, |
| 122 | + isActive: true, |
| 123 | + validateOnChain: true, |
| 124 | + page: 1, |
| 125 | + orderBy: "createdAt", |
| 126 | + orderDirection: "desc", |
| 127 | + }); |
26 | 128 |
|
| 129 | + if (isLoading) return <p>Loading…</p>; |
| 130 | + if (isError) return <button onClick={() => refetch()}>Retry</button>; |
| 131 | + return <pre>{JSON.stringify(data, null, 2)}</pre>; |
| 132 | +} |
| 133 | + |
| 134 | +// Mutations (deploy/fund/update/approve/change-status/release/dispute/resolve) |
| 135 | +import { useEscrowsMutations } from "@/components/tw-blocks/tanstak/useEscrowsMutations"; |
| 136 | + |
| 137 | +export function DeployButton({ address }: { address: string }) { |
| 138 | + const { deployEscrow } = useEscrowsMutations(); |
| 139 | + return ( |
| 140 | + <button |
| 141 | + onClick={() => |
| 142 | + deployEscrow.mutate({ |
| 143 | + payload: { /* InitializeSingleReleaseEscrowPayload */ }, |
| 144 | + type: "single-release", |
| 145 | + address, |
| 146 | + }) |
| 147 | + } |
| 148 | + > |
| 149 | + Deploy |
| 150 | + </button> |
| 151 | + ); |
| 152 | +} |
27 | 153 | ``` |
28 | 154 |
|
29 | 155 | ## Available Blocks |
30 | 156 |
|
31 | 157 | In order to see all of them, just run this script: |
32 | 158 |
|
33 | 159 | ```shell |
34 | | -NPM LIST SSSSSSSSSSSSSSSSSSSSSS |
| 160 | +# Scaffold top-level groups |
| 161 | +npx trustless-work add providers |
| 162 | +npx trustless-work add wallet-kit |
| 163 | +npx trustless-work add handle-errors |
| 164 | +npx trustless-work add helpers |
| 165 | +npx trustless-work add tanstak |
| 166 | +npx trustless-work add escrows |
| 167 | + |
| 168 | +# Escrow context providers |
| 169 | +npx trustless-work add escrows/escrow-context |
| 170 | + |
| 171 | +# Escrows by role |
| 172 | +npx trustless-work add escrows/escrows-by-role |
| 173 | +npx trustless-work add escrows/escrows-by-role/table |
| 174 | +npx trustless-work add escrows/escrows-by-role/cards |
| 175 | + |
| 176 | +# Escrows by signer |
| 177 | +npx trustless-work add escrows/escrows-by-signer |
| 178 | +npx trustless-work add escrows/escrows-by-signer/table |
| 179 | +npx trustless-work add escrows/escrows-by-signer/cards |
| 180 | + |
| 181 | +# Escrow details (optional standalone) |
| 182 | +npx trustless-work add escrows/details |
| 183 | + |
| 184 | +# Single-release flows |
| 185 | +npx trustless-work add escrows/single-release |
| 186 | +npx trustless-work add escrows/single-release/initialize-escrow |
| 187 | +npx trustless-work add escrows/single-release/approve-milestone |
| 188 | +npx trustless-work add escrows/single-release/change-milestone-status |
| 189 | +npx trustless-work add escrows/single-release/fund-escrow |
| 190 | +npx trustless-work add escrows/single-release/release-escrow |
| 191 | +npx trustless-work add escrows/single-release/dispute-escrow |
| 192 | +npx trustless-work add escrows/single-release/resolve-dispute |
| 193 | +npx trustless-work add escrows/single-release/update-escrow |
35 | 194 | ``` |
36 | 195 |
|
37 | | -### E |
38 | | -- `useInitializeEscrow`: Create a new escrow |
| 196 | +### Escrows |
| 197 | +- Cards and tables to browse escrows (by role or by signer) with filters, pagination, and sort |
| 198 | +- Detail dialog with actions gated by roles and escrow flags |
| 199 | +- Dialogs/forms for single-release lifecycle (initialize, fund, approve, change status, release, dispute, resolve, update) |
| 200 | + |
| 201 | +Using cards (by role): |
| 202 | +```tsx |
| 203 | +import { EscrowDialogsProvider } from "@/components/tw-blocks/escrows/escrow-context/EscrowDialogsProvider"; |
| 204 | +import { EscrowsByRoleCards } from "@/components/tw-blocks/escrows/escrows-by-role/cards/EscrowsCards"; |
| 205 | + |
| 206 | +export default function Screen() { |
| 207 | + return ( |
| 208 | + <EscrowDialogsProvider> |
| 209 | + <EscrowsByRoleCards /> |
| 210 | + </EscrowDialogsProvider> |
| 211 | + ); |
| 212 | +} |
| 213 | +``` |
39 | 214 |
|
40 | 215 | Make sure to: |
41 | | -1. U |
| 216 | +1. Set `NEXT_PUBLIC_API_KEY` and run the app against the correct environment (the provider defaults to `development`). |
| 217 | +2. Configure your UI base imports. CLI uses `.twblocks.json` `uiBase` to replace `__UI_BASE__`. If your UI alias differs, pass `--ui-base`: |
| 218 | + ```bash |
| 219 | + npx trustless-work add escrows/escrows-by-role/cards --ui-base "@/components/ui" |
| 220 | + ``` |
| 221 | +3. Wrap your app with all providers in the order: `ReactQueryClientProvider` → `TrustlessWorkProvider` → `WalletProvider` → `EscrowProvider`. |
42 | 222 |
|
43 | 223 | ## Best Practices |
44 | 224 |
|
45 | | -1. |
| 225 | +1. Providers |
| 226 | + - `ReactQueryClientProvider`: global query cache and devtools. |
| 227 | + - `TrustlessWorkProvider`: sets API `baseURL` and `apiKey` via `TrustlessWorkConfig` from `@trustless-work/escrow`. |
| 228 | + - `WalletProvider`: minimal wallet state (address/name) persisted in localStorage; used by wallet button and mutations. |
| 229 | + - `EscrowProvider`: holds the currently selected escrow and roles; persisted in localStorage. |
| 230 | + - `EscrowDialogsProvider`: centralizes dialog open/close state for escrow UI. |
| 231 | + - `EscrowAmountProvider`: computes receiver/platform/fee splits for releases. |
| 232 | + |
| 233 | +2. Queries and caching |
| 234 | + - Use provided queries: `useEscrowsByRoleQuery`, `useEscrowsBySignerQuery`. |
| 235 | + - All mutations invalidate `['escrows']` automatically. |
| 236 | + |
| 237 | +3. Error handling |
| 238 | + - Use `handleError(error)` from `handle-errors/handle.ts` to map Axios and wallet errors to normalized types (`ApiErrorTypes`). |
| 239 | + ```ts |
| 240 | + import { handleError } from "@/components/tw-blocks/handle-errors/handle"; |
| 241 | + try { /* ... */ } catch (e) { const err = handleError(e as any); /* show toast */ } |
| 242 | + ``` |
| 243 | + |
| 244 | +4. Wallet-kit |
| 245 | + - `WalletButton` opens a modal using `@creit.tech/stellar-wallets-kit` and stores address/name in `WalletProvider`. |
| 246 | + - `signTransaction({ unsignedTransaction, address })` signs and returns XDR used by mutations. |
| 247 | + - `trustlines` and `trustlineOptions` include common assets for testnet/mainnet. |
| 248 | + |
| 249 | +5. Env and network |
| 250 | + - Use `development` (default) or `mainNet` from `@trustless-work/escrow` in `TrustlessWorkProvider`. |
| 251 | + - Keep your API key in env and never commit it. |
46 | 252 |
|
47 | 253 | ## Contributing |
48 | 254 |
|
|
0 commit comments