@echoxyz/sonar-react 0.2.0 → 0.3.0
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/CHANGELOG.md +13 -0
- package/README.md +54 -10
- package/dist/index.cjs +82 -5
- package/dist/index.d.cts +17 -2
- package/dist/index.d.ts +17 -2
- package/dist/index.js +81 -5
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -78,27 +78,69 @@ export default function OAuthCallback() {
|
|
|
78
78
|
}
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
4.
|
|
81
|
+
4. Load the Sonar entity associated with the user's wallet
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
import { useSonarEntity } from "./hooks/useSonarEntity";
|
|
85
|
+
import { useAccount } from "wagmi";
|
|
86
|
+
|
|
87
|
+
const ExampleEntityPanel = () => {
|
|
88
|
+
const { address, isConnected } = useAccount();
|
|
89
|
+
const { authenticated, loading, entity, error } = useSonarEntity({
|
|
90
|
+
saleUUID: "<your-sale-uuid>",
|
|
91
|
+
wallet: { address, isConnected },
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
if (!isConnected || !authenticated) {
|
|
95
|
+
return <p>Connect your wallet and Sonar account to continue</p>;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (loading) {
|
|
99
|
+
return <p>Loading...</p>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (error) {
|
|
103
|
+
return <p>Error: {error.message}</p>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (!entity) {
|
|
107
|
+
return <p>No entity found for this wallet. Please link your wallet on Sonar to continue.</p>;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<div>
|
|
112
|
+
<span>entity.Label</span>
|
|
113
|
+
<span>entity.EntitySetupState</span>
|
|
114
|
+
<span>entity.EntitySaleEligibility</span>
|
|
115
|
+
</div>
|
|
116
|
+
);
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
5. Optional: call APIs with the low level client to implement the purchase flow:
|
|
82
122
|
|
|
83
123
|
```tsx
|
|
84
124
|
import { useEffect } from "react";
|
|
85
|
-
import {
|
|
125
|
+
import { useSonarEntity } from "./hooks/useSonarEntity";
|
|
126
|
+
import { useAccount } from "wagmi";
|
|
86
127
|
import { EntityType } from "@echoxyz/sonar-core";
|
|
87
128
|
|
|
88
129
|
export function Example() {
|
|
89
|
-
const {
|
|
130
|
+
const { address, isConnected } = useAccount();
|
|
131
|
+
// Would normally need to handle loading and error states like above
|
|
132
|
+
const { entity } = useSonarEntity({
|
|
133
|
+
saleUUID: "<your-sale-uuid>",
|
|
134
|
+
wallet: { address, isConnected },
|
|
135
|
+
});
|
|
90
136
|
const client = useSonarClient();
|
|
91
137
|
|
|
92
138
|
useEffect(() => {
|
|
93
|
-
if (!
|
|
139
|
+
if (!entity) {
|
|
94
140
|
return;
|
|
95
141
|
}
|
|
96
142
|
|
|
97
143
|
(async () => {
|
|
98
|
-
const { Entities } = await client.listAvailableEntities({ saleUUID: "<your-sale-uuid>" });
|
|
99
|
-
if (Entities.length === 0) return;
|
|
100
|
-
|
|
101
|
-
const entity = Entities[0];
|
|
102
144
|
const pre = await client.prePurchaseCheck({
|
|
103
145
|
saleUUID: "<your-sale-uuid>",
|
|
104
146
|
entityUUID: entity.EntityUUID,
|
|
@@ -118,11 +160,11 @@ export function Example() {
|
|
|
118
160
|
|
|
119
161
|
const alloc = await client.fetchAllocation({
|
|
120
162
|
saleUUID: "<your-sale-uuid>",
|
|
121
|
-
walletAddress
|
|
163
|
+
walletAddress,
|
|
122
164
|
});
|
|
123
165
|
console.log(alloc);
|
|
124
166
|
})();
|
|
125
|
-
}, [
|
|
167
|
+
}, [entity]);
|
|
126
168
|
|
|
127
169
|
return null;
|
|
128
170
|
}
|
|
@@ -141,6 +183,8 @@ export function Example() {
|
|
|
141
183
|
- `useSonarAuth()` → `{ authenticated, ready, token?, login(), completeOAuth({ code, state }), logout() }`
|
|
142
184
|
|
|
143
185
|
- `useSonarClient()` → low-level `SonarClient` instance.
|
|
186
|
+
|
|
187
|
+
- `useSonarEntity()` → `{ authenticated, loading, entity?, error? }` high-level convenience hook for fetching a Sonar entity by wallet address.
|
|
144
188
|
|
|
145
189
|
## Notes
|
|
146
190
|
|
package/dist/index.cjs
CHANGED
|
@@ -22,11 +22,12 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
SonarProvider: () => SonarProvider,
|
|
24
24
|
useSonarAuth: () => useSonarAuth,
|
|
25
|
-
useSonarClient: () => useSonarClient
|
|
25
|
+
useSonarClient: () => useSonarClient,
|
|
26
|
+
useSonarEntity: () => useSonarEntity
|
|
26
27
|
});
|
|
27
28
|
module.exports = __toCommonJS(index_exports);
|
|
28
29
|
|
|
29
|
-
// src/
|
|
30
|
+
// src/provider.tsx
|
|
30
31
|
var import_sonar_core = require("@echoxyz/sonar-core");
|
|
31
32
|
var import_react = require("react");
|
|
32
33
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -102,23 +103,99 @@ function SonarProvider({ children, config }) {
|
|
|
102
103
|
const clientValue = (0, import_react.useMemo)(() => ({ client }), [client]);
|
|
103
104
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AuthContext.Provider, { value: authValue, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ClientContext.Provider, { value: clientValue, children }) });
|
|
104
105
|
}
|
|
106
|
+
|
|
107
|
+
// src/hooks.ts
|
|
108
|
+
var import_sonar_core2 = require("@echoxyz/sonar-core");
|
|
109
|
+
var import_react2 = require("react");
|
|
105
110
|
function useSonarAuth() {
|
|
106
|
-
const ctx = (0,
|
|
111
|
+
const ctx = (0, import_react2.useContext)(AuthContext);
|
|
107
112
|
if (!ctx) {
|
|
108
113
|
throw new Error("useSonarAuth must be used within a SonarProvider");
|
|
109
114
|
}
|
|
110
115
|
return ctx;
|
|
111
116
|
}
|
|
112
117
|
function useSonarClient() {
|
|
113
|
-
const ctx = (0,
|
|
118
|
+
const ctx = (0, import_react2.useContext)(ClientContext);
|
|
114
119
|
if (!ctx) {
|
|
115
120
|
throw new Error("useSonarClient must be used within a SonarProvider");
|
|
116
121
|
}
|
|
117
122
|
return ctx.client;
|
|
118
123
|
}
|
|
124
|
+
function useSonarEntity(args) {
|
|
125
|
+
const { authenticated, ready } = useSonarAuth();
|
|
126
|
+
const client = useSonarClient();
|
|
127
|
+
if (!args.saleUUID) {
|
|
128
|
+
throw new Error("saleUUID is required");
|
|
129
|
+
}
|
|
130
|
+
const saleUUID = args.saleUUID;
|
|
131
|
+
const activeWallet = args.wallet.address;
|
|
132
|
+
const walletConnected = args.wallet.isConnected;
|
|
133
|
+
const [state, setState] = (0, import_react2.useState)({
|
|
134
|
+
loading: false,
|
|
135
|
+
hasFetched: false
|
|
136
|
+
});
|
|
137
|
+
const fullyConnected = ready && authenticated && Boolean(activeWallet) && walletConnected;
|
|
138
|
+
const refetch = (0, import_react2.useCallback)(async () => {
|
|
139
|
+
if (!saleUUID || !activeWallet || !fullyConnected) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
setState((s) => ({ ...s, loading: true }));
|
|
143
|
+
try {
|
|
144
|
+
const resp = await client.readEntity({
|
|
145
|
+
saleUUID,
|
|
146
|
+
walletAddress: activeWallet
|
|
147
|
+
});
|
|
148
|
+
setState({
|
|
149
|
+
loading: false,
|
|
150
|
+
entity: resp.Entity,
|
|
151
|
+
error: void 0,
|
|
152
|
+
hasFetched: true
|
|
153
|
+
});
|
|
154
|
+
} catch (err) {
|
|
155
|
+
if (err instanceof import_sonar_core2.APIError && err.status === 404) {
|
|
156
|
+
setState({
|
|
157
|
+
loading: false,
|
|
158
|
+
entity: void 0,
|
|
159
|
+
error: void 0,
|
|
160
|
+
hasFetched: true
|
|
161
|
+
});
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
165
|
+
setState({ loading: false, entity: void 0, error, hasFetched: true });
|
|
166
|
+
}
|
|
167
|
+
}, [client, saleUUID, activeWallet, fullyConnected]);
|
|
168
|
+
const reset = (0, import_react2.useCallback)(() => {
|
|
169
|
+
setState({
|
|
170
|
+
loading: false,
|
|
171
|
+
hasFetched: false,
|
|
172
|
+
entity: void 0,
|
|
173
|
+
error: void 0
|
|
174
|
+
});
|
|
175
|
+
}, []);
|
|
176
|
+
(0, import_react2.useEffect)(() => {
|
|
177
|
+
if (fullyConnected) {
|
|
178
|
+
if (!state.hasFetched && !state.loading) {
|
|
179
|
+
refetch();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}, [fullyConnected, state.hasFetched, state.loading, refetch]);
|
|
183
|
+
(0, import_react2.useEffect)(() => {
|
|
184
|
+
if (ready && (!authenticated || !walletConnected || !activeWallet)) {
|
|
185
|
+
reset();
|
|
186
|
+
}
|
|
187
|
+
}, [ready, authenticated, walletConnected, activeWallet, reset]);
|
|
188
|
+
return {
|
|
189
|
+
authenticated,
|
|
190
|
+
loading: state.loading,
|
|
191
|
+
entity: state.entity,
|
|
192
|
+
error: state.error
|
|
193
|
+
};
|
|
194
|
+
}
|
|
119
195
|
// Annotate the CommonJS export names for ESM import in node:
|
|
120
196
|
0 && (module.exports = {
|
|
121
197
|
SonarProvider,
|
|
122
198
|
useSonarAuth,
|
|
123
|
-
useSonarClient
|
|
199
|
+
useSonarClient,
|
|
200
|
+
useSonarEntity
|
|
124
201
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { SonarClient } from '@echoxyz/sonar-core';
|
|
3
2
|
import React from 'react';
|
|
3
|
+
import { SonarClient, EntityDetails } from '@echoxyz/sonar-core';
|
|
4
4
|
|
|
5
5
|
type SonarProviderProps = {
|
|
6
6
|
children: React.ReactNode;
|
|
@@ -26,7 +26,22 @@ type AuthContextValue = {
|
|
|
26
26
|
logout: () => void;
|
|
27
27
|
};
|
|
28
28
|
declare function SonarProvider({ children, config }: SonarProviderProps): react_jsx_runtime.JSX.Element;
|
|
29
|
+
|
|
29
30
|
declare function useSonarAuth(): AuthContextValue;
|
|
30
31
|
declare function useSonarClient(): SonarClient;
|
|
32
|
+
type WalletConnection = {
|
|
33
|
+
address?: string;
|
|
34
|
+
isConnected: boolean;
|
|
35
|
+
};
|
|
36
|
+
type UseSonarEntityResult = {
|
|
37
|
+
authenticated: boolean;
|
|
38
|
+
loading: boolean;
|
|
39
|
+
entity?: EntityDetails;
|
|
40
|
+
error?: Error;
|
|
41
|
+
};
|
|
42
|
+
declare function useSonarEntity(args: {
|
|
43
|
+
saleUUID: string;
|
|
44
|
+
wallet: WalletConnection;
|
|
45
|
+
}): UseSonarEntityResult;
|
|
31
46
|
|
|
32
|
-
export { SonarProvider, type SonarProviderConfig, useSonarAuth, useSonarClient };
|
|
47
|
+
export { SonarProvider, type SonarProviderConfig, type UseSonarEntityResult, type WalletConnection, useSonarAuth, useSonarClient, useSonarEntity };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { SonarClient } from '@echoxyz/sonar-core';
|
|
3
2
|
import React from 'react';
|
|
3
|
+
import { SonarClient, EntityDetails } from '@echoxyz/sonar-core';
|
|
4
4
|
|
|
5
5
|
type SonarProviderProps = {
|
|
6
6
|
children: React.ReactNode;
|
|
@@ -26,7 +26,22 @@ type AuthContextValue = {
|
|
|
26
26
|
logout: () => void;
|
|
27
27
|
};
|
|
28
28
|
declare function SonarProvider({ children, config }: SonarProviderProps): react_jsx_runtime.JSX.Element;
|
|
29
|
+
|
|
29
30
|
declare function useSonarAuth(): AuthContextValue;
|
|
30
31
|
declare function useSonarClient(): SonarClient;
|
|
32
|
+
type WalletConnection = {
|
|
33
|
+
address?: string;
|
|
34
|
+
isConnected: boolean;
|
|
35
|
+
};
|
|
36
|
+
type UseSonarEntityResult = {
|
|
37
|
+
authenticated: boolean;
|
|
38
|
+
loading: boolean;
|
|
39
|
+
entity?: EntityDetails;
|
|
40
|
+
error?: Error;
|
|
41
|
+
};
|
|
42
|
+
declare function useSonarEntity(args: {
|
|
43
|
+
saleUUID: string;
|
|
44
|
+
wallet: WalletConnection;
|
|
45
|
+
}): UseSonarEntityResult;
|
|
31
46
|
|
|
32
|
-
export { SonarProvider, type SonarProviderConfig, useSonarAuth, useSonarClient };
|
|
47
|
+
export { SonarProvider, type SonarProviderConfig, type UseSonarEntityResult, type WalletConnection, useSonarAuth, useSonarClient, useSonarEntity };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// src/
|
|
1
|
+
// src/provider.tsx
|
|
2
2
|
import { buildAuthorizationUrl, createClient, generatePKCEParams } from "@echoxyz/sonar-core";
|
|
3
|
-
import { createContext, useCallback,
|
|
3
|
+
import { createContext, useCallback, useEffect, useMemo, useState } from "react";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
var AuthContext = createContext(void 0);
|
|
6
6
|
var ClientContext = createContext(void 0);
|
|
@@ -74,22 +74,98 @@ function SonarProvider({ children, config }) {
|
|
|
74
74
|
const clientValue = useMemo(() => ({ client }), [client]);
|
|
75
75
|
return /* @__PURE__ */ jsx(AuthContext.Provider, { value: authValue, children: /* @__PURE__ */ jsx(ClientContext.Provider, { value: clientValue, children }) });
|
|
76
76
|
}
|
|
77
|
+
|
|
78
|
+
// src/hooks.ts
|
|
79
|
+
import { APIError } from "@echoxyz/sonar-core";
|
|
80
|
+
import { useCallback as useCallback2, useContext as useContext2, useEffect as useEffect2, useState as useState2 } from "react";
|
|
77
81
|
function useSonarAuth() {
|
|
78
|
-
const ctx =
|
|
82
|
+
const ctx = useContext2(AuthContext);
|
|
79
83
|
if (!ctx) {
|
|
80
84
|
throw new Error("useSonarAuth must be used within a SonarProvider");
|
|
81
85
|
}
|
|
82
86
|
return ctx;
|
|
83
87
|
}
|
|
84
88
|
function useSonarClient() {
|
|
85
|
-
const ctx =
|
|
89
|
+
const ctx = useContext2(ClientContext);
|
|
86
90
|
if (!ctx) {
|
|
87
91
|
throw new Error("useSonarClient must be used within a SonarProvider");
|
|
88
92
|
}
|
|
89
93
|
return ctx.client;
|
|
90
94
|
}
|
|
95
|
+
function useSonarEntity(args) {
|
|
96
|
+
const { authenticated, ready } = useSonarAuth();
|
|
97
|
+
const client = useSonarClient();
|
|
98
|
+
if (!args.saleUUID) {
|
|
99
|
+
throw new Error("saleUUID is required");
|
|
100
|
+
}
|
|
101
|
+
const saleUUID = args.saleUUID;
|
|
102
|
+
const activeWallet = args.wallet.address;
|
|
103
|
+
const walletConnected = args.wallet.isConnected;
|
|
104
|
+
const [state, setState] = useState2({
|
|
105
|
+
loading: false,
|
|
106
|
+
hasFetched: false
|
|
107
|
+
});
|
|
108
|
+
const fullyConnected = ready && authenticated && Boolean(activeWallet) && walletConnected;
|
|
109
|
+
const refetch = useCallback2(async () => {
|
|
110
|
+
if (!saleUUID || !activeWallet || !fullyConnected) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
setState((s) => ({ ...s, loading: true }));
|
|
114
|
+
try {
|
|
115
|
+
const resp = await client.readEntity({
|
|
116
|
+
saleUUID,
|
|
117
|
+
walletAddress: activeWallet
|
|
118
|
+
});
|
|
119
|
+
setState({
|
|
120
|
+
loading: false,
|
|
121
|
+
entity: resp.Entity,
|
|
122
|
+
error: void 0,
|
|
123
|
+
hasFetched: true
|
|
124
|
+
});
|
|
125
|
+
} catch (err) {
|
|
126
|
+
if (err instanceof APIError && err.status === 404) {
|
|
127
|
+
setState({
|
|
128
|
+
loading: false,
|
|
129
|
+
entity: void 0,
|
|
130
|
+
error: void 0,
|
|
131
|
+
hasFetched: true
|
|
132
|
+
});
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
136
|
+
setState({ loading: false, entity: void 0, error, hasFetched: true });
|
|
137
|
+
}
|
|
138
|
+
}, [client, saleUUID, activeWallet, fullyConnected]);
|
|
139
|
+
const reset = useCallback2(() => {
|
|
140
|
+
setState({
|
|
141
|
+
loading: false,
|
|
142
|
+
hasFetched: false,
|
|
143
|
+
entity: void 0,
|
|
144
|
+
error: void 0
|
|
145
|
+
});
|
|
146
|
+
}, []);
|
|
147
|
+
useEffect2(() => {
|
|
148
|
+
if (fullyConnected) {
|
|
149
|
+
if (!state.hasFetched && !state.loading) {
|
|
150
|
+
refetch();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}, [fullyConnected, state.hasFetched, state.loading, refetch]);
|
|
154
|
+
useEffect2(() => {
|
|
155
|
+
if (ready && (!authenticated || !walletConnected || !activeWallet)) {
|
|
156
|
+
reset();
|
|
157
|
+
}
|
|
158
|
+
}, [ready, authenticated, walletConnected, activeWallet, reset]);
|
|
159
|
+
return {
|
|
160
|
+
authenticated,
|
|
161
|
+
loading: state.loading,
|
|
162
|
+
entity: state.entity,
|
|
163
|
+
error: state.error
|
|
164
|
+
};
|
|
165
|
+
}
|
|
91
166
|
export {
|
|
92
167
|
SonarProvider,
|
|
93
168
|
useSonarAuth,
|
|
94
|
-
useSonarClient
|
|
169
|
+
useSonarClient,
|
|
170
|
+
useSonarEntity
|
|
95
171
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@echoxyz/sonar-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"react": ">=18"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@echoxyz/sonar-core": "0.
|
|
19
|
+
"@echoxyz/sonar-core": "0.2.0"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@testing-library/react": "^16.0.0",
|