@explorins/pers-sdk-react-native 2.3.6 → 2.3.8
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/LICENSE +21 -0
- package/README.md +1266 -1244
- package/dist/__tests__/PersSDKProvider.test.js +33 -0
- package/dist/hooks/useBusiness.d.ts +2 -2
- package/dist/hooks/useBusiness.d.ts.map +1 -1
- package/dist/hooks/useBusiness.js +2 -2
- package/dist/hooks/useIPFSUrl.d.ts +3 -3
- package/dist/hooks/useIPFSUrl.d.ts.map +1 -1
- package/dist/hooks/useIPFSUrl.js +7 -7
- package/dist/hooks/useTransactions.d.ts.map +1 -1
- package/dist/hooks/useTransactions.js +13 -5
- package/dist/hooks/useWeb3.js +4 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2412 -492
- package/dist/index.js.map +1 -1
- package/dist/providers/PersSDKProvider.d.ts +4 -0
- package/dist/providers/PersSDKProvider.d.ts.map +1 -1
- package/dist/providers/PersSDKProvider.js +14 -0
- package/dist/providers/react-native-http-client.d.ts +2 -0
- package/dist/providers/react-native-http-client.d.ts.map +1 -1
- package/dist/providers/react-native-http-client.js +5 -2
- package/dist/storage/rn-secure-storage.d.ts.map +1 -1
- package/dist/storage/rn-secure-storage.js +21 -8
- package/package.json +3 -3
- package/src/__tests__/PersSDKProvider.test.tsx +484 -420
- package/src/__tests__/setup.ts +40 -40
- package/src/hooks/index.ts +60 -60
- package/src/hooks/useAnalytics.ts +327 -327
- package/src/hooks/useAuth.ts +265 -265
- package/src/hooks/useBookings.ts +191 -191
- package/src/hooks/useBusiness.ts +251 -251
- package/src/hooks/useCampaigns.ts +500 -500
- package/src/hooks/useDonations.ts +66 -66
- package/src/hooks/useEvents.ts +372 -372
- package/src/hooks/useFiles.ts +155 -155
- package/src/hooks/useIPFSUrl.ts +192 -192
- package/src/hooks/usePurchases.ts +65 -65
- package/src/hooks/useRedemptions.ts +467 -467
- package/src/hooks/useTenants.ts +72 -72
- package/src/hooks/useTokenBalances.ts +385 -385
- package/src/hooks/useTokens.ts +313 -313
- package/src/hooks/useTransactionSigner.ts +611 -611
- package/src/hooks/useTransactions.ts +299 -290
- package/src/hooks/useTriggerSources.ts +301 -301
- package/src/hooks/useUserStatus.ts +61 -61
- package/src/hooks/useUsers.ts +167 -167
- package/src/hooks/useWeb3.ts +355 -355
- package/src/index.ts +777 -774
- package/src/polyfills/index.ts +160 -160
- package/src/polyfills/web3-polyfills.ts +97 -97
- package/src/providers/PersSDKProvider.tsx +393 -374
- package/src/providers/react-native-auth-provider.ts +110 -110
- package/src/providers/react-native-http-client.ts +150 -145
- package/src/providers/rn-dpop-provider.ts +190 -190
- package/src/storage/async-storage-token-storage.ts +185 -185
- package/src/storage/rn-secure-storage.ts +182 -170
- package/src/types/react-native-globals.d.ts +45 -45
- package/src/utils/index.ts +8 -8
- package/src/utils/platform-detection.ts +86 -86
- package/dist/index-CzLxqePZ.js +0 -7717
- package/dist/index-CzLxqePZ.js.map +0 -1
|
@@ -1,501 +1,501 @@
|
|
|
1
|
-
import { useCallback } from 'react';
|
|
2
|
-
import { usePersSDK } from '../providers/PersSDKProvider';
|
|
3
|
-
import type {
|
|
4
|
-
CampaignClaimRequestDTO,
|
|
5
|
-
CampaignDTO,
|
|
6
|
-
CampaignClaimDTO,
|
|
7
|
-
CampaignTriggerDTO,
|
|
8
|
-
PaginatedResponseDTO,
|
|
9
|
-
CampaignClaimIncludeRelation,
|
|
10
|
-
CampaignIncludeRelation,
|
|
11
|
-
SortOrder,
|
|
12
|
-
CampaignFilterOptions,
|
|
13
|
-
// DynamicContext
|
|
14
|
-
} from '@explorins/pers-sdk';
|
|
15
|
-
import type { CampaignClaimFilters } from '@explorins/pers-sdk/campaign';
|
|
16
|
-
|
|
17
|
-
// Re-export for consumers
|
|
18
|
-
export type { CampaignClaimFilters } from '@explorins/pers-sdk/campaign';
|
|
19
|
-
export type { CampaignFilterOptions } from '@explorins/pers-sdk';
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Options for fetching campaigns
|
|
23
|
-
* @deprecated Use CampaignFilterOptions from '@explorins/pers-sdk/campaign' instead
|
|
24
|
-
*/
|
|
25
|
-
export interface GetCampaignsOptions {
|
|
26
|
-
/** Filter by tag(s) - single tag or array for OR match */
|
|
27
|
-
tags?: string | string[];
|
|
28
|
-
/** Free text search across name and description (case-insensitive) */
|
|
29
|
-
search?: string;
|
|
30
|
-
/** Filter by business ID */
|
|
31
|
-
businessId?: string;
|
|
32
|
-
/** Filter campaigns starting on or after this date */
|
|
33
|
-
startDate?: Date | string;
|
|
34
|
-
/** Filter campaigns ending on or before this date */
|
|
35
|
-
endDate?: Date | string;
|
|
36
|
-
/** Page number (1-indexed) */
|
|
37
|
-
page?: number;
|
|
38
|
-
/** Items per page */
|
|
39
|
-
limit?: number;
|
|
40
|
-
/** Sort field */
|
|
41
|
-
sortBy?: 'name' | 'createdAt' | 'startDate';
|
|
42
|
-
/** Sort order */
|
|
43
|
-
sortOrder?: SortOrder;
|
|
44
|
-
/** Relations to include: 'triggerSources', 'businesses', 'claimCount' */
|
|
45
|
-
include?: CampaignIncludeRelation[];
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export const useCampaigns = () => {
|
|
49
|
-
const { sdk, isInitialized, isAuthenticated } = usePersSDK();
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Get active campaigns with optional filters and include relations
|
|
53
|
-
*
|
|
54
|
-
* @param options - Filter, pagination, and include options
|
|
55
|
-
* @returns Promise resolving to paginated active campaigns
|
|
56
|
-
*
|
|
57
|
-
* @example
|
|
58
|
-
* ```typescript
|
|
59
|
-
* // Simple: get active campaigns with trigger sources
|
|
60
|
-
* const { data: campaigns } = await getActiveCampaigns({ include: ['triggerSources'] });
|
|
61
|
-
*
|
|
62
|
-
* // With pagination
|
|
63
|
-
* const { data, pagination } = await getActiveCampaigns({
|
|
64
|
-
* page: 1,
|
|
65
|
-
* limit: 10,
|
|
66
|
-
* include: ['triggerSources', 'businesses']
|
|
67
|
-
* });
|
|
68
|
-
*
|
|
69
|
-
* // Filter by date range
|
|
70
|
-
* const { data } = await getActiveCampaigns({
|
|
71
|
-
* startDate: '2026-05-01',
|
|
72
|
-
* endDate: '2026-12-31'
|
|
73
|
-
* });
|
|
74
|
-
*
|
|
75
|
-
* // Get campaigns with claim count
|
|
76
|
-
* const { data } = await getActiveCampaigns({ include: ['claimCount'] });
|
|
77
|
-
* data.forEach(c => console.log(`${c.name}: ${c.claimCount} claims`));
|
|
78
|
-
* ```
|
|
79
|
-
*/
|
|
80
|
-
const getActiveCampaigns = useCallback(async (
|
|
81
|
-
options?: GetCampaignsOptions
|
|
82
|
-
): Promise<PaginatedResponseDTO<CampaignDTO>> => {
|
|
83
|
-
if (!isInitialized || !sdk) {
|
|
84
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
const result = await sdk.campaigns.getCampaigns({
|
|
89
|
-
active: true,
|
|
90
|
-
...options
|
|
91
|
-
});
|
|
92
|
-
return result;
|
|
93
|
-
} catch (error) {
|
|
94
|
-
console.error('Failed to fetch active campaigns:', error);
|
|
95
|
-
throw error;
|
|
96
|
-
}
|
|
97
|
-
}, [sdk, isInitialized]);
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Get campaign by ID with optional include relations
|
|
101
|
-
*
|
|
102
|
-
* @param campaignId - The campaign ID
|
|
103
|
-
* @param include - Relations to include: 'triggerSources', 'businesses', 'claimCount'
|
|
104
|
-
* @returns Promise resolving to campaign data
|
|
105
|
-
*
|
|
106
|
-
* @example
|
|
107
|
-
* ```typescript
|
|
108
|
-
* // Get campaign with all related data
|
|
109
|
-
* const campaign = await getCampaignById('campaign-123', ['triggerSources', 'businesses']);
|
|
110
|
-
* console.log('Trigger sources:', campaign.included?.triggerSources);
|
|
111
|
-
*
|
|
112
|
-
* // Get campaign with claim count
|
|
113
|
-
* const campaign = await getCampaignById('campaign-123', ['claimCount']);
|
|
114
|
-
* console.log('Total claims:', campaign.claimCount);
|
|
115
|
-
* ```
|
|
116
|
-
*/
|
|
117
|
-
const getCampaignById = useCallback(async (
|
|
118
|
-
campaignId: string,
|
|
119
|
-
include?: CampaignIncludeRelation[]
|
|
120
|
-
): Promise<CampaignDTO | null> => {
|
|
121
|
-
if (!isInitialized || !sdk) {
|
|
122
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
const result = await sdk.campaigns.getCampaignById(campaignId, include);
|
|
127
|
-
return result;
|
|
128
|
-
} catch (error) {
|
|
129
|
-
console.error('Failed to fetch campaign:', error);
|
|
130
|
-
throw error;
|
|
131
|
-
}
|
|
132
|
-
}, [sdk, isInitialized]);
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Claim a campaign reward with optional dynamic context
|
|
136
|
-
*
|
|
137
|
-
* Triggers a campaign claim for the authenticated user. The campaign must be active
|
|
138
|
-
* and the user must meet all eligibility requirements. Supports dynamic context for
|
|
139
|
-
* personalized NFT generation when the campaign issues ERC721 tokens.
|
|
140
|
-
*
|
|
141
|
-
* @param request - Campaign claim request with optional context
|
|
142
|
-
* @param request.campaignId - ID of the campaign to claim (optional if using triggerSourceId)
|
|
143
|
-
* @param request.triggerSourceId - ID of trigger source (QR, NFC, etc.)
|
|
144
|
-
* @param request.context - Dynamic context for NFT personalization
|
|
145
|
-
* @param request.metadata - Additional metadata for the claim
|
|
146
|
-
* @param request.latitude - User's latitude for geo-validated claims
|
|
147
|
-
* @param request.longitude - User's longitude for geo-validated claims
|
|
148
|
-
* @returns Promise resolving to campaign claim result
|
|
149
|
-
*
|
|
150
|
-
* @example Basic campaign claim
|
|
151
|
-
* ```typescript
|
|
152
|
-
* const claim = await claimCampaign({
|
|
153
|
-
* triggerSourceId: 'qr-code-123',
|
|
154
|
-
* });
|
|
155
|
-
* ```
|
|
156
|
-
*
|
|
157
|
-
* @example Campaign claim with dynamic context (personalized NFT)
|
|
158
|
-
* ```typescript
|
|
159
|
-
* import { DynamicContext } from '@explorins/pers-sdk-react-native';
|
|
160
|
-
*
|
|
161
|
-
* const context: DynamicContext = {
|
|
162
|
-
* // Validity - token valid for 30 days
|
|
163
|
-
* validityDate: new Date().toISOString(),
|
|
164
|
-
* validityDuration: 30,
|
|
165
|
-
*
|
|
166
|
-
* // AI prompt context - available as {{context.xxx}} in prompts
|
|
167
|
-
* visitorName: 'John Doe',
|
|
168
|
-
* visitLocation: 'Grand Hotel Lobby',
|
|
169
|
-
* membershipTier: 'Gold',
|
|
170
|
-
* };
|
|
171
|
-
*
|
|
172
|
-
* const claim = await claimCampaign({
|
|
173
|
-
* triggerSourceId: 'hotel-checkin-qr',
|
|
174
|
-
* context,
|
|
175
|
-
* });
|
|
176
|
-
* ```
|
|
177
|
-
*
|
|
178
|
-
* @example Geo-validated claim with context
|
|
179
|
-
* ```typescript
|
|
180
|
-
* const claim = await claimCampaign({
|
|
181
|
-
* triggerSourceId: 'museum-entrance-nfc',
|
|
182
|
-
* latitude: 48.8606,
|
|
183
|
-
* longitude: 2.3376,
|
|
184
|
-
* context: {
|
|
185
|
-
* visitorType: 'Adult',
|
|
186
|
-
* ticketCategory: 'General Admission',
|
|
187
|
-
* }
|
|
188
|
-
* });
|
|
189
|
-
* ```
|
|
190
|
-
*/
|
|
191
|
-
const claimCampaign = useCallback(async (request: CampaignClaimRequestDTO): Promise<CampaignClaimDTO | null> => {
|
|
192
|
-
if (!isInitialized || !sdk) {
|
|
193
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
194
|
-
}
|
|
195
|
-
if (!isAuthenticated) {
|
|
196
|
-
throw new Error('SDK not authenticated. claimCampaign requires authentication.');
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
try {
|
|
200
|
-
const result = await sdk.campaigns.claimCampaign(request);
|
|
201
|
-
return result;
|
|
202
|
-
} catch (error) {
|
|
203
|
-
console.error('Failed to claim campaign:', error);
|
|
204
|
-
throw error;
|
|
205
|
-
}
|
|
206
|
-
}, [sdk, isInitialized, isAuthenticated]);
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Get user's campaign claims with optional pagination and include relations
|
|
210
|
-
*
|
|
211
|
-
* @param options - Optional options including pagination and include relations
|
|
212
|
-
* @returns Promise resolving to paginated campaign claims
|
|
213
|
-
*
|
|
214
|
-
* @example
|
|
215
|
-
* ```typescript
|
|
216
|
-
* // Get user's claims with campaign details
|
|
217
|
-
* const { data: claims } = await getUserClaims({ include: ['campaign', 'business'] });
|
|
218
|
-
* claims.forEach(claim => {
|
|
219
|
-
* console.log('Campaign:', claim.included?.campaign?.name);
|
|
220
|
-
* });
|
|
221
|
-
*
|
|
222
|
-
* // With pagination
|
|
223
|
-
* const { data } = await getUserClaims({ page: 1, limit: 10, include: ['campaign'] });
|
|
224
|
-
* ```
|
|
225
|
-
*/
|
|
226
|
-
const getUserClaims = useCallback(async (options?: {
|
|
227
|
-
page?: number;
|
|
228
|
-
limit?: number;
|
|
229
|
-
include?: CampaignClaimIncludeRelation[];
|
|
230
|
-
}): Promise<PaginatedResponseDTO<CampaignClaimDTO>> => {
|
|
231
|
-
if (!isInitialized || !sdk) {
|
|
232
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
233
|
-
}
|
|
234
|
-
if (!isAuthenticated) {
|
|
235
|
-
console.warn('SDK not authenticated. getUserClaims requires authentication.');
|
|
236
|
-
return { data: [], pagination: { page: 1, limit: 0, total: 0, pages: 0, hasNext: false, hasPrev: false } };
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
try {
|
|
240
|
-
const result = await sdk.campaigns.getUserClaims(options);
|
|
241
|
-
return result;
|
|
242
|
-
} catch (error) {
|
|
243
|
-
console.error('Failed to fetch user claims:', error);
|
|
244
|
-
throw error;
|
|
245
|
-
}
|
|
246
|
-
}, [sdk, isInitialized, isAuthenticated]);
|
|
247
|
-
|
|
248
|
-
const getCampaignTriggers = useCallback(async (): Promise<PaginatedResponseDTO<CampaignTriggerDTO>> => {
|
|
249
|
-
if (!isInitialized || !sdk) {
|
|
250
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
try {
|
|
254
|
-
const result = await sdk.campaigns.getCampaignTriggers();
|
|
255
|
-
return result;
|
|
256
|
-
} catch (error) {
|
|
257
|
-
console.error('Failed to fetch campaign triggers:', error);
|
|
258
|
-
throw error;
|
|
259
|
-
}
|
|
260
|
-
}, [sdk, isInitialized]);
|
|
261
|
-
|
|
262
|
-
// Admin methods
|
|
263
|
-
/**
|
|
264
|
-
* Admin: Get all campaigns with optional filters and include relations
|
|
265
|
-
*
|
|
266
|
-
* @param options - Filter, pagination, and include options (same as getActiveCampaigns but active is optional)
|
|
267
|
-
* @returns Promise resolving to paginated campaigns
|
|
268
|
-
*
|
|
269
|
-
* @example
|
|
270
|
-
* ```typescript
|
|
271
|
-
* // Get all campaigns
|
|
272
|
-
* const { data } = await getAllCampaigns();
|
|
273
|
-
*
|
|
274
|
-
* // Get only active campaigns with trigger sources
|
|
275
|
-
* const { data } = await getAllCampaigns({ active: true, include: ['triggerSources'] });
|
|
276
|
-
*
|
|
277
|
-
* // Filter by date range with claim count
|
|
278
|
-
* const { data } = await getAllCampaigns({
|
|
279
|
-
* startDate: '2026-05-01',
|
|
280
|
-
* endDate: '2026-12-31',
|
|
281
|
-
* include: ['claimCount']
|
|
282
|
-
* });
|
|
283
|
-
* data.forEach(c => console.log(`${c.name}: ${c.claimCount} claims`));
|
|
284
|
-
*
|
|
285
|
-
* // With pagination and sorting
|
|
286
|
-
* const { data } = await getAllCampaigns({
|
|
287
|
-
* page: 1,
|
|
288
|
-
* limit: 20,
|
|
289
|
-
* sortBy: 'createdAt',
|
|
290
|
-
* sortOrder: 'DESC'
|
|
291
|
-
* });
|
|
292
|
-
* ```
|
|
293
|
-
*/
|
|
294
|
-
const getAllCampaigns = useCallback(async (
|
|
295
|
-
options?: GetCampaignsOptions & { active?: boolean }
|
|
296
|
-
): Promise<PaginatedResponseDTO<CampaignDTO>> => {
|
|
297
|
-
if (!isInitialized || !sdk) {
|
|
298
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
try {
|
|
302
|
-
const result = await sdk.campaigns.getCampaigns(options);
|
|
303
|
-
return result;
|
|
304
|
-
} catch (error) {
|
|
305
|
-
console.error('Failed to fetch all campaigns:', error);
|
|
306
|
-
throw error;
|
|
307
|
-
}
|
|
308
|
-
}, [sdk, isInitialized]);
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* Admin: Get campaign claims with optional filters and include relations
|
|
312
|
-
*
|
|
313
|
-
* @param filters - Optional filters for campaign, user, business, and date range
|
|
314
|
-
* @param filters.campaignId - Filter by specific campaign ID
|
|
315
|
-
* @param filters.userId - Filter by user ID
|
|
316
|
-
* @param filters.businessId - Filter by business ID
|
|
317
|
-
* @param filters.dateFrom - Filter claims created on or after this date (ISO 8601 format)
|
|
318
|
-
* @param filters.dateTo - Filter claims created on or before this date (ISO 8601 format)
|
|
319
|
-
* @param filters.page - Page number (1-indexed)
|
|
320
|
-
* @param filters.limit - Items per page
|
|
321
|
-
* @param filters.sortBy - Field to sort by
|
|
322
|
-
* @param filters.sortOrder - Sort direction
|
|
323
|
-
* @param include - Relations to include: 'campaign', 'user', 'business'
|
|
324
|
-
* @returns Promise resolving to paginated campaign claims
|
|
325
|
-
*
|
|
326
|
-
* @example
|
|
327
|
-
* ```typescript
|
|
328
|
-
* // Get all claims with user details
|
|
329
|
-
* const { data: claims } = await getCampaignClaims({}, ['user']);
|
|
330
|
-
*
|
|
331
|
-
* // Get claims for a specific campaign
|
|
332
|
-
* const { data } = await getCampaignClaims({ campaignId: 'campaign-123' }, ['user', 'business']);
|
|
333
|
-
*
|
|
334
|
-
* // Filter by date range
|
|
335
|
-
* const { data } = await getCampaignClaims({
|
|
336
|
-
* dateFrom: '2026-01-01',
|
|
337
|
-
* dateTo: '2026-03-31'
|
|
338
|
-
* }, ['campaign']);
|
|
339
|
-
* ```
|
|
340
|
-
*/
|
|
341
|
-
const getCampaignClaims = useCallback(async (
|
|
342
|
-
filters?: CampaignClaimFilters,
|
|
343
|
-
include?: CampaignClaimIncludeRelation[]
|
|
344
|
-
): Promise<PaginatedResponseDTO<CampaignClaimDTO>> => {
|
|
345
|
-
if (!isInitialized || !sdk) {
|
|
346
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
try {
|
|
350
|
-
const result = await sdk.campaigns.getCampaignClaims(filters, include);
|
|
351
|
-
return result;
|
|
352
|
-
} catch (error) {
|
|
353
|
-
console.error('Failed to fetch campaign claims:', error);
|
|
354
|
-
throw error;
|
|
355
|
-
}
|
|
356
|
-
}, [sdk, isInitialized]);
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* Admin: Get campaign claims by user ID with optional include relations
|
|
360
|
-
*
|
|
361
|
-
* @param userId - The user ID
|
|
362
|
-
* @param include - Relations to include: 'campaign', 'user', 'business'
|
|
363
|
-
* @returns Promise resolving to paginated campaign claims
|
|
364
|
-
*/
|
|
365
|
-
const getCampaignClaimsByUserId = useCallback(async (
|
|
366
|
-
userId: string,
|
|
367
|
-
include?: CampaignClaimIncludeRelation[]
|
|
368
|
-
): Promise<PaginatedResponseDTO<CampaignClaimDTO>> => {
|
|
369
|
-
if (!isInitialized || !sdk) {
|
|
370
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
try {
|
|
374
|
-
const result = await sdk.campaigns.getCampaignClaimsByUserId(userId, undefined, include);
|
|
375
|
-
return result;
|
|
376
|
-
} catch (error) {
|
|
377
|
-
console.error('Failed to fetch campaign claims by user ID:', error);
|
|
378
|
-
throw error;
|
|
379
|
-
}
|
|
380
|
-
}, [sdk, isInitialized]);
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Admin: Get campaign claims by business ID with optional include relations
|
|
384
|
-
*
|
|
385
|
-
* @param businessId - The business ID
|
|
386
|
-
* @param include - Relations to include: 'campaign', 'user', 'business'
|
|
387
|
-
* @returns Promise resolving to paginated campaign claims
|
|
388
|
-
*/
|
|
389
|
-
const getCampaignClaimsByBusinessId = useCallback(async (
|
|
390
|
-
businessId: string,
|
|
391
|
-
include?: CampaignClaimIncludeRelation[]
|
|
392
|
-
): Promise<PaginatedResponseDTO<CampaignClaimDTO>> => {
|
|
393
|
-
if (!isInitialized || !sdk) {
|
|
394
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
try {
|
|
398
|
-
const result = await sdk.campaigns.getCampaignClaimsByBusinessId(businessId, undefined, include);
|
|
399
|
-
return result;
|
|
400
|
-
} catch (error) {
|
|
401
|
-
console.error('Failed to fetch campaign claims by business ID:', error);
|
|
402
|
-
throw error;
|
|
403
|
-
}
|
|
404
|
-
}, [sdk, isInitialized]);
|
|
405
|
-
|
|
406
|
-
// ==========================================
|
|
407
|
-
// TRIGGER SOURCE ASSIGNMENT (Admin)
|
|
408
|
-
// Note: TriggerSource CRUD is in useTriggerSources hook
|
|
409
|
-
// ==========================================
|
|
410
|
-
|
|
411
|
-
/**
|
|
412
|
-
* Admin: Assign a trigger source to a campaign
|
|
413
|
-
*
|
|
414
|
-
* Associates a trigger source (QR code, NFC tag, etc.) with a campaign.
|
|
415
|
-
* A campaign can have multiple trigger sources.
|
|
416
|
-
*
|
|
417
|
-
* Note: To create/update/delete trigger sources, use `useTriggerSources` hook.
|
|
418
|
-
*
|
|
419
|
-
* @param campaignId - Campaign UUID
|
|
420
|
-
* @param triggerSourceId - Trigger source UUID
|
|
421
|
-
* @returns Promise resolving to updated campaign
|
|
422
|
-
*
|
|
423
|
-
* @example
|
|
424
|
-
* ```typescript
|
|
425
|
-
* const { create } = useTriggerSources();
|
|
426
|
-
* const { assignTriggerSource } = useCampaigns();
|
|
427
|
-
*
|
|
428
|
-
* // Create trigger source first
|
|
429
|
-
* const source = await create({ type: 'QR_CODE', name: 'Store QR' });
|
|
430
|
-
*
|
|
431
|
-
* // Then assign to campaign
|
|
432
|
-
* const updated = await assignTriggerSource('campaign-123', source.id);
|
|
433
|
-
* ```
|
|
434
|
-
*/
|
|
435
|
-
const assignTriggerSource = useCallback(async (
|
|
436
|
-
campaignId: string,
|
|
437
|
-
triggerSourceId: string
|
|
438
|
-
): Promise<CampaignDTO> => {
|
|
439
|
-
if (!isInitialized || !sdk) {
|
|
440
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
441
|
-
}
|
|
442
|
-
if (!isAuthenticated) {
|
|
443
|
-
throw new Error('SDK not authenticated. assignTriggerSource requires admin authentication.');
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
try {
|
|
447
|
-
const result = await sdk.campaigns.assignTriggerSource(campaignId, triggerSourceId);
|
|
448
|
-
return result;
|
|
449
|
-
} catch (error) {
|
|
450
|
-
console.error('Failed to assign trigger source:', error);
|
|
451
|
-
throw error;
|
|
452
|
-
}
|
|
453
|
-
}, [sdk, isInitialized, isAuthenticated]);
|
|
454
|
-
|
|
455
|
-
/**
|
|
456
|
-
* Admin: Remove a trigger source from a campaign
|
|
457
|
-
*
|
|
458
|
-
* Removes the association between a trigger source and a campaign.
|
|
459
|
-
* The trigger source itself is not deleted.
|
|
460
|
-
*
|
|
461
|
-
* @param campaignId - Campaign UUID
|
|
462
|
-
* @param triggerSourceId - Trigger source UUID
|
|
463
|
-
* @returns Promise resolving to updated campaign
|
|
464
|
-
*/
|
|
465
|
-
const removeTriggerSource = useCallback(async (
|
|
466
|
-
campaignId: string,
|
|
467
|
-
triggerSourceId: string
|
|
468
|
-
): Promise<CampaignDTO> => {
|
|
469
|
-
if (!isInitialized || !sdk) {
|
|
470
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
471
|
-
}
|
|
472
|
-
if (!isAuthenticated) {
|
|
473
|
-
throw new Error('SDK not authenticated. removeTriggerSource requires admin authentication.');
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
try {
|
|
477
|
-
const result = await sdk.campaigns.removeTriggerSource(campaignId, triggerSourceId);
|
|
478
|
-
return result;
|
|
479
|
-
} catch (error) {
|
|
480
|
-
console.error('Failed to remove trigger source:', error);
|
|
481
|
-
throw error;
|
|
482
|
-
}
|
|
483
|
-
}, [sdk, isInitialized, isAuthenticated]);
|
|
484
|
-
|
|
485
|
-
return {
|
|
486
|
-
getActiveCampaigns,
|
|
487
|
-
getCampaignById,
|
|
488
|
-
claimCampaign,
|
|
489
|
-
getUserClaims,
|
|
490
|
-
getCampaignTriggers,
|
|
491
|
-
getAllCampaigns,
|
|
492
|
-
getCampaignClaims,
|
|
493
|
-
getCampaignClaimsByUserId,
|
|
494
|
-
getCampaignClaimsByBusinessId,
|
|
495
|
-
assignTriggerSource,
|
|
496
|
-
removeTriggerSource,
|
|
497
|
-
isAvailable: isInitialized && !!sdk?.campaigns,
|
|
498
|
-
};
|
|
499
|
-
};
|
|
500
|
-
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { usePersSDK } from '../providers/PersSDKProvider';
|
|
3
|
+
import type {
|
|
4
|
+
CampaignClaimRequestDTO,
|
|
5
|
+
CampaignDTO,
|
|
6
|
+
CampaignClaimDTO,
|
|
7
|
+
CampaignTriggerDTO,
|
|
8
|
+
PaginatedResponseDTO,
|
|
9
|
+
CampaignClaimIncludeRelation,
|
|
10
|
+
CampaignIncludeRelation,
|
|
11
|
+
SortOrder,
|
|
12
|
+
CampaignFilterOptions,
|
|
13
|
+
// DynamicContext
|
|
14
|
+
} from '@explorins/pers-sdk';
|
|
15
|
+
import type { CampaignClaimFilters } from '@explorins/pers-sdk/campaign';
|
|
16
|
+
|
|
17
|
+
// Re-export for consumers
|
|
18
|
+
export type { CampaignClaimFilters } from '@explorins/pers-sdk/campaign';
|
|
19
|
+
export type { CampaignFilterOptions } from '@explorins/pers-sdk';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Options for fetching campaigns
|
|
23
|
+
* @deprecated Use CampaignFilterOptions from '@explorins/pers-sdk/campaign' instead
|
|
24
|
+
*/
|
|
25
|
+
export interface GetCampaignsOptions {
|
|
26
|
+
/** Filter by tag(s) - single tag or array for OR match */
|
|
27
|
+
tags?: string | string[];
|
|
28
|
+
/** Free text search across name and description (case-insensitive) */
|
|
29
|
+
search?: string;
|
|
30
|
+
/** Filter by business ID */
|
|
31
|
+
businessId?: string;
|
|
32
|
+
/** Filter campaigns starting on or after this date */
|
|
33
|
+
startDate?: Date | string;
|
|
34
|
+
/** Filter campaigns ending on or before this date */
|
|
35
|
+
endDate?: Date | string;
|
|
36
|
+
/** Page number (1-indexed) */
|
|
37
|
+
page?: number;
|
|
38
|
+
/** Items per page */
|
|
39
|
+
limit?: number;
|
|
40
|
+
/** Sort field */
|
|
41
|
+
sortBy?: 'name' | 'createdAt' | 'startDate';
|
|
42
|
+
/** Sort order */
|
|
43
|
+
sortOrder?: SortOrder;
|
|
44
|
+
/** Relations to include: 'triggerSources', 'businesses', 'claimCount' */
|
|
45
|
+
include?: CampaignIncludeRelation[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const useCampaigns = () => {
|
|
49
|
+
const { sdk, isInitialized, isAuthenticated } = usePersSDK();
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get active campaigns with optional filters and include relations
|
|
53
|
+
*
|
|
54
|
+
* @param options - Filter, pagination, and include options
|
|
55
|
+
* @returns Promise resolving to paginated active campaigns
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* // Simple: get active campaigns with trigger sources
|
|
60
|
+
* const { data: campaigns } = await getActiveCampaigns({ include: ['triggerSources'] });
|
|
61
|
+
*
|
|
62
|
+
* // With pagination
|
|
63
|
+
* const { data, pagination } = await getActiveCampaigns({
|
|
64
|
+
* page: 1,
|
|
65
|
+
* limit: 10,
|
|
66
|
+
* include: ['triggerSources', 'businesses']
|
|
67
|
+
* });
|
|
68
|
+
*
|
|
69
|
+
* // Filter by date range
|
|
70
|
+
* const { data } = await getActiveCampaigns({
|
|
71
|
+
* startDate: '2026-05-01',
|
|
72
|
+
* endDate: '2026-12-31'
|
|
73
|
+
* });
|
|
74
|
+
*
|
|
75
|
+
* // Get campaigns with claim count
|
|
76
|
+
* const { data } = await getActiveCampaigns({ include: ['claimCount'] });
|
|
77
|
+
* data.forEach(c => console.log(`${c.name}: ${c.claimCount} claims`));
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
const getActiveCampaigns = useCallback(async (
|
|
81
|
+
options?: GetCampaignsOptions
|
|
82
|
+
): Promise<PaginatedResponseDTO<CampaignDTO>> => {
|
|
83
|
+
if (!isInitialized || !sdk) {
|
|
84
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const result = await sdk.campaigns.getCampaigns({
|
|
89
|
+
active: true,
|
|
90
|
+
...options
|
|
91
|
+
});
|
|
92
|
+
return result;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error('Failed to fetch active campaigns:', error);
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
}, [sdk, isInitialized]);
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Get campaign by ID with optional include relations
|
|
101
|
+
*
|
|
102
|
+
* @param campaignId - The campaign ID
|
|
103
|
+
* @param include - Relations to include: 'triggerSources', 'businesses', 'claimCount'
|
|
104
|
+
* @returns Promise resolving to campaign data
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* // Get campaign with all related data
|
|
109
|
+
* const campaign = await getCampaignById('campaign-123', ['triggerSources', 'businesses']);
|
|
110
|
+
* console.log('Trigger sources:', campaign.included?.triggerSources);
|
|
111
|
+
*
|
|
112
|
+
* // Get campaign with claim count
|
|
113
|
+
* const campaign = await getCampaignById('campaign-123', ['claimCount']);
|
|
114
|
+
* console.log('Total claims:', campaign.claimCount);
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
const getCampaignById = useCallback(async (
|
|
118
|
+
campaignId: string,
|
|
119
|
+
include?: CampaignIncludeRelation[]
|
|
120
|
+
): Promise<CampaignDTO | null> => {
|
|
121
|
+
if (!isInitialized || !sdk) {
|
|
122
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
const result = await sdk.campaigns.getCampaignById(campaignId, include);
|
|
127
|
+
return result;
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error('Failed to fetch campaign:', error);
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
}, [sdk, isInitialized]);
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Claim a campaign reward with optional dynamic context
|
|
136
|
+
*
|
|
137
|
+
* Triggers a campaign claim for the authenticated user. The campaign must be active
|
|
138
|
+
* and the user must meet all eligibility requirements. Supports dynamic context for
|
|
139
|
+
* personalized NFT generation when the campaign issues ERC721 tokens.
|
|
140
|
+
*
|
|
141
|
+
* @param request - Campaign claim request with optional context
|
|
142
|
+
* @param request.campaignId - ID of the campaign to claim (optional if using triggerSourceId)
|
|
143
|
+
* @param request.triggerSourceId - ID of trigger source (QR, NFC, etc.)
|
|
144
|
+
* @param request.context - Dynamic context for NFT personalization
|
|
145
|
+
* @param request.metadata - Additional metadata for the claim
|
|
146
|
+
* @param request.latitude - User's latitude for geo-validated claims
|
|
147
|
+
* @param request.longitude - User's longitude for geo-validated claims
|
|
148
|
+
* @returns Promise resolving to campaign claim result
|
|
149
|
+
*
|
|
150
|
+
* @example Basic campaign claim
|
|
151
|
+
* ```typescript
|
|
152
|
+
* const claim = await claimCampaign({
|
|
153
|
+
* triggerSourceId: 'qr-code-123',
|
|
154
|
+
* });
|
|
155
|
+
* ```
|
|
156
|
+
*
|
|
157
|
+
* @example Campaign claim with dynamic context (personalized NFT)
|
|
158
|
+
* ```typescript
|
|
159
|
+
* import { DynamicContext } from '@explorins/pers-sdk-react-native';
|
|
160
|
+
*
|
|
161
|
+
* const context: DynamicContext = {
|
|
162
|
+
* // Validity - token valid for 30 days
|
|
163
|
+
* validityDate: new Date().toISOString(),
|
|
164
|
+
* validityDuration: 30,
|
|
165
|
+
*
|
|
166
|
+
* // AI prompt context - available as {{context.xxx}} in prompts
|
|
167
|
+
* visitorName: 'John Doe',
|
|
168
|
+
* visitLocation: 'Grand Hotel Lobby',
|
|
169
|
+
* membershipTier: 'Gold',
|
|
170
|
+
* };
|
|
171
|
+
*
|
|
172
|
+
* const claim = await claimCampaign({
|
|
173
|
+
* triggerSourceId: 'hotel-checkin-qr',
|
|
174
|
+
* context,
|
|
175
|
+
* });
|
|
176
|
+
* ```
|
|
177
|
+
*
|
|
178
|
+
* @example Geo-validated claim with context
|
|
179
|
+
* ```typescript
|
|
180
|
+
* const claim = await claimCampaign({
|
|
181
|
+
* triggerSourceId: 'museum-entrance-nfc',
|
|
182
|
+
* latitude: 48.8606,
|
|
183
|
+
* longitude: 2.3376,
|
|
184
|
+
* context: {
|
|
185
|
+
* visitorType: 'Adult',
|
|
186
|
+
* ticketCategory: 'General Admission',
|
|
187
|
+
* }
|
|
188
|
+
* });
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
const claimCampaign = useCallback(async (request: CampaignClaimRequestDTO): Promise<CampaignClaimDTO | null> => {
|
|
192
|
+
if (!isInitialized || !sdk) {
|
|
193
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
194
|
+
}
|
|
195
|
+
if (!isAuthenticated) {
|
|
196
|
+
throw new Error('SDK not authenticated. claimCampaign requires authentication.');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
const result = await sdk.campaigns.claimCampaign(request);
|
|
201
|
+
return result;
|
|
202
|
+
} catch (error) {
|
|
203
|
+
console.error('Failed to claim campaign:', error);
|
|
204
|
+
throw error;
|
|
205
|
+
}
|
|
206
|
+
}, [sdk, isInitialized, isAuthenticated]);
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Get user's campaign claims with optional pagination and include relations
|
|
210
|
+
*
|
|
211
|
+
* @param options - Optional options including pagination and include relations
|
|
212
|
+
* @returns Promise resolving to paginated campaign claims
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```typescript
|
|
216
|
+
* // Get user's claims with campaign details
|
|
217
|
+
* const { data: claims } = await getUserClaims({ include: ['campaign', 'business'] });
|
|
218
|
+
* claims.forEach(claim => {
|
|
219
|
+
* console.log('Campaign:', claim.included?.campaign?.name);
|
|
220
|
+
* });
|
|
221
|
+
*
|
|
222
|
+
* // With pagination
|
|
223
|
+
* const { data } = await getUserClaims({ page: 1, limit: 10, include: ['campaign'] });
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
const getUserClaims = useCallback(async (options?: {
|
|
227
|
+
page?: number;
|
|
228
|
+
limit?: number;
|
|
229
|
+
include?: CampaignClaimIncludeRelation[];
|
|
230
|
+
}): Promise<PaginatedResponseDTO<CampaignClaimDTO>> => {
|
|
231
|
+
if (!isInitialized || !sdk) {
|
|
232
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
233
|
+
}
|
|
234
|
+
if (!isAuthenticated) {
|
|
235
|
+
console.warn('SDK not authenticated. getUserClaims requires authentication.');
|
|
236
|
+
return { data: [], pagination: { page: 1, limit: 0, total: 0, pages: 0, hasNext: false, hasPrev: false } };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
try {
|
|
240
|
+
const result = await sdk.campaigns.getUserClaims(options);
|
|
241
|
+
return result;
|
|
242
|
+
} catch (error) {
|
|
243
|
+
console.error('Failed to fetch user claims:', error);
|
|
244
|
+
throw error;
|
|
245
|
+
}
|
|
246
|
+
}, [sdk, isInitialized, isAuthenticated]);
|
|
247
|
+
|
|
248
|
+
const getCampaignTriggers = useCallback(async (): Promise<PaginatedResponseDTO<CampaignTriggerDTO>> => {
|
|
249
|
+
if (!isInitialized || !sdk) {
|
|
250
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
const result = await sdk.campaigns.getCampaignTriggers();
|
|
255
|
+
return result;
|
|
256
|
+
} catch (error) {
|
|
257
|
+
console.error('Failed to fetch campaign triggers:', error);
|
|
258
|
+
throw error;
|
|
259
|
+
}
|
|
260
|
+
}, [sdk, isInitialized]);
|
|
261
|
+
|
|
262
|
+
// Admin methods
|
|
263
|
+
/**
|
|
264
|
+
* Admin: Get all campaigns with optional filters and include relations
|
|
265
|
+
*
|
|
266
|
+
* @param options - Filter, pagination, and include options (same as getActiveCampaigns but active is optional)
|
|
267
|
+
* @returns Promise resolving to paginated campaigns
|
|
268
|
+
*
|
|
269
|
+
* @example
|
|
270
|
+
* ```typescript
|
|
271
|
+
* // Get all campaigns
|
|
272
|
+
* const { data } = await getAllCampaigns();
|
|
273
|
+
*
|
|
274
|
+
* // Get only active campaigns with trigger sources
|
|
275
|
+
* const { data } = await getAllCampaigns({ active: true, include: ['triggerSources'] });
|
|
276
|
+
*
|
|
277
|
+
* // Filter by date range with claim count
|
|
278
|
+
* const { data } = await getAllCampaigns({
|
|
279
|
+
* startDate: '2026-05-01',
|
|
280
|
+
* endDate: '2026-12-31',
|
|
281
|
+
* include: ['claimCount']
|
|
282
|
+
* });
|
|
283
|
+
* data.forEach(c => console.log(`${c.name}: ${c.claimCount} claims`));
|
|
284
|
+
*
|
|
285
|
+
* // With pagination and sorting
|
|
286
|
+
* const { data } = await getAllCampaigns({
|
|
287
|
+
* page: 1,
|
|
288
|
+
* limit: 20,
|
|
289
|
+
* sortBy: 'createdAt',
|
|
290
|
+
* sortOrder: 'DESC'
|
|
291
|
+
* });
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
294
|
+
const getAllCampaigns = useCallback(async (
|
|
295
|
+
options?: GetCampaignsOptions & { active?: boolean }
|
|
296
|
+
): Promise<PaginatedResponseDTO<CampaignDTO>> => {
|
|
297
|
+
if (!isInitialized || !sdk) {
|
|
298
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
try {
|
|
302
|
+
const result = await sdk.campaigns.getCampaigns(options);
|
|
303
|
+
return result;
|
|
304
|
+
} catch (error) {
|
|
305
|
+
console.error('Failed to fetch all campaigns:', error);
|
|
306
|
+
throw error;
|
|
307
|
+
}
|
|
308
|
+
}, [sdk, isInitialized]);
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Admin: Get campaign claims with optional filters and include relations
|
|
312
|
+
*
|
|
313
|
+
* @param filters - Optional filters for campaign, user, business, and date range
|
|
314
|
+
* @param filters.campaignId - Filter by specific campaign ID
|
|
315
|
+
* @param filters.userId - Filter by user ID
|
|
316
|
+
* @param filters.businessId - Filter by business ID
|
|
317
|
+
* @param filters.dateFrom - Filter claims created on or after this date (ISO 8601 format)
|
|
318
|
+
* @param filters.dateTo - Filter claims created on or before this date (ISO 8601 format)
|
|
319
|
+
* @param filters.page - Page number (1-indexed)
|
|
320
|
+
* @param filters.limit - Items per page
|
|
321
|
+
* @param filters.sortBy - Field to sort by
|
|
322
|
+
* @param filters.sortOrder - Sort direction
|
|
323
|
+
* @param include - Relations to include: 'campaign', 'user', 'business'
|
|
324
|
+
* @returns Promise resolving to paginated campaign claims
|
|
325
|
+
*
|
|
326
|
+
* @example
|
|
327
|
+
* ```typescript
|
|
328
|
+
* // Get all claims with user details
|
|
329
|
+
* const { data: claims } = await getCampaignClaims({}, ['user']);
|
|
330
|
+
*
|
|
331
|
+
* // Get claims for a specific campaign
|
|
332
|
+
* const { data } = await getCampaignClaims({ campaignId: 'campaign-123' }, ['user', 'business']);
|
|
333
|
+
*
|
|
334
|
+
* // Filter by date range
|
|
335
|
+
* const { data } = await getCampaignClaims({
|
|
336
|
+
* dateFrom: '2026-01-01',
|
|
337
|
+
* dateTo: '2026-03-31'
|
|
338
|
+
* }, ['campaign']);
|
|
339
|
+
* ```
|
|
340
|
+
*/
|
|
341
|
+
const getCampaignClaims = useCallback(async (
|
|
342
|
+
filters?: CampaignClaimFilters,
|
|
343
|
+
include?: CampaignClaimIncludeRelation[]
|
|
344
|
+
): Promise<PaginatedResponseDTO<CampaignClaimDTO>> => {
|
|
345
|
+
if (!isInitialized || !sdk) {
|
|
346
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
try {
|
|
350
|
+
const result = await sdk.campaigns.getCampaignClaims(filters, include);
|
|
351
|
+
return result;
|
|
352
|
+
} catch (error) {
|
|
353
|
+
console.error('Failed to fetch campaign claims:', error);
|
|
354
|
+
throw error;
|
|
355
|
+
}
|
|
356
|
+
}, [sdk, isInitialized]);
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Admin: Get campaign claims by user ID with optional include relations
|
|
360
|
+
*
|
|
361
|
+
* @param userId - The user ID
|
|
362
|
+
* @param include - Relations to include: 'campaign', 'user', 'business'
|
|
363
|
+
* @returns Promise resolving to paginated campaign claims
|
|
364
|
+
*/
|
|
365
|
+
const getCampaignClaimsByUserId = useCallback(async (
|
|
366
|
+
userId: string,
|
|
367
|
+
include?: CampaignClaimIncludeRelation[]
|
|
368
|
+
): Promise<PaginatedResponseDTO<CampaignClaimDTO>> => {
|
|
369
|
+
if (!isInitialized || !sdk) {
|
|
370
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
try {
|
|
374
|
+
const result = await sdk.campaigns.getCampaignClaimsByUserId(userId, undefined, include);
|
|
375
|
+
return result;
|
|
376
|
+
} catch (error) {
|
|
377
|
+
console.error('Failed to fetch campaign claims by user ID:', error);
|
|
378
|
+
throw error;
|
|
379
|
+
}
|
|
380
|
+
}, [sdk, isInitialized]);
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Admin: Get campaign claims by business ID with optional include relations
|
|
384
|
+
*
|
|
385
|
+
* @param businessId - The business ID
|
|
386
|
+
* @param include - Relations to include: 'campaign', 'user', 'business'
|
|
387
|
+
* @returns Promise resolving to paginated campaign claims
|
|
388
|
+
*/
|
|
389
|
+
const getCampaignClaimsByBusinessId = useCallback(async (
|
|
390
|
+
businessId: string,
|
|
391
|
+
include?: CampaignClaimIncludeRelation[]
|
|
392
|
+
): Promise<PaginatedResponseDTO<CampaignClaimDTO>> => {
|
|
393
|
+
if (!isInitialized || !sdk) {
|
|
394
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
try {
|
|
398
|
+
const result = await sdk.campaigns.getCampaignClaimsByBusinessId(businessId, undefined, include);
|
|
399
|
+
return result;
|
|
400
|
+
} catch (error) {
|
|
401
|
+
console.error('Failed to fetch campaign claims by business ID:', error);
|
|
402
|
+
throw error;
|
|
403
|
+
}
|
|
404
|
+
}, [sdk, isInitialized]);
|
|
405
|
+
|
|
406
|
+
// ==========================================
|
|
407
|
+
// TRIGGER SOURCE ASSIGNMENT (Admin)
|
|
408
|
+
// Note: TriggerSource CRUD is in useTriggerSources hook
|
|
409
|
+
// ==========================================
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Admin: Assign a trigger source to a campaign
|
|
413
|
+
*
|
|
414
|
+
* Associates a trigger source (QR code, NFC tag, etc.) with a campaign.
|
|
415
|
+
* A campaign can have multiple trigger sources.
|
|
416
|
+
*
|
|
417
|
+
* Note: To create/update/delete trigger sources, use `useTriggerSources` hook.
|
|
418
|
+
*
|
|
419
|
+
* @param campaignId - Campaign UUID
|
|
420
|
+
* @param triggerSourceId - Trigger source UUID
|
|
421
|
+
* @returns Promise resolving to updated campaign
|
|
422
|
+
*
|
|
423
|
+
* @example
|
|
424
|
+
* ```typescript
|
|
425
|
+
* const { create } = useTriggerSources();
|
|
426
|
+
* const { assignTriggerSource } = useCampaigns();
|
|
427
|
+
*
|
|
428
|
+
* // Create trigger source first
|
|
429
|
+
* const source = await create({ type: 'QR_CODE', name: 'Store QR' });
|
|
430
|
+
*
|
|
431
|
+
* // Then assign to campaign
|
|
432
|
+
* const updated = await assignTriggerSource('campaign-123', source.id);
|
|
433
|
+
* ```
|
|
434
|
+
*/
|
|
435
|
+
const assignTriggerSource = useCallback(async (
|
|
436
|
+
campaignId: string,
|
|
437
|
+
triggerSourceId: string
|
|
438
|
+
): Promise<CampaignDTO> => {
|
|
439
|
+
if (!isInitialized || !sdk) {
|
|
440
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
441
|
+
}
|
|
442
|
+
if (!isAuthenticated) {
|
|
443
|
+
throw new Error('SDK not authenticated. assignTriggerSource requires admin authentication.');
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
try {
|
|
447
|
+
const result = await sdk.campaigns.assignTriggerSource(campaignId, triggerSourceId);
|
|
448
|
+
return result;
|
|
449
|
+
} catch (error) {
|
|
450
|
+
console.error('Failed to assign trigger source:', error);
|
|
451
|
+
throw error;
|
|
452
|
+
}
|
|
453
|
+
}, [sdk, isInitialized, isAuthenticated]);
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Admin: Remove a trigger source from a campaign
|
|
457
|
+
*
|
|
458
|
+
* Removes the association between a trigger source and a campaign.
|
|
459
|
+
* The trigger source itself is not deleted.
|
|
460
|
+
*
|
|
461
|
+
* @param campaignId - Campaign UUID
|
|
462
|
+
* @param triggerSourceId - Trigger source UUID
|
|
463
|
+
* @returns Promise resolving to updated campaign
|
|
464
|
+
*/
|
|
465
|
+
const removeTriggerSource = useCallback(async (
|
|
466
|
+
campaignId: string,
|
|
467
|
+
triggerSourceId: string
|
|
468
|
+
): Promise<CampaignDTO> => {
|
|
469
|
+
if (!isInitialized || !sdk) {
|
|
470
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
471
|
+
}
|
|
472
|
+
if (!isAuthenticated) {
|
|
473
|
+
throw new Error('SDK not authenticated. removeTriggerSource requires admin authentication.');
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
try {
|
|
477
|
+
const result = await sdk.campaigns.removeTriggerSource(campaignId, triggerSourceId);
|
|
478
|
+
return result;
|
|
479
|
+
} catch (error) {
|
|
480
|
+
console.error('Failed to remove trigger source:', error);
|
|
481
|
+
throw error;
|
|
482
|
+
}
|
|
483
|
+
}, [sdk, isInitialized, isAuthenticated]);
|
|
484
|
+
|
|
485
|
+
return {
|
|
486
|
+
getActiveCampaigns,
|
|
487
|
+
getCampaignById,
|
|
488
|
+
claimCampaign,
|
|
489
|
+
getUserClaims,
|
|
490
|
+
getCampaignTriggers,
|
|
491
|
+
getAllCampaigns,
|
|
492
|
+
getCampaignClaims,
|
|
493
|
+
getCampaignClaimsByUserId,
|
|
494
|
+
getCampaignClaimsByBusinessId,
|
|
495
|
+
assignTriggerSource,
|
|
496
|
+
removeTriggerSource,
|
|
497
|
+
isAvailable: isInitialized && !!sdk?.campaigns,
|
|
498
|
+
};
|
|
499
|
+
};
|
|
500
|
+
|
|
501
501
|
export type CampaignHook = ReturnType<typeof useCampaigns>;
|