@echoxyz/sonar-react 0.12.1 → 0.12.2

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 CHANGED
@@ -1,5 +1,16 @@
1
1
  # @echoxyz/sonar-react
2
2
 
3
+ ## 0.12.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 171a0db: Added support for ReadEntityInvestmentHistory API
8
+ - Updated dependencies [c551d7c]
9
+ - Updated dependencies [e276112]
10
+ - Updated dependencies [171a0db]
11
+ - Updated dependencies [b2cd697]
12
+ - @echoxyz/sonar-core@0.13.0
13
+
3
14
  ## 0.12.1
4
15
 
5
16
  ### Patch Changes
package/README.md CHANGED
@@ -77,7 +77,41 @@ export default function OAuthCallback() {
77
77
  }
78
78
  ```
79
79
 
80
- 4. Load the Sonar entity associated with the user's wallet
80
+ 4. (Optional) Load the authenticated user's profile
81
+
82
+ ```tsx
83
+ import { useSonarProfile } from "@echoxyz/sonar-react";
84
+
85
+ const UserProfilePanel = () => {
86
+ const { authenticated, loading, profile, error } = useSonarProfile();
87
+
88
+ if (!authenticated) {
89
+ return <p>Please sign in to view your profile</p>;
90
+ }
91
+
92
+ if (loading) {
93
+ return <p>Loading...</p>;
94
+ }
95
+
96
+ if (error) {
97
+ return <p>Error: {error.message}</p>;
98
+ }
99
+
100
+ if (!profile) {
101
+ return null;
102
+ }
103
+
104
+ return (
105
+ <div>
106
+ <span>Entity ID: {profile.EntityID}</span>
107
+ {/* EmailAddress only present if authorized with contact:email scope */}
108
+ {profile.EmailAddress && <span>Email: {profile.EmailAddress}</span>}
109
+ </div>
110
+ );
111
+ };
112
+ ```
113
+
114
+ 5. Load the Sonar entity associated with the user's wallet
81
115
 
82
116
  ```tsx
83
117
  import { useSonarEntity } from "./hooks/useSonarEntity";
@@ -118,76 +152,63 @@ const ExampleEntityPanel = () => {
118
152
 
119
153
  If you want to fetch all entities associated with the logged in user, you can use the `useSonarEntities` hook.
120
154
 
121
- 5. Implement the purchase flow
155
+ 6. Implement the purchase flow
122
156
 
123
157
  ```tsx
124
- function Example({
125
- entityID,
126
- walletAddress,
127
- }: {
128
- entityID: string;
129
- walletAddress: string;
130
- }) {
131
- const sonarPurchaser = useSonarPurchase({
132
- saleUUID: sonarConfig.saleUUID,
133
- entityID,
134
- entityType,
135
- walletAddress,
136
- });
137
-
138
- if (sonarPurchaser.loading) {
139
- return <p>Loading...</p>;
140
- }
141
-
142
- if (sonarPurchaser.error) {
143
- return <p>Error: {error.message}</p>;
144
- }
145
-
146
- return (
147
- <div>
148
- {sonarPurchaser.readyToPurchase && (
149
- <PurchaseButton
150
- generatePurchasePermit={sonarPurchaser.generatePurchasePermit}
151
- />
152
- )}
153
-
154
- {!sonarPurchaser.readyToPurchase &&
155
- sonarPurchaser.failureReason ===
156
- PrePurchaseFailureReason.REQUIRES_LIVENESS && (
157
- <button
158
- onClick={() => {
159
- window.open(prePurchaseCheckResult.LivenessCheckURL, "_blank");
160
- }}
161
- >
162
- Complete liveness check to purchase
163
- </button>
164
- )}
165
- </div>
166
- );
158
+ function Example({ entityID, walletAddress }: { entityID: string; walletAddress: string }) {
159
+ const sonarPurchaser = useSonarPurchase({
160
+ saleUUID: sonarConfig.saleUUID,
161
+ entityID,
162
+ entityType,
163
+ walletAddress,
164
+ });
165
+
166
+ if (sonarPurchaser.loading) {
167
+ return <p>Loading...</p>;
168
+ }
169
+
170
+ if (sonarPurchaser.error) {
171
+ return <p>Error: {error.message}</p>;
172
+ }
173
+
174
+ return (
175
+ <div>
176
+ {sonarPurchaser.readyToPurchase && (
177
+ <PurchaseButton generatePurchasePermit={sonarPurchaser.generatePurchasePermit} />
178
+ )}
179
+
180
+ {!sonarPurchaser.readyToPurchase &&
181
+ sonarPurchaser.failureReason === PrePurchaseFailureReason.REQUIRES_LIVENESS && (
182
+ <button
183
+ onClick={() => {
184
+ window.open(prePurchaseCheckResult.LivenessCheckURL, "_blank");
185
+ }}
186
+ >
187
+ Complete liveness check to purchase
188
+ </button>
189
+ )}
190
+ </div>
191
+ );
167
192
  }
168
193
 
169
194
  function PurchaseButton({
170
- generatePurchasePermit,
195
+ generatePurchasePermit,
171
196
  }: {
172
- generatePurchasePermit: () => Promise<GeneratePurchasePermitResponse>;
197
+ generatePurchasePermit: () => Promise<GeneratePurchasePermitResponse>;
173
198
  }) {
174
- const purchase = async () => {
175
- const response = await generatePurchasePermit();
176
- const r = response as unknown as {
177
- Signature: string;
178
- PermitJSON: BasicPermitV2;
199
+ const purchase = async () => {
200
+ const response = await generatePurchasePermit();
201
+ const r = response as unknown as {
202
+ Signature: string;
203
+ PermitJSON: BasicPermitV2;
204
+ };
205
+ if (r.Signature && r.PermitJSON) {
206
+ console.log(permit.Signature, permit.Permit);
207
+ return;
208
+ }
179
209
  };
180
- if (r.Signature && r.PermitJSON) {
181
- console.log(permit.Signature, permit.Permit);
182
- return;
183
- }
184
- };
185
210
 
186
- return (
187
- <button onClick={purchase}>
188
- Purchase
189
- </button>
190
- );
211
+ return <button onClick={purchase}>Purchase</button>;
191
212
  }
192
213
  ```
193
214
 
@@ -203,9 +224,13 @@ function PurchaseButton({
203
224
  - `useSonarAuth()` → `{ authenticated, ready, token?, login(), completeOAuth({ code, state }), logout() }`
204
225
 
205
226
  - `useSonarClient()` → low-level `SonarClient` instance.
206
-
227
+
228
+ - `useSonarProfile()` → `{ authenticated, loading, profile?, error? }` high-level hook for fetching the authenticated user's profile (entity ID and email).
229
+
207
230
  - `useSonarEntity()` → `{ authenticated, loading, entity?, error? }` high-level convenience hook for fetching a Sonar entity by wallet address.
208
231
 
232
+ - `useSonarEntities()` → `{ authenticated, loading, entities?, error? }` high-level hook for fetching all entities available to the authenticated user.
233
+
209
234
  ## Notes
210
235
 
211
236
  - Tokens are not auto-refreshed. On expiry, call `logout()` and re-run the OAuth flow.
package/dist/index.cjs CHANGED
@@ -21,10 +21,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  SonarProvider: () => SonarProvider,
24
+ useEntityInvestmentHistory: () => useEntityInvestmentHistory,
24
25
  useSonarAuth: () => useSonarAuth,
25
26
  useSonarClient: () => useSonarClient,
26
27
  useSonarEntities: () => useSonarEntities,
27
28
  useSonarEntity: () => useSonarEntity,
29
+ useSonarProfile: () => useSonarProfile,
28
30
  useSonarPurchase: () => useSonarPurchase
29
31
  });
30
32
  module.exports = __toCommonJS(index_exports);
@@ -308,12 +310,110 @@ function useSonarPurchase(args) {
308
310
  }, [saleUUID, entityID, walletAddress, client, generatePurchasePermit]);
309
311
  return state;
310
312
  }
313
+ function useSonarProfile() {
314
+ const { authenticated, ready } = useSonarAuth();
315
+ const client = useSonarClient();
316
+ const [state, setState] = (0, import_react2.useState)({
317
+ loading: false
318
+ });
319
+ const fullyConnected = ready && authenticated;
320
+ const refetch = (0, import_react2.useCallback)(async () => {
321
+ if (!fullyConnected) {
322
+ return;
323
+ }
324
+ setState((s) => ({ ...s, loading: true }));
325
+ try {
326
+ const resp = await client.myProfile();
327
+ setState({
328
+ loading: false,
329
+ profile: resp,
330
+ error: void 0
331
+ });
332
+ } catch (err) {
333
+ const error = err instanceof Error ? err : new Error(String(err));
334
+ setState({ loading: false, profile: void 0, error });
335
+ }
336
+ }, [client, fullyConnected]);
337
+ const reset = (0, import_react2.useCallback)(() => {
338
+ setState({
339
+ loading: false,
340
+ profile: void 0,
341
+ error: void 0
342
+ });
343
+ }, []);
344
+ (0, import_react2.useEffect)(() => {
345
+ if (fullyConnected) {
346
+ refetch();
347
+ }
348
+ }, [fullyConnected, refetch]);
349
+ (0, import_react2.useEffect)(() => {
350
+ if (ready && !authenticated) {
351
+ reset();
352
+ }
353
+ }, [ready, authenticated, reset]);
354
+ return {
355
+ authenticated,
356
+ loading: state.loading,
357
+ profile: state.profile,
358
+ error: state.error
359
+ };
360
+ }
361
+ function useEntityInvestmentHistory() {
362
+ const { authenticated, ready } = useSonarAuth();
363
+ const client = useSonarClient();
364
+ const [state, setState] = (0, import_react2.useState)({
365
+ loading: false
366
+ });
367
+ const fullyConnected = ready && authenticated;
368
+ const refetch = (0, import_react2.useCallback)(async () => {
369
+ if (!fullyConnected) {
370
+ return;
371
+ }
372
+ setState((s) => ({ ...s, loading: true }));
373
+ try {
374
+ const resp = await client.readEntityInvestmentHistory();
375
+ setState({
376
+ loading: false,
377
+ investmentHistory: resp,
378
+ error: void 0
379
+ });
380
+ } catch (err) {
381
+ const error = err instanceof Error ? err : new Error(String(err));
382
+ setState({ loading: false, investmentHistory: void 0, error });
383
+ }
384
+ }, [client, fullyConnected]);
385
+ const reset = (0, import_react2.useCallback)(() => {
386
+ setState({
387
+ loading: false,
388
+ investmentHistory: void 0,
389
+ error: void 0
390
+ });
391
+ }, []);
392
+ (0, import_react2.useEffect)(() => {
393
+ if (fullyConnected) {
394
+ refetch();
395
+ }
396
+ }, [fullyConnected, refetch]);
397
+ (0, import_react2.useEffect)(() => {
398
+ if (ready && !authenticated) {
399
+ reset();
400
+ }
401
+ }, [ready, authenticated, reset]);
402
+ return {
403
+ authenticated,
404
+ loading: state.loading,
405
+ investmentHistory: state.investmentHistory,
406
+ error: state.error
407
+ };
408
+ }
311
409
  // Annotate the CommonJS export names for ESM import in node:
312
410
  0 && (module.exports = {
313
411
  SonarProvider,
412
+ useEntityInvestmentHistory,
314
413
  useSonarAuth,
315
414
  useSonarClient,
316
415
  useSonarEntities,
317
416
  useSonarEntity,
417
+ useSonarProfile,
318
418
  useSonarPurchase
319
419
  });
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React from 'react';
3
- import { SonarClient, EntityDetails, GeneratePurchasePermitResponse, PrePurchaseFailureReason, EntityID } from '@echoxyz/sonar-core';
3
+ import { SonarClient, EntityDetails, GeneratePurchasePermitResponse, PrePurchaseFailureReason, EntityID, MyProfileResponse, EntityInvestmentHistoryResponse } from '@echoxyz/sonar-core';
4
4
 
5
5
  type SonarProviderProps = {
6
6
  children: React.ReactNode;
@@ -77,5 +77,19 @@ declare function useSonarPurchase(args: {
77
77
  entityID: EntityID;
78
78
  walletAddress: string;
79
79
  }): UseSonarPurchaseResult;
80
+ type UseSonarProfileResult = {
81
+ authenticated: boolean;
82
+ loading: boolean;
83
+ profile?: MyProfileResponse;
84
+ error?: Error;
85
+ };
86
+ declare function useSonarProfile(): UseSonarProfileResult;
87
+ type UseEntityInvestmentHistoryResult = {
88
+ authenticated: boolean;
89
+ loading: boolean;
90
+ investmentHistory?: EntityInvestmentHistoryResponse;
91
+ error?: Error;
92
+ };
93
+ declare function useEntityInvestmentHistory(): UseEntityInvestmentHistoryResult;
80
94
 
81
- export { SonarProvider, type SonarProviderConfig, type UseSonarEntitiesResult, type UseSonarEntityResult, type UseSonarPurchaseResult, type UseSonarPurchaseResultError, type UseSonarPurchaseResultLoading, type UseSonarPurchaseResultNotReadyToPurchase, type UseSonarPurchaseResultReadyToPurchase, useSonarAuth, useSonarClient, useSonarEntities, useSonarEntity, useSonarPurchase };
95
+ export { SonarProvider, type SonarProviderConfig, type UseEntityInvestmentHistoryResult, type UseSonarEntitiesResult, type UseSonarEntityResult, type UseSonarProfileResult, type UseSonarPurchaseResult, type UseSonarPurchaseResultError, type UseSonarPurchaseResultLoading, type UseSonarPurchaseResultNotReadyToPurchase, type UseSonarPurchaseResultReadyToPurchase, useEntityInvestmentHistory, useSonarAuth, useSonarClient, useSonarEntities, useSonarEntity, useSonarProfile, useSonarPurchase };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React from 'react';
3
- import { SonarClient, EntityDetails, GeneratePurchasePermitResponse, PrePurchaseFailureReason, EntityID } from '@echoxyz/sonar-core';
3
+ import { SonarClient, EntityDetails, GeneratePurchasePermitResponse, PrePurchaseFailureReason, EntityID, MyProfileResponse, EntityInvestmentHistoryResponse } from '@echoxyz/sonar-core';
4
4
 
5
5
  type SonarProviderProps = {
6
6
  children: React.ReactNode;
@@ -77,5 +77,19 @@ declare function useSonarPurchase(args: {
77
77
  entityID: EntityID;
78
78
  walletAddress: string;
79
79
  }): UseSonarPurchaseResult;
80
+ type UseSonarProfileResult = {
81
+ authenticated: boolean;
82
+ loading: boolean;
83
+ profile?: MyProfileResponse;
84
+ error?: Error;
85
+ };
86
+ declare function useSonarProfile(): UseSonarProfileResult;
87
+ type UseEntityInvestmentHistoryResult = {
88
+ authenticated: boolean;
89
+ loading: boolean;
90
+ investmentHistory?: EntityInvestmentHistoryResponse;
91
+ error?: Error;
92
+ };
93
+ declare function useEntityInvestmentHistory(): UseEntityInvestmentHistoryResult;
80
94
 
81
- export { SonarProvider, type SonarProviderConfig, type UseSonarEntitiesResult, type UseSonarEntityResult, type UseSonarPurchaseResult, type UseSonarPurchaseResultError, type UseSonarPurchaseResultLoading, type UseSonarPurchaseResultNotReadyToPurchase, type UseSonarPurchaseResultReadyToPurchase, useSonarAuth, useSonarClient, useSonarEntities, useSonarEntity, useSonarPurchase };
95
+ export { SonarProvider, type SonarProviderConfig, type UseEntityInvestmentHistoryResult, type UseSonarEntitiesResult, type UseSonarEntityResult, type UseSonarProfileResult, type UseSonarPurchaseResult, type UseSonarPurchaseResultError, type UseSonarPurchaseResultLoading, type UseSonarPurchaseResultNotReadyToPurchase, type UseSonarPurchaseResultReadyToPurchase, useEntityInvestmentHistory, useSonarAuth, useSonarClient, useSonarEntities, useSonarEntity, useSonarProfile, useSonarPurchase };
package/dist/index.js CHANGED
@@ -279,11 +279,109 @@ function useSonarPurchase(args) {
279
279
  }, [saleUUID, entityID, walletAddress, client, generatePurchasePermit]);
280
280
  return state;
281
281
  }
282
+ function useSonarProfile() {
283
+ const { authenticated, ready } = useSonarAuth();
284
+ const client = useSonarClient();
285
+ const [state, setState] = useState2({
286
+ loading: false
287
+ });
288
+ const fullyConnected = ready && authenticated;
289
+ const refetch = useCallback2(async () => {
290
+ if (!fullyConnected) {
291
+ return;
292
+ }
293
+ setState((s) => ({ ...s, loading: true }));
294
+ try {
295
+ const resp = await client.myProfile();
296
+ setState({
297
+ loading: false,
298
+ profile: resp,
299
+ error: void 0
300
+ });
301
+ } catch (err) {
302
+ const error = err instanceof Error ? err : new Error(String(err));
303
+ setState({ loading: false, profile: void 0, error });
304
+ }
305
+ }, [client, fullyConnected]);
306
+ const reset = useCallback2(() => {
307
+ setState({
308
+ loading: false,
309
+ profile: void 0,
310
+ error: void 0
311
+ });
312
+ }, []);
313
+ useEffect2(() => {
314
+ if (fullyConnected) {
315
+ refetch();
316
+ }
317
+ }, [fullyConnected, refetch]);
318
+ useEffect2(() => {
319
+ if (ready && !authenticated) {
320
+ reset();
321
+ }
322
+ }, [ready, authenticated, reset]);
323
+ return {
324
+ authenticated,
325
+ loading: state.loading,
326
+ profile: state.profile,
327
+ error: state.error
328
+ };
329
+ }
330
+ function useEntityInvestmentHistory() {
331
+ const { authenticated, ready } = useSonarAuth();
332
+ const client = useSonarClient();
333
+ const [state, setState] = useState2({
334
+ loading: false
335
+ });
336
+ const fullyConnected = ready && authenticated;
337
+ const refetch = useCallback2(async () => {
338
+ if (!fullyConnected) {
339
+ return;
340
+ }
341
+ setState((s) => ({ ...s, loading: true }));
342
+ try {
343
+ const resp = await client.readEntityInvestmentHistory();
344
+ setState({
345
+ loading: false,
346
+ investmentHistory: resp,
347
+ error: void 0
348
+ });
349
+ } catch (err) {
350
+ const error = err instanceof Error ? err : new Error(String(err));
351
+ setState({ loading: false, investmentHistory: void 0, error });
352
+ }
353
+ }, [client, fullyConnected]);
354
+ const reset = useCallback2(() => {
355
+ setState({
356
+ loading: false,
357
+ investmentHistory: void 0,
358
+ error: void 0
359
+ });
360
+ }, []);
361
+ useEffect2(() => {
362
+ if (fullyConnected) {
363
+ refetch();
364
+ }
365
+ }, [fullyConnected, refetch]);
366
+ useEffect2(() => {
367
+ if (ready && !authenticated) {
368
+ reset();
369
+ }
370
+ }, [ready, authenticated, reset]);
371
+ return {
372
+ authenticated,
373
+ loading: state.loading,
374
+ investmentHistory: state.investmentHistory,
375
+ error: state.error
376
+ };
377
+ }
282
378
  export {
283
379
  SonarProvider,
380
+ useEntityInvestmentHistory,
284
381
  useSonarAuth,
285
382
  useSonarClient,
286
383
  useSonarEntities,
287
384
  useSonarEntity,
385
+ useSonarProfile,
288
386
  useSonarPurchase
289
387
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@echoxyz/sonar-react",
3
- "version": "0.12.1",
3
+ "version": "0.12.2",
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.12.0"
19
+ "@echoxyz/sonar-core": "0.13.0"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@testing-library/react": "^16.0.0",