@explorins/pers-sdk-react-native 2.1.2 → 2.1.5
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/README.md +7 -7
- package/dist/hooks/index.d.ts +6 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useAnalytics.d.ts +37 -14
- package/dist/hooks/useAnalytics.d.ts.map +1 -1
- package/dist/hooks/useAnalytics.js +239 -19
- package/dist/hooks/useCampaigns.d.ts +14 -6
- package/dist/hooks/useCampaigns.d.ts.map +1 -1
- package/dist/hooks/useCampaigns.js +144 -10
- package/dist/hooks/useRedemptions.d.ts +5 -2
- package/dist/hooks/useRedemptions.d.ts.map +1 -1
- package/dist/hooks/useRedemptions.js +53 -2
- package/dist/hooks/useTokenBalances.d.ts.map +1 -1
- package/dist/hooks/useTokenBalances.js +21 -8
- package/dist/hooks/useTransactions.d.ts +8 -5
- package/dist/hooks/useTransactions.d.ts.map +1 -1
- package/dist/hooks/useTransactions.js +70 -27
- package/dist/hooks/useTriggerSources.d.ts +76 -0
- package/dist/hooks/useTriggerSources.d.ts.map +1 -0
- package/dist/hooks/useTriggerSources.js +272 -0
- package/dist/index.d.ts +12 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2742 -495
- package/dist/index.js.map +1 -1
- package/dist/providers/PersSDKProvider.d.ts +1 -12
- package/dist/providers/PersSDKProvider.d.ts.map +1 -1
- package/dist/providers/PersSDKProvider.js +50 -25
- package/package.json +2 -2
- package/src/hooks/index.ts +17 -1
- package/src/hooks/useAnalytics.ts +268 -21
- package/src/hooks/useCampaigns.ts +176 -14
- package/src/hooks/useRedemptions.ts +66 -3
- package/src/hooks/useTokenBalances.ts +23 -9
- package/src/hooks/useTransactions.ts +84 -29
- package/src/hooks/useTriggerSources.ts +301 -0
- package/src/index.ts +33 -3
- package/src/providers/PersSDKProvider.tsx +58 -39
|
@@ -1,21 +1,9 @@
|
|
|
1
1
|
import React, { ReactNode } from 'react';
|
|
2
2
|
import { PersSDK, PersConfig, DefaultAuthProvider } from '@explorins/pers-sdk/core';
|
|
3
3
|
import { UserDTO, AdminDTO } from '@explorins/pers-shared';
|
|
4
|
-
import type { AuthManager, UserManager, TokenManager, BusinessManager, CampaignManager, RedemptionManager, TransactionManager, PurchaseManager, TenantManager, AnalyticsManager, DonationManager } from '@explorins/pers-sdk/core';
|
|
5
4
|
export type { PersConfig } from '@explorins/pers-sdk/core';
|
|
6
5
|
export interface PersSDKContext {
|
|
7
6
|
sdk: PersSDK | null;
|
|
8
|
-
auth: AuthManager | null;
|
|
9
|
-
users: UserManager | null;
|
|
10
|
-
tokens: TokenManager | null;
|
|
11
|
-
businesses: BusinessManager | null;
|
|
12
|
-
campaigns: CampaignManager | null;
|
|
13
|
-
redemptions: RedemptionManager | null;
|
|
14
|
-
transactions: TransactionManager | null;
|
|
15
|
-
purchases: PurchaseManager | null;
|
|
16
|
-
tenants: TenantManager | null;
|
|
17
|
-
analytics: AnalyticsManager | null;
|
|
18
|
-
donations: DonationManager | null;
|
|
19
7
|
authProvider: DefaultAuthProvider | null;
|
|
20
8
|
isInitialized: boolean;
|
|
21
9
|
isAuthenticated: boolean;
|
|
@@ -23,6 +11,7 @@ export interface PersSDKContext {
|
|
|
23
11
|
initialize: (config: PersConfig) => Promise<void>;
|
|
24
12
|
setAuthenticationState: (user: UserDTO | AdminDTO | null, isAuthenticated: boolean) => void;
|
|
25
13
|
refreshUserData: () => Promise<void>;
|
|
14
|
+
restoreSession: () => Promise<UserDTO | null>;
|
|
26
15
|
}
|
|
27
16
|
export declare const PersSDKProvider: React.FC<{
|
|
28
17
|
children: ReactNode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PersSDKProvider.d.ts","sourceRoot":"","sources":["../../src/providers/PersSDKProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAuC,SAAS,EAA2C,MAAM,OAAO,CAAC;AAEvH,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAIpF,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"PersSDKProvider.d.ts","sourceRoot":"","sources":["../../src/providers/PersSDKProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAuC,SAAS,EAA2C,MAAM,OAAO,CAAC;AAEvH,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAIpF,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAkB3D,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,MAAM,WAAW,cAAc;IAE7B,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IAGpB,YAAY,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAGzC,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAAC;IAGhC,UAAU,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,sBAAsB,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,EAAE,eAAe,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5F,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,cAAc,EAAE,MAAM,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;CAC/C;AAMD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC;IACrC,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB,CAwOA,CAAC;AAGF,eAAO,MAAM,UAAU,QAAO,cAQ7B,CAAC"}
|
|
@@ -10,11 +10,19 @@ const SDKContext = createContext(null);
|
|
|
10
10
|
// Provider component
|
|
11
11
|
export const PersSDKProvider = ({ children, config }) => {
|
|
12
12
|
const initializingRef = useRef(false);
|
|
13
|
+
// State refs for stable functions to read current values
|
|
14
|
+
const sdkRef = useRef(null);
|
|
15
|
+
const isInitializedRef = useRef(false);
|
|
16
|
+
const isAuthenticatedRef = useRef(false);
|
|
13
17
|
const [sdk, setSdk] = useState(null);
|
|
14
18
|
const [authProvider, setAuthProvider] = useState(null);
|
|
15
19
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
16
20
|
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
|
17
21
|
const [user, setUser] = useState(null);
|
|
22
|
+
// Keep state refs in sync immediately (not in useEffect to avoid race conditions)
|
|
23
|
+
sdkRef.current = sdk;
|
|
24
|
+
isInitializedRef.current = isInitialized;
|
|
25
|
+
isAuthenticatedRef.current = isAuthenticated;
|
|
18
26
|
const initialize = useCallback(async (config) => {
|
|
19
27
|
// Prevent multiple initializations
|
|
20
28
|
if (isInitialized || initializingRef.current) {
|
|
@@ -81,18 +89,40 @@ export const PersSDKProvider = ({ children, config }) => {
|
|
|
81
89
|
}
|
|
82
90
|
}, [config, isInitialized, initialize]);
|
|
83
91
|
const refreshUserData = useCallback(async () => {
|
|
84
|
-
|
|
85
|
-
|
|
92
|
+
// Read from refs to get current values
|
|
93
|
+
const currentSdk = sdkRef.current;
|
|
94
|
+
const currentIsInitialized = isInitializedRef.current;
|
|
95
|
+
if (!currentSdk || !currentIsInitialized) {
|
|
96
|
+
throw new Error('SDK not initialized. Cannot refresh user data.');
|
|
86
97
|
}
|
|
87
98
|
try {
|
|
88
|
-
const freshUserData = await
|
|
99
|
+
const freshUserData = await currentSdk.users.getCurrentUser();
|
|
89
100
|
setUser(freshUserData);
|
|
90
101
|
}
|
|
91
102
|
catch (error) {
|
|
92
103
|
console.error('Failed to refresh user data:', error);
|
|
93
104
|
throw error;
|
|
94
105
|
}
|
|
95
|
-
}, [
|
|
106
|
+
}, []); // No dependencies - reads from refs
|
|
107
|
+
const restoreSession = useCallback(async () => {
|
|
108
|
+
// Read from refs to get current values
|
|
109
|
+
const currentSdk = sdkRef.current;
|
|
110
|
+
const currentIsInitialized = isInitializedRef.current;
|
|
111
|
+
if (!currentSdk || !currentIsInitialized) {
|
|
112
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const userData = await currentSdk.restoreSession();
|
|
116
|
+
if (userData) {
|
|
117
|
+
setAuthenticationState(userData, true);
|
|
118
|
+
}
|
|
119
|
+
return userData;
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
console.error('[PersSDK] Failed to restore session:', error);
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
}, [setAuthenticationState]); // Depends on setAuthenticationState
|
|
96
126
|
// Listen for authentication events from core SDK
|
|
97
127
|
// Set up immediately when SDK is created (don't wait for isInitialized)
|
|
98
128
|
// to catch session_restored events that fire during SDK initialization
|
|
@@ -105,13 +135,18 @@ export const PersSDKProvider = ({ children, config }) => {
|
|
|
105
135
|
// Session restored successfully - sync React state
|
|
106
136
|
if (event.type === 'session_restored') {
|
|
107
137
|
console.log('[PersSDK] Session restoration event received, syncing state...');
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
.
|
|
113
|
-
|
|
114
|
-
|
|
138
|
+
// Read user from event details if available, otherwise fetch
|
|
139
|
+
const userId = event.details?.userId;
|
|
140
|
+
if (userId) {
|
|
141
|
+
// User ID available, fetch user data
|
|
142
|
+
sdk.users.getCurrentUser()
|
|
143
|
+
.then(userData => {
|
|
144
|
+
setAuthenticationState(userData, true);
|
|
145
|
+
})
|
|
146
|
+
.catch(error => {
|
|
147
|
+
console.error('[PersSDK] Failed to sync restored session:', error);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
115
150
|
}
|
|
116
151
|
// Session restoration failed or auth error - clear React state
|
|
117
152
|
if (event.type === 'session_restoration_failed' || event.code === 'AUTH_FAILED') {
|
|
@@ -149,28 +184,17 @@ export const PersSDKProvider = ({ children, config }) => {
|
|
|
149
184
|
const contextValue = useMemo(() => ({
|
|
150
185
|
// Main SDK instance
|
|
151
186
|
sdk,
|
|
152
|
-
// Manager shortcuts for convenience
|
|
153
|
-
auth: sdk?.auth || null,
|
|
154
|
-
users: sdk?.users || null,
|
|
155
|
-
tokens: sdk?.tokens || null,
|
|
156
|
-
businesses: sdk?.businesses || null,
|
|
157
|
-
campaigns: sdk?.campaigns || null,
|
|
158
|
-
redemptions: sdk?.redemptions || null,
|
|
159
|
-
transactions: sdk?.transactions || null,
|
|
160
|
-
purchases: sdk?.purchases || null,
|
|
161
|
-
tenants: sdk?.tenants || null,
|
|
162
|
-
analytics: sdk?.analytics || null,
|
|
163
|
-
donations: sdk?.donations || null,
|
|
164
187
|
// Platform-specific providers
|
|
165
188
|
authProvider,
|
|
166
189
|
// State
|
|
167
190
|
isInitialized,
|
|
168
191
|
isAuthenticated,
|
|
169
192
|
user,
|
|
170
|
-
// Methods
|
|
193
|
+
// Methods - expose functions directly, not through refs
|
|
171
194
|
initialize,
|
|
172
195
|
setAuthenticationState,
|
|
173
196
|
refreshUserData,
|
|
197
|
+
restoreSession,
|
|
174
198
|
}), [
|
|
175
199
|
sdk,
|
|
176
200
|
authProvider,
|
|
@@ -179,7 +203,8 @@ export const PersSDKProvider = ({ children, config }) => {
|
|
|
179
203
|
user,
|
|
180
204
|
initialize,
|
|
181
205
|
setAuthenticationState,
|
|
182
|
-
refreshUserData
|
|
206
|
+
refreshUserData,
|
|
207
|
+
restoreSession
|
|
183
208
|
]);
|
|
184
209
|
return (_jsx(SDKContext.Provider, { value: contextValue, children: children }));
|
|
185
210
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@explorins/pers-sdk-react-native",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.5",
|
|
4
4
|
"description": "React Native SDK for PERS Platform - Tourism Loyalty System with Blockchain Transaction Signing and WebAuthn Authentication",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"author": "eXplorins",
|
|
38
38
|
"license": "MIT",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@explorins/pers-sdk": "^2.1.
|
|
40
|
+
"@explorins/pers-sdk": "^2.1.6",
|
|
41
41
|
"@explorins/pers-signer": "^1.0.33",
|
|
42
42
|
"buffer": "^6.0.3",
|
|
43
43
|
"ethers": "^6.15.0",
|
package/src/hooks/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ export { useFiles } from './useFiles';
|
|
|
16
16
|
export { useAnalytics } from './useAnalytics';
|
|
17
17
|
export { useDonations } from './useDonations';
|
|
18
18
|
export { useEvents } from './useEvents';
|
|
19
|
+
export { useTriggerSources } from './useTriggerSources';
|
|
19
20
|
|
|
20
21
|
// Re-export auth-related types for convenience
|
|
21
22
|
export type { RawUserData } from './useAuth';
|
|
@@ -34,4 +35,19 @@ export type {
|
|
|
34
35
|
TokenBalanceWithToken,
|
|
35
36
|
UseTokenBalancesOptions,
|
|
36
37
|
UseTokenBalancesResult
|
|
37
|
-
} from './useTokenBalances';
|
|
38
|
+
} from './useTokenBalances';
|
|
39
|
+
|
|
40
|
+
// Export campaign-related types
|
|
41
|
+
export type { CampaignClaimFilters, CampaignHook } from './useCampaigns';
|
|
42
|
+
|
|
43
|
+
// Export redemption-related types
|
|
44
|
+
export type { RedemptionRedeemFilters, RedemptionHook } from './useRedemptions';
|
|
45
|
+
|
|
46
|
+
// Export transaction-related types
|
|
47
|
+
export type { TransactionQueryOptions, TransactionHook } from './useTransactions';
|
|
48
|
+
|
|
49
|
+
// Export trigger source-related types
|
|
50
|
+
export type { TriggerSourceQueryOptions, TriggerSourceHook } from './useTriggerSources';
|
|
51
|
+
|
|
52
|
+
// Export analytics-related types
|
|
53
|
+
export type { AnalyticsHook } from './useAnalytics';
|
|
@@ -2,35 +2,63 @@ import { useCallback } from 'react';
|
|
|
2
2
|
import { usePersSDK } from '../providers/PersSDKProvider';
|
|
3
3
|
import {
|
|
4
4
|
TransactionAnalyticsRequestDTO,
|
|
5
|
-
TransactionAnalyticsResponseDTO
|
|
5
|
+
TransactionAnalyticsResponseDTO,
|
|
6
|
+
CampaignClaimAnalyticsRequestDTO,
|
|
7
|
+
CampaignClaimAnalyticsResponseDTO,
|
|
8
|
+
UserAnalyticsRequestDTO,
|
|
9
|
+
UserAnalyticsResponseDTO,
|
|
10
|
+
UserRankingAnalyticsRequestDTO,
|
|
11
|
+
UserRankingAnalyticsResponseDTO,
|
|
12
|
+
BusinessRankingAnalyticsRequestDTO,
|
|
13
|
+
BusinessRankingAnalyticsResponseDTO,
|
|
14
|
+
RetentionAnalyticsRequestDTO,
|
|
15
|
+
RetentionAnalyticsResponseDTO
|
|
6
16
|
} from '@explorins/pers-shared';
|
|
7
17
|
|
|
8
18
|
/**
|
|
9
19
|
* React hook for analytics operations in the PERS SDK
|
|
10
20
|
*
|
|
11
|
-
* Provides
|
|
12
|
-
*
|
|
21
|
+
* Provides comprehensive analytics and business intelligence capabilities:
|
|
22
|
+
* - **Transaction Analytics**: Volume, trends, business performance
|
|
23
|
+
* - **Campaign Claim Analytics**: Campaign performance and claim patterns
|
|
24
|
+
* - **User Analytics**: Engagement metrics with per-active-user averages
|
|
25
|
+
* - **User Ranking**: Leaderboards with full user details
|
|
26
|
+
* - **Business Ranking**: Business performance rankings
|
|
27
|
+
* - **Retention Analytics**: Monthly retention metrics
|
|
13
28
|
*
|
|
14
29
|
* @returns Analytics hook with methods for data analysis
|
|
15
30
|
*
|
|
16
|
-
* @example
|
|
31
|
+
* @example Basic Transaction Analytics
|
|
17
32
|
* ```typescript
|
|
18
33
|
* function AnalyticsComponent() {
|
|
19
34
|
* const { getTransactionAnalytics } = useAnalytics();
|
|
20
35
|
*
|
|
21
36
|
* const loadAnalytics = async () => {
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* } catch (error) {
|
|
29
|
-
* console.error('Failed to load analytics:', error);
|
|
30
|
-
* }
|
|
37
|
+
* const analytics = await getTransactionAnalytics({
|
|
38
|
+
* startDate: '2024-01-01',
|
|
39
|
+
* endDate: '2024-01-31',
|
|
40
|
+
* groupBy: 'day'
|
|
41
|
+
* });
|
|
42
|
+
* console.log('Transaction analytics:', analytics);
|
|
31
43
|
* };
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
32
46
|
*
|
|
33
|
-
*
|
|
47
|
+
* @example User Leaderboard
|
|
48
|
+
* ```typescript
|
|
49
|
+
* function LeaderboardScreen() {
|
|
50
|
+
* const { getUserRanking } = useAnalytics();
|
|
51
|
+
*
|
|
52
|
+
* const loadLeaderboard = async () => {
|
|
53
|
+
* const ranking = await getUserRanking({
|
|
54
|
+
* sortBy: 'totalTransactions',
|
|
55
|
+
* sortOrder: 'DESC',
|
|
56
|
+
* limit: 50
|
|
57
|
+
* });
|
|
58
|
+
* ranking.results.forEach((user, i) => {
|
|
59
|
+
* console.log(`#${i + 1}: ${user.email} - ${user.totalTransactions} txns`);
|
|
60
|
+
* });
|
|
61
|
+
* };
|
|
34
62
|
* }
|
|
35
63
|
* ```
|
|
36
64
|
*/
|
|
@@ -46,19 +74,17 @@ export const useAnalytics = () => {
|
|
|
46
74
|
*
|
|
47
75
|
* @example
|
|
48
76
|
* ```typescript
|
|
49
|
-
* const { getTransactionAnalytics } = useAnalytics();
|
|
50
77
|
* const analytics = await getTransactionAnalytics({
|
|
51
|
-
* groupBy: ['day'],
|
|
52
|
-
* metrics: ['count', 'sum'],
|
|
53
78
|
* startDate: '2024-01-01',
|
|
54
79
|
* endDate: '2024-01-31',
|
|
55
|
-
*
|
|
80
|
+
* groupBy: 'day',
|
|
81
|
+
* metrics: ['count', 'sum']
|
|
56
82
|
* });
|
|
57
|
-
* console.log('Daily transaction analytics:', analytics.results);
|
|
58
|
-
* console.log('Execution time:', analytics.metadata.executionTime);
|
|
59
83
|
* ```
|
|
60
84
|
*/
|
|
61
|
-
const getTransactionAnalytics = useCallback(async (
|
|
85
|
+
const getTransactionAnalytics = useCallback(async (
|
|
86
|
+
request: TransactionAnalyticsRequestDTO
|
|
87
|
+
): Promise<TransactionAnalyticsResponseDTO> => {
|
|
62
88
|
if (!isInitialized || !sdk) {
|
|
63
89
|
throw new Error('SDK not initialized. Call initialize() first.');
|
|
64
90
|
}
|
|
@@ -72,8 +98,229 @@ export const useAnalytics = () => {
|
|
|
72
98
|
}
|
|
73
99
|
}, [sdk, isInitialized]);
|
|
74
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Retrieves campaign claim analytics with aggregation
|
|
103
|
+
*
|
|
104
|
+
* Provides insights into campaign performance, claim patterns, and user engagement.
|
|
105
|
+
*
|
|
106
|
+
* @param request - Analytics request with filters, groupBy, and metrics
|
|
107
|
+
* @returns Promise resolving to campaign claim analytics data
|
|
108
|
+
*
|
|
109
|
+
* @example Claims per campaign
|
|
110
|
+
* ```typescript
|
|
111
|
+
* const analytics = await getCampaignClaimAnalytics({
|
|
112
|
+
* filters: { status: 'COMPLETED' },
|
|
113
|
+
* groupBy: ['campaignId'],
|
|
114
|
+
* metrics: ['count'],
|
|
115
|
+
* sortBy: 'count',
|
|
116
|
+
* sortOrder: 'DESC',
|
|
117
|
+
* limit: 10
|
|
118
|
+
* });
|
|
119
|
+
* console.log('Top campaigns:', analytics.results);
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
const getCampaignClaimAnalytics = useCallback(async (
|
|
123
|
+
request: CampaignClaimAnalyticsRequestDTO
|
|
124
|
+
): Promise<CampaignClaimAnalyticsResponseDTO> => {
|
|
125
|
+
if (!isInitialized || !sdk) {
|
|
126
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
const result = await sdk.analytics.getCampaignClaimAnalytics(request);
|
|
131
|
+
return result;
|
|
132
|
+
} catch (error) {
|
|
133
|
+
console.error('Failed to fetch campaign claim analytics:', error);
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
}, [sdk, isInitialized]);
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Retrieves user analytics with engagement metrics
|
|
140
|
+
*
|
|
141
|
+
* Includes both per-user and per-active-user metrics for accurate engagement insights.
|
|
142
|
+
* Per-active-user metrics show concentrated engagement among active users.
|
|
143
|
+
*
|
|
144
|
+
* @param request - Analytics request with optional filters and date range
|
|
145
|
+
* @returns Promise resolving to user analytics data
|
|
146
|
+
*
|
|
147
|
+
* @example Compare per-user vs per-active-user metrics
|
|
148
|
+
* ```typescript
|
|
149
|
+
* const analytics = await getUserAnalytics({
|
|
150
|
+
* startDate: new Date('2026-02-01'),
|
|
151
|
+
* endDate: new Date('2026-02-28')
|
|
152
|
+
* });
|
|
153
|
+
*
|
|
154
|
+
* console.log(`Active users: ${analytics.activeUsers} / ${analytics.totalUsers}`);
|
|
155
|
+
* console.log(`Engagement rate: ${analytics.engagementRate.toFixed(1)}%`);
|
|
156
|
+
*
|
|
157
|
+
* // Per-active-user metrics (more meaningful)
|
|
158
|
+
* console.log(`Avg transactions per active user: ${analytics.averageTransactionsPerActiveUser}`);
|
|
159
|
+
* ```
|
|
160
|
+
*
|
|
161
|
+
* @example Business-specific analytics
|
|
162
|
+
* ```typescript
|
|
163
|
+
* const analytics = await getUserAnalytics({
|
|
164
|
+
* filters: { businessId: 'business-123' },
|
|
165
|
+
* startDate: new Date('2026-01-01'),
|
|
166
|
+
* endDate: new Date('2026-12-31')
|
|
167
|
+
* });
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
const getUserAnalytics = useCallback(async (
|
|
171
|
+
request: UserAnalyticsRequestDTO = {}
|
|
172
|
+
): Promise<UserAnalyticsResponseDTO> => {
|
|
173
|
+
if (!isInitialized || !sdk) {
|
|
174
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
const result = await sdk.analytics.getUserAnalytics(request);
|
|
179
|
+
return result;
|
|
180
|
+
} catch (error) {
|
|
181
|
+
console.error('Failed to fetch user analytics:', error);
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
}, [sdk, isInitialized]);
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Retrieves user transaction ranking with enriched user data
|
|
188
|
+
*
|
|
189
|
+
* Returns ranked list of users with full user details (email, externalUserId)
|
|
190
|
+
* and transaction metrics. Ideal for leaderboards, engagement analysis,
|
|
191
|
+
* and identifying power users.
|
|
192
|
+
*
|
|
193
|
+
* @param request - Ranking request with filters, sorting, and limit
|
|
194
|
+
* @returns Promise resolving to ranked user list with transaction metrics
|
|
195
|
+
*
|
|
196
|
+
* @example Top 50 users by transaction count
|
|
197
|
+
* ```typescript
|
|
198
|
+
* const ranking = await getUserRanking({
|
|
199
|
+
* sortBy: 'totalTransactions',
|
|
200
|
+
* sortOrder: 'DESC',
|
|
201
|
+
* limit: 50
|
|
202
|
+
* });
|
|
203
|
+
*
|
|
204
|
+
* ranking.results.forEach((user, index) => {
|
|
205
|
+
* console.log(`#${index + 1}: ${user.email || user.externalUserId}`);
|
|
206
|
+
* console.log(` Transactions: ${user.totalTransactions}`);
|
|
207
|
+
* console.log(` Token spent: ${user.tokenSpent}`);
|
|
208
|
+
* });
|
|
209
|
+
* ```
|
|
210
|
+
*
|
|
211
|
+
* @example Top STAMP spenders
|
|
212
|
+
* ```typescript
|
|
213
|
+
* const ranking = await getUserRanking({
|
|
214
|
+
* filters: { tokenType: 'STAMP' },
|
|
215
|
+
* sortBy: 'tokenSpent',
|
|
216
|
+
* sortOrder: 'DESC',
|
|
217
|
+
* limit: 20
|
|
218
|
+
* });
|
|
219
|
+
* ```
|
|
220
|
+
*/
|
|
221
|
+
const getUserRanking = useCallback(async (
|
|
222
|
+
request: UserRankingAnalyticsRequestDTO = {}
|
|
223
|
+
): Promise<UserRankingAnalyticsResponseDTO> => {
|
|
224
|
+
if (!isInitialized || !sdk) {
|
|
225
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
const result = await sdk.analytics.getUserRanking(request);
|
|
230
|
+
return result;
|
|
231
|
+
} catch (error) {
|
|
232
|
+
console.error('Failed to fetch user ranking:', error);
|
|
233
|
+
throw error;
|
|
234
|
+
}
|
|
235
|
+
}, [sdk, isInitialized]);
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Retrieves business transaction ranking with enriched business data
|
|
239
|
+
*
|
|
240
|
+
* Returns ranked list of businesses with transaction metrics for
|
|
241
|
+
* partner analytics and performance dashboards.
|
|
242
|
+
*
|
|
243
|
+
* @param request - Ranking request with filters, sorting, and limit
|
|
244
|
+
* @returns Promise resolving to ranked business list
|
|
245
|
+
*
|
|
246
|
+
* @example Top businesses by transaction count
|
|
247
|
+
* ```typescript
|
|
248
|
+
* const ranking = await getBusinessRanking({
|
|
249
|
+
* sortBy: 'totalTransactions',
|
|
250
|
+
* sortOrder: 'DESC',
|
|
251
|
+
* limit: 20
|
|
252
|
+
* });
|
|
253
|
+
*
|
|
254
|
+
* ranking.results.forEach((business, index) => {
|
|
255
|
+
* console.log(`#${index + 1}: ${business.businessId}`);
|
|
256
|
+
* console.log(` Transactions: ${business.totalTransactions}`);
|
|
257
|
+
* console.log(` Token spent: ${business.tokenSpent}`);
|
|
258
|
+
* });
|
|
259
|
+
* ```
|
|
260
|
+
*/
|
|
261
|
+
const getBusinessRanking = useCallback(async (
|
|
262
|
+
request: BusinessRankingAnalyticsRequestDTO = {}
|
|
263
|
+
): Promise<BusinessRankingAnalyticsResponseDTO> => {
|
|
264
|
+
if (!isInitialized || !sdk) {
|
|
265
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
const result = await sdk.analytics.getBusinessRanking(request);
|
|
270
|
+
return result;
|
|
271
|
+
} catch (error) {
|
|
272
|
+
console.error('Failed to fetch business ranking:', error);
|
|
273
|
+
throw error;
|
|
274
|
+
}
|
|
275
|
+
}, [sdk, isInitialized]);
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Retrieves monthly user retention analytics
|
|
279
|
+
*
|
|
280
|
+
* Returns monthly retention data with active, new, and returning users
|
|
281
|
+
* along with retention rates. Useful for churn analysis and engagement trends.
|
|
282
|
+
*
|
|
283
|
+
* @param request - Retention request with monthsBack and filters
|
|
284
|
+
* @returns Promise resolving to monthly retention data
|
|
285
|
+
*
|
|
286
|
+
* @example Get 12 months of retention data
|
|
287
|
+
* ```typescript
|
|
288
|
+
* const retention = await getRetentionAnalytics({
|
|
289
|
+
* monthsBack: 12
|
|
290
|
+
* });
|
|
291
|
+
*
|
|
292
|
+
* retention.results.forEach(month => {
|
|
293
|
+
* console.log(`${month.month}:`);
|
|
294
|
+
* console.log(` Active: ${month.activeUsers}`);
|
|
295
|
+
* console.log(` New: ${month.newUsers}`);
|
|
296
|
+
* console.log(` Returning: ${month.returningUsers}`);
|
|
297
|
+
* console.log(` Retention Rate: ${month.retentionRate.toFixed(1)}%`);
|
|
298
|
+
* });
|
|
299
|
+
* ```
|
|
300
|
+
*/
|
|
301
|
+
const getRetentionAnalytics = useCallback(async (
|
|
302
|
+
request: RetentionAnalyticsRequestDTO = {}
|
|
303
|
+
): Promise<RetentionAnalyticsResponseDTO> => {
|
|
304
|
+
if (!isInitialized || !sdk) {
|
|
305
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
try {
|
|
309
|
+
const result = await sdk.analytics.getRetentionAnalytics(request);
|
|
310
|
+
return result;
|
|
311
|
+
} catch (error) {
|
|
312
|
+
console.error('Failed to fetch retention analytics:', error);
|
|
313
|
+
throw error;
|
|
314
|
+
}
|
|
315
|
+
}, [sdk, isInitialized]);
|
|
316
|
+
|
|
75
317
|
return {
|
|
76
318
|
getTransactionAnalytics,
|
|
319
|
+
getCampaignClaimAnalytics,
|
|
320
|
+
getUserAnalytics,
|
|
321
|
+
getUserRanking,
|
|
322
|
+
getBusinessRanking,
|
|
323
|
+
getRetentionAnalytics,
|
|
77
324
|
isAvailable: isInitialized && !!sdk?.analytics,
|
|
78
325
|
};
|
|
79
326
|
};
|