@explorins/pers-sdk-react-native 2.1.3 → 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/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 +2459 -393
- package/dist/index.js.map +1 -1
- 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/useTransactions.ts +84 -29
- package/src/hooks/useTriggerSources.ts +301 -0
- package/src/index.ts +33 -3
package/dist/index.js
CHANGED
|
@@ -2828,6 +2828,28 @@ exports.SortOrder = void 0;
|
|
|
2828
2828
|
SortOrder["DESC"] = "DESC";
|
|
2829
2829
|
})(exports.SortOrder || (exports.SortOrder = {}));
|
|
2830
2830
|
|
|
2831
|
+
/**
|
|
2832
|
+
* ProcessRecordStatus - Status for business process records that create blockchain transactions
|
|
2833
|
+
*
|
|
2834
|
+
* Used for tracking the lifecycle of business operations (campaigns, redemptions) that
|
|
2835
|
+
* trigger blockchain transactions. This is distinct from TransactionStatus which tracks
|
|
2836
|
+
* the blockchain transaction itself.
|
|
2837
|
+
*
|
|
2838
|
+
* Usage:
|
|
2839
|
+
* - Campaign Claims (user claims rewards via blockchain transactions)
|
|
2840
|
+
* - Redemption Redeems (user redeems items via blockchain transactions)
|
|
2841
|
+
* - Any business process creating blockchain transactions that need status tracking
|
|
2842
|
+
*
|
|
2843
|
+
* NOT for blockchain transactions themselves - use TransactionStatus instead.
|
|
2844
|
+
*/
|
|
2845
|
+
exports.ProcessRecordStatus = void 0;
|
|
2846
|
+
(function (ProcessRecordStatus) {
|
|
2847
|
+
ProcessRecordStatus["PENDING"] = "PENDING";
|
|
2848
|
+
ProcessRecordStatus["PROCESSING"] = "PROCESSING";
|
|
2849
|
+
ProcessRecordStatus["COMPLETED"] = "COMPLETED";
|
|
2850
|
+
ProcessRecordStatus["FAILED"] = "FAILED"; // Transaction processing failed (blockchain or validation error)
|
|
2851
|
+
})(exports.ProcessRecordStatus || (exports.ProcessRecordStatus = {}));
|
|
2852
|
+
|
|
2831
2853
|
exports.PurchaseStatus = void 0;
|
|
2832
2854
|
(function (PurchaseStatus) {
|
|
2833
2855
|
// after creation of payment and before payment is done by user
|
|
@@ -2847,35 +2869,30 @@ exports.PurchaseCurrency = void 0;
|
|
|
2847
2869
|
PurchaseCurrency["EUR"] = "eur";
|
|
2848
2870
|
})(exports.PurchaseCurrency || (exports.PurchaseCurrency = {}));
|
|
2849
2871
|
|
|
2850
|
-
exports.RedemptionRedeemStatus = void 0;
|
|
2851
|
-
(function (RedemptionRedeemStatus) {
|
|
2852
|
-
RedemptionRedeemStatus["PENDING"] = "PENDING";
|
|
2853
|
-
RedemptionRedeemStatus["PROCESSING"] = "PROCESSING";
|
|
2854
|
-
RedemptionRedeemStatus["COMPLETED"] = "COMPLETED";
|
|
2855
|
-
RedemptionRedeemStatus["FAILED"] = "FAILED"; // Processing failed
|
|
2856
|
-
})(exports.RedemptionRedeemStatus || (exports.RedemptionRedeemStatus = {}));
|
|
2857
|
-
|
|
2858
2872
|
/**
|
|
2859
2873
|
* Trigger Source Types
|
|
2860
2874
|
* Defines the different types of triggers that can activate a campaign flow
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2875
|
+
* Using const object pattern for better extensibility without requiring deploys
|
|
2876
|
+
*/
|
|
2877
|
+
const TRIGGER_SOURCE_TYPES = {
|
|
2878
|
+
QR_CODE: 'QR_CODE',
|
|
2879
|
+
NFC_TAG: 'NFC_TAG',
|
|
2880
|
+
API_WEBHOOK: 'API_WEBHOOK',
|
|
2881
|
+
GPS_GEOFENCE: 'GPS_GEOFENCE',
|
|
2882
|
+
TRANSACTION: 'TRANSACTION',
|
|
2883
|
+
};
|
|
2884
|
+
// Export values array for validation
|
|
2885
|
+
const TRIGGER_SOURCE_TYPE_VALUES = Object.values(TRIGGER_SOURCE_TYPES);
|
|
2869
2886
|
/**
|
|
2870
2887
|
* Source Logic Types
|
|
2871
2888
|
* Defines how multiple trigger sources combine to activate a flow
|
|
2872
2889
|
* Currently only ANY (OR logic) is implemented
|
|
2873
2890
|
*/
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2891
|
+
const SOURCE_LOGIC_TYPES = {
|
|
2892
|
+
ANY: 'any'
|
|
2893
|
+
// Future: ALL: 'all', SEQUENCE: 'sequence', WEIGHTED: 'weighted'
|
|
2894
|
+
};
|
|
2895
|
+
const SOURCE_LOGIC_TYPE_VALUES = Object.values(SOURCE_LOGIC_TYPES);
|
|
2879
2896
|
|
|
2880
2897
|
exports.CampaignConditionType = void 0;
|
|
2881
2898
|
(function (CampaignConditionType) {
|
|
@@ -3104,6 +3121,103 @@ const Domains = {
|
|
|
3104
3121
|
AUDIT: 'audit',
|
|
3105
3122
|
};
|
|
3106
3123
|
|
|
3124
|
+
/**
|
|
3125
|
+
* SQL operator mapping for query operators
|
|
3126
|
+
* Maps abstract query operators to SQL equivalents
|
|
3127
|
+
*/
|
|
3128
|
+
const QUERY_OPERATOR_SQL_MAP = {
|
|
3129
|
+
eq: '=',
|
|
3130
|
+
ne: '!=',
|
|
3131
|
+
gt: '>',
|
|
3132
|
+
gte: '>=',
|
|
3133
|
+
lt: '<',
|
|
3134
|
+
lte: '<=',
|
|
3135
|
+
in: 'IN',
|
|
3136
|
+
nin: 'NOT IN'
|
|
3137
|
+
};
|
|
3138
|
+
|
|
3139
|
+
/**
|
|
3140
|
+
* Helper to validate includes array at runtime
|
|
3141
|
+
*/
|
|
3142
|
+
const VALID_RELATIONS = ['user', 'campaign', 'business', 'triggerSource'];
|
|
3143
|
+
function isValidRelation(value) {
|
|
3144
|
+
return VALID_RELATIONS.includes(value);
|
|
3145
|
+
}
|
|
3146
|
+
|
|
3147
|
+
/**
|
|
3148
|
+
* Valid transaction relations for runtime validation
|
|
3149
|
+
*/
|
|
3150
|
+
const VALID_TRANSACTION_RELATIONS = [
|
|
3151
|
+
'sender',
|
|
3152
|
+
'recipient',
|
|
3153
|
+
'business'
|
|
3154
|
+
];
|
|
3155
|
+
/**
|
|
3156
|
+
* Type guard to validate relation strings at runtime
|
|
3157
|
+
*/
|
|
3158
|
+
function isValidTransactionRelation(value) {
|
|
3159
|
+
return VALID_TRANSACTION_RELATIONS.includes(value);
|
|
3160
|
+
}
|
|
3161
|
+
|
|
3162
|
+
/**
|
|
3163
|
+
* Array of all valid campaign include relations
|
|
3164
|
+
* Used for runtime validation
|
|
3165
|
+
*/
|
|
3166
|
+
const VALID_CAMPAIGN_RELATIONS = [
|
|
3167
|
+
'triggerSources',
|
|
3168
|
+
'businesses'
|
|
3169
|
+
];
|
|
3170
|
+
/**
|
|
3171
|
+
* Type guard to validate campaign include relation at runtime
|
|
3172
|
+
*
|
|
3173
|
+
* @param value - String to validate
|
|
3174
|
+
* @returns True if value is a valid CampaignIncludeRelation
|
|
3175
|
+
*/
|
|
3176
|
+
function isValidCampaignRelation(value) {
|
|
3177
|
+
return VALID_CAMPAIGN_RELATIONS.includes(value);
|
|
3178
|
+
}
|
|
3179
|
+
|
|
3180
|
+
/**
|
|
3181
|
+
* Array of all valid campaign claim include relations
|
|
3182
|
+
* Used for runtime validation
|
|
3183
|
+
*/
|
|
3184
|
+
const VALID_CAMPAIGN_CLAIM_RELATIONS = [
|
|
3185
|
+
'campaign',
|
|
3186
|
+
'user',
|
|
3187
|
+
'business',
|
|
3188
|
+
'triggerSource',
|
|
3189
|
+
'transactions'
|
|
3190
|
+
];
|
|
3191
|
+
/**
|
|
3192
|
+
* Type guard to validate campaign claim include relation at runtime
|
|
3193
|
+
*
|
|
3194
|
+
* @param value - String to validate
|
|
3195
|
+
* @returns True if value is a valid CampaignClaimIncludeRelation
|
|
3196
|
+
*/
|
|
3197
|
+
function isValidCampaignClaimRelation(value) {
|
|
3198
|
+
return VALID_CAMPAIGN_CLAIM_RELATIONS.includes(value);
|
|
3199
|
+
}
|
|
3200
|
+
|
|
3201
|
+
/**
|
|
3202
|
+
* Array of all valid redemption redeem include relations
|
|
3203
|
+
* Used for runtime validation
|
|
3204
|
+
*/
|
|
3205
|
+
const VALID_REDEMPTION_REDEEM_RELATIONS = [
|
|
3206
|
+
'redemption',
|
|
3207
|
+
'user',
|
|
3208
|
+
'business',
|
|
3209
|
+
'transactions'
|
|
3210
|
+
];
|
|
3211
|
+
/**
|
|
3212
|
+
* Type guard to validate redemption redeem include relation at runtime
|
|
3213
|
+
*
|
|
3214
|
+
* @param value - String to validate
|
|
3215
|
+
* @returns True if value is a valid RedemptionRedeemIncludeRelation
|
|
3216
|
+
*/
|
|
3217
|
+
function isValidRedemptionRedeemRelation(value) {
|
|
3218
|
+
return VALID_REDEMPTION_REDEEM_RELATIONS.includes(value);
|
|
3219
|
+
}
|
|
3220
|
+
|
|
3107
3221
|
/**
|
|
3108
3222
|
* Transaction format constants for Ethereum and EVM-compatible chains
|
|
3109
3223
|
* Using const assertions for zero runtime overhead
|
|
@@ -3642,10 +3756,30 @@ class UserApi {
|
|
|
3642
3756
|
* ADMIN: Get all remote users with query parameters
|
|
3643
3757
|
* Uses new RESTful /users endpoint with role-based access
|
|
3644
3758
|
* Note: Admin users get full data, non-admin users get public profiles only
|
|
3759
|
+
*
|
|
3760
|
+
* @param options - Pagination options (page, limit, sortBy, sortOrder)
|
|
3761
|
+
* @param search - Optional search query to filter users
|
|
3762
|
+
*
|
|
3763
|
+
* @example
|
|
3764
|
+
* ```typescript
|
|
3765
|
+
* // Get users sorted by email
|
|
3766
|
+
* const users = await sdk.users.getAllUsers({
|
|
3767
|
+
* page: 1,
|
|
3768
|
+
* limit: 10,
|
|
3769
|
+
* sortBy: 'email',
|
|
3770
|
+
* sortOrder: SortOrder.ASC
|
|
3771
|
+
* });
|
|
3772
|
+
*
|
|
3773
|
+
* // Search for users
|
|
3774
|
+
* const searchResults = await sdk.users.getAllUsers({ page: 1, limit: 10 }, 'john');
|
|
3775
|
+
* ```
|
|
3645
3776
|
*/
|
|
3646
|
-
async getAllRemoteUsers(options) {
|
|
3777
|
+
async getAllRemoteUsers(options, search) {
|
|
3647
3778
|
const params = buildPaginationParams(options);
|
|
3648
|
-
|
|
3779
|
+
if (search) {
|
|
3780
|
+
params.set('search', search);
|
|
3781
|
+
}
|
|
3782
|
+
const url = `${this.basePath}?merge=soft&${params.toString()}`;
|
|
3649
3783
|
const response = await this.apiClient.get(url);
|
|
3650
3784
|
return normalizeToPaginated(response);
|
|
3651
3785
|
}
|
|
@@ -3740,9 +3874,11 @@ class UserService {
|
|
|
3740
3874
|
/**
|
|
3741
3875
|
* ADMIN: Get all remote users
|
|
3742
3876
|
* ✅ FIXED: Matches API method signature (no parameters needed)
|
|
3877
|
+
* @param options - Pagination options
|
|
3878
|
+
* @param search - Optional search query
|
|
3743
3879
|
*/
|
|
3744
|
-
async getAllRemoteUsers(options) {
|
|
3745
|
-
return this.userApi.getAllRemoteUsers(options);
|
|
3880
|
+
async getAllRemoteUsers(options, search) {
|
|
3881
|
+
return this.userApi.getAllRemoteUsers(options, search);
|
|
3746
3882
|
}
|
|
3747
3883
|
/**
|
|
3748
3884
|
* ADMIN: Update user as admin
|
|
@@ -4913,6 +5049,19 @@ class CampaignApi {
|
|
|
4913
5049
|
* Get campaigns with pagination support
|
|
4914
5050
|
* Returns paginated response with metadata (total, page, limit, hasMore)
|
|
4915
5051
|
* Intelligent access: Public gets active only, Business gets own campaigns, Admin gets all
|
|
5052
|
+
*
|
|
5053
|
+
* @param options - Filter, pagination, and include options
|
|
5054
|
+
* @param options.include - Relations to include: 'triggerSources', 'businesses'
|
|
5055
|
+
*
|
|
5056
|
+
* @example
|
|
5057
|
+
* ```typescript
|
|
5058
|
+
* // Get campaigns with trigger sources included
|
|
5059
|
+
* const campaigns = await api.getCampaigns({ include: ['triggerSources'] });
|
|
5060
|
+
* campaigns.data.forEach(c => console.log(c.included?.triggerSources));
|
|
5061
|
+
*
|
|
5062
|
+
* // Get campaigns with both relations
|
|
5063
|
+
* const full = await api.getCampaigns({ include: ['triggerSources', 'businesses'] });
|
|
5064
|
+
* ```
|
|
4916
5065
|
*/
|
|
4917
5066
|
async getCampaigns(options) {
|
|
4918
5067
|
const params = [];
|
|
@@ -4929,14 +5078,28 @@ class CampaignApi {
|
|
|
4929
5078
|
params.push(`sortBy=${options.sortBy}`);
|
|
4930
5079
|
if (options?.sortOrder)
|
|
4931
5080
|
params.push(`sortOrder=${options.sortOrder}`);
|
|
5081
|
+
if (options?.include?.length)
|
|
5082
|
+
params.push(`include=${options.include.join(',')}`);
|
|
4932
5083
|
return this.apiClient.get(`/campaigns?${params.join('&')}`);
|
|
4933
5084
|
}
|
|
4934
5085
|
/**
|
|
4935
5086
|
* PUBLIC: Get campaign by ID
|
|
4936
5087
|
* NEW: /campaigns/{id}
|
|
5088
|
+
*
|
|
5089
|
+
* @param id - Campaign UUID
|
|
5090
|
+
* @param include - Relations to include: 'triggerSources', 'businesses'
|
|
5091
|
+
*
|
|
5092
|
+
* @example
|
|
5093
|
+
* ```typescript
|
|
5094
|
+
* // Get campaign with all relations
|
|
5095
|
+
* const campaign = await api.getCampaignById('123', ['triggerSources', 'businesses']);
|
|
5096
|
+
* console.log(campaign.included?.triggerSources);
|
|
5097
|
+
* console.log(campaign.included?.businesses);
|
|
5098
|
+
* ```
|
|
4937
5099
|
*/
|
|
4938
|
-
async getCampaignById(id) {
|
|
4939
|
-
|
|
5100
|
+
async getCampaignById(id, include) {
|
|
5101
|
+
const params = include?.length ? `?include=${include.join(',')}` : '';
|
|
5102
|
+
return this.apiClient.get(`/campaigns/${id}${params}`);
|
|
4940
5103
|
}
|
|
4941
5104
|
/**
|
|
4942
5105
|
* ADMIN: Create campaign
|
|
@@ -5055,6 +5218,16 @@ class CampaignApi {
|
|
|
5055
5218
|
const response = await this.apiClient.get(`/campaign-triggers?${params.toString()}`);
|
|
5056
5219
|
return normalizeToPaginated(response);
|
|
5057
5220
|
}
|
|
5221
|
+
/**
|
|
5222
|
+
* PUBLIC: Get campaign trigger by ID
|
|
5223
|
+
* NEW: GET /campaign-triggers/{id}
|
|
5224
|
+
*
|
|
5225
|
+
* @param triggerId - Campaign trigger UUID
|
|
5226
|
+
* @returns Campaign trigger details
|
|
5227
|
+
*/
|
|
5228
|
+
async getCampaignTriggerById(triggerId) {
|
|
5229
|
+
return this.apiClient.get(`/campaign-triggers/${triggerId}`);
|
|
5230
|
+
}
|
|
5058
5231
|
/**
|
|
5059
5232
|
* ADMIN: Create campaign trigger
|
|
5060
5233
|
* NEW: POST /campaign-triggers
|
|
@@ -5083,6 +5256,13 @@ class CampaignApi {
|
|
|
5083
5256
|
async setCampaignTrigger(campaignId, triggerId) {
|
|
5084
5257
|
return this.apiClient.put(`/campaign-triggers/${triggerId}/assign/${campaignId}`, {});
|
|
5085
5258
|
}
|
|
5259
|
+
/**
|
|
5260
|
+
* ADMIN: Remove trigger from campaign (unassign)
|
|
5261
|
+
* NEW: DELETE /campaign-triggers/{triggerId}/assign/{campaignId}
|
|
5262
|
+
*/
|
|
5263
|
+
async removeCampaignTrigger(campaignId, triggerId) {
|
|
5264
|
+
return this.apiClient.delete(`/campaign-triggers/${triggerId}/assign/${campaignId}`);
|
|
5265
|
+
}
|
|
5086
5266
|
/**
|
|
5087
5267
|
* ADMIN: Add/Remove condition to trigger
|
|
5088
5268
|
* NEW: PUT /campaign-triggers/{triggerId}/conditions/{conditionId}
|
|
@@ -5154,7 +5334,7 @@ class CampaignApi {
|
|
|
5154
5334
|
* });
|
|
5155
5335
|
* ```
|
|
5156
5336
|
*/
|
|
5157
|
-
async getClaims(filters) {
|
|
5337
|
+
async getClaims(filters, include) {
|
|
5158
5338
|
const params = buildPaginationParams(filters);
|
|
5159
5339
|
// Add filter parameters
|
|
5160
5340
|
if (filters?.campaignId)
|
|
@@ -5163,6 +5343,10 @@ class CampaignApi {
|
|
|
5163
5343
|
params.set('userId', filters.userId);
|
|
5164
5344
|
if (filters?.businessId)
|
|
5165
5345
|
params.set('businessId', filters.businessId);
|
|
5346
|
+
// Add include parameter
|
|
5347
|
+
if (include && include.length > 0) {
|
|
5348
|
+
include.forEach(relation => params.append('include', relation));
|
|
5349
|
+
}
|
|
5166
5350
|
const endpoint = `/campaigns/claims?${params.toString()}`;
|
|
5167
5351
|
const response = await this.apiClient.get(endpoint);
|
|
5168
5352
|
return normalizeToPaginated(response);
|
|
@@ -5172,13 +5356,42 @@ class CampaignApi {
|
|
|
5172
5356
|
* Uses /me endpoint for authenticated user context
|
|
5173
5357
|
*
|
|
5174
5358
|
* @param options - Pagination options
|
|
5359
|
+
* @param include - Optional relations to include (campaign, user, business)
|
|
5175
5360
|
* @returns Paginated list of user's claims
|
|
5176
5361
|
*/
|
|
5177
|
-
async getClaimsLoggedUser(options) {
|
|
5362
|
+
async getClaimsLoggedUser(options, include) {
|
|
5178
5363
|
const params = buildPaginationParams(options);
|
|
5364
|
+
// Add include parameter
|
|
5365
|
+
if (include && include.length > 0) {
|
|
5366
|
+
include.forEach(relation => params.append('include', relation));
|
|
5367
|
+
}
|
|
5179
5368
|
const response = await this.apiClient.get(`/campaigns/claims/me?${params.toString()}`);
|
|
5180
5369
|
return normalizeToPaginated(response);
|
|
5181
5370
|
}
|
|
5371
|
+
// ==========================================
|
|
5372
|
+
// TRIGGER SOURCE ASSIGNMENT (/campaigns/{id}/trigger-sources)
|
|
5373
|
+
// Note: TriggerSource CRUD is in TriggerSourceApi
|
|
5374
|
+
// ==========================================
|
|
5375
|
+
/**
|
|
5376
|
+
* ADMIN: Assign a trigger source to a campaign
|
|
5377
|
+
*
|
|
5378
|
+
* @param campaignId - Campaign UUID
|
|
5379
|
+
* @param triggerSourceId - Trigger source UUID
|
|
5380
|
+
* @returns Updated campaign with trigger source assigned
|
|
5381
|
+
*/
|
|
5382
|
+
async assignTriggerSourceToCampaign(campaignId, triggerSourceId) {
|
|
5383
|
+
return this.apiClient.put(`/campaigns/${campaignId}/trigger-sources/${triggerSourceId}`, {});
|
|
5384
|
+
}
|
|
5385
|
+
/**
|
|
5386
|
+
* ADMIN: Remove a trigger source from a campaign
|
|
5387
|
+
*
|
|
5388
|
+
* @param campaignId - Campaign UUID
|
|
5389
|
+
* @param triggerSourceId - Trigger source UUID
|
|
5390
|
+
* @returns Updated campaign with trigger source removed
|
|
5391
|
+
*/
|
|
5392
|
+
async removeTriggerSourceFromCampaign(campaignId, triggerSourceId) {
|
|
5393
|
+
return this.apiClient.delete(`/campaigns/${campaignId}/trigger-sources/${triggerSourceId}`);
|
|
5394
|
+
}
|
|
5182
5395
|
}
|
|
5183
5396
|
|
|
5184
5397
|
/**
|
|
@@ -5198,9 +5411,11 @@ class CampaignService {
|
|
|
5198
5411
|
// ==========================================
|
|
5199
5412
|
/**
|
|
5200
5413
|
* PUBLIC: Get campaign by ID
|
|
5414
|
+
* @param id - Campaign UUID
|
|
5415
|
+
* @param include - Relations to include: 'triggerSources', 'businesses'
|
|
5201
5416
|
*/
|
|
5202
|
-
async getCampaignById(id) {
|
|
5203
|
-
return this.campaignApi.getCampaignById(id);
|
|
5417
|
+
async getCampaignById(id, include) {
|
|
5418
|
+
return this.campaignApi.getCampaignById(id, include);
|
|
5204
5419
|
}
|
|
5205
5420
|
// ==========================================
|
|
5206
5421
|
// AUTHENTICATED OPERATIONS
|
|
@@ -5213,9 +5428,11 @@ class CampaignService {
|
|
|
5213
5428
|
}
|
|
5214
5429
|
/**
|
|
5215
5430
|
* AUTH: Get claims for logged user with pagination
|
|
5431
|
+
* @param options - Pagination options
|
|
5432
|
+
* @param include - Optional relations to include (campaign, user, business)
|
|
5216
5433
|
*/
|
|
5217
|
-
async getClaimsForLoggedUser(options) {
|
|
5218
|
-
return this.campaignApi.getClaimsLoggedUser(options);
|
|
5434
|
+
async getClaimsForLoggedUser(options, include) {
|
|
5435
|
+
return this.campaignApi.getClaimsLoggedUser(options, include);
|
|
5219
5436
|
}
|
|
5220
5437
|
// ==========================================
|
|
5221
5438
|
// CAMPAIGN OPERATIONS (Paginated)
|
|
@@ -5229,6 +5446,7 @@ class CampaignService {
|
|
|
5229
5446
|
* @param options.limit - Items per page (default: 50)
|
|
5230
5447
|
* @param options.sortBy - Sort field
|
|
5231
5448
|
* @param options.sortOrder - Sort direction
|
|
5449
|
+
* @param options.include - Relations to include: 'triggerSources', 'businesses'
|
|
5232
5450
|
*/
|
|
5233
5451
|
async getCampaigns(options) {
|
|
5234
5452
|
return this.campaignApi.getCampaigns(options);
|
|
@@ -5239,6 +5457,30 @@ class CampaignService {
|
|
|
5239
5457
|
async getCampaignTriggers(options) {
|
|
5240
5458
|
return this.campaignApi.getCampaignTriggers(options);
|
|
5241
5459
|
}
|
|
5460
|
+
/**
|
|
5461
|
+
* ADMIN: Get campaign trigger by ID
|
|
5462
|
+
*/
|
|
5463
|
+
async getCampaignTriggerById(triggerId) {
|
|
5464
|
+
return this.campaignApi.getCampaignTriggerById(triggerId);
|
|
5465
|
+
}
|
|
5466
|
+
/**
|
|
5467
|
+
* ADMIN: Create campaign trigger
|
|
5468
|
+
*/
|
|
5469
|
+
async createCampaignTrigger(data) {
|
|
5470
|
+
return this.campaignApi.createCampaignTrigger(data);
|
|
5471
|
+
}
|
|
5472
|
+
/**
|
|
5473
|
+
* ADMIN: Update campaign trigger
|
|
5474
|
+
*/
|
|
5475
|
+
async updateCampaignTrigger(triggerId, data) {
|
|
5476
|
+
return this.campaignApi.updateCampaignTrigger(triggerId, data);
|
|
5477
|
+
}
|
|
5478
|
+
/**
|
|
5479
|
+
* ADMIN: Delete campaign trigger
|
|
5480
|
+
*/
|
|
5481
|
+
async deleteCampaignTrigger(triggerId) {
|
|
5482
|
+
return this.campaignApi.deleteCampaignTrigger(triggerId);
|
|
5483
|
+
}
|
|
5242
5484
|
/**
|
|
5243
5485
|
* ADMIN: Toggle campaign active status
|
|
5244
5486
|
*/
|
|
@@ -5263,6 +5505,12 @@ class CampaignService {
|
|
|
5263
5505
|
async setCampaignTrigger(campaignId, triggerId) {
|
|
5264
5506
|
return this.campaignApi.setCampaignTrigger(campaignId, triggerId);
|
|
5265
5507
|
}
|
|
5508
|
+
/**
|
|
5509
|
+
* ADMIN: Remove trigger from campaign (unassign)
|
|
5510
|
+
*/
|
|
5511
|
+
async removeCampaignTrigger(campaignId, triggerId) {
|
|
5512
|
+
return this.campaignApi.removeCampaignTrigger(campaignId, triggerId);
|
|
5513
|
+
}
|
|
5266
5514
|
/**
|
|
5267
5515
|
* ADMIN: Update campaign
|
|
5268
5516
|
*/
|
|
@@ -5298,21 +5546,45 @@ class CampaignService {
|
|
|
5298
5546
|
}
|
|
5299
5547
|
/**
|
|
5300
5548
|
* ADMIN: Get campaign claims with optional filters and pagination
|
|
5549
|
+
* @param filters - Filter and pagination options
|
|
5550
|
+
* @param include - Optional relations to include (campaign, user, business)
|
|
5301
5551
|
*/
|
|
5302
|
-
async getCampaignClaims(filters) {
|
|
5303
|
-
return this.campaignApi.getClaims(filters);
|
|
5552
|
+
async getCampaignClaims(filters, include) {
|
|
5553
|
+
return this.campaignApi.getClaims(filters, include);
|
|
5304
5554
|
}
|
|
5305
5555
|
/**
|
|
5306
5556
|
* ADMIN: Get campaign claims by user ID with pagination
|
|
5557
|
+
* @param userId - User ID to filter by
|
|
5558
|
+
* @param options - Pagination options
|
|
5559
|
+
* @param include - Optional relations to include (campaign, user, business)
|
|
5307
5560
|
*/
|
|
5308
|
-
async getCampaignClaimsByUserId(userId, options) {
|
|
5309
|
-
return this.campaignApi.getClaims({ userId, ...options });
|
|
5561
|
+
async getCampaignClaimsByUserId(userId, options, include) {
|
|
5562
|
+
return this.campaignApi.getClaims({ userId, ...options }, include);
|
|
5310
5563
|
}
|
|
5311
5564
|
/**
|
|
5312
5565
|
* ADMIN: Get campaign claims by business ID with pagination
|
|
5566
|
+
* @param businessId - Business ID to filter by
|
|
5567
|
+
* @param options - Pagination options
|
|
5568
|
+
* @param include - Optional relations to include (campaign, user, business)
|
|
5569
|
+
*/
|
|
5570
|
+
async getCampaignClaimsByBusinessId(businessId, options, include) {
|
|
5571
|
+
return this.campaignApi.getClaims({ businessId, ...options }, include);
|
|
5572
|
+
}
|
|
5573
|
+
// ==========================================
|
|
5574
|
+
// TRIGGER SOURCE ASSIGNMENT
|
|
5575
|
+
// Note: TriggerSource CRUD is in TriggerSourceService
|
|
5576
|
+
// ==========================================
|
|
5577
|
+
/**
|
|
5578
|
+
* ADMIN: Assign a trigger source to a campaign
|
|
5313
5579
|
*/
|
|
5314
|
-
async
|
|
5315
|
-
return this.campaignApi.
|
|
5580
|
+
async assignTriggerSourceToCampaign(campaignId, triggerSourceId) {
|
|
5581
|
+
return this.campaignApi.assignTriggerSourceToCampaign(campaignId, triggerSourceId);
|
|
5582
|
+
}
|
|
5583
|
+
/**
|
|
5584
|
+
* ADMIN: Remove a trigger source from a campaign
|
|
5585
|
+
*/
|
|
5586
|
+
async removeTriggerSourceFromCampaign(campaignId, triggerSourceId) {
|
|
5587
|
+
return this.campaignApi.removeTriggerSourceFromCampaign(campaignId, triggerSourceId);
|
|
5316
5588
|
}
|
|
5317
5589
|
}
|
|
5318
5590
|
|
|
@@ -5344,12 +5616,7 @@ class RedemptionApi {
|
|
|
5344
5616
|
* - Public users: Get active redemptions only
|
|
5345
5617
|
* - Admin users: Get all redemptions with optional filtering
|
|
5346
5618
|
*
|
|
5347
|
-
* @param options
|
|
5348
|
-
* @param options.adminAccess - Force admin access (requires admin auth)
|
|
5349
|
-
* @param options.page - Page number (default: 1)
|
|
5350
|
-
* @param options.limit - Items per page (default: 50)
|
|
5351
|
-
* @param options.sortBy - Sort field
|
|
5352
|
-
* @param options.sortOrder - Sort order (asc/desc)
|
|
5619
|
+
* @param options - Filter and pagination options (active, adminAccess, page, limit, sortBy, sortOrder)
|
|
5353
5620
|
* @returns Paginated response with redemptions
|
|
5354
5621
|
*/
|
|
5355
5622
|
async getRedemptions(options) {
|
|
@@ -5416,17 +5683,11 @@ class RedemptionApi {
|
|
|
5416
5683
|
* - Users: See only their own redeems (userId/businessId filters ignored)
|
|
5417
5684
|
* - Admins: Can filter by userId, businessId, or redemptionId
|
|
5418
5685
|
*
|
|
5419
|
-
* @param filters
|
|
5420
|
-
* @param
|
|
5421
|
-
* @param filters.businessId - Admin only: Filter by business ID
|
|
5422
|
-
* @param filters.myRedeems - Force user's own redeems (uses /me endpoint)
|
|
5423
|
-
* @param filters.page - Page number (default: 1)
|
|
5424
|
-
* @param filters.limit - Items per page (default: 50)
|
|
5425
|
-
* @param filters.sortBy - Sort field
|
|
5426
|
-
* @param filters.sortOrder - Sort order (asc/desc)
|
|
5686
|
+
* @param filters - Filter and pagination options (redemptionId, userId, businessId, myRedeems, page, limit, sortBy, sortOrder)
|
|
5687
|
+
* @param include - Optional relations to include (redemption, user, business)
|
|
5427
5688
|
* @returns Paginated response with redemption redeems
|
|
5428
5689
|
*/
|
|
5429
|
-
async getRedemptionRedeems(filters) {
|
|
5690
|
+
async getRedemptionRedeems(filters, include) {
|
|
5430
5691
|
let url = `${this.basePath}/redeems`;
|
|
5431
5692
|
const params = buildPaginationParams(filters);
|
|
5432
5693
|
// Use convenience endpoint for user's own redeems
|
|
@@ -5435,6 +5696,10 @@ class RedemptionApi {
|
|
|
5435
5696
|
if (filters?.redemptionId) {
|
|
5436
5697
|
params.append('redemptionId', filters.redemptionId);
|
|
5437
5698
|
}
|
|
5699
|
+
// Add include parameter
|
|
5700
|
+
if (include && include.length > 0) {
|
|
5701
|
+
include.forEach(relation => params.append('include', relation));
|
|
5702
|
+
}
|
|
5438
5703
|
const response = await this.apiClient.get(`${url}?${params.toString()}`);
|
|
5439
5704
|
return normalizeToPaginated(response);
|
|
5440
5705
|
}
|
|
@@ -5445,14 +5710,26 @@ class RedemptionApi {
|
|
|
5445
5710
|
params.append('userId', filters.userId);
|
|
5446
5711
|
if (filters?.businessId)
|
|
5447
5712
|
params.append('businessId', filters.businessId);
|
|
5713
|
+
// Add include parameter
|
|
5714
|
+
if (include && include.length > 0) {
|
|
5715
|
+
include.forEach(relation => params.append('include', relation));
|
|
5716
|
+
}
|
|
5448
5717
|
const response = await this.apiClient.get(`${url}?${params.toString()}`);
|
|
5449
5718
|
return normalizeToPaginated(response);
|
|
5450
5719
|
}
|
|
5451
5720
|
/**
|
|
5452
5721
|
* UNIFIED: Get specific redemption redeem by ID
|
|
5722
|
+
* @param id - Redemption redeem ID
|
|
5723
|
+
* @param include - Optional relations to include (redemption, user, business)
|
|
5453
5724
|
*/
|
|
5454
|
-
async getRedemptionRedeemById(id) {
|
|
5455
|
-
|
|
5725
|
+
async getRedemptionRedeemById(id, include) {
|
|
5726
|
+
const params = new URLSearchParams();
|
|
5727
|
+
// Add include parameter
|
|
5728
|
+
if (include && include.length > 0) {
|
|
5729
|
+
include.forEach(relation => params.append('include', relation));
|
|
5730
|
+
}
|
|
5731
|
+
const url = `${this.basePath}/redeems/${id}${params.toString() ? `?${params.toString()}` : ''}`;
|
|
5732
|
+
return this.apiClient.get(url);
|
|
5456
5733
|
}
|
|
5457
5734
|
// ==========================================
|
|
5458
5735
|
// USER OPERATIONS (JWT + Project Key)
|
|
@@ -5463,10 +5740,11 @@ class RedemptionApi {
|
|
|
5463
5740
|
* Uses convenience endpoint /redemption-redeems/me with optional filtering
|
|
5464
5741
|
* @param redemptionId - Optional filter by specific redemption
|
|
5465
5742
|
* @param options - Pagination options (page, limit, sortBy, sortOrder)
|
|
5743
|
+
* @param include - Optional relations to include (redemption, user, business)
|
|
5466
5744
|
* @returns Paginated response with user's redemption redeems
|
|
5467
5745
|
*/
|
|
5468
|
-
async getUserRedeems(redemptionId, options) {
|
|
5469
|
-
return this.getRedemptionRedeems({ myRedeems: true, redemptionId, ...options });
|
|
5746
|
+
async getUserRedeems(redemptionId, options, include) {
|
|
5747
|
+
return this.getRedemptionRedeems({ myRedeems: true, redemptionId, ...options }, include);
|
|
5470
5748
|
}
|
|
5471
5749
|
// ==========================================
|
|
5472
5750
|
// ADMIN OPERATIONS (Tenant Admin JWT)
|
|
@@ -5599,15 +5877,19 @@ class RedemptionService {
|
|
|
5599
5877
|
}
|
|
5600
5878
|
/**
|
|
5601
5879
|
* UNIFIED: Get redemption redeems with filtering and pagination
|
|
5880
|
+
* @param filters - Filter options
|
|
5881
|
+
* @param include - Optional relations to include (redemption, user, business)
|
|
5602
5882
|
*/
|
|
5603
|
-
async getRedemptionRedeems(filters) {
|
|
5604
|
-
return this.redemptionApi.getRedemptionRedeems(filters);
|
|
5883
|
+
async getRedemptionRedeems(filters, include) {
|
|
5884
|
+
return this.redemptionApi.getRedemptionRedeems(filters, include);
|
|
5605
5885
|
}
|
|
5606
5886
|
/**
|
|
5607
5887
|
* Convenience: Get user redemptions with pagination
|
|
5888
|
+
* @param options - Pagination options
|
|
5889
|
+
* @param include - Optional relations to include (redemption, user, business)
|
|
5608
5890
|
*/
|
|
5609
|
-
async getUserRedeems(options) {
|
|
5610
|
-
return this.redemptionApi.getUserRedeems(undefined, options);
|
|
5891
|
+
async getUserRedeems(options, include) {
|
|
5892
|
+
return this.redemptionApi.getUserRedeems(undefined, options, include);
|
|
5611
5893
|
}
|
|
5612
5894
|
// ==========================================
|
|
5613
5895
|
// ADMIN OPERATIONS
|
|
@@ -5672,9 +5954,19 @@ class TransactionApi {
|
|
|
5672
5954
|
* Get transaction by ID (public endpoint)
|
|
5673
5955
|
*
|
|
5674
5956
|
* UPDATED: /transaction/{id} → /transactions/{id}
|
|
5957
|
+
* UPDATED: Added support for include parameter to enrich with sender/recipient/business entities
|
|
5958
|
+
*
|
|
5959
|
+
* @param transactionId - Transaction ID
|
|
5960
|
+
* @param include - Optional relations to include (sender, recipient, business)
|
|
5675
5961
|
*/
|
|
5676
|
-
async getTransactionById(transactionId) {
|
|
5677
|
-
|
|
5962
|
+
async getTransactionById(transactionId, include) {
|
|
5963
|
+
let url = `${this.basePath}/${transactionId}`;
|
|
5964
|
+
if (include && include.length > 0) {
|
|
5965
|
+
const params = new URLSearchParams();
|
|
5966
|
+
include.forEach(relation => params.append('include', relation));
|
|
5967
|
+
url += `?${params.toString()}`;
|
|
5968
|
+
}
|
|
5969
|
+
return this.apiClient.get(url);
|
|
5678
5970
|
}
|
|
5679
5971
|
/**
|
|
5680
5972
|
* Unique method to create a transaction
|
|
@@ -5688,13 +5980,78 @@ class TransactionApi {
|
|
|
5688
5980
|
// ==========================================
|
|
5689
5981
|
// AUTHENTICATED USER OPERATIONS
|
|
5690
5982
|
// ==========================================
|
|
5983
|
+
/**
|
|
5984
|
+
* Helper to build query params from TransactionQueryOptions
|
|
5985
|
+
* Handles all filter options and include parameter
|
|
5986
|
+
*/
|
|
5987
|
+
buildTransactionQueryParams(options) {
|
|
5988
|
+
const params = buildPaginationParams(options);
|
|
5989
|
+
if (!options)
|
|
5990
|
+
return params;
|
|
5991
|
+
// Search and identification filters
|
|
5992
|
+
if (options.search)
|
|
5993
|
+
params.append('search', options.search);
|
|
5994
|
+
if (options.participantId)
|
|
5995
|
+
params.append('participantId', options.participantId);
|
|
5996
|
+
if (options.participantAddress)
|
|
5997
|
+
params.append('participantAddress', options.participantAddress);
|
|
5998
|
+
// Business and process filters
|
|
5999
|
+
if (options.engagedBusinessId)
|
|
6000
|
+
params.append('engagedBusinessId', options.engagedBusinessId);
|
|
6001
|
+
if (options.businessScopeId)
|
|
6002
|
+
params.append('businessScopeId', options.businessScopeId);
|
|
6003
|
+
if (options.triggerProcessId)
|
|
6004
|
+
params.append('triggerProcessId', options.triggerProcessId);
|
|
6005
|
+
// Token filters
|
|
6006
|
+
if (options.tokenAddress)
|
|
6007
|
+
params.append('tokenAddress', options.tokenAddress);
|
|
6008
|
+
if (options.tokenType) {
|
|
6009
|
+
if (Array.isArray(options.tokenType)) {
|
|
6010
|
+
options.tokenType.forEach(type => params.append('tokenType', type));
|
|
6011
|
+
}
|
|
6012
|
+
else {
|
|
6013
|
+
params.append('tokenType', options.tokenType);
|
|
6014
|
+
}
|
|
6015
|
+
}
|
|
6016
|
+
// Transaction classification filters (arrays or single values)
|
|
6017
|
+
if (options.role) {
|
|
6018
|
+
if (Array.isArray(options.role)) {
|
|
6019
|
+
options.role.forEach(role => params.append('role', role));
|
|
6020
|
+
}
|
|
6021
|
+
else {
|
|
6022
|
+
params.append('role', options.role);
|
|
6023
|
+
}
|
|
6024
|
+
}
|
|
6025
|
+
if (options.status) {
|
|
6026
|
+
if (Array.isArray(options.status)) {
|
|
6027
|
+
options.status.forEach(status => params.append('status', status));
|
|
6028
|
+
}
|
|
6029
|
+
else {
|
|
6030
|
+
params.append('status', options.status);
|
|
6031
|
+
}
|
|
6032
|
+
}
|
|
6033
|
+
if (options.type) {
|
|
6034
|
+
if (Array.isArray(options.type)) {
|
|
6035
|
+
options.type.forEach(type => params.append('type', type));
|
|
6036
|
+
}
|
|
6037
|
+
else {
|
|
6038
|
+
params.append('type', options.type);
|
|
6039
|
+
}
|
|
6040
|
+
}
|
|
6041
|
+
// Include relations for entity enrichment
|
|
6042
|
+
if (options.include && options.include.length > 0) {
|
|
6043
|
+
options.include.forEach(relation => params.append('include', relation));
|
|
6044
|
+
}
|
|
6045
|
+
return params;
|
|
6046
|
+
}
|
|
5691
6047
|
/**
|
|
5692
6048
|
* AUTH: Get user transaction history with role-based filtering and pagination
|
|
5693
6049
|
*
|
|
5694
|
-
* UPDATED: Uses consolidated /transactions/me endpoint with
|
|
5695
|
-
*
|
|
6050
|
+
* UPDATED: Uses consolidated /transactions/me endpoint with all filter options
|
|
6051
|
+
* UPDATED: Added support for include parameter to enrich with sender/recipient/business entities
|
|
6052
|
+
* UPDATED: Now supports all TransactionFiltersDTO filters (triggerProcessId, status, type, etc.)
|
|
5696
6053
|
*
|
|
5697
|
-
* @param options - Pagination and
|
|
6054
|
+
* @param options - Pagination, filter, and include options
|
|
5698
6055
|
* @returns Paginated list of user's transactions
|
|
5699
6056
|
*
|
|
5700
6057
|
* @example
|
|
@@ -5702,24 +6059,30 @@ class TransactionApi {
|
|
|
5702
6059
|
* // Get first page of all transactions
|
|
5703
6060
|
* const page1 = await transactionApi.getUserTransactionHistory();
|
|
5704
6061
|
*
|
|
5705
|
-
* // Filter by role
|
|
5706
|
-
* const
|
|
6062
|
+
* // Filter by role and status
|
|
6063
|
+
* const completed = await transactionApi.getUserTransactionHistory({
|
|
5707
6064
|
* role: TransactionRole.SENDER,
|
|
6065
|
+
* status: TransactionStatus.COMPLETED,
|
|
5708
6066
|
* page: 1,
|
|
5709
6067
|
* limit: 50
|
|
5710
6068
|
* });
|
|
5711
6069
|
*
|
|
5712
|
-
* //
|
|
5713
|
-
*
|
|
6070
|
+
* // Filter by trigger process (e.g., from campaign claim or redemption)
|
|
6071
|
+
* const claimTransactions = await transactionApi.getUserTransactionHistory({
|
|
6072
|
+
* triggerProcessId: 'claim-abc123',
|
|
6073
|
+
* include: ['sender', 'recipient', 'business']
|
|
6074
|
+
* });
|
|
6075
|
+
*
|
|
6076
|
+
* // Access included entities
|
|
6077
|
+
* claimTransactions.data.forEach(tx => {
|
|
6078
|
+
* if (tx.included?.engagedBusiness) {
|
|
6079
|
+
* console.log('Business:', tx.included.engagedBusiness.displayName);
|
|
6080
|
+
* }
|
|
6081
|
+
* });
|
|
5714
6082
|
* ```
|
|
5715
6083
|
*/
|
|
5716
6084
|
async getUserTransactionHistory(options) {
|
|
5717
|
-
const params =
|
|
5718
|
-
// Add role parameter if specified
|
|
5719
|
-
if (options?.role) {
|
|
5720
|
-
params.set('role', options.role);
|
|
5721
|
-
}
|
|
5722
|
-
// Backend already returns PaginatedResponseDTO - return it directly
|
|
6085
|
+
const params = this.buildTransactionQueryParams(options);
|
|
5723
6086
|
return this.apiClient.get(`${this.basePath}/me?${params.toString()}`);
|
|
5724
6087
|
}
|
|
5725
6088
|
/**
|
|
@@ -5769,45 +6132,17 @@ class TransactionApi {
|
|
|
5769
6132
|
async prepareClientSignedTransaction(request) {
|
|
5770
6133
|
return this.apiClient.post(`${this.basePath}`, request);
|
|
5771
6134
|
}
|
|
5772
|
-
/**
|
|
5773
|
-
* ADMIN: Get all tenant transactions with pagination and filtering
|
|
5774
|
-
*
|
|
5775
|
-
* UPDATED: /transaction/admin → /transactions
|
|
5776
|
-
* FIXED: Now correctly returns paginated response (was incorrectly unwrapping to array)
|
|
5777
|
-
*
|
|
5778
|
-
* @param options - Pagination and filter options
|
|
5779
|
-
* @returns Paginated list of tenant transactions
|
|
5780
|
-
*
|
|
5781
|
-
* @example
|
|
5782
|
-
* ```typescript
|
|
5783
|
-
* // Get first page
|
|
5784
|
-
* const page1 = await transactionApi.getTenantTransactions();
|
|
5785
|
-
*
|
|
5786
|
-
* // Get specific page with custom limit
|
|
5787
|
-
* const page2 = await transactionApi.getTenantTransactions({
|
|
5788
|
-
* page: 2,
|
|
5789
|
-
* limit: 100
|
|
5790
|
-
* });
|
|
5791
|
-
*
|
|
5792
|
-
* // Access data
|
|
5793
|
-
* page1.data.forEach(tx => console.log(tx.id));
|
|
5794
|
-
* ```
|
|
5795
|
-
*
|
|
5796
|
-
* @deprecated Consider using getPaginatedTransactions() for more advanced filtering
|
|
5797
|
-
*/
|
|
5798
|
-
async getTenantTransactions(options) {
|
|
5799
|
-
const params = buildPaginationParams(options);
|
|
5800
|
-
// Backend already returns PaginatedResponseDTO - return it directly
|
|
5801
|
-
return this.apiClient.get(`${this.basePath}?${params.toString()}`);
|
|
5802
|
-
}
|
|
5803
6135
|
/**
|
|
5804
6136
|
* ADMIN: Get paginated transactions with filtering and sorting
|
|
5805
6137
|
*
|
|
5806
6138
|
* UPDATED: /transaction/admin → /transactions (same endpoint, better structure)
|
|
6139
|
+
*
|
|
6140
|
+
* @param options - Pagination request with filters and optional include relations
|
|
5807
6141
|
*/
|
|
5808
|
-
async getPaginatedTransactions(
|
|
5809
|
-
const queryString = this.buildQueryParams(
|
|
5810
|
-
|
|
6142
|
+
async getPaginatedTransactions(options) {
|
|
6143
|
+
const queryString = this.buildQueryParams(options).toString();
|
|
6144
|
+
const fullUrl = `${this.basePath}?${queryString}`;
|
|
6145
|
+
return this.apiClient.get(fullUrl);
|
|
5811
6146
|
}
|
|
5812
6147
|
/**
|
|
5813
6148
|
* ADMIN: Export transactions to CSV
|
|
@@ -5861,7 +6196,7 @@ class TransactionApi {
|
|
|
5861
6196
|
}
|
|
5862
6197
|
/**
|
|
5863
6198
|
* Helper to convert DTO object to URLSearchParams
|
|
5864
|
-
* Handles nested 'filters' object and
|
|
6199
|
+
* Handles nested 'filters' object, arrays, and include parameter correctly.
|
|
5865
6200
|
*/
|
|
5866
6201
|
buildQueryParams(params) {
|
|
5867
6202
|
const query = new URLSearchParams();
|
|
@@ -5874,7 +6209,11 @@ class TransactionApi {
|
|
|
5874
6209
|
query.append('sortBy', params.sortBy);
|
|
5875
6210
|
if (params.sortOrder)
|
|
5876
6211
|
query.append('sortOrder', params.sortOrder);
|
|
5877
|
-
// 2. Handle
|
|
6212
|
+
// 2. Handle Include Relations (root level)
|
|
6213
|
+
if (params.include && params.include.length > 0) {
|
|
6214
|
+
params.include.forEach((relation) => query.append('include', relation));
|
|
6215
|
+
}
|
|
6216
|
+
// 3. Handle Nested Filters
|
|
5878
6217
|
if (params.filters) {
|
|
5879
6218
|
Object.entries(params.filters).forEach(([key, value]) => {
|
|
5880
6219
|
// Skip undefined/null values
|
|
@@ -5912,9 +6251,12 @@ class TransactionService {
|
|
|
5912
6251
|
}
|
|
5913
6252
|
/**
|
|
5914
6253
|
* Get transaction by ID
|
|
6254
|
+
*
|
|
6255
|
+
* @param transactionId - Transaction ID
|
|
6256
|
+
* @param include - Optional relations to include (sender, recipient, business)
|
|
5915
6257
|
*/
|
|
5916
|
-
async getTransactionById(transactionId) {
|
|
5917
|
-
return this.transactionApi.getTransactionById(transactionId);
|
|
6258
|
+
async getTransactionById(transactionId, include) {
|
|
6259
|
+
return this.transactionApi.getTransactionById(transactionId, include);
|
|
5918
6260
|
}
|
|
5919
6261
|
// ==========================================
|
|
5920
6262
|
// AUTHENTICATED OPERATIONS
|
|
@@ -5932,14 +6274,13 @@ class TransactionService {
|
|
|
5932
6274
|
return this.transactionApi.submitSignedTransaction(signedTxData);
|
|
5933
6275
|
}
|
|
5934
6276
|
/**
|
|
5935
|
-
* AUTH: Get user transaction history
|
|
6277
|
+
* AUTH: Get user transaction history with comprehensive filtering
|
|
5936
6278
|
*
|
|
5937
|
-
* @param
|
|
5938
|
-
* @param options - Pagination options
|
|
6279
|
+
* @param options - Query options including filters, pagination, and include relations
|
|
5939
6280
|
* @returns Paginated transaction history
|
|
5940
6281
|
*/
|
|
5941
|
-
async getUserTransactionHistory(
|
|
5942
|
-
return this.transactionApi.getUserTransactionHistory(
|
|
6282
|
+
async getUserTransactionHistory(options) {
|
|
6283
|
+
return this.transactionApi.getUserTransactionHistory(options);
|
|
5943
6284
|
}
|
|
5944
6285
|
/**
|
|
5945
6286
|
* AUTH: Prepare existing transaction for client-side signing
|
|
@@ -5971,20 +6312,11 @@ class TransactionService {
|
|
|
5971
6312
|
/* async createAdminTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
|
|
5972
6313
|
return this.transactionApi.createAdminTransaction(request);
|
|
5973
6314
|
} */
|
|
5974
|
-
/**
|
|
5975
|
-
* ADMIN: Get all tenant transactions with pagination
|
|
5976
|
-
*
|
|
5977
|
-
* @param options - Pagination options
|
|
5978
|
-
* @returns Paginated tenant transactions
|
|
5979
|
-
*/
|
|
5980
|
-
async getTenantTransactions(options) {
|
|
5981
|
-
return this.transactionApi.getTenantTransactions(options || {});
|
|
5982
|
-
}
|
|
5983
6315
|
/**
|
|
5984
6316
|
* ADMIN: Get paginated transactions with filtering and sorting
|
|
5985
6317
|
*/
|
|
5986
|
-
async getPaginatedTransactions(
|
|
5987
|
-
return this.transactionApi.getPaginatedTransactions(
|
|
6318
|
+
async getPaginatedTransactions(options) {
|
|
6319
|
+
return this.transactionApi.getPaginatedTransactions(options);
|
|
5988
6320
|
}
|
|
5989
6321
|
/**
|
|
5990
6322
|
* ADMIN: Export transactions to CSV
|
|
@@ -6739,7 +7071,191 @@ class AnalyticsApi {
|
|
|
6739
7071
|
* ADMIN: Get transaction analytics with filtering and aggregation
|
|
6740
7072
|
*/
|
|
6741
7073
|
async getTransactionAnalytics(request) {
|
|
6742
|
-
return this.apiClient.post('/transactions
|
|
7074
|
+
return this.apiClient.post('/analytics/transactions', request);
|
|
7075
|
+
}
|
|
7076
|
+
/**
|
|
7077
|
+
* ADMIN: Get campaign claim analytics with aggregation (charts, metrics, grouping)
|
|
7078
|
+
*
|
|
7079
|
+
* This endpoint is for aggregated analytics only (groupBy/metrics).
|
|
7080
|
+
* For enriched list data with nested objects, use campaign.getClaims() instead.
|
|
7081
|
+
*
|
|
7082
|
+
* @example Claims per campaign
|
|
7083
|
+
* ```typescript
|
|
7084
|
+
* const response = await analyticsApi.getCampaignClaimAnalytics({
|
|
7085
|
+
* filters: { status: 'COMPLETED' },
|
|
7086
|
+
* groupBy: ['campaignId'],
|
|
7087
|
+
* metrics: ['count'],
|
|
7088
|
+
* sortBy: 'count',
|
|
7089
|
+
* sortOrder: SortOrder.DESC,
|
|
7090
|
+
* limit: 10
|
|
7091
|
+
* });
|
|
7092
|
+
* ```
|
|
7093
|
+
*
|
|
7094
|
+
* @example Claims over time by status
|
|
7095
|
+
* ```typescript
|
|
7096
|
+
* const response = await analyticsApi.getCampaignClaimAnalytics({
|
|
7097
|
+
* groupBy: ['month', 'status'],
|
|
7098
|
+
* metrics: ['count'],
|
|
7099
|
+
* sortBy: 'month',
|
|
7100
|
+
* sortOrder: SortOrder.DESC,
|
|
7101
|
+
* startDate: new Date('2026-01-01'),
|
|
7102
|
+
* endDate: new Date('2026-12-31')
|
|
7103
|
+
* });
|
|
7104
|
+
* ```
|
|
7105
|
+
*/
|
|
7106
|
+
async getCampaignClaimAnalytics(request) {
|
|
7107
|
+
return this.apiClient.post('/analytics/campaign-claims', request);
|
|
7108
|
+
}
|
|
7109
|
+
/**
|
|
7110
|
+
* ADMIN: Get user analytics with engagement metrics
|
|
7111
|
+
*
|
|
7112
|
+
* Returns aggregated user statistics including engagement rate, active users,
|
|
7113
|
+
* transaction metrics, and per-active-user averages (more accurate than all-user averages).
|
|
7114
|
+
*
|
|
7115
|
+
* Request structure matches TransactionAnalytics and CampaignClaimAnalytics for consistency:
|
|
7116
|
+
* - filters object for business-specific scoping
|
|
7117
|
+
* - startDate/endDate at root level for date range filtering
|
|
7118
|
+
*
|
|
7119
|
+
* @param request - Analytics request with optional filters and date range
|
|
7120
|
+
* @returns Aggregated user metrics with per-user and per-active-user averages
|
|
7121
|
+
*
|
|
7122
|
+
* @example Basic user analytics (all time, all businesses)
|
|
7123
|
+
* ```typescript
|
|
7124
|
+
* const analytics = await analyticsApi.getUserAnalytics({});
|
|
7125
|
+
* console.log(`Total users: ${analytics.totalUsers}`);
|
|
7126
|
+
* console.log(`Active users: ${analytics.activeUsers}`);
|
|
7127
|
+
* console.log(`Engagement rate: ${analytics.engagementRate}%`);
|
|
7128
|
+
*
|
|
7129
|
+
* // Per-user averages (includes inactive users)
|
|
7130
|
+
* console.log(`Avg transactions per user: ${analytics.averageTransactionsPerUser}`);
|
|
7131
|
+
*
|
|
7132
|
+
* // Per-active-user averages (only engaged users - more useful!)
|
|
7133
|
+
* console.log(`Avg transactions per active user: ${analytics.averageTransactionsPerActiveUser}`);
|
|
7134
|
+
* ```
|
|
7135
|
+
*
|
|
7136
|
+
* @example Filtered by date range
|
|
7137
|
+
* ```typescript
|
|
7138
|
+
* const analytics = await analyticsApi.getUserAnalytics({
|
|
7139
|
+
* startDate: new Date('2026-01-01'),
|
|
7140
|
+
* endDate: new Date('2026-01-31')
|
|
7141
|
+
* });
|
|
7142
|
+
* console.log(`January metrics:`);
|
|
7143
|
+
* console.log(`Active users: ${analytics.activeUsers}`);
|
|
7144
|
+
* console.log(`New users: ${analytics.newUsers}`);
|
|
7145
|
+
* console.log(`Date range applied: ${analytics.metadata.dateRange?.startDate} - ${analytics.metadata.dateRange?.endDate}`);
|
|
7146
|
+
* ```
|
|
7147
|
+
*
|
|
7148
|
+
* @example Business-specific analytics with filters
|
|
7149
|
+
* ```typescript
|
|
7150
|
+
* const analytics = await analyticsApi.getUserAnalytics({
|
|
7151
|
+
* filters: { businessId: 'biz-123' },
|
|
7152
|
+
* startDate: new Date('2026-01-01'),
|
|
7153
|
+
* endDate: new Date('2026-12-31')
|
|
7154
|
+
* });
|
|
7155
|
+
* console.log(`Business customer engagement in 2026:`);
|
|
7156
|
+
* console.log(`Active customers: ${analytics.activeUsers}`);
|
|
7157
|
+
* console.log(`Avg claims per active customer: ${analytics.averageClaimsPerActiveUser.toFixed(2)}`);
|
|
7158
|
+
* console.log(`Customer engagement rate: ${analytics.engagementRate.toFixed(1)}%`);
|
|
7159
|
+
* ```
|
|
7160
|
+
*/
|
|
7161
|
+
async getUserAnalytics(request = {}) {
|
|
7162
|
+
return this.apiClient.post('/analytics/users', request);
|
|
7163
|
+
}
|
|
7164
|
+
/**
|
|
7165
|
+
* ADMIN: Get user transaction ranking with enriched user data
|
|
7166
|
+
*
|
|
7167
|
+
* Returns ranked list of users with full user details and transaction metrics.
|
|
7168
|
+
* Data enrichment happens via efficient SQL JOINs + UNION (handles legacy transactions).
|
|
7169
|
+
*
|
|
7170
|
+
* Use Cases:
|
|
7171
|
+
* - Admin leaderboards showing top users by activity
|
|
7172
|
+
* - User engagement analysis with full user context
|
|
7173
|
+
* - Identifying power users for campaigns
|
|
7174
|
+
*
|
|
7175
|
+
* @param request - Ranking request with filters, sorting, and limit
|
|
7176
|
+
* @returns Ranked list with user details (email, externalUserId) and transaction metrics
|
|
7177
|
+
*
|
|
7178
|
+
* @example Top 50 users by transaction count
|
|
7179
|
+
* ```typescript
|
|
7180
|
+
* const ranking = await analyticsApi.getUserRanking({
|
|
7181
|
+
* sortBy: 'totalTransactions',
|
|
7182
|
+
* sortOrder: SortOrder.DESC,
|
|
7183
|
+
* limit: 50
|
|
7184
|
+
* });
|
|
7185
|
+
*
|
|
7186
|
+
* ranking.results.forEach((user, index) => {
|
|
7187
|
+
* console.log(`#${index + 1}: ${user.email || user.externalUserId} - ${user.totalTransactions} transactions`);
|
|
7188
|
+
* });
|
|
7189
|
+
* ```
|
|
7190
|
+
*
|
|
7191
|
+
* @example Top users by STAMP spending
|
|
7192
|
+
* ```typescript
|
|
7193
|
+
* const ranking = await analyticsApi.getUserRanking({
|
|
7194
|
+
* filters: { tokenType: 'STAMP' },
|
|
7195
|
+
* sortBy: 'tokenSpent',
|
|
7196
|
+
* sortOrder: SortOrder.DESC,
|
|
7197
|
+
* limit: 20
|
|
7198
|
+
* });
|
|
7199
|
+
* ```
|
|
7200
|
+
*
|
|
7201
|
+
* @example Business-specific leaderboard with date range
|
|
7202
|
+
* ```typescript
|
|
7203
|
+
* const ranking = await analyticsApi.getUserRanking({
|
|
7204
|
+
* filters: {
|
|
7205
|
+
* businessId: 'business-uuid-here',
|
|
7206
|
+
* tokenType: 'CREDIT'
|
|
7207
|
+
* },
|
|
7208
|
+
* sortBy: 'totalTransactions',
|
|
7209
|
+
* sortOrder: SortOrder.DESC,
|
|
7210
|
+
* limit: 100,
|
|
7211
|
+
* startDate: new Date('2026-01-01'),
|
|
7212
|
+
* endDate: new Date('2026-12-31')
|
|
7213
|
+
* });
|
|
7214
|
+
* console.log(`Top ${ranking.totalUsers} users for business in 2026`);
|
|
7215
|
+
* ```
|
|
7216
|
+
*/
|
|
7217
|
+
async getUserRanking(request = {}) {
|
|
7218
|
+
return this.apiClient.post('/analytics/users/ranking', request);
|
|
7219
|
+
}
|
|
7220
|
+
/**
|
|
7221
|
+
* ADMIN: Get business transaction ranking with enriched business data
|
|
7222
|
+
*
|
|
7223
|
+
* Returns ranked list of businesses with full business details and transaction metrics.
|
|
7224
|
+
* Data enrichment happens via efficient SQL JOINs + UNION (handles legacy transactions).
|
|
7225
|
+
*
|
|
7226
|
+
* @param request - Ranking request with filters, sorting, and limit
|
|
7227
|
+
* @returns Ranked list with business details and transaction metrics
|
|
7228
|
+
*
|
|
7229
|
+
* @example Top 50 businesses by transaction count
|
|
7230
|
+
* ```typescript
|
|
7231
|
+
* const ranking = await analyticsApi.getBusinessRanking({
|
|
7232
|
+
* sortBy: 'totalTransactions',
|
|
7233
|
+
* sortOrder: SortOrder.DESC,
|
|
7234
|
+
* limit: 50
|
|
7235
|
+
* });
|
|
7236
|
+
* ```
|
|
7237
|
+
*/
|
|
7238
|
+
async getBusinessRanking(request = {}) {
|
|
7239
|
+
return this.apiClient.post('/analytics/businesses/ranking', request);
|
|
7240
|
+
}
|
|
7241
|
+
/**
|
|
7242
|
+
* ADMIN: Get monthly user retention analytics
|
|
7243
|
+
*
|
|
7244
|
+
* Returns monthly retention data with active/new/returning users and retention rates.
|
|
7245
|
+
* Replaces 13 separate API calls with 1 efficient recursive CTE query.
|
|
7246
|
+
*
|
|
7247
|
+
* @param request - Retention analytics request with monthsBack and filters
|
|
7248
|
+
* @returns Monthly retention data with user metrics and retention rates
|
|
7249
|
+
*
|
|
7250
|
+
* @example Last 13 months retention
|
|
7251
|
+
* ```typescript
|
|
7252
|
+
* const retention = await analyticsApi.getRetentionAnalytics({
|
|
7253
|
+
* monthsBack: 13
|
|
7254
|
+
* });
|
|
7255
|
+
* ```
|
|
7256
|
+
*/
|
|
7257
|
+
async getRetentionAnalytics(request = {}) {
|
|
7258
|
+
return this.apiClient.post('/analytics/users/retention', request);
|
|
6743
7259
|
}
|
|
6744
7260
|
}
|
|
6745
7261
|
|
|
@@ -6764,6 +7280,47 @@ class AnalyticsService {
|
|
|
6764
7280
|
async getTransactionAnalytics(request) {
|
|
6765
7281
|
return this.analyticsApi.getTransactionAnalytics(request);
|
|
6766
7282
|
}
|
|
7283
|
+
/**
|
|
7284
|
+
* ADMIN: Get campaign claim analytics with aggregation
|
|
7285
|
+
*/
|
|
7286
|
+
async getCampaignClaimAnalytics(request) {
|
|
7287
|
+
return this.analyticsApi.getCampaignClaimAnalytics(request);
|
|
7288
|
+
}
|
|
7289
|
+
/**
|
|
7290
|
+
* ADMIN: Get user analytics with engagement metrics
|
|
7291
|
+
*
|
|
7292
|
+
* Returns aggregated user statistics including engagement rate, active users,
|
|
7293
|
+
* transaction metrics, and claims/redemption averages.
|
|
7294
|
+
*/
|
|
7295
|
+
async getUserAnalytics(request = {}) {
|
|
7296
|
+
return this.analyticsApi.getUserAnalytics(request);
|
|
7297
|
+
}
|
|
7298
|
+
/**
|
|
7299
|
+
* ADMIN: Get user transaction ranking with enriched user data
|
|
7300
|
+
*
|
|
7301
|
+
* Returns ranked list of users with full user details (email, externalUserId)
|
|
7302
|
+
* and transaction metrics. Efficient data enrichment via SQL JOINs + UNION.
|
|
7303
|
+
*/
|
|
7304
|
+
async getUserRanking(request = {}) {
|
|
7305
|
+
return this.analyticsApi.getUserRanking(request);
|
|
7306
|
+
}
|
|
7307
|
+
/**
|
|
7308
|
+
* ADMIN: Get business transaction ranking with enriched business data
|
|
7309
|
+
*
|
|
7310
|
+
* Returns ranked list of businesses with full business details and transaction metrics.
|
|
7311
|
+
*/
|
|
7312
|
+
async getBusinessRanking(request = {}) {
|
|
7313
|
+
return this.analyticsApi.getBusinessRanking(request);
|
|
7314
|
+
}
|
|
7315
|
+
/**
|
|
7316
|
+
* ADMIN: Get monthly user retention analytics
|
|
7317
|
+
*
|
|
7318
|
+
* Returns monthly retention data with user metrics and retention rates.
|
|
7319
|
+
* Replaces 13 separate API calls with 1 efficient query.
|
|
7320
|
+
*/
|
|
7321
|
+
async getRetentionAnalytics(request = {}) {
|
|
7322
|
+
return this.analyticsApi.getRetentionAnalytics(request);
|
|
7323
|
+
}
|
|
6767
7324
|
}
|
|
6768
7325
|
|
|
6769
7326
|
/**
|
|
@@ -6813,6 +7370,144 @@ class DonationService {
|
|
|
6813
7370
|
}
|
|
6814
7371
|
}
|
|
6815
7372
|
|
|
7373
|
+
/**
|
|
7374
|
+
* Platform-Agnostic TriggerSource API Client
|
|
7375
|
+
*
|
|
7376
|
+
* Handles all trigger source operations:
|
|
7377
|
+
* - CRUD operations for trigger sources (QR codes, NFC tags, GPS geofences, webhooks, etc.)
|
|
7378
|
+
* - Trigger sources are independent entities that can be assigned to campaigns
|
|
7379
|
+
*
|
|
7380
|
+
* Uses @explorins/pers-shared DTOs for consistency with backend.
|
|
7381
|
+
*/
|
|
7382
|
+
class TriggerSourceApi {
|
|
7383
|
+
constructor(apiClient) {
|
|
7384
|
+
this.apiClient = apiClient;
|
|
7385
|
+
}
|
|
7386
|
+
/**
|
|
7387
|
+
* PUBLIC: Get trigger sources with optional filters and pagination
|
|
7388
|
+
*
|
|
7389
|
+
* @param options - Filter and pagination options
|
|
7390
|
+
* @returns Paginated list of trigger sources
|
|
7391
|
+
*
|
|
7392
|
+
* @example
|
|
7393
|
+
* ```typescript
|
|
7394
|
+
* // Get all QR code trigger sources
|
|
7395
|
+
* const qrSources = await triggerSourceApi.getTriggerSources({ type: 'QR_CODE' });
|
|
7396
|
+
*
|
|
7397
|
+
* // Get trigger sources for a specific campaign
|
|
7398
|
+
* const campaignSources = await triggerSourceApi.getTriggerSources({
|
|
7399
|
+
* campaignId: 'campaign-123',
|
|
7400
|
+
* page: 1,
|
|
7401
|
+
* limit: 20
|
|
7402
|
+
* });
|
|
7403
|
+
* ```
|
|
7404
|
+
*/
|
|
7405
|
+
async getTriggerSources(options) {
|
|
7406
|
+
const params = buildPaginationParams(options);
|
|
7407
|
+
if (options?.type)
|
|
7408
|
+
params.set('type', options.type);
|
|
7409
|
+
if (options?.businessId)
|
|
7410
|
+
params.set('businessId', options.businessId);
|
|
7411
|
+
if (options?.campaignId)
|
|
7412
|
+
params.set('campaignId', options.campaignId);
|
|
7413
|
+
if (options?.active !== undefined)
|
|
7414
|
+
params.set('active', String(options.active));
|
|
7415
|
+
const response = await this.apiClient.get(`/trigger-sources?${params.toString()}`);
|
|
7416
|
+
return normalizeToPaginated(response);
|
|
7417
|
+
}
|
|
7418
|
+
/**
|
|
7419
|
+
* PUBLIC: Get trigger source by ID
|
|
7420
|
+
*
|
|
7421
|
+
* @param triggerSourceId - UUID of the trigger source
|
|
7422
|
+
* @returns Trigger source details
|
|
7423
|
+
*/
|
|
7424
|
+
async getTriggerSourceById(triggerSourceId) {
|
|
7425
|
+
return this.apiClient.get(`/trigger-sources/${triggerSourceId}`);
|
|
7426
|
+
}
|
|
7427
|
+
/**
|
|
7428
|
+
* ADMIN: Create a new trigger source
|
|
7429
|
+
*
|
|
7430
|
+
* @param triggerSource - Trigger source creation data
|
|
7431
|
+
* @returns Created trigger source
|
|
7432
|
+
*
|
|
7433
|
+
* @example
|
|
7434
|
+
* ```typescript
|
|
7435
|
+
* const qrSource = await triggerSourceApi.createTriggerSource({
|
|
7436
|
+
* type: 'QR_CODE',
|
|
7437
|
+
* name: 'Store Entrance QR',
|
|
7438
|
+
* description: 'QR code at main entrance',
|
|
7439
|
+
* businessId: 'business-123',
|
|
7440
|
+
* coordsLatitude: 47.6062,
|
|
7441
|
+
* coordsLongitude: -122.3321
|
|
7442
|
+
* });
|
|
7443
|
+
* ```
|
|
7444
|
+
*/
|
|
7445
|
+
async createTriggerSource(triggerSource) {
|
|
7446
|
+
return this.apiClient.post('/trigger-sources', triggerSource);
|
|
7447
|
+
}
|
|
7448
|
+
/**
|
|
7449
|
+
* ADMIN: Update a trigger source
|
|
7450
|
+
*
|
|
7451
|
+
* @param triggerSourceId - UUID of the trigger source to update
|
|
7452
|
+
* @param triggerSource - Updated trigger source data (partial)
|
|
7453
|
+
* @returns Updated trigger source
|
|
7454
|
+
*/
|
|
7455
|
+
async updateTriggerSource(triggerSourceId, triggerSource) {
|
|
7456
|
+
return this.apiClient.put(`/trigger-sources/${triggerSourceId}`, triggerSource);
|
|
7457
|
+
}
|
|
7458
|
+
/**
|
|
7459
|
+
* ADMIN: Delete (soft delete) a trigger source
|
|
7460
|
+
*
|
|
7461
|
+
* @param triggerSourceId - UUID of the trigger source to delete
|
|
7462
|
+
* @returns Success status
|
|
7463
|
+
*/
|
|
7464
|
+
async deleteTriggerSource(triggerSourceId) {
|
|
7465
|
+
return this.apiClient.delete(`/trigger-sources/${triggerSourceId}`);
|
|
7466
|
+
}
|
|
7467
|
+
}
|
|
7468
|
+
|
|
7469
|
+
/**
|
|
7470
|
+
* Platform-Agnostic TriggerSource Service
|
|
7471
|
+
*
|
|
7472
|
+
* Contains trigger source business logic and operations that work across platforms.
|
|
7473
|
+
* No framework dependencies - pure TypeScript business logic.
|
|
7474
|
+
*/
|
|
7475
|
+
class TriggerSourceService {
|
|
7476
|
+
constructor(triggerSourceApi) {
|
|
7477
|
+
this.triggerSourceApi = triggerSourceApi;
|
|
7478
|
+
}
|
|
7479
|
+
/**
|
|
7480
|
+
* Get trigger sources with optional filters
|
|
7481
|
+
*/
|
|
7482
|
+
async getTriggerSources(options) {
|
|
7483
|
+
return this.triggerSourceApi.getTriggerSources(options);
|
|
7484
|
+
}
|
|
7485
|
+
/**
|
|
7486
|
+
* Get trigger source by ID
|
|
7487
|
+
*/
|
|
7488
|
+
async getTriggerSourceById(triggerSourceId) {
|
|
7489
|
+
return this.triggerSourceApi.getTriggerSourceById(triggerSourceId);
|
|
7490
|
+
}
|
|
7491
|
+
/**
|
|
7492
|
+
* ADMIN: Create a new trigger source
|
|
7493
|
+
*/
|
|
7494
|
+
async createTriggerSource(triggerSource) {
|
|
7495
|
+
return this.triggerSourceApi.createTriggerSource(triggerSource);
|
|
7496
|
+
}
|
|
7497
|
+
/**
|
|
7498
|
+
* ADMIN: Update a trigger source
|
|
7499
|
+
*/
|
|
7500
|
+
async updateTriggerSource(triggerSourceId, triggerSource) {
|
|
7501
|
+
return this.triggerSourceApi.updateTriggerSource(triggerSourceId, triggerSource);
|
|
7502
|
+
}
|
|
7503
|
+
/**
|
|
7504
|
+
* ADMIN: Delete a trigger source
|
|
7505
|
+
*/
|
|
7506
|
+
async deleteTriggerSource(triggerSourceId) {
|
|
7507
|
+
return this.triggerSourceApi.deleteTriggerSource(triggerSourceId);
|
|
7508
|
+
}
|
|
7509
|
+
}
|
|
7510
|
+
|
|
6816
7511
|
/**
|
|
6817
7512
|
* PERS SDK Configuration interfaces and utilities
|
|
6818
7513
|
*
|
|
@@ -6896,10 +7591,7 @@ class AuthApi {
|
|
|
6896
7591
|
* Authenticates a user in a business context with role included in JWT.
|
|
6897
7592
|
*
|
|
6898
7593
|
* @param jwt - Authentication token (passkey or Firebase JWT)
|
|
6899
|
-
* @param options - Business authentication options
|
|
6900
|
-
* @param options.businessId - The business ID to authenticate as
|
|
6901
|
-
* - If user has single business membership, auto-selected
|
|
6902
|
-
* - If user has multiple memberships without businessId, throws MULTIPLE_CONTEXT_SELECTION_REQUIRED
|
|
7594
|
+
* @param options - Business authentication options (businessId for multi-business users, auto-selected if single membership)
|
|
6903
7595
|
* @returns Session response with business context and role in JWT
|
|
6904
7596
|
* @throws MultipleContextSelectionError when businessId is required but not provided
|
|
6905
7597
|
*
|
|
@@ -7018,10 +7710,7 @@ class AuthService {
|
|
|
7018
7710
|
* the user's role within that business.
|
|
7019
7711
|
*
|
|
7020
7712
|
* @param jwt - Authentication token (passkey or Firebase JWT)
|
|
7021
|
-
* @param options - Business authentication options
|
|
7022
|
-
* @param options.businessId - The business ID to authenticate as
|
|
7023
|
-
* - If user has single business membership, auto-selected
|
|
7024
|
-
* - If user has multiple memberships without businessId, throws MULTIPLE_CONTEXT_SELECTION_REQUIRED
|
|
7713
|
+
* @param options - Business authentication options (businessId for multi-business users)
|
|
7025
7714
|
* @returns Session response with business context and role baked into JWT
|
|
7026
7715
|
* @throws MultipleContextSelectionRequiredError when businessId is required but not provided
|
|
7027
7716
|
*
|
|
@@ -7912,13 +8601,15 @@ class PersApiClient {
|
|
|
7912
8601
|
* @internal
|
|
7913
8602
|
*/
|
|
7914
8603
|
emitErrorEvent(errorDetails, errorMessage, endpoint, method, status, error) {
|
|
7915
|
-
console.log('[PersApiClient] emitErrorEvent called', {
|
|
7916
|
-
|
|
7917
|
-
|
|
7918
|
-
|
|
7919
|
-
|
|
7920
|
-
|
|
7921
|
-
|
|
8604
|
+
/* console.log('[PersApiClient] emitErrorEvent called', {
|
|
8605
|
+
hasEvents: !!this._events,
|
|
8606
|
+
instanceId: this._events?.instanceId ?? 'none',
|
|
8607
|
+
subscriberCount: this._events?.subscriberCount ?? 0,
|
|
8608
|
+
domain: errorDetails.domain,
|
|
8609
|
+
code: errorDetails.code,
|
|
8610
|
+
status: status,
|
|
8611
|
+
message: errorDetails.message || errorMessage
|
|
8612
|
+
}); */
|
|
7922
8613
|
this._events?.emitError({
|
|
7923
8614
|
domain: errorDetails.domain || 'external',
|
|
7924
8615
|
type: errorDetails.code || 'API_ERROR',
|
|
@@ -8351,8 +9042,7 @@ class AuthManager {
|
|
|
8351
9042
|
* throws `MULTIPLE_CONTEXT_SELECTION_REQUIRED` error with available options
|
|
8352
9043
|
*
|
|
8353
9044
|
* @param jwtToken - JWT token from auth provider (passkey, Firebase, etc.)
|
|
8354
|
-
* @param options - Business authentication options
|
|
8355
|
-
* @param options.businessId - The business ID to authenticate as (required for multi-business users)
|
|
9045
|
+
* @param options - Business authentication options (businessId for multi-business users)
|
|
8356
9046
|
* @returns Promise resolving to authentication response with business context and role in JWT
|
|
8357
9047
|
* @throws Error with code `MULTIPLE_CONTEXT_SELECTION_REQUIRED` when businessId is needed
|
|
8358
9048
|
*
|
|
@@ -8779,26 +9469,49 @@ class UserManager {
|
|
|
8779
9469
|
* requires administrator privileges and returns full user profiles including
|
|
8780
9470
|
* private information.
|
|
8781
9471
|
*
|
|
8782
|
-
* @
|
|
9472
|
+
* @param options - Pagination options (page, limit, sortBy, sortOrder)
|
|
9473
|
+
* @param search - Optional search query to filter users
|
|
9474
|
+
* @returns Promise resolving to paginated users with complete data
|
|
8783
9475
|
* @throws {PersApiError} When not authenticated as admin
|
|
8784
9476
|
*
|
|
8785
|
-
* @example
|
|
9477
|
+
* @example Basic Usage
|
|
8786
9478
|
* ```typescript
|
|
8787
9479
|
* // Admin operation - requires admin authentication
|
|
8788
9480
|
* try {
|
|
8789
|
-
* const
|
|
8790
|
-
* console.log(`Total users: ${
|
|
9481
|
+
* const result = await sdk.users.getAllUsers();
|
|
9482
|
+
* console.log(`Total users: ${result.pagination.total}`);
|
|
8791
9483
|
*
|
|
8792
|
-
*
|
|
8793
|
-
* console.log(`${user.
|
|
9484
|
+
* result.data.forEach(user => {
|
|
9485
|
+
* console.log(`${user.firstName} - ${user.email} - Active: ${user.isActive}`);
|
|
8794
9486
|
* });
|
|
8795
9487
|
* } catch (error) {
|
|
8796
9488
|
* console.log('Admin access required');
|
|
8797
9489
|
* }
|
|
8798
9490
|
* ```
|
|
9491
|
+
*
|
|
9492
|
+
* @example With Sorting
|
|
9493
|
+
* ```typescript
|
|
9494
|
+
* import { SortOrder } from '@explorins/pers-sdk';
|
|
9495
|
+
*
|
|
9496
|
+
* // Get users sorted by email ascending
|
|
9497
|
+
* const result = await sdk.users.getAllUsers({
|
|
9498
|
+
* page: 1,
|
|
9499
|
+
* limit: 20,
|
|
9500
|
+
* sortBy: 'email',
|
|
9501
|
+
* sortOrder: SortOrder.ASC
|
|
9502
|
+
* });
|
|
9503
|
+
*
|
|
9504
|
+
* // Get users sorted by creation date (newest first)
|
|
9505
|
+
* const recent = await sdk.users.getAllUsers({
|
|
9506
|
+
* page: 1,
|
|
9507
|
+
* limit: 10,
|
|
9508
|
+
* sortBy: 'createdAt',
|
|
9509
|
+
* sortOrder: SortOrder.DESC
|
|
9510
|
+
* });
|
|
9511
|
+
* ```
|
|
8799
9512
|
*/
|
|
8800
|
-
async getAllUsers(options) {
|
|
8801
|
-
return this.userService.getAllRemoteUsers(options);
|
|
9513
|
+
async getAllUsers(options, search) {
|
|
9514
|
+
return this.userService.getAllRemoteUsers(options, search);
|
|
8802
9515
|
}
|
|
8803
9516
|
/**
|
|
8804
9517
|
* Business/Admin: Create or update a user
|
|
@@ -9963,6 +10676,7 @@ class CampaignManager {
|
|
|
9963
10676
|
* business partnerships, eligibility criteria, and claiming requirements.
|
|
9964
10677
|
*
|
|
9965
10678
|
* @param campaignId - Unique campaign identifier
|
|
10679
|
+
* @param include - Relations to include: 'triggerSources', 'businesses'
|
|
9966
10680
|
* @returns Promise resolving to campaign data with complete details
|
|
9967
10681
|
* @throws {PersApiError} When campaign with specified ID is not found
|
|
9968
10682
|
*
|
|
@@ -9991,9 +10705,17 @@ class CampaignManager {
|
|
|
9991
10705
|
* console.log('Campaign not found:', error.message);
|
|
9992
10706
|
* }
|
|
9993
10707
|
* ```
|
|
10708
|
+
*
|
|
10709
|
+
* @example With Include Relations
|
|
10710
|
+
* ```typescript
|
|
10711
|
+
* // Get campaign with trigger sources and businesses included
|
|
10712
|
+
* const campaign = await sdk.campaigns.getCampaignById('campaign-123', ['triggerSources', 'businesses']);
|
|
10713
|
+
* console.log('Trigger sources:', campaign.included?.triggerSources);
|
|
10714
|
+
* console.log('Businesses:', campaign.included?.businesses);
|
|
10715
|
+
* ```
|
|
9994
10716
|
*/
|
|
9995
|
-
async getCampaignById(campaignId) {
|
|
9996
|
-
return this.campaignService.getCampaignById(campaignId);
|
|
10717
|
+
async getCampaignById(campaignId, include) {
|
|
10718
|
+
return this.campaignService.getCampaignById(campaignId, include);
|
|
9997
10719
|
}
|
|
9998
10720
|
/**
|
|
9999
10721
|
* Claim a campaign reward
|
|
@@ -10099,7 +10821,8 @@ class CampaignManager {
|
|
|
10099
10821
|
* ```
|
|
10100
10822
|
*/
|
|
10101
10823
|
async getUserClaims(options) {
|
|
10102
|
-
|
|
10824
|
+
const { include, ...paginationOptions } = options || {};
|
|
10825
|
+
return this.campaignService.getClaimsForLoggedUser(paginationOptions, include);
|
|
10103
10826
|
}
|
|
10104
10827
|
/**
|
|
10105
10828
|
* Get campaigns with pagination support
|
|
@@ -10107,13 +10830,7 @@ class CampaignManager {
|
|
|
10107
10830
|
* Returns campaigns with pagination metadata for efficient data loading.
|
|
10108
10831
|
* Intelligent access: Public gets active only, Business gets own campaigns, Admin gets all.
|
|
10109
10832
|
*
|
|
10110
|
-
* @param options - Pagination and filter options
|
|
10111
|
-
* @param options.active - Filter by active status (true/false/undefined for all)
|
|
10112
|
-
* @param options.businessId - Filter by business engagement
|
|
10113
|
-
* @param options.page - Page number (1-based, default: 1)
|
|
10114
|
-
* @param options.limit - Items per page (default: 50)
|
|
10115
|
-
* @param options.sortBy - Sort field ('name', 'createdAt', 'startDate')
|
|
10116
|
-
* @param options.sortOrder - Sort direction ('ASC' or 'DESC')
|
|
10833
|
+
* @param options - Pagination and filter options (page, limit, sortBy, sortOrder, active, businessId, include)
|
|
10117
10834
|
* @returns Promise resolving to paginated campaigns with metadata
|
|
10118
10835
|
*
|
|
10119
10836
|
* @example
|
|
@@ -10138,6 +10855,11 @@ class CampaignManager {
|
|
|
10138
10855
|
* page: 1,
|
|
10139
10856
|
* limit: 25
|
|
10140
10857
|
* });
|
|
10858
|
+
*
|
|
10859
|
+
* // Include related data (trigger sources and businesses)
|
|
10860
|
+
* const campaignsWithRelations = await sdk.campaigns.getCampaigns({
|
|
10861
|
+
* include: ['triggerSources', 'businesses']
|
|
10862
|
+
* });
|
|
10141
10863
|
* ```
|
|
10142
10864
|
*/
|
|
10143
10865
|
async getCampaigns(options) {
|
|
@@ -10255,57 +10977,188 @@ class CampaignManager {
|
|
|
10255
10977
|
async toggleCampaignTestnet(campaignId) {
|
|
10256
10978
|
return this.campaignService.toggleCampaignTestnet(campaignId);
|
|
10257
10979
|
}
|
|
10980
|
+
// ==========================================
|
|
10981
|
+
// CAMPAIGN TRIGGER OPERATIONS
|
|
10982
|
+
// Rules & limits for campaign activation
|
|
10983
|
+
// ==========================================
|
|
10258
10984
|
/**
|
|
10259
|
-
* Admin: Get campaign triggers
|
|
10985
|
+
* Admin: Get all campaign triggers (paginated)
|
|
10260
10986
|
*
|
|
10261
|
-
* Retrieves all
|
|
10262
|
-
*
|
|
10263
|
-
* Requires administrator privileges.
|
|
10987
|
+
* Retrieves all campaign trigger rules that define rate limits, geo-validation,
|
|
10988
|
+
* conditions, and trigger types for campaign activation.
|
|
10264
10989
|
*
|
|
10265
|
-
* @
|
|
10990
|
+
* @param options - Pagination options
|
|
10991
|
+
* @returns Promise resolving to paginated list of campaign triggers
|
|
10266
10992
|
*
|
|
10267
10993
|
* @example
|
|
10268
10994
|
* ```typescript
|
|
10269
|
-
*
|
|
10270
|
-
*
|
|
10271
|
-
*
|
|
10272
|
-
*
|
|
10273
|
-
* triggers.forEach(trigger => {
|
|
10274
|
-
* console.log(`- ${trigger.name}: ${trigger.description}`);
|
|
10275
|
-
* console.log(` Type: ${trigger.type}`);
|
|
10276
|
-
* console.log(` Parameters: ${JSON.stringify(trigger.parameters)}`);
|
|
10995
|
+
* const triggers = await sdk.campaigns.getCampaignTriggers({ page: 1, limit: 20 });
|
|
10996
|
+
* console.log(`Found ${triggers.total} triggers`);
|
|
10997
|
+
* triggers.data.forEach(trigger => {
|
|
10998
|
+
* console.log(`- ${trigger.name}: max ${trigger.maxPerDayPerUser}/day`);
|
|
10277
10999
|
* });
|
|
10278
11000
|
* ```
|
|
10279
11001
|
*/
|
|
10280
11002
|
async getCampaignTriggers(options) {
|
|
10281
|
-
return this.campaignService.getCampaignTriggers();
|
|
11003
|
+
return this.campaignService.getCampaignTriggers(options);
|
|
11004
|
+
}
|
|
11005
|
+
/**
|
|
11006
|
+
* Admin: Get campaign trigger by ID
|
|
11007
|
+
*
|
|
11008
|
+
* @param triggerId - The campaign trigger ID
|
|
11009
|
+
* @returns Promise resolving to the campaign trigger
|
|
11010
|
+
*
|
|
11011
|
+
* @example
|
|
11012
|
+
* ```typescript
|
|
11013
|
+
* const trigger = await sdk.campaigns.getCampaignTriggerById('trigger-123');
|
|
11014
|
+
* console.log('Max per day:', trigger.maxPerDayPerUser);
|
|
11015
|
+
* ```
|
|
11016
|
+
*/
|
|
11017
|
+
async getCampaignTriggerById(triggerId) {
|
|
11018
|
+
return this.campaignService.getCampaignTriggerById(triggerId);
|
|
11019
|
+
}
|
|
11020
|
+
/**
|
|
11021
|
+
* Admin: Create a new campaign trigger
|
|
11022
|
+
*
|
|
11023
|
+
* Creates a trigger rule that defines rate limits, geo-validation, and conditions
|
|
11024
|
+
* for campaign activation. Triggers are created independently and then assigned
|
|
11025
|
+
* to campaigns via `setCampaignTrigger()`.
|
|
11026
|
+
*
|
|
11027
|
+
* @param data - Trigger configuration
|
|
11028
|
+
* @returns Promise resolving to created trigger
|
|
11029
|
+
*
|
|
11030
|
+
* @example
|
|
11031
|
+
* ```typescript
|
|
11032
|
+
* const trigger = await sdk.campaigns.createCampaignTrigger({
|
|
11033
|
+
* name: 'Daily Check-in',
|
|
11034
|
+
* maxPerDayPerUser: 1,
|
|
11035
|
+
* maxPerUser: 100,
|
|
11036
|
+
* minCooldownSeconds: 3600,
|
|
11037
|
+
* maxGeoDistanceInMeters: 50,
|
|
11038
|
+
* triggerType: 'CLAIM_BY_USER'
|
|
11039
|
+
* });
|
|
11040
|
+
*
|
|
11041
|
+
* // Then assign to campaign
|
|
11042
|
+
* await sdk.campaigns.setCampaignTrigger(campaignId, trigger.id);
|
|
11043
|
+
* ```
|
|
11044
|
+
*/
|
|
11045
|
+
async createCampaignTrigger(data) {
|
|
11046
|
+
const result = await this.campaignService.createCampaignTrigger(data);
|
|
11047
|
+
this.events?.emitSuccess({
|
|
11048
|
+
domain: 'campaign',
|
|
11049
|
+
type: 'CAMPAIGN_TRIGGER_CREATED',
|
|
11050
|
+
userMessage: `Trigger "${data.name}" created successfully`,
|
|
11051
|
+
details: { triggerId: result.id, name: data.name }
|
|
11052
|
+
});
|
|
11053
|
+
return result;
|
|
11054
|
+
}
|
|
11055
|
+
/**
|
|
11056
|
+
* Admin: Update an existing campaign trigger
|
|
11057
|
+
*
|
|
11058
|
+
* @param triggerId - The campaign trigger ID
|
|
11059
|
+
* @param data - Updated trigger configuration (partial)
|
|
11060
|
+
* @returns Promise resolving to updated trigger
|
|
11061
|
+
*
|
|
11062
|
+
* @example
|
|
11063
|
+
* ```typescript
|
|
11064
|
+
* const updated = await sdk.campaigns.updateCampaignTrigger('trigger-123', {
|
|
11065
|
+
* maxPerDayPerUser: 5,
|
|
11066
|
+
* minCooldownSeconds: 1800
|
|
11067
|
+
* });
|
|
11068
|
+
* ```
|
|
11069
|
+
*/
|
|
11070
|
+
async updateCampaignTrigger(triggerId, data) {
|
|
11071
|
+
const result = await this.campaignService.updateCampaignTrigger(triggerId, data);
|
|
11072
|
+
this.events?.emitSuccess({
|
|
11073
|
+
domain: 'campaign',
|
|
11074
|
+
type: 'CAMPAIGN_TRIGGER_UPDATED',
|
|
11075
|
+
userMessage: 'Trigger updated successfully',
|
|
11076
|
+
details: { triggerId, updates: Object.keys(data) }
|
|
11077
|
+
});
|
|
11078
|
+
return result;
|
|
11079
|
+
}
|
|
11080
|
+
/**
|
|
11081
|
+
* Admin: Delete a campaign trigger
|
|
11082
|
+
*
|
|
11083
|
+
* @param triggerId - The campaign trigger ID
|
|
11084
|
+
* @returns Promise resolving to success status
|
|
11085
|
+
*
|
|
11086
|
+
* @example
|
|
11087
|
+
* ```typescript
|
|
11088
|
+
* await sdk.campaigns.deleteCampaignTrigger('trigger-123');
|
|
11089
|
+
* ```
|
|
11090
|
+
*/
|
|
11091
|
+
async deleteCampaignTrigger(triggerId) {
|
|
11092
|
+
const result = await this.campaignService.deleteCampaignTrigger(triggerId);
|
|
11093
|
+
this.events?.emitSuccess({
|
|
11094
|
+
domain: 'campaign',
|
|
11095
|
+
type: 'CAMPAIGN_TRIGGER_DELETED',
|
|
11096
|
+
userMessage: 'Trigger deleted successfully',
|
|
11097
|
+
details: { triggerId }
|
|
11098
|
+
});
|
|
11099
|
+
return result;
|
|
10282
11100
|
}
|
|
10283
11101
|
/**
|
|
10284
|
-
* Admin:
|
|
11102
|
+
* Admin: Assign a trigger to a campaign
|
|
10285
11103
|
*
|
|
10286
|
-
* Associates a
|
|
10287
|
-
*
|
|
11104
|
+
* Associates a trigger rule with a campaign. A campaign can have only one trigger
|
|
11105
|
+
* at a time. Assigning a new trigger replaces any existing trigger.
|
|
10288
11106
|
*
|
|
10289
11107
|
* @param campaignId - ID of the campaign
|
|
10290
11108
|
* @param triggerId - ID of the trigger to associate
|
|
10291
|
-
* @returns Promise resolving to updated campaign
|
|
10292
|
-
* @throws {PersApiError} When not authenticated as admin or entities not found
|
|
11109
|
+
* @returns Promise resolving to updated campaign
|
|
10293
11110
|
*
|
|
10294
11111
|
* @example
|
|
10295
11112
|
* ```typescript
|
|
10296
|
-
* // Admin operation - set up automatic campaign trigger
|
|
10297
11113
|
* const updated = await sdk.campaigns.setCampaignTrigger(
|
|
10298
|
-
* '
|
|
10299
|
-
* '
|
|
11114
|
+
* 'campaign-123',
|
|
11115
|
+
* 'trigger-456'
|
|
10300
11116
|
* );
|
|
10301
|
-
*
|
|
10302
|
-
* console.log('Trigger set for campaign:', updated.title);
|
|
10303
|
-
* console.log('Trigger will activate on user registration');
|
|
11117
|
+
* console.log('Trigger assigned:', updated.trigger?.name);
|
|
10304
11118
|
* ```
|
|
10305
11119
|
*/
|
|
10306
11120
|
async setCampaignTrigger(campaignId, triggerId) {
|
|
10307
|
-
|
|
11121
|
+
const result = await this.campaignService.setCampaignTrigger(campaignId, triggerId);
|
|
11122
|
+
this.events?.emitSuccess({
|
|
11123
|
+
domain: 'campaign',
|
|
11124
|
+
type: 'CAMPAIGN_TRIGGER_ASSIGNED',
|
|
11125
|
+
userMessage: 'Trigger assigned to campaign',
|
|
11126
|
+
details: { campaignId, triggerId }
|
|
11127
|
+
});
|
|
11128
|
+
return result;
|
|
10308
11129
|
}
|
|
11130
|
+
/**
|
|
11131
|
+
* Admin: Remove a trigger from a campaign
|
|
11132
|
+
*
|
|
11133
|
+
* Removes the trigger rule from a campaign. The trigger itself is not deleted
|
|
11134
|
+
* and can be reassigned to other campaigns.
|
|
11135
|
+
*
|
|
11136
|
+
* @param campaignId - ID of the campaign
|
|
11137
|
+
* @param triggerId - ID of the trigger to remove
|
|
11138
|
+
* @returns Promise resolving to updated campaign
|
|
11139
|
+
*
|
|
11140
|
+
* @example
|
|
11141
|
+
* ```typescript
|
|
11142
|
+
* const updated = await sdk.campaigns.removeCampaignTrigger(
|
|
11143
|
+
* 'campaign-123',
|
|
11144
|
+
* 'trigger-456'
|
|
11145
|
+
* );
|
|
11146
|
+
* console.log('Trigger removed:', updated.trigger === null);
|
|
11147
|
+
* ```
|
|
11148
|
+
*/
|
|
11149
|
+
async removeCampaignTrigger(campaignId, triggerId) {
|
|
11150
|
+
const result = await this.campaignService.removeCampaignTrigger(campaignId, triggerId);
|
|
11151
|
+
this.events?.emitSuccess({
|
|
11152
|
+
domain: 'campaign',
|
|
11153
|
+
type: 'CAMPAIGN_TRIGGER_REMOVED',
|
|
11154
|
+
userMessage: 'Trigger removed from campaign',
|
|
11155
|
+
details: { campaignId, triggerId }
|
|
11156
|
+
});
|
|
11157
|
+
return result;
|
|
11158
|
+
}
|
|
11159
|
+
// ==========================================
|
|
11160
|
+
// TOKEN UNIT OPERATIONS
|
|
11161
|
+
// ==========================================
|
|
10309
11162
|
/**
|
|
10310
11163
|
* Admin: Create campaign token unit
|
|
10311
11164
|
*
|
|
@@ -10514,8 +11367,8 @@ class CampaignManager {
|
|
|
10514
11367
|
* });
|
|
10515
11368
|
* ```
|
|
10516
11369
|
*/
|
|
10517
|
-
async getCampaignClaims(filters) {
|
|
10518
|
-
return this.campaignService.getCampaignClaims(filters);
|
|
11370
|
+
async getCampaignClaims(filters, include) {
|
|
11371
|
+
return this.campaignService.getCampaignClaims(filters, include);
|
|
10519
11372
|
}
|
|
10520
11373
|
/**
|
|
10521
11374
|
* Admin: Get campaign claims by user ID
|
|
@@ -10550,8 +11403,8 @@ class CampaignManager {
|
|
|
10550
11403
|
* console.log(`\nTotal rewards earned: ${totalRewards}`);
|
|
10551
11404
|
* ```
|
|
10552
11405
|
*/
|
|
10553
|
-
async getCampaignClaimsByUserId(userId, options) {
|
|
10554
|
-
return this.campaignService.getCampaignClaimsByUserId(userId);
|
|
11406
|
+
async getCampaignClaimsByUserId(userId, options, include) {
|
|
11407
|
+
return this.campaignService.getCampaignClaimsByUserId(userId, options, include);
|
|
10555
11408
|
}
|
|
10556
11409
|
/**
|
|
10557
11410
|
* Admin: Get campaign claims by business ID
|
|
@@ -10591,8 +11444,79 @@ class CampaignManager {
|
|
|
10591
11444
|
* console.log(`\nTotal rewards distributed: ${totalRewardsDistributed}`);
|
|
10592
11445
|
* ```
|
|
10593
11446
|
*/
|
|
10594
|
-
async getCampaignClaimsByBusinessId(businessId, options) {
|
|
10595
|
-
return this.campaignService.getCampaignClaimsByBusinessId(businessId);
|
|
11447
|
+
async getCampaignClaimsByBusinessId(businessId, options, include) {
|
|
11448
|
+
return this.campaignService.getCampaignClaimsByBusinessId(businessId, options, include);
|
|
11449
|
+
}
|
|
11450
|
+
// ==========================================
|
|
11451
|
+
// TRIGGER SOURCE ASSIGNMENT
|
|
11452
|
+
// Note: TriggerSource CRUD is in TriggerSourceManager (sdk.triggerSources)
|
|
11453
|
+
// ==========================================
|
|
11454
|
+
/**
|
|
11455
|
+
* Admin: Assign a trigger source to a campaign
|
|
11456
|
+
*
|
|
11457
|
+
* Associates a trigger source with a campaign, enabling the trigger source
|
|
11458
|
+
* to activate campaign rewards when triggered. A campaign can have multiple
|
|
11459
|
+
* trigger sources. Requires administrator privileges.
|
|
11460
|
+
*
|
|
11461
|
+
* Note: To create/update/delete trigger sources, use `sdk.triggerSources`.
|
|
11462
|
+
*
|
|
11463
|
+
* @param campaignId - Campaign UUID
|
|
11464
|
+
* @param triggerSourceId - Trigger source UUID
|
|
11465
|
+
* @returns Promise resolving to updated campaign with trigger source assigned
|
|
11466
|
+
* @throws {PersApiError} When not authenticated as admin or entities not found
|
|
11467
|
+
*
|
|
11468
|
+
* @example
|
|
11469
|
+
* ```typescript
|
|
11470
|
+
* // Create trigger source first
|
|
11471
|
+
* const source = await sdk.triggerSources.create({
|
|
11472
|
+
* type: 'QR_CODE',
|
|
11473
|
+
* name: 'Store Entrance QR'
|
|
11474
|
+
* });
|
|
11475
|
+
*
|
|
11476
|
+
* // Then assign to campaign
|
|
11477
|
+
* const updated = await sdk.campaigns.assignTriggerSource(
|
|
11478
|
+
* 'campaign-123',
|
|
11479
|
+
* source.id
|
|
11480
|
+
* );
|
|
11481
|
+
*
|
|
11482
|
+
* console.log('Trigger source assigned:', updated.triggerSourceIds.length);
|
|
11483
|
+
* ```
|
|
11484
|
+
*/
|
|
11485
|
+
async assignTriggerSource(campaignId, triggerSourceId) {
|
|
11486
|
+
const result = await this.campaignService.assignTriggerSourceToCampaign(campaignId, triggerSourceId);
|
|
11487
|
+
this.events?.emitSuccess({
|
|
11488
|
+
domain: 'campaign',
|
|
11489
|
+
type: 'TRIGGER_SOURCE_ASSIGNED',
|
|
11490
|
+
userMessage: 'Trigger source assigned to campaign',
|
|
11491
|
+
details: { campaignId, triggerSourceId }
|
|
11492
|
+
});
|
|
11493
|
+
return result;
|
|
11494
|
+
}
|
|
11495
|
+
/**
|
|
11496
|
+
* Admin: Remove a trigger source from a campaign
|
|
11497
|
+
*
|
|
11498
|
+
* Removes the association between a trigger source and a campaign. The trigger
|
|
11499
|
+
* source itself is not deleted and can be reassigned to other campaigns.
|
|
11500
|
+
* Requires administrator privileges.
|
|
11501
|
+
*
|
|
11502
|
+
* @param campaignId - Campaign UUID
|
|
11503
|
+
* @param triggerSourceId - Trigger source UUID
|
|
11504
|
+
* @returns Promise resolving to updated campaign with trigger source removed
|
|
11505
|
+
* @throws {PersApiError} When not authenticated as admin or entities not found
|
|
11506
|
+
*
|
|
11507
|
+
* @example
|
|
11508
|
+
* ```typescript
|
|
11509
|
+
* // Remove a trigger source from a campaign
|
|
11510
|
+
* const updated = await sdk.campaigns.removeTriggerSource(
|
|
11511
|
+
* 'campaign-123',
|
|
11512
|
+
* 'source-456'
|
|
11513
|
+
* );
|
|
11514
|
+
*
|
|
11515
|
+
* console.log('Remaining trigger source IDs:', updated.triggerSourceIds.length);
|
|
11516
|
+
* ```
|
|
11517
|
+
*/
|
|
11518
|
+
async removeTriggerSource(campaignId, triggerSourceId) {
|
|
11519
|
+
return this.campaignService.removeTriggerSourceFromCampaign(campaignId, triggerSourceId);
|
|
10596
11520
|
}
|
|
10597
11521
|
/**
|
|
10598
11522
|
* Get the full campaign service for advanced operations
|
|
@@ -10976,8 +11900,57 @@ class RedemptionManager {
|
|
|
10976
11900
|
* });
|
|
10977
11901
|
* ```
|
|
10978
11902
|
*/
|
|
10979
|
-
async getUserRedemptions(options) {
|
|
10980
|
-
return this.redemptionService.getUserRedeems(options);
|
|
11903
|
+
async getUserRedemptions(options, include) {
|
|
11904
|
+
return this.redemptionService.getUserRedeems(options, include);
|
|
11905
|
+
}
|
|
11906
|
+
/**
|
|
11907
|
+
* Admin: Get all redemption redeems with filtering and enriched data
|
|
11908
|
+
*
|
|
11909
|
+
* Retrieves all redemption redeems across the platform with filtering capabilities.
|
|
11910
|
+
* This is an admin-level operation that allows monitoring and analytics of redemption
|
|
11911
|
+
* activity. Supports filtering by user, redemption offer, and enrichment of related entities.
|
|
11912
|
+
*
|
|
11913
|
+
* @param filters - Filter options (userId, redemptionId, pagination)
|
|
11914
|
+
* @param include - Optional relations to include for enrichment
|
|
11915
|
+
* @returns Promise resolving to paginated list of redemption redeems
|
|
11916
|
+
* @throws {PersApiError} When not authenticated as admin
|
|
11917
|
+
*
|
|
11918
|
+
* @example Get All Redeems
|
|
11919
|
+
* ```typescript
|
|
11920
|
+
* // Admin operation - get all redemption redeems
|
|
11921
|
+
* const { data: allRedeems, pagination } = await sdk.redemptions.getRedemptionRedeems();
|
|
11922
|
+
*
|
|
11923
|
+
* console.log(`Total redeems: ${pagination.total}`);
|
|
11924
|
+
* console.log(`Page ${pagination.page} of ${pagination.pages}`);
|
|
11925
|
+
* ```
|
|
11926
|
+
*
|
|
11927
|
+
* @example Filter by User
|
|
11928
|
+
* ```typescript
|
|
11929
|
+
* // Get redeems for specific user
|
|
11930
|
+
* const { data: userRedeems } = await sdk.redemptions.getRedemptionRedeems({
|
|
11931
|
+
* userId: 'user-123',
|
|
11932
|
+
* limit: 50
|
|
11933
|
+
* });
|
|
11934
|
+
*
|
|
11935
|
+
* console.log(`User has ${userRedeems.length} redemptions`);
|
|
11936
|
+
* ```
|
|
11937
|
+
*
|
|
11938
|
+
* @example With Enriched Data
|
|
11939
|
+
* ```typescript
|
|
11940
|
+
* const { data: redeems } = await sdk.redemptions.getRedemptionRedeems(
|
|
11941
|
+
* { page: 1, limit: 20 },
|
|
11942
|
+
* ['redemption', 'user', 'business']
|
|
11943
|
+
* );
|
|
11944
|
+
*
|
|
11945
|
+
* redeems.forEach(redeem => {
|
|
11946
|
+
* const redemptionName = redeem.included?.redemption?.name || 'Unknown';
|
|
11947
|
+
* const userEmail = redeem.included?.user?.email || redeem.userId;
|
|
11948
|
+
* console.log(`${redemptionName} - ${userEmail}`);
|
|
11949
|
+
* });
|
|
11950
|
+
* ```
|
|
11951
|
+
*/
|
|
11952
|
+
async getRedemptionRedeems(filters, include) {
|
|
11953
|
+
return this.redemptionService.getRedemptionRedeems(filters, include);
|
|
10981
11954
|
}
|
|
10982
11955
|
/**
|
|
10983
11956
|
* Admin: Create new redemption offer
|
|
@@ -11220,8 +12193,8 @@ class RedemptionManager {
|
|
|
11220
12193
|
*
|
|
11221
12194
|
* @example Administrative Reporting
|
|
11222
12195
|
* ```typescript
|
|
11223
|
-
* // Admin: Get
|
|
11224
|
-
* const allTransactions = await sdk.transactions.
|
|
12196
|
+
* // Admin: Get paginated transactions for analysis
|
|
12197
|
+
* const allTransactions = await sdk.transactions.getPaginatedTransactions({ page: 1, limit: 100 });
|
|
11225
12198
|
*
|
|
11226
12199
|
* // Export transaction data
|
|
11227
12200
|
* const csvBlob = await sdk.transactions.exportTransactionsCSV();
|
|
@@ -11244,13 +12217,18 @@ class TransactionManager {
|
|
|
11244
12217
|
* Provides complete transaction audit trail and verification data.
|
|
11245
12218
|
*
|
|
11246
12219
|
* @param transactionId - Unique transaction identifier
|
|
12220
|
+
* @param include - Optional relations to include (sender, recipient, business) for enriched entity data
|
|
11247
12221
|
* @returns Promise resolving to complete transaction data
|
|
11248
12222
|
* @throws {PersApiError} When transaction with specified ID is not found or access denied
|
|
11249
12223
|
*
|
|
11250
12224
|
* @example
|
|
11251
12225
|
* ```typescript
|
|
11252
12226
|
* try {
|
|
11253
|
-
*
|
|
12227
|
+
* // Get transaction with enriched sender/recipient data
|
|
12228
|
+
* const transaction = await sdk.transactions.getTransactionById(
|
|
12229
|
+
* 'txn-abc123',
|
|
12230
|
+
* ['sender', 'recipient', 'business']
|
|
12231
|
+
* );
|
|
11254
12232
|
*
|
|
11255
12233
|
* console.log('Transaction Details:');
|
|
11256
12234
|
* console.log('ID:', transaction.id);
|
|
@@ -11263,16 +12241,19 @@ class TransactionManager {
|
|
|
11263
12241
|
* console.log('Description:', transaction.description);
|
|
11264
12242
|
* }
|
|
11265
12243
|
*
|
|
11266
|
-
*
|
|
11267
|
-
*
|
|
12244
|
+
* // Access enriched sender data
|
|
12245
|
+
* if (transaction.included?.sender) {
|
|
12246
|
+
* console.log('Sender:', transaction.included.sender);
|
|
11268
12247
|
* }
|
|
11269
12248
|
*
|
|
11270
|
-
* //
|
|
11271
|
-
* if (transaction.
|
|
11272
|
-
* console.log('
|
|
11273
|
-
*
|
|
11274
|
-
*
|
|
11275
|
-
*
|
|
12249
|
+
* // Access enriched recipient data
|
|
12250
|
+
* if (transaction.included?.recipient) {
|
|
12251
|
+
* console.log('Recipient:', transaction.included.recipient);
|
|
12252
|
+
* }
|
|
12253
|
+
*
|
|
12254
|
+
* // Access enriched business data
|
|
12255
|
+
* if (transaction.included?.engagedBusiness) {
|
|
12256
|
+
* console.log('Business:', transaction.included.engagedBusiness.displayName);
|
|
11276
12257
|
* }
|
|
11277
12258
|
*
|
|
11278
12259
|
* // Show blockchain confirmation
|
|
@@ -11285,8 +12266,8 @@ class TransactionManager {
|
|
|
11285
12266
|
* }
|
|
11286
12267
|
* ```
|
|
11287
12268
|
*/
|
|
11288
|
-
async getTransactionById(transactionId) {
|
|
11289
|
-
return this.transactionService.getTransactionById(transactionId);
|
|
12269
|
+
async getTransactionById(transactionId, include) {
|
|
12270
|
+
return this.transactionService.getTransactionById(transactionId, include);
|
|
11290
12271
|
}
|
|
11291
12272
|
/**
|
|
11292
12273
|
* Create a new transaction
|
|
@@ -11380,150 +12361,62 @@ class TransactionManager {
|
|
|
11380
12361
|
/**
|
|
11381
12362
|
* Get user's transaction history
|
|
11382
12363
|
*
|
|
11383
|
-
* Retrieves transaction history for the authenticated user
|
|
11384
|
-
*
|
|
12364
|
+
* Retrieves transaction history for the authenticated user with comprehensive
|
|
12365
|
+
* filtering options. Provides chronological view of all user's loyalty
|
|
11385
12366
|
* activities including purchases, rewards, redemptions, and transfers.
|
|
12367
|
+
* Optionally enrich with related entities (sender, recipient, business).
|
|
11386
12368
|
*
|
|
11387
|
-
* @param
|
|
11388
|
-
* @
|
|
11389
|
-
* @returns Promise resolving to array of user's transactions
|
|
12369
|
+
* @param options - Query options including filters, pagination, and include relations
|
|
12370
|
+
* @returns Promise resolving to paginated transaction data with optional included entities
|
|
11390
12371
|
*
|
|
11391
12372
|
* @example All Transactions
|
|
11392
12373
|
* ```typescript
|
|
11393
|
-
* const
|
|
12374
|
+
* const result = await sdk.transactions.getUserTransactionHistory();
|
|
11394
12375
|
*
|
|
11395
|
-
* console.log(`
|
|
12376
|
+
* console.log(`Transaction History (${result.data.length} of ${result.pagination.total} transactions)`);
|
|
11396
12377
|
*
|
|
11397
|
-
*
|
|
12378
|
+
* result.data.forEach((transaction, index) => {
|
|
11398
12379
|
* const date = new Date(transaction.createdAt).toLocaleDateString();
|
|
11399
12380
|
* console.log(`\n${index + 1}. ${transaction.type} - ${date}`);
|
|
11400
12381
|
* console.log(` ${transaction.description || 'No description'}`);
|
|
11401
12382
|
* console.log(` Status: ${transaction.status}`);
|
|
11402
|
-
*
|
|
11403
|
-
* if (transaction.amount && transaction.currency) {
|
|
11404
|
-
* console.log(` Amount: ${transaction.amount} ${transaction.currency}`);
|
|
11405
|
-
* }
|
|
11406
|
-
*
|
|
11407
|
-
* if (transaction.business) {
|
|
11408
|
-
* console.log(` Business: ${transaction.business.displayName}`);
|
|
11409
|
-
* }
|
|
11410
12383
|
* });
|
|
11411
12384
|
* ```
|
|
11412
12385
|
*
|
|
11413
|
-
* @example
|
|
12386
|
+
* @example Filter by Role and Status
|
|
11414
12387
|
* ```typescript
|
|
11415
|
-
* // Get only
|
|
11416
|
-
* const
|
|
11417
|
-
*
|
|
11418
|
-
*
|
|
11419
|
-
*
|
|
11420
|
-
*
|
|
11421
|
-
*
|
|
11422
|
-
* if (purchase.amount) {
|
|
11423
|
-
* totalSpent += purchase.amount;
|
|
11424
|
-
* }
|
|
11425
|
-
*
|
|
11426
|
-
* if (purchase.tokensEarned?.length) {
|
|
11427
|
-
* purchase.tokensEarned.forEach(reward => {
|
|
11428
|
-
* totalRewards += reward.amount;
|
|
11429
|
-
* });
|
|
11430
|
-
* }
|
|
12388
|
+
* // Get only completed sent transactions
|
|
12389
|
+
* const sent = await sdk.transactions.getUserTransactionHistory({
|
|
12390
|
+
* role: TransactionRole.SENDER,
|
|
12391
|
+
* status: TransactionStatus.COMPLETED,
|
|
12392
|
+
* include: ['recipient', 'business'],
|
|
12393
|
+
* page: 1,
|
|
12394
|
+
* limit: 50
|
|
11431
12395
|
* });
|
|
11432
12396
|
*
|
|
11433
|
-
*
|
|
11434
|
-
*
|
|
11435
|
-
* console.log(`Total spent: $${totalSpent.toFixed(2)}`);
|
|
11436
|
-
* console.log(`Total rewards earned: ${totalRewards} points`);
|
|
11437
|
-
* ```
|
|
11438
|
-
*
|
|
11439
|
-
* @example Recent Activity
|
|
11440
|
-
* ```typescript
|
|
11441
|
-
* const recentTransactions = await sdk.transactions.getUserTransactionHistory('ALL');
|
|
11442
|
-
*
|
|
11443
|
-
* // Filter to last 30 days
|
|
11444
|
-
* const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
|
|
11445
|
-
* const recentActivity = recentTransactions.filter(t =>
|
|
11446
|
-
* new Date(t.createdAt) > thirtyDaysAgo
|
|
11447
|
-
* );
|
|
11448
|
-
*
|
|
11449
|
-
* console.log(`Recent Activity (${recentActivity.length} transactions in last 30 days):`);
|
|
11450
|
-
*
|
|
11451
|
-
* // Group by type
|
|
11452
|
-
* const activityByType = recentActivity.reduce((acc, t) => {
|
|
11453
|
-
* acc[t.type] = (acc[t.type] || 0) + 1;
|
|
11454
|
-
* return acc;
|
|
11455
|
-
* }, {});
|
|
11456
|
-
*
|
|
11457
|
-
* Object.entries(activityByType).forEach(([type, count]) => {
|
|
11458
|
-
* console.log(`${type}: ${count} transactions`);
|
|
12397
|
+
* sent.data.forEach(tx => {
|
|
12398
|
+
* console.log(`Sent to: ${tx.included?.recipient?.displayName || tx.recipientAddress}`);
|
|
11459
12399
|
* });
|
|
11460
12400
|
* ```
|
|
11461
|
-
*/
|
|
11462
|
-
async getUserTransactionHistory(role, options) {
|
|
11463
|
-
return this.transactionService.getUserTransactionHistory(role, options);
|
|
11464
|
-
}
|
|
11465
|
-
/**
|
|
11466
|
-
* Admin: Get all tenant transactions
|
|
11467
|
-
*
|
|
11468
|
-
* Retrieves all transactions across the entire tenant/organization for
|
|
11469
|
-
* comprehensive reporting and analysis. This operation requires administrator
|
|
11470
|
-
* privileges and provides system-wide transaction visibility.
|
|
11471
|
-
*
|
|
11472
|
-
* @param limit - Maximum number of transactions to return (default: 1000)
|
|
11473
|
-
* @returns Promise resolving to array of all tenant transactions
|
|
11474
|
-
* @throws {PersApiError} When not authenticated as administrator
|
|
11475
12401
|
*
|
|
11476
|
-
* @example
|
|
12402
|
+
* @example Filter by Trigger Process (Campaign/Redemption)
|
|
11477
12403
|
* ```typescript
|
|
11478
|
-
* //
|
|
11479
|
-
* const
|
|
11480
|
-
*
|
|
11481
|
-
*
|
|
11482
|
-
* console.log(`Total transactions: ${allTransactions.length}`);
|
|
11483
|
-
*
|
|
11484
|
-
* // Analyze by status
|
|
11485
|
-
* const statusCounts = allTransactions.reduce((acc, t) => {
|
|
11486
|
-
* acc[t.status] = (acc[t.status] || 0) + 1;
|
|
11487
|
-
* return acc;
|
|
11488
|
-
* }, {});
|
|
11489
|
-
*
|
|
11490
|
-
* console.log('\nBy status:');
|
|
11491
|
-
* Object.entries(statusCounts).forEach(([status, count]) => {
|
|
11492
|
-
* console.log(`${status}: ${count} transactions`);
|
|
12404
|
+
* // Get all transactions triggered by a specific campaign claim
|
|
12405
|
+
* const claimTxs = await sdk.transactions.getUserTransactionHistory({
|
|
12406
|
+
* triggerProcessId: 'claim-abc123',
|
|
12407
|
+
* include: ['sender', 'recipient', 'business']
|
|
11493
12408
|
* });
|
|
11494
12409
|
*
|
|
11495
|
-
*
|
|
11496
|
-
*
|
|
11497
|
-
*
|
|
11498
|
-
*
|
|
11499
|
-
*
|
|
11500
|
-
*
|
|
11501
|
-
* console.log('\nBy type:');
|
|
11502
|
-
* Object.entries(typeCounts).forEach(([type, count]) => {
|
|
11503
|
-
* console.log(`${type}: ${count} transactions`);
|
|
12410
|
+
* claimTxs.data.forEach(tx => {
|
|
12411
|
+
* console.log('Transaction from claim:', tx.id);
|
|
12412
|
+
* if (tx.included?.engagedBusiness) {
|
|
12413
|
+
* console.log('Business:', tx.included.engagedBusiness.displayName);
|
|
12414
|
+
* }
|
|
11504
12415
|
* });
|
|
11505
|
-
*
|
|
11506
|
-
* // Calculate volume metrics
|
|
11507
|
-
* const totalVolume = allTransactions.reduce((sum, t) =>
|
|
11508
|
-
* sum + (t.amount || 0), 0
|
|
11509
|
-
* );
|
|
11510
|
-
*
|
|
11511
|
-
* const avgTransactionSize = totalVolume / allTransactions.length;
|
|
11512
|
-
*
|
|
11513
|
-
* console.log('\nVolume metrics:');
|
|
11514
|
-
* console.log(`Total volume: $${totalVolume.toFixed(2)}`);
|
|
11515
|
-
* console.log(`Average transaction: $${avgTransactionSize.toFixed(2)}`);
|
|
11516
|
-
*
|
|
11517
|
-
* // Recent activity analysis
|
|
11518
|
-
* const last24Hours = allTransactions.filter(t =>
|
|
11519
|
-
* new Date(t.createdAt) > new Date(Date.now() - 24 * 60 * 60 * 1000)
|
|
11520
|
-
* );
|
|
11521
|
-
*
|
|
11522
|
-
* console.log(`\n⏰ Last 24 hours: ${last24Hours.length} transactions`);
|
|
11523
12416
|
* ```
|
|
11524
12417
|
*/
|
|
11525
|
-
async
|
|
11526
|
-
return this.transactionService.
|
|
12418
|
+
async getUserTransactionHistory(options) {
|
|
12419
|
+
return this.transactionService.getUserTransactionHistory(options);
|
|
11527
12420
|
}
|
|
11528
12421
|
/**
|
|
11529
12422
|
* Admin: Get paginated transactions
|
|
@@ -11532,7 +12425,7 @@ class TransactionManager {
|
|
|
11532
12425
|
* handling. This operation requires administrator privileges and is used for
|
|
11533
12426
|
* detailed transaction analysis and reporting interfaces.
|
|
11534
12427
|
*
|
|
11535
|
-
* @param
|
|
12428
|
+
* @param options - Pagination, filtering parameters, and optional include relations
|
|
11536
12429
|
* @returns Promise resolving to paginated transaction results with metadata
|
|
11537
12430
|
* @throws {PersApiError} When not authenticated as administrator
|
|
11538
12431
|
*
|
|
@@ -11587,9 +12480,24 @@ class TransactionManager {
|
|
|
11587
12480
|
* console.log(`$${transaction.amount} - ${transaction.business?.displayName}`);
|
|
11588
12481
|
* });
|
|
11589
12482
|
* ```
|
|
12483
|
+
*
|
|
12484
|
+
* @example With Included Relations
|
|
12485
|
+
* ```typescript
|
|
12486
|
+
* // Include sender and recipient entities
|
|
12487
|
+
* const result = await sdk.transactions.getPaginatedTransactions({
|
|
12488
|
+
* page: 1,
|
|
12489
|
+
* limit: 50,
|
|
12490
|
+
* include: ['sender', 'recipient', 'business']
|
|
12491
|
+
* });
|
|
12492
|
+
*
|
|
12493
|
+
* result.data.forEach(tx => {
|
|
12494
|
+
* if (tx.included?.sender) console.log('From:', tx.included.sender);
|
|
12495
|
+
* if (tx.included?.recipient) console.log('To:', tx.included.recipient);
|
|
12496
|
+
* });
|
|
12497
|
+
* ```
|
|
11590
12498
|
*/
|
|
11591
|
-
async getPaginatedTransactions(
|
|
11592
|
-
return this.transactionService.getPaginatedTransactions(
|
|
12499
|
+
async getPaginatedTransactions(options) {
|
|
12500
|
+
return this.transactionService.getPaginatedTransactions(options);
|
|
11593
12501
|
}
|
|
11594
12502
|
/**
|
|
11595
12503
|
* Admin: Export transactions as CSV
|
|
@@ -13252,6 +14160,179 @@ class AnalyticsManager {
|
|
|
13252
14160
|
async getTransactionAnalytics(request) {
|
|
13253
14161
|
return this.analyticsService.getTransactionAnalytics(request);
|
|
13254
14162
|
}
|
|
14163
|
+
/**
|
|
14164
|
+
* Get campaign claim analytics with aggregation
|
|
14165
|
+
*
|
|
14166
|
+
* Retrieves aggregated analytics for campaign claims with flexible grouping,
|
|
14167
|
+
* filtering, and metric selection. Provides insights into campaign performance,
|
|
14168
|
+
* claim patterns, and user engagement across the loyalty ecosystem.
|
|
14169
|
+
*
|
|
14170
|
+
* @param request - Analytics request with filters, groupBy, and metrics
|
|
14171
|
+
* @returns Promise resolving to campaign claim analytics data
|
|
14172
|
+
*
|
|
14173
|
+
* @example Claims per campaign
|
|
14174
|
+
* ```typescript
|
|
14175
|
+
* const analytics = await sdk.analytics.getCampaignClaimAnalytics({
|
|
14176
|
+
* filters: { status: 'COMPLETED' },
|
|
14177
|
+
* groupBy: ['campaignId'],
|
|
14178
|
+
* metrics: ['count'],
|
|
14179
|
+
* sortBy: 'count',
|
|
14180
|
+
* sortOrder: 'DESC',
|
|
14181
|
+
* limit: 10
|
|
14182
|
+
* });
|
|
14183
|
+
*
|
|
14184
|
+
* console.log('Top campaigns:', analytics.results);
|
|
14185
|
+
* ```
|
|
14186
|
+
*/
|
|
14187
|
+
async getCampaignClaimAnalytics(request) {
|
|
14188
|
+
return this.analyticsService.getCampaignClaimAnalytics(request);
|
|
14189
|
+
}
|
|
14190
|
+
/**
|
|
14191
|
+
* Get user analytics with engagement metrics
|
|
14192
|
+
*
|
|
14193
|
+
* Retrieves aggregated user statistics including engagement rate, active users,
|
|
14194
|
+
* transaction metrics, and per-active-user averages. Provides comprehensive
|
|
14195
|
+
* insights into user behavior, engagement patterns, and platform adoption metrics.
|
|
14196
|
+
*
|
|
14197
|
+
* NEW: Added per-active-user metrics (averageTransactionsPerActiveUser, etc.) which
|
|
14198
|
+
* show concentrated engagement among active users - more useful than diluted all-user averages.
|
|
14199
|
+
*
|
|
14200
|
+
* Request structure matches TransactionAnalytics and CampaignClaimAnalytics:
|
|
14201
|
+
* - Use filters object for business-specific scoping
|
|
14202
|
+
* - startDate/endDate at root level for date range filtering
|
|
14203
|
+
*
|
|
14204
|
+
* @param request - Analytics request with optional filters and date range
|
|
14205
|
+
* @returns Promise resolving to user analytics data with per-user and per-active-user metrics
|
|
14206
|
+
*
|
|
14207
|
+
* @example Basic user analytics (compare per-user vs per-active-user)
|
|
14208
|
+
* ```typescript
|
|
14209
|
+
* const analytics = await sdk.analytics.getUserAnalytics({});
|
|
14210
|
+
* console.log(`Total users: ${analytics.totalUsers}`);
|
|
14211
|
+
* console.log(`Active users: ${analytics.activeUsers} (${analytics.engagementRate.toFixed(1)}%)`);
|
|
14212
|
+
*
|
|
14213
|
+
* // Per-user averages (includes inactive users - lower numbers)
|
|
14214
|
+
* console.log(`\\nPer-User Averages (all users):`);
|
|
14215
|
+
* console.log(` Transactions: ${analytics.averageTransactionsPerUser.toFixed(2)}`);
|
|
14216
|
+
* console.log(` Claims: ${analytics.averageClaimsPerUser.toFixed(2)}`);
|
|
14217
|
+
* console.log(` Redemptions: ${analytics.averageRedemptionsPerUser.toFixed(2)}`);
|
|
14218
|
+
*
|
|
14219
|
+
* // Per-active-user averages (only engaged users - higher, more meaningful numbers)
|
|
14220
|
+
* console.log(`\\nPer-Active-User Averages (engaged users only):`);
|
|
14221
|
+
* console.log(` Transactions: ${analytics.averageTransactionsPerActiveUser.toFixed(2)}`);
|
|
14222
|
+
* console.log(` Claims: ${analytics.averageClaimsPerActiveUser.toFixed(2)}`);
|
|
14223
|
+
* console.log(` Redemptions: ${analytics.averageRedemptionsPerActiveUser.toFixed(2)}`);
|
|
14224
|
+
* ```
|
|
14225
|
+
*
|
|
14226
|
+
* @example Monthly user analytics with date range
|
|
14227
|
+
* ```typescript
|
|
14228
|
+
* const analytics = await sdk.analytics.getUserAnalytics({
|
|
14229
|
+
* startDate: new Date('2026-02-01'),
|
|
14230
|
+
* endDate: new Date('2026-02-28')
|
|
14231
|
+
* });
|
|
14232
|
+
*
|
|
14233
|
+
* console.log('February 2026 User Metrics:');
|
|
14234
|
+
* console.log(`Total users: ${analytics.totalUsers}`);
|
|
14235
|
+
* console.log(`Active users: ${analytics.activeUsers}`);
|
|
14236
|
+
* console.log(`New users: ${analytics.newUsers}`);
|
|
14237
|
+
* console.log(`Engagement rate: ${analytics.engagementRate.toFixed(2)}%`);
|
|
14238
|
+
* console.log(`Total transaction volume: $${analytics.totalTransactionVolume.toLocaleString()}`);
|
|
14239
|
+
* console.log(`Avg transaction amount: $${analytics.averageTransactionAmount.toFixed(2)}`);
|
|
14240
|
+
* console.log(`\\nFilters applied: ${analytics.metadata.dateRange?.startDate} to ${analytics.metadata.dateRange?.endDate}`);
|
|
14241
|
+
* ```
|
|
14242
|
+
*
|
|
14243
|
+
* @example Business-specific user analytics with filters
|
|
14244
|
+
* ```typescript
|
|
14245
|
+
* const analytics = await sdk.analytics.getUserAnalytics({
|
|
14246
|
+
* filters: { businessId: 'business-123' },
|
|
14247
|
+
* startDate: new Date('2026-01-01'),
|
|
14248
|
+
* endDate: new Date('2026-12-31')
|
|
14249
|
+
* });
|
|
14250
|
+
*
|
|
14251
|
+
* console.log(`Business customer metrics for 2026:`);
|
|
14252
|
+
* console.log(`Active customers: ${analytics.activeUsers} / ${analytics.totalUsers}`);
|
|
14253
|
+
* console.log(`Customer engagement: ${analytics.engagementRate.toFixed(1)}%`);
|
|
14254
|
+
* console.log(`Avg spend per customer: $${analytics.averageTransactionAmount.toFixed(2)}`);
|
|
14255
|
+
* console.log(`Avg spend per active customer: $${(analytics.totalTransactionVolume / analytics.activeUsers).toFixed(2)}`);
|
|
14256
|
+
* console.log(`Avg claims per active customer: ${analytics.averageClaimsPerActiveUser.toFixed(2)}`);
|
|
14257
|
+
* ```
|
|
14258
|
+
*/
|
|
14259
|
+
async getUserAnalytics(request = {}) {
|
|
14260
|
+
return this.analyticsService.getUserAnalytics(request);
|
|
14261
|
+
}
|
|
14262
|
+
/**
|
|
14263
|
+
* Get user transaction ranking with enriched user data
|
|
14264
|
+
*
|
|
14265
|
+
* Retrieves ranked list of users with full user details (email, externalUserId)
|
|
14266
|
+
* and transaction metrics. Data enrichment happens via efficient SQL JOINs + UNION
|
|
14267
|
+
* (handles legacy transactions). Ideal for leaderboards, engagement analysis, and
|
|
14268
|
+
* identifying power users for targeted campaigns.
|
|
14269
|
+
*
|
|
14270
|
+
* Use Cases:
|
|
14271
|
+
* - Admin leaderboards showing top users by activity
|
|
14272
|
+
* - User engagement analysis with full user context
|
|
14273
|
+
* - Identifying power users for campaigns
|
|
14274
|
+
* - Customer segmentation by transaction behavior
|
|
14275
|
+
*
|
|
14276
|
+
* @param request - Ranking request with filters, sorting, and limit
|
|
14277
|
+
* @returns Promise resolving to ranked user list with transaction metrics
|
|
14278
|
+
*
|
|
14279
|
+
* @example Top 50 users by transaction count
|
|
14280
|
+
* ```typescript
|
|
14281
|
+
* const ranking = await sdk.analytics.getUserRanking({
|
|
14282
|
+
* sortBy: 'totalTransactions',
|
|
14283
|
+
* sortOrder: 'DESC',
|
|
14284
|
+
* limit: 50
|
|
14285
|
+
* });
|
|
14286
|
+
*
|
|
14287
|
+
* console.log(`Top ${ranking.totalUsers} users:`);
|
|
14288
|
+
* ranking.results.forEach((user, index) => {
|
|
14289
|
+
* console.log(`#${index + 1}: ${user.email || user.externalUserId}`);
|
|
14290
|
+
* console.log(` Transactions: ${user.totalTransactions}`);
|
|
14291
|
+
* console.log(` Token spent: ${user.tokenSpent}`);
|
|
14292
|
+
* });
|
|
14293
|
+
* ```
|
|
14294
|
+
*
|
|
14295
|
+
* @example Top users by STAMP spending
|
|
14296
|
+
* ```typescript
|
|
14297
|
+
* const ranking = await sdk.analytics.getUserRanking({
|
|
14298
|
+
* filters: { tokenType: 'STAMP' },
|
|
14299
|
+
* sortBy: 'tokenSpent',
|
|
14300
|
+
* sortOrder: 'DESC',
|
|
14301
|
+
* limit: 20
|
|
14302
|
+
* });
|
|
14303
|
+
*
|
|
14304
|
+
* console.log('Top 20 STAMP spenders:');
|
|
14305
|
+
* ranking.results.forEach((user, index) => {
|
|
14306
|
+
* const identifier = user.email || user.externalUserId || user.userId;
|
|
14307
|
+
* console.log(`${index + 1}. ${identifier} - ${user.tokenSpent} STAMP`);
|
|
14308
|
+
* });
|
|
14309
|
+
* ```
|
|
14310
|
+
*/
|
|
14311
|
+
async getUserRanking(request = {}) {
|
|
14312
|
+
return this.analyticsService.getUserRanking(request);
|
|
14313
|
+
}
|
|
14314
|
+
/**
|
|
14315
|
+
* Get business transaction ranking with enriched business data
|
|
14316
|
+
*
|
|
14317
|
+
* Returns ranked list of businesses with full business details and transaction metrics.
|
|
14318
|
+
*
|
|
14319
|
+
* @param request - Ranking request with filters, sorting, and limit
|
|
14320
|
+
* @returns Promise resolving to ranked business list
|
|
14321
|
+
*/
|
|
14322
|
+
async getBusinessRanking(request = {}) {
|
|
14323
|
+
return this.analyticsService.getBusinessRanking(request);
|
|
14324
|
+
}
|
|
14325
|
+
/**
|
|
14326
|
+
* Get monthly user retention analytics
|
|
14327
|
+
*
|
|
14328
|
+
* Returns monthly retention data with user metrics and retention rates.
|
|
14329
|
+
*
|
|
14330
|
+
* @param request - Retention request with monthsBack and filters
|
|
14331
|
+
* @returns Promise resolving to monthly retention data
|
|
14332
|
+
*/
|
|
14333
|
+
async getRetentionAnalytics(request = {}) {
|
|
14334
|
+
return this.analyticsService.getRetentionAnalytics(request);
|
|
14335
|
+
}
|
|
13255
14336
|
/**
|
|
13256
14337
|
* Get the full analytics service for advanced operations
|
|
13257
14338
|
*
|
|
@@ -13346,6 +14427,222 @@ class DonationManager {
|
|
|
13346
14427
|
}
|
|
13347
14428
|
}
|
|
13348
14429
|
|
|
14430
|
+
/**
|
|
14431
|
+
* TriggerSource Manager - Clean, high-level interface for trigger source operations
|
|
14432
|
+
*
|
|
14433
|
+
* Manages trigger sources which are physical or digital activation points for campaigns:
|
|
14434
|
+
* - QR_CODE: Scannable QR codes
|
|
14435
|
+
* - NFC_TAG: NFC tap points
|
|
14436
|
+
* - GPS_GEOFENCE: Location-based triggers
|
|
14437
|
+
* - API_WEBHOOK: External system integration
|
|
14438
|
+
* - TRANSACTION: Purchase/payment based triggers
|
|
14439
|
+
*
|
|
14440
|
+
* Trigger sources are independent entities that can be created, managed, and then
|
|
14441
|
+
* assigned to campaigns. This separation allows reuse and flexible campaign configuration.
|
|
14442
|
+
*
|
|
14443
|
+
* @group Managers
|
|
14444
|
+
* @category TriggerSource Management
|
|
14445
|
+
*
|
|
14446
|
+
* @example Basic TriggerSource Operations
|
|
14447
|
+
* ```typescript
|
|
14448
|
+
* // Get all QR code trigger sources
|
|
14449
|
+
* const qrSources = await sdk.triggerSources.getAll({ type: 'QR_CODE' });
|
|
14450
|
+
*
|
|
14451
|
+
* // Create a new QR code trigger source
|
|
14452
|
+
* const source = await sdk.triggerSources.create({
|
|
14453
|
+
* type: 'QR_CODE',
|
|
14454
|
+
* name: 'Store Entrance QR',
|
|
14455
|
+
* businessId: 'business-123'
|
|
14456
|
+
* });
|
|
14457
|
+
*
|
|
14458
|
+
* // Assign to campaign (via CampaignManager)
|
|
14459
|
+
* await sdk.campaigns.assignTriggerSource('campaign-456', source.id);
|
|
14460
|
+
* ```
|
|
14461
|
+
*/
|
|
14462
|
+
class TriggerSourceManager {
|
|
14463
|
+
constructor(apiClient, events) {
|
|
14464
|
+
this.apiClient = apiClient;
|
|
14465
|
+
this.events = events;
|
|
14466
|
+
const triggerSourceApi = new TriggerSourceApi(apiClient);
|
|
14467
|
+
this.triggerSourceService = new TriggerSourceService(triggerSourceApi);
|
|
14468
|
+
}
|
|
14469
|
+
/**
|
|
14470
|
+
* Get trigger sources with optional filters and pagination
|
|
14471
|
+
*
|
|
14472
|
+
* Retrieves trigger sources (QR codes, NFC tags, GPS geofences, webhooks, etc.)
|
|
14473
|
+
* that can be used to activate campaigns. Supports filtering by type, business,
|
|
14474
|
+
* campaign association, and active status.
|
|
14475
|
+
*
|
|
14476
|
+
* @param options - Filter and pagination options
|
|
14477
|
+
* @returns Promise resolving to paginated trigger sources
|
|
14478
|
+
*
|
|
14479
|
+
* @example
|
|
14480
|
+
* ```typescript
|
|
14481
|
+
* // Get all QR code trigger sources
|
|
14482
|
+
* const qrSources = await sdk.triggerSources.getAll({ type: 'QR_CODE' });
|
|
14483
|
+
*
|
|
14484
|
+
* // Get trigger sources for a specific business
|
|
14485
|
+
* const businessSources = await sdk.triggerSources.getAll({
|
|
14486
|
+
* businessId: 'business-123',
|
|
14487
|
+
* active: true,
|
|
14488
|
+
* page: 1,
|
|
14489
|
+
* limit: 20
|
|
14490
|
+
* });
|
|
14491
|
+
*
|
|
14492
|
+
* // Get trigger sources assigned to a campaign
|
|
14493
|
+
* const campaignSources = await sdk.triggerSources.getAll({
|
|
14494
|
+
* campaignId: 'campaign-456'
|
|
14495
|
+
* });
|
|
14496
|
+
* ```
|
|
14497
|
+
*/
|
|
14498
|
+
async getAll(options) {
|
|
14499
|
+
return this.triggerSourceService.getTriggerSources(options);
|
|
14500
|
+
}
|
|
14501
|
+
/**
|
|
14502
|
+
* Get trigger source by ID
|
|
14503
|
+
*
|
|
14504
|
+
* Retrieves detailed information for a specific trigger source including
|
|
14505
|
+
* its type, location, metadata, and usage analytics.
|
|
14506
|
+
*
|
|
14507
|
+
* @param triggerSourceId - UUID of the trigger source
|
|
14508
|
+
* @returns Promise resolving to trigger source details
|
|
14509
|
+
* @throws {PersApiError} When trigger source with specified ID is not found
|
|
14510
|
+
*
|
|
14511
|
+
* @example
|
|
14512
|
+
* ```typescript
|
|
14513
|
+
* const source = await sdk.triggerSources.getById('source-123');
|
|
14514
|
+
*
|
|
14515
|
+
* console.log('Trigger Source:', source.name);
|
|
14516
|
+
* console.log('Type:', source.type);
|
|
14517
|
+
* console.log('Active:', source.isActive);
|
|
14518
|
+
*
|
|
14519
|
+
* if (source.coordsLatitude && source.coordsLongitude) {
|
|
14520
|
+
* console.log('Location:', source.coordsLatitude, source.coordsLongitude);
|
|
14521
|
+
* }
|
|
14522
|
+
* ```
|
|
14523
|
+
*/
|
|
14524
|
+
async getById(triggerSourceId) {
|
|
14525
|
+
return this.triggerSourceService.getTriggerSourceById(triggerSourceId);
|
|
14526
|
+
}
|
|
14527
|
+
/**
|
|
14528
|
+
* Admin: Create a new trigger source
|
|
14529
|
+
*
|
|
14530
|
+
* Creates a new trigger source (QR code, NFC tag, GPS geofence, webhook, or
|
|
14531
|
+
* transaction-based trigger) that can be assigned to campaigns. Requires
|
|
14532
|
+
* administrator privileges.
|
|
14533
|
+
*
|
|
14534
|
+
* @param triggerSource - Trigger source creation data
|
|
14535
|
+
* @returns Promise resolving to created trigger source
|
|
14536
|
+
* @throws {PersApiError} When not authenticated as admin or validation fails
|
|
14537
|
+
*
|
|
14538
|
+
* @example
|
|
14539
|
+
* ```typescript
|
|
14540
|
+
* // Create a QR code trigger source
|
|
14541
|
+
* const qrSource = await sdk.triggerSources.create({
|
|
14542
|
+
* type: 'QR_CODE',
|
|
14543
|
+
* name: 'Store Entrance QR',
|
|
14544
|
+
* description: 'QR code at main entrance',
|
|
14545
|
+
* businessId: 'business-123',
|
|
14546
|
+
* coordsLatitude: 47.6062,
|
|
14547
|
+
* coordsLongitude: -122.3321
|
|
14548
|
+
* });
|
|
14549
|
+
*
|
|
14550
|
+
* // Create an NFC tag trigger source
|
|
14551
|
+
* const nfcSource = await sdk.triggerSources.create({
|
|
14552
|
+
* type: 'NFC_TAG',
|
|
14553
|
+
* name: 'Product Display NFC',
|
|
14554
|
+
* metadata: { productId: 'SKU-12345' }
|
|
14555
|
+
* });
|
|
14556
|
+
*
|
|
14557
|
+
* // Create a GPS geofence trigger source
|
|
14558
|
+
* const geoSource = await sdk.triggerSources.create({
|
|
14559
|
+
* type: 'GPS_GEOFENCE',
|
|
14560
|
+
* name: 'Store Area',
|
|
14561
|
+
* coordsLatitude: 47.6062,
|
|
14562
|
+
* coordsLongitude: -122.3321,
|
|
14563
|
+
* metadata: { radiusMeters: 100 }
|
|
14564
|
+
* });
|
|
14565
|
+
* ```
|
|
14566
|
+
*/
|
|
14567
|
+
async create(triggerSource) {
|
|
14568
|
+
const result = await this.triggerSourceService.createTriggerSource(triggerSource);
|
|
14569
|
+
this.events?.emitSuccess({
|
|
14570
|
+
domain: 'trigger-source',
|
|
14571
|
+
type: 'TRIGGER_SOURCE_CREATED',
|
|
14572
|
+
userMessage: 'Trigger source created successfully',
|
|
14573
|
+
details: { triggerSourceId: result.id, type: result.type }
|
|
14574
|
+
});
|
|
14575
|
+
return result;
|
|
14576
|
+
}
|
|
14577
|
+
/**
|
|
14578
|
+
* Admin: Update a trigger source
|
|
14579
|
+
*
|
|
14580
|
+
* Updates an existing trigger source's configuration. All fields are optional;
|
|
14581
|
+
* only provided fields will be updated. Requires administrator privileges.
|
|
14582
|
+
*
|
|
14583
|
+
* @param triggerSourceId - UUID of the trigger source to update
|
|
14584
|
+
* @param triggerSource - Updated trigger source data (partial)
|
|
14585
|
+
* @returns Promise resolving to updated trigger source
|
|
14586
|
+
* @throws {PersApiError} When not authenticated as admin or trigger source not found
|
|
14587
|
+
*
|
|
14588
|
+
* @example
|
|
14589
|
+
* ```typescript
|
|
14590
|
+
* // Update trigger source name and location
|
|
14591
|
+
* const updated = await sdk.triggerSources.update('source-123', {
|
|
14592
|
+
* name: 'Updated Store Entrance QR',
|
|
14593
|
+
* description: 'New description',
|
|
14594
|
+
* coordsLatitude: 47.6063,
|
|
14595
|
+
* coordsLongitude: -122.3322
|
|
14596
|
+
* });
|
|
14597
|
+
* ```
|
|
14598
|
+
*/
|
|
14599
|
+
async update(triggerSourceId, triggerSource) {
|
|
14600
|
+
const result = await this.triggerSourceService.updateTriggerSource(triggerSourceId, triggerSource);
|
|
14601
|
+
this.events?.emitSuccess({
|
|
14602
|
+
domain: 'trigger-source',
|
|
14603
|
+
type: 'TRIGGER_SOURCE_UPDATED',
|
|
14604
|
+
userMessage: 'Trigger source updated successfully',
|
|
14605
|
+
details: { triggerSourceId }
|
|
14606
|
+
});
|
|
14607
|
+
return result;
|
|
14608
|
+
}
|
|
14609
|
+
/**
|
|
14610
|
+
* Admin: Delete a trigger source
|
|
14611
|
+
*
|
|
14612
|
+
* Soft deletes a trigger source, making it inactive. The trigger source will
|
|
14613
|
+
* be removed from any campaigns it was assigned to. Requires administrator
|
|
14614
|
+
* privileges.
|
|
14615
|
+
*
|
|
14616
|
+
* @param triggerSourceId - UUID of the trigger source to delete
|
|
14617
|
+
* @returns Promise resolving to success status
|
|
14618
|
+
* @throws {PersApiError} When not authenticated as admin or trigger source not found
|
|
14619
|
+
*
|
|
14620
|
+
* @example
|
|
14621
|
+
* ```typescript
|
|
14622
|
+
* const success = await sdk.triggerSources.delete('source-123');
|
|
14623
|
+
* console.log('Trigger source deleted:', success);
|
|
14624
|
+
* ```
|
|
14625
|
+
*/
|
|
14626
|
+
async delete(triggerSourceId) {
|
|
14627
|
+
const result = await this.triggerSourceService.deleteTriggerSource(triggerSourceId);
|
|
14628
|
+
this.events?.emitSuccess({
|
|
14629
|
+
domain: 'trigger-source',
|
|
14630
|
+
type: 'TRIGGER_SOURCE_DELETED',
|
|
14631
|
+
userMessage: 'Trigger source deleted successfully',
|
|
14632
|
+
details: { triggerSourceId }
|
|
14633
|
+
});
|
|
14634
|
+
return result;
|
|
14635
|
+
}
|
|
14636
|
+
/**
|
|
14637
|
+
* Get the full trigger source service for advanced operations
|
|
14638
|
+
*
|
|
14639
|
+
* @returns TriggerSourceService instance with full API access
|
|
14640
|
+
*/
|
|
14641
|
+
getTriggerSourceService() {
|
|
14642
|
+
return this.triggerSourceService;
|
|
14643
|
+
}
|
|
14644
|
+
}
|
|
14645
|
+
|
|
13349
14646
|
/**
|
|
13350
14647
|
* @fileoverview PERS SDK - Platform-agnostic TypeScript SDK with High-Level Managers
|
|
13351
14648
|
*
|
|
@@ -13832,6 +15129,40 @@ class PersSDK {
|
|
|
13832
15129
|
}
|
|
13833
15130
|
return this._donations;
|
|
13834
15131
|
}
|
|
15132
|
+
/**
|
|
15133
|
+
* TriggerSource manager - High-level trigger source operations (Admin Only)
|
|
15134
|
+
*
|
|
15135
|
+
* Provides CRUD operations for managing trigger sources (QR codes, NFC tags,
|
|
15136
|
+
* GPS geofences, API webhooks). TriggerSources are standalone entities that
|
|
15137
|
+
* can be assigned to campaigns via the campaigns manager.
|
|
15138
|
+
*
|
|
15139
|
+
* @returns TriggerSourceManager instance
|
|
15140
|
+
*
|
|
15141
|
+
* @example TriggerSource Operations
|
|
15142
|
+
* ```typescript
|
|
15143
|
+
* // Create a QR code trigger source
|
|
15144
|
+
* const qrSource = await sdk.triggerSources.create({
|
|
15145
|
+
* name: 'Store Entrance QR',
|
|
15146
|
+
* type: 'QR_CODE',
|
|
15147
|
+
* description: 'QR code at main entrance'
|
|
15148
|
+
* });
|
|
15149
|
+
*
|
|
15150
|
+
* // Get all trigger sources
|
|
15151
|
+
* const sources = await sdk.triggerSources.getAll();
|
|
15152
|
+
*
|
|
15153
|
+
* // Update trigger source
|
|
15154
|
+
* await sdk.triggerSources.update(sourceId, { name: 'Updated Name' });
|
|
15155
|
+
*
|
|
15156
|
+
* // Assign to campaign (via campaigns manager)
|
|
15157
|
+
* await sdk.campaigns.assignTriggerSource(campaignId, qrSource.id);
|
|
15158
|
+
* ```
|
|
15159
|
+
*/
|
|
15160
|
+
get triggerSources() {
|
|
15161
|
+
if (!this._triggerSources) {
|
|
15162
|
+
this._triggerSources = new TriggerSourceManager(this.apiClient, this._events);
|
|
15163
|
+
}
|
|
15164
|
+
return this._triggerSources;
|
|
15165
|
+
}
|
|
13835
15166
|
/**
|
|
13836
15167
|
* Gets the API client for direct PERS API requests
|
|
13837
15168
|
*
|
|
@@ -37030,25 +38361,32 @@ const useTransactions = () => {
|
|
|
37030
38361
|
}
|
|
37031
38362
|
}, [sdk, isInitialized, signAndSubmitTransactionWithJWT, isSignerAvailable]);
|
|
37032
38363
|
/**
|
|
37033
|
-
* Retrieves a specific transaction by its ID
|
|
38364
|
+
* Retrieves a specific transaction by its ID with optional include relations
|
|
37034
38365
|
*
|
|
37035
38366
|
* @param transactionId - Unique identifier of the transaction
|
|
38367
|
+
* @param include - Optional relations to include (sender, recipient, business) for enriched entity data
|
|
37036
38368
|
* @returns Promise resolving to transaction data or null if not found
|
|
37037
38369
|
* @throws Error if SDK is not initialized
|
|
37038
38370
|
*
|
|
37039
38371
|
* @example
|
|
37040
38372
|
* ```typescript
|
|
37041
38373
|
* const { getTransactionById } = useTransactions();
|
|
38374
|
+
*
|
|
38375
|
+
* // Basic retrieval
|
|
37042
38376
|
* const transaction = await getTransactionById('txn-123');
|
|
37043
|
-
*
|
|
38377
|
+
*
|
|
38378
|
+
* // With enriched sender/recipient data
|
|
38379
|
+
* const enrichedTx = await getTransactionById('txn-123', ['sender', 'recipient', 'business']);
|
|
38380
|
+
* console.log('Sender:', enrichedTx?.included?.sender);
|
|
38381
|
+
* console.log('Business:', enrichedTx?.included?.engagedBusiness?.displayName);
|
|
37044
38382
|
* ```
|
|
37045
38383
|
*/
|
|
37046
|
-
const getTransactionById = react.useCallback(async (transactionId) => {
|
|
38384
|
+
const getTransactionById = react.useCallback(async (transactionId, include) => {
|
|
37047
38385
|
if (!isInitialized || !sdk) {
|
|
37048
38386
|
throw new Error('SDK not initialized. Call initialize() first.');
|
|
37049
38387
|
}
|
|
37050
38388
|
try {
|
|
37051
|
-
const result = await sdk.transactions.getTransactionById(transactionId);
|
|
38389
|
+
const result = await sdk.transactions.getTransactionById(transactionId, include);
|
|
37052
38390
|
return result;
|
|
37053
38391
|
}
|
|
37054
38392
|
catch (error) {
|
|
@@ -37057,25 +38395,48 @@ const useTransactions = () => {
|
|
|
37057
38395
|
}
|
|
37058
38396
|
}, [sdk, isInitialized]);
|
|
37059
38397
|
/**
|
|
37060
|
-
* Retrieves transaction history for the authenticated user
|
|
38398
|
+
* Retrieves transaction history for the authenticated user with comprehensive filtering
|
|
38399
|
+
*
|
|
38400
|
+
* Supports filtering by role, status, type, business, token, and more.
|
|
38401
|
+
* Optionally enrich with related entities (sender, recipient, business).
|
|
37061
38402
|
*
|
|
37062
|
-
* @param
|
|
37063
|
-
* @returns Promise resolving to array of user's transactions
|
|
38403
|
+
* @param options - Query options including filters, pagination, and include relations
|
|
38404
|
+
* @returns Promise resolving to paginated array of user's transactions
|
|
37064
38405
|
* @throws Error if SDK is not initialized
|
|
37065
38406
|
*
|
|
37066
38407
|
* @example
|
|
37067
38408
|
* ```typescript
|
|
37068
38409
|
* const { getUserTransactionHistory } = useTransactions();
|
|
37069
|
-
*
|
|
37070
|
-
*
|
|
38410
|
+
*
|
|
38411
|
+
* // Simple: Get all transactions
|
|
38412
|
+
* const allTransactions = await getUserTransactionHistory();
|
|
38413
|
+
*
|
|
38414
|
+
* // Filter by role (legacy support)
|
|
38415
|
+
* const sentTransactions = await getUserTransactionHistory({ role: 'SENDER' });
|
|
38416
|
+
*
|
|
38417
|
+
* // Advanced filtering with include relations
|
|
38418
|
+
* const filtered = await getUserTransactionHistory({
|
|
38419
|
+
* role: 'SENDER',
|
|
38420
|
+
* status: 'COMPLETED',
|
|
38421
|
+
* engagedBusinessId: 'business-123',
|
|
38422
|
+
* include: ['recipient', 'business'],
|
|
38423
|
+
* page: 1,
|
|
38424
|
+
* limit: 20
|
|
38425
|
+
* });
|
|
38426
|
+
*
|
|
38427
|
+
* // Access enriched data
|
|
38428
|
+
* filtered.data.forEach(tx => {
|
|
38429
|
+
* console.log('Recipient:', tx.included?.recipient);
|
|
38430
|
+
* console.log('Business:', tx.included?.engagedBusiness?.displayName);
|
|
38431
|
+
* });
|
|
37071
38432
|
* ```
|
|
37072
38433
|
*/
|
|
37073
|
-
const getUserTransactionHistory = react.useCallback(async (
|
|
38434
|
+
const getUserTransactionHistory = react.useCallback(async (options) => {
|
|
37074
38435
|
if (!isInitialized || !sdk) {
|
|
37075
38436
|
throw new Error('SDK not initialized. Call initialize() first.');
|
|
37076
38437
|
}
|
|
37077
38438
|
try {
|
|
37078
|
-
const result = await sdk.transactions.getUserTransactionHistory(
|
|
38439
|
+
const result = await sdk.transactions.getUserTransactionHistory(options);
|
|
37079
38440
|
return result;
|
|
37080
38441
|
}
|
|
37081
38442
|
catch (error) {
|
|
@@ -37083,25 +38444,39 @@ const useTransactions = () => {
|
|
|
37083
38444
|
throw error;
|
|
37084
38445
|
}
|
|
37085
38446
|
}, [sdk, isInitialized]);
|
|
37086
|
-
|
|
37087
|
-
|
|
37088
|
-
|
|
37089
|
-
|
|
37090
|
-
|
|
37091
|
-
|
|
37092
|
-
|
|
37093
|
-
|
|
37094
|
-
|
|
37095
|
-
|
|
37096
|
-
|
|
37097
|
-
|
|
37098
|
-
|
|
37099
|
-
|
|
38447
|
+
/**
|
|
38448
|
+
* Admin: Get paginated transactions with optional include relations
|
|
38449
|
+
*
|
|
38450
|
+
* @param params - Pagination and filtering parameters
|
|
38451
|
+
* @param include - Optional relations to include for enriched entity data
|
|
38452
|
+
* @returns Promise resolving to paginated transaction results
|
|
38453
|
+
* @throws Error if SDK is not initialized
|
|
38454
|
+
*
|
|
38455
|
+
* @example
|
|
38456
|
+
* ```typescript
|
|
38457
|
+
* const { getPaginatedTransactions } = useTransactions();
|
|
38458
|
+
*
|
|
38459
|
+
* // Basic pagination
|
|
38460
|
+
* const result = await getPaginatedTransactions({ page: 1, limit: 50 });
|
|
38461
|
+
*
|
|
38462
|
+
* // With include relations
|
|
38463
|
+
* const enrichedResult = await getPaginatedTransactions(
|
|
38464
|
+
* { page: 1, limit: 50, sortBy: 'createdAt', sortOrder: 'DESC' },
|
|
38465
|
+
* include: ['sender', 'recipient', 'business']
|
|
38466
|
+
* });
|
|
38467
|
+
*
|
|
38468
|
+
* enrichedResult.data.forEach(tx => {
|
|
38469
|
+
* console.log('From:', tx.included?.sender);
|
|
38470
|
+
* console.log('To:', tx.included?.recipient);
|
|
38471
|
+
* });
|
|
38472
|
+
* ```
|
|
38473
|
+
*/
|
|
38474
|
+
const getPaginatedTransactions = react.useCallback(async (options) => {
|
|
37100
38475
|
if (!isInitialized || !sdk) {
|
|
37101
38476
|
throw new Error('SDK not initialized. Call initialize() first.');
|
|
37102
38477
|
}
|
|
37103
38478
|
try {
|
|
37104
|
-
const result = await sdk.transactions.getPaginatedTransactions(
|
|
38479
|
+
const result = await sdk.transactions.getPaginatedTransactions(options);
|
|
37105
38480
|
return result;
|
|
37106
38481
|
}
|
|
37107
38482
|
catch (error) {
|
|
@@ -37126,7 +38501,6 @@ const useTransactions = () => {
|
|
|
37126
38501
|
createTransaction,
|
|
37127
38502
|
getTransactionById,
|
|
37128
38503
|
getUserTransactionHistory,
|
|
37129
|
-
getTenantTransactions,
|
|
37130
38504
|
getPaginatedTransactions,
|
|
37131
38505
|
exportTransactionsCSV,
|
|
37132
38506
|
isAvailable: isInitialized && !!sdk?.transactions,
|
|
@@ -37359,12 +38733,26 @@ const useCampaigns = () => {
|
|
|
37359
38733
|
throw error;
|
|
37360
38734
|
}
|
|
37361
38735
|
}, [sdk, isInitialized]);
|
|
37362
|
-
|
|
38736
|
+
/**
|
|
38737
|
+
* Get campaign by ID with optional include relations
|
|
38738
|
+
*
|
|
38739
|
+
* @param campaignId - The campaign ID
|
|
38740
|
+
* @param include - Relations to include: 'triggerSources', 'businesses'
|
|
38741
|
+
* @returns Promise resolving to campaign data
|
|
38742
|
+
*
|
|
38743
|
+
* @example
|
|
38744
|
+
* ```typescript
|
|
38745
|
+
* // Get campaign with all related data
|
|
38746
|
+
* const campaign = await getCampaignById('campaign-123', ['triggerSources', 'businesses']);
|
|
38747
|
+
* console.log('Trigger sources:', campaign.included?.triggerSources);
|
|
38748
|
+
* ```
|
|
38749
|
+
*/
|
|
38750
|
+
const getCampaignById = react.useCallback(async (campaignId, include) => {
|
|
37363
38751
|
if (!isInitialized || !sdk) {
|
|
37364
38752
|
throw new Error('SDK not initialized. Call initialize() first.');
|
|
37365
38753
|
}
|
|
37366
38754
|
try {
|
|
37367
|
-
const result = await sdk.campaigns.getCampaignById(campaignId);
|
|
38755
|
+
const result = await sdk.campaigns.getCampaignById(campaignId, include);
|
|
37368
38756
|
return result;
|
|
37369
38757
|
}
|
|
37370
38758
|
catch (error) {
|
|
@@ -37388,7 +38776,25 @@ const useCampaigns = () => {
|
|
|
37388
38776
|
throw error;
|
|
37389
38777
|
}
|
|
37390
38778
|
}, [sdk, isInitialized, isAuthenticated]);
|
|
37391
|
-
|
|
38779
|
+
/**
|
|
38780
|
+
* Get user's campaign claims with optional pagination and include relations
|
|
38781
|
+
*
|
|
38782
|
+
* @param options - Optional options including pagination and include relations
|
|
38783
|
+
* @returns Promise resolving to paginated campaign claims
|
|
38784
|
+
*
|
|
38785
|
+
* @example
|
|
38786
|
+
* ```typescript
|
|
38787
|
+
* // Get user's claims with campaign details
|
|
38788
|
+
* const { data: claims } = await getUserClaims({ include: ['campaign', 'business'] });
|
|
38789
|
+
* claims.forEach(claim => {
|
|
38790
|
+
* console.log('Campaign:', claim.included?.campaign?.title);
|
|
38791
|
+
* });
|
|
38792
|
+
*
|
|
38793
|
+
* // With pagination
|
|
38794
|
+
* const { data } = await getUserClaims({ page: 1, limit: 10, include: ['campaign'] });
|
|
38795
|
+
* ```
|
|
38796
|
+
*/
|
|
38797
|
+
const getUserClaims = react.useCallback(async (options) => {
|
|
37392
38798
|
if (!isInitialized || !sdk) {
|
|
37393
38799
|
throw new Error('SDK not initialized. Call initialize() first.');
|
|
37394
38800
|
}
|
|
@@ -37397,7 +38803,7 @@ const useCampaigns = () => {
|
|
|
37397
38803
|
return { data: [], pagination: { page: 1, limit: 0, total: 0, pages: 0, hasNext: false, hasPrev: false } };
|
|
37398
38804
|
}
|
|
37399
38805
|
try {
|
|
37400
|
-
const result = await sdk.campaigns.getUserClaims();
|
|
38806
|
+
const result = await sdk.campaigns.getUserClaims(options);
|
|
37401
38807
|
return result;
|
|
37402
38808
|
}
|
|
37403
38809
|
catch (error) {
|
|
@@ -37432,12 +38838,28 @@ const useCampaigns = () => {
|
|
|
37432
38838
|
throw error;
|
|
37433
38839
|
}
|
|
37434
38840
|
}, [sdk, isInitialized]);
|
|
37435
|
-
|
|
38841
|
+
/**
|
|
38842
|
+
* Admin: Get campaign claims with optional filters and include relations
|
|
38843
|
+
*
|
|
38844
|
+
* @param filters - Optional filters for campaign, user, or business
|
|
38845
|
+
* @param include - Relations to include: 'campaign', 'user', 'business'
|
|
38846
|
+
* @returns Promise resolving to paginated campaign claims
|
|
38847
|
+
*
|
|
38848
|
+
* @example
|
|
38849
|
+
* ```typescript
|
|
38850
|
+
* // Get all claims with user details
|
|
38851
|
+
* const { data: claims } = await getCampaignClaims({}, ['user']);
|
|
38852
|
+
*
|
|
38853
|
+
* // Get claims for a specific campaign
|
|
38854
|
+
* const { data } = await getCampaignClaims({ campaignId: 'campaign-123' }, ['user', 'business']);
|
|
38855
|
+
* ```
|
|
38856
|
+
*/
|
|
38857
|
+
const getCampaignClaims = react.useCallback(async (filters, include) => {
|
|
37436
38858
|
if (!isInitialized || !sdk) {
|
|
37437
38859
|
throw new Error('SDK not initialized. Call initialize() first.');
|
|
37438
38860
|
}
|
|
37439
38861
|
try {
|
|
37440
|
-
const result = await sdk.campaigns.getCampaignClaims();
|
|
38862
|
+
const result = await sdk.campaigns.getCampaignClaims(filters, include);
|
|
37441
38863
|
return result;
|
|
37442
38864
|
}
|
|
37443
38865
|
catch (error) {
|
|
@@ -37445,12 +38867,19 @@ const useCampaigns = () => {
|
|
|
37445
38867
|
throw error;
|
|
37446
38868
|
}
|
|
37447
38869
|
}, [sdk, isInitialized]);
|
|
37448
|
-
|
|
38870
|
+
/**
|
|
38871
|
+
* Admin: Get campaign claims by user ID with optional include relations
|
|
38872
|
+
*
|
|
38873
|
+
* @param userId - The user ID
|
|
38874
|
+
* @param include - Relations to include: 'campaign', 'user', 'business'
|
|
38875
|
+
* @returns Promise resolving to paginated campaign claims
|
|
38876
|
+
*/
|
|
38877
|
+
const getCampaignClaimsByUserId = react.useCallback(async (userId, include) => {
|
|
37449
38878
|
if (!isInitialized || !sdk) {
|
|
37450
38879
|
throw new Error('SDK not initialized. Call initialize() first.');
|
|
37451
38880
|
}
|
|
37452
38881
|
try {
|
|
37453
|
-
const result = await sdk.campaigns.getCampaignClaimsByUserId(userId);
|
|
38882
|
+
const result = await sdk.campaigns.getCampaignClaimsByUserId(userId, undefined, include);
|
|
37454
38883
|
return result;
|
|
37455
38884
|
}
|
|
37456
38885
|
catch (error) {
|
|
@@ -37458,12 +38887,19 @@ const useCampaigns = () => {
|
|
|
37458
38887
|
throw error;
|
|
37459
38888
|
}
|
|
37460
38889
|
}, [sdk, isInitialized]);
|
|
37461
|
-
|
|
38890
|
+
/**
|
|
38891
|
+
* Admin: Get campaign claims by business ID with optional include relations
|
|
38892
|
+
*
|
|
38893
|
+
* @param businessId - The business ID
|
|
38894
|
+
* @param include - Relations to include: 'campaign', 'user', 'business'
|
|
38895
|
+
* @returns Promise resolving to paginated campaign claims
|
|
38896
|
+
*/
|
|
38897
|
+
const getCampaignClaimsByBusinessId = react.useCallback(async (businessId, include) => {
|
|
37462
38898
|
if (!isInitialized || !sdk) {
|
|
37463
38899
|
throw new Error('SDK not initialized. Call initialize() first.');
|
|
37464
38900
|
}
|
|
37465
38901
|
try {
|
|
37466
|
-
const result = await sdk.campaigns.getCampaignClaimsByBusinessId(businessId);
|
|
38902
|
+
const result = await sdk.campaigns.getCampaignClaimsByBusinessId(businessId, undefined, include);
|
|
37467
38903
|
return result;
|
|
37468
38904
|
}
|
|
37469
38905
|
catch (error) {
|
|
@@ -37471,6 +38907,76 @@ const useCampaigns = () => {
|
|
|
37471
38907
|
throw error;
|
|
37472
38908
|
}
|
|
37473
38909
|
}, [sdk, isInitialized]);
|
|
38910
|
+
// ==========================================
|
|
38911
|
+
// TRIGGER SOURCE ASSIGNMENT (Admin)
|
|
38912
|
+
// Note: TriggerSource CRUD is in useTriggerSources hook
|
|
38913
|
+
// ==========================================
|
|
38914
|
+
/**
|
|
38915
|
+
* Admin: Assign a trigger source to a campaign
|
|
38916
|
+
*
|
|
38917
|
+
* Associates a trigger source (QR code, NFC tag, etc.) with a campaign.
|
|
38918
|
+
* A campaign can have multiple trigger sources.
|
|
38919
|
+
*
|
|
38920
|
+
* Note: To create/update/delete trigger sources, use `useTriggerSources` hook.
|
|
38921
|
+
*
|
|
38922
|
+
* @param campaignId - Campaign UUID
|
|
38923
|
+
* @param triggerSourceId - Trigger source UUID
|
|
38924
|
+
* @returns Promise resolving to updated campaign
|
|
38925
|
+
*
|
|
38926
|
+
* @example
|
|
38927
|
+
* ```typescript
|
|
38928
|
+
* const { create } = useTriggerSources();
|
|
38929
|
+
* const { assignTriggerSource } = useCampaigns();
|
|
38930
|
+
*
|
|
38931
|
+
* // Create trigger source first
|
|
38932
|
+
* const source = await create({ type: 'QR_CODE', name: 'Store QR' });
|
|
38933
|
+
*
|
|
38934
|
+
* // Then assign to campaign
|
|
38935
|
+
* const updated = await assignTriggerSource('campaign-123', source.id);
|
|
38936
|
+
* ```
|
|
38937
|
+
*/
|
|
38938
|
+
const assignTriggerSource = react.useCallback(async (campaignId, triggerSourceId) => {
|
|
38939
|
+
if (!isInitialized || !sdk) {
|
|
38940
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
38941
|
+
}
|
|
38942
|
+
if (!isAuthenticated) {
|
|
38943
|
+
throw new Error('SDK not authenticated. assignTriggerSource requires admin authentication.');
|
|
38944
|
+
}
|
|
38945
|
+
try {
|
|
38946
|
+
const result = await sdk.campaigns.assignTriggerSource(campaignId, triggerSourceId);
|
|
38947
|
+
return result;
|
|
38948
|
+
}
|
|
38949
|
+
catch (error) {
|
|
38950
|
+
console.error('Failed to assign trigger source:', error);
|
|
38951
|
+
throw error;
|
|
38952
|
+
}
|
|
38953
|
+
}, [sdk, isInitialized, isAuthenticated]);
|
|
38954
|
+
/**
|
|
38955
|
+
* Admin: Remove a trigger source from a campaign
|
|
38956
|
+
*
|
|
38957
|
+
* Removes the association between a trigger source and a campaign.
|
|
38958
|
+
* The trigger source itself is not deleted.
|
|
38959
|
+
*
|
|
38960
|
+
* @param campaignId - Campaign UUID
|
|
38961
|
+
* @param triggerSourceId - Trigger source UUID
|
|
38962
|
+
* @returns Promise resolving to updated campaign
|
|
38963
|
+
*/
|
|
38964
|
+
const removeTriggerSource = react.useCallback(async (campaignId, triggerSourceId) => {
|
|
38965
|
+
if (!isInitialized || !sdk) {
|
|
38966
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
38967
|
+
}
|
|
38968
|
+
if (!isAuthenticated) {
|
|
38969
|
+
throw new Error('SDK not authenticated. removeTriggerSource requires admin authentication.');
|
|
38970
|
+
}
|
|
38971
|
+
try {
|
|
38972
|
+
const result = await sdk.campaigns.removeTriggerSource(campaignId, triggerSourceId);
|
|
38973
|
+
return result;
|
|
38974
|
+
}
|
|
38975
|
+
catch (error) {
|
|
38976
|
+
console.error('Failed to remove trigger source:', error);
|
|
38977
|
+
throw error;
|
|
38978
|
+
}
|
|
38979
|
+
}, [sdk, isInitialized, isAuthenticated]);
|
|
37474
38980
|
return {
|
|
37475
38981
|
getActiveCampaigns,
|
|
37476
38982
|
getCampaignById,
|
|
@@ -37481,6 +38987,8 @@ const useCampaigns = () => {
|
|
|
37481
38987
|
getCampaignClaims,
|
|
37482
38988
|
getCampaignClaimsByUserId,
|
|
37483
38989
|
getCampaignClaimsByBusinessId,
|
|
38990
|
+
assignTriggerSource,
|
|
38991
|
+
removeTriggerSource,
|
|
37484
38992
|
isAvailable: isInitialized && !!sdk?.campaigns,
|
|
37485
38993
|
};
|
|
37486
38994
|
};
|
|
@@ -37509,7 +39017,23 @@ const useRedemptions = () => {
|
|
|
37509
39017
|
throw error;
|
|
37510
39018
|
}
|
|
37511
39019
|
}, [sdk, isInitialized]);
|
|
37512
|
-
|
|
39020
|
+
/**
|
|
39021
|
+
* Get user's redemption history with optional include relations
|
|
39022
|
+
*
|
|
39023
|
+
* @param include - Relations to include: 'redemption', 'user', 'business'
|
|
39024
|
+
* @returns Promise resolving to paginated redemption history
|
|
39025
|
+
*
|
|
39026
|
+
* @example
|
|
39027
|
+
* ```typescript
|
|
39028
|
+
* // Get user redemptions with full redemption details
|
|
39029
|
+
* const { data: redeems } = await getUserRedemptions(['redemption', 'business']);
|
|
39030
|
+
* redeems.forEach(redeem => {
|
|
39031
|
+
* console.log('Redemption:', redeem.included?.redemption?.title);
|
|
39032
|
+
* console.log('Business:', redeem.included?.business?.displayName);
|
|
39033
|
+
* });
|
|
39034
|
+
* ```
|
|
39035
|
+
*/
|
|
39036
|
+
const getUserRedemptions = react.useCallback(async (include) => {
|
|
37513
39037
|
if (!isInitialized || !sdk) {
|
|
37514
39038
|
throw new Error('SDK not initialized. Call initialize() first.');
|
|
37515
39039
|
}
|
|
@@ -37518,7 +39042,7 @@ const useRedemptions = () => {
|
|
|
37518
39042
|
return { data: [], pagination: { page: 1, limit: 0, total: 0, pages: 0, hasNext: false, hasPrev: false } };
|
|
37519
39043
|
}
|
|
37520
39044
|
try {
|
|
37521
|
-
const result = await sdk.redemptions.getUserRedemptions();
|
|
39045
|
+
const result = await sdk.redemptions.getUserRedemptions(undefined, include);
|
|
37522
39046
|
return result;
|
|
37523
39047
|
}
|
|
37524
39048
|
catch (error) {
|
|
@@ -37572,6 +39096,40 @@ const useRedemptions = () => {
|
|
|
37572
39096
|
}
|
|
37573
39097
|
}, [sdk, isInitialized, isAuthenticated, signAndSubmitTransactionWithJWT, isSignerAvailable]);
|
|
37574
39098
|
// Admin methods
|
|
39099
|
+
/**
|
|
39100
|
+
* Admin: Get all redemption redeems with filters and include relations
|
|
39101
|
+
*
|
|
39102
|
+
* Retrieves all redemption redeems across the platform with filtering.
|
|
39103
|
+
*
|
|
39104
|
+
* @param filters - Optional filters for user, redemption, and pagination
|
|
39105
|
+
* @param include - Relations to include: 'redemption', 'user', 'business'
|
|
39106
|
+
* @returns Promise resolving to paginated redemption redeems
|
|
39107
|
+
*
|
|
39108
|
+
* @example
|
|
39109
|
+
* ```typescript
|
|
39110
|
+
* // Get all redeems with user details
|
|
39111
|
+
* const { data: redeems } = await getRedemptionRedeems({}, ['user', 'redemption']);
|
|
39112
|
+
*
|
|
39113
|
+
* // Filter by specific user
|
|
39114
|
+
* const { data: userRedeems } = await getRedemptionRedeems(
|
|
39115
|
+
* { userId: 'user-123' },
|
|
39116
|
+
* ['redemption']
|
|
39117
|
+
* );
|
|
39118
|
+
* ```
|
|
39119
|
+
*/
|
|
39120
|
+
const getRedemptionRedeems = react.useCallback(async (filters, include) => {
|
|
39121
|
+
if (!isInitialized || !sdk) {
|
|
39122
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
39123
|
+
}
|
|
39124
|
+
try {
|
|
39125
|
+
const result = await sdk.redemptions.getRedemptionRedeems(filters, include);
|
|
39126
|
+
return result;
|
|
39127
|
+
}
|
|
39128
|
+
catch (error) {
|
|
39129
|
+
console.error('Failed to fetch redemption redeems:', error);
|
|
39130
|
+
throw error;
|
|
39131
|
+
}
|
|
39132
|
+
}, [sdk, isInitialized]);
|
|
37575
39133
|
const createRedemption = react.useCallback(async (redemptionData) => {
|
|
37576
39134
|
if (!isInitialized || !sdk) {
|
|
37577
39135
|
throw new Error('SDK not initialized. Call initialize() first.');
|
|
@@ -37629,6 +39187,7 @@ const useRedemptions = () => {
|
|
|
37629
39187
|
getUserRedemptions,
|
|
37630
39188
|
redeem,
|
|
37631
39189
|
getRedemptionTypes,
|
|
39190
|
+
getRedemptionRedeems,
|
|
37632
39191
|
createRedemption,
|
|
37633
39192
|
updateRedemption,
|
|
37634
39193
|
toggleRedemptionStatus,
|
|
@@ -38057,29 +39616,47 @@ const useFiles = () => {
|
|
|
38057
39616
|
/**
|
|
38058
39617
|
* React hook for analytics operations in the PERS SDK
|
|
38059
39618
|
*
|
|
38060
|
-
* Provides
|
|
38061
|
-
*
|
|
39619
|
+
* Provides comprehensive analytics and business intelligence capabilities:
|
|
39620
|
+
* - **Transaction Analytics**: Volume, trends, business performance
|
|
39621
|
+
* - **Campaign Claim Analytics**: Campaign performance and claim patterns
|
|
39622
|
+
* - **User Analytics**: Engagement metrics with per-active-user averages
|
|
39623
|
+
* - **User Ranking**: Leaderboards with full user details
|
|
39624
|
+
* - **Business Ranking**: Business performance rankings
|
|
39625
|
+
* - **Retention Analytics**: Monthly retention metrics
|
|
38062
39626
|
*
|
|
38063
39627
|
* @returns Analytics hook with methods for data analysis
|
|
38064
39628
|
*
|
|
38065
|
-
* @example
|
|
39629
|
+
* @example Basic Transaction Analytics
|
|
38066
39630
|
* ```typescript
|
|
38067
39631
|
* function AnalyticsComponent() {
|
|
38068
39632
|
* const { getTransactionAnalytics } = useAnalytics();
|
|
38069
39633
|
*
|
|
38070
39634
|
* const loadAnalytics = async () => {
|
|
38071
|
-
*
|
|
38072
|
-
*
|
|
38073
|
-
*
|
|
38074
|
-
*
|
|
38075
|
-
*
|
|
38076
|
-
*
|
|
38077
|
-
* } catch (error) {
|
|
38078
|
-
* console.error('Failed to load analytics:', error);
|
|
38079
|
-
* }
|
|
39635
|
+
* const analytics = await getTransactionAnalytics({
|
|
39636
|
+
* startDate: '2024-01-01',
|
|
39637
|
+
* endDate: '2024-01-31',
|
|
39638
|
+
* groupBy: 'day'
|
|
39639
|
+
* });
|
|
39640
|
+
* console.log('Transaction analytics:', analytics);
|
|
38080
39641
|
* };
|
|
39642
|
+
* }
|
|
39643
|
+
* ```
|
|
38081
39644
|
*
|
|
38082
|
-
*
|
|
39645
|
+
* @example User Leaderboard
|
|
39646
|
+
* ```typescript
|
|
39647
|
+
* function LeaderboardScreen() {
|
|
39648
|
+
* const { getUserRanking } = useAnalytics();
|
|
39649
|
+
*
|
|
39650
|
+
* const loadLeaderboard = async () => {
|
|
39651
|
+
* const ranking = await getUserRanking({
|
|
39652
|
+
* sortBy: 'totalTransactions',
|
|
39653
|
+
* sortOrder: 'DESC',
|
|
39654
|
+
* limit: 50
|
|
39655
|
+
* });
|
|
39656
|
+
* ranking.results.forEach((user, i) => {
|
|
39657
|
+
* console.log(`#${i + 1}: ${user.email} - ${user.totalTransactions} txns`);
|
|
39658
|
+
* });
|
|
39659
|
+
* };
|
|
38083
39660
|
* }
|
|
38084
39661
|
* ```
|
|
38085
39662
|
*/
|
|
@@ -38094,16 +39671,12 @@ const useAnalytics = () => {
|
|
|
38094
39671
|
*
|
|
38095
39672
|
* @example
|
|
38096
39673
|
* ```typescript
|
|
38097
|
-
* const { getTransactionAnalytics } = useAnalytics();
|
|
38098
39674
|
* const analytics = await getTransactionAnalytics({
|
|
38099
|
-
* groupBy: ['day'],
|
|
38100
|
-
* metrics: ['count', 'sum'],
|
|
38101
39675
|
* startDate: '2024-01-01',
|
|
38102
39676
|
* endDate: '2024-01-31',
|
|
38103
|
-
*
|
|
39677
|
+
* groupBy: 'day',
|
|
39678
|
+
* metrics: ['count', 'sum']
|
|
38104
39679
|
* });
|
|
38105
|
-
* console.log('Daily transaction analytics:', analytics.results);
|
|
38106
|
-
* console.log('Execution time:', analytics.metadata.executionTime);
|
|
38107
39680
|
* ```
|
|
38108
39681
|
*/
|
|
38109
39682
|
const getTransactionAnalytics = react.useCallback(async (request) => {
|
|
@@ -38119,8 +39692,214 @@ const useAnalytics = () => {
|
|
|
38119
39692
|
throw error;
|
|
38120
39693
|
}
|
|
38121
39694
|
}, [sdk, isInitialized]);
|
|
39695
|
+
/**
|
|
39696
|
+
* Retrieves campaign claim analytics with aggregation
|
|
39697
|
+
*
|
|
39698
|
+
* Provides insights into campaign performance, claim patterns, and user engagement.
|
|
39699
|
+
*
|
|
39700
|
+
* @param request - Analytics request with filters, groupBy, and metrics
|
|
39701
|
+
* @returns Promise resolving to campaign claim analytics data
|
|
39702
|
+
*
|
|
39703
|
+
* @example Claims per campaign
|
|
39704
|
+
* ```typescript
|
|
39705
|
+
* const analytics = await getCampaignClaimAnalytics({
|
|
39706
|
+
* filters: { status: 'COMPLETED' },
|
|
39707
|
+
* groupBy: ['campaignId'],
|
|
39708
|
+
* metrics: ['count'],
|
|
39709
|
+
* sortBy: 'count',
|
|
39710
|
+
* sortOrder: 'DESC',
|
|
39711
|
+
* limit: 10
|
|
39712
|
+
* });
|
|
39713
|
+
* console.log('Top campaigns:', analytics.results);
|
|
39714
|
+
* ```
|
|
39715
|
+
*/
|
|
39716
|
+
const getCampaignClaimAnalytics = react.useCallback(async (request) => {
|
|
39717
|
+
if (!isInitialized || !sdk) {
|
|
39718
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
39719
|
+
}
|
|
39720
|
+
try {
|
|
39721
|
+
const result = await sdk.analytics.getCampaignClaimAnalytics(request);
|
|
39722
|
+
return result;
|
|
39723
|
+
}
|
|
39724
|
+
catch (error) {
|
|
39725
|
+
console.error('Failed to fetch campaign claim analytics:', error);
|
|
39726
|
+
throw error;
|
|
39727
|
+
}
|
|
39728
|
+
}, [sdk, isInitialized]);
|
|
39729
|
+
/**
|
|
39730
|
+
* Retrieves user analytics with engagement metrics
|
|
39731
|
+
*
|
|
39732
|
+
* Includes both per-user and per-active-user metrics for accurate engagement insights.
|
|
39733
|
+
* Per-active-user metrics show concentrated engagement among active users.
|
|
39734
|
+
*
|
|
39735
|
+
* @param request - Analytics request with optional filters and date range
|
|
39736
|
+
* @returns Promise resolving to user analytics data
|
|
39737
|
+
*
|
|
39738
|
+
* @example Compare per-user vs per-active-user metrics
|
|
39739
|
+
* ```typescript
|
|
39740
|
+
* const analytics = await getUserAnalytics({
|
|
39741
|
+
* startDate: new Date('2026-02-01'),
|
|
39742
|
+
* endDate: new Date('2026-02-28')
|
|
39743
|
+
* });
|
|
39744
|
+
*
|
|
39745
|
+
* console.log(`Active users: ${analytics.activeUsers} / ${analytics.totalUsers}`);
|
|
39746
|
+
* console.log(`Engagement rate: ${analytics.engagementRate.toFixed(1)}%`);
|
|
39747
|
+
*
|
|
39748
|
+
* // Per-active-user metrics (more meaningful)
|
|
39749
|
+
* console.log(`Avg transactions per active user: ${analytics.averageTransactionsPerActiveUser}`);
|
|
39750
|
+
* ```
|
|
39751
|
+
*
|
|
39752
|
+
* @example Business-specific analytics
|
|
39753
|
+
* ```typescript
|
|
39754
|
+
* const analytics = await getUserAnalytics({
|
|
39755
|
+
* filters: { businessId: 'business-123' },
|
|
39756
|
+
* startDate: new Date('2026-01-01'),
|
|
39757
|
+
* endDate: new Date('2026-12-31')
|
|
39758
|
+
* });
|
|
39759
|
+
* ```
|
|
39760
|
+
*/
|
|
39761
|
+
const getUserAnalytics = react.useCallback(async (request = {}) => {
|
|
39762
|
+
if (!isInitialized || !sdk) {
|
|
39763
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
39764
|
+
}
|
|
39765
|
+
try {
|
|
39766
|
+
const result = await sdk.analytics.getUserAnalytics(request);
|
|
39767
|
+
return result;
|
|
39768
|
+
}
|
|
39769
|
+
catch (error) {
|
|
39770
|
+
console.error('Failed to fetch user analytics:', error);
|
|
39771
|
+
throw error;
|
|
39772
|
+
}
|
|
39773
|
+
}, [sdk, isInitialized]);
|
|
39774
|
+
/**
|
|
39775
|
+
* Retrieves user transaction ranking with enriched user data
|
|
39776
|
+
*
|
|
39777
|
+
* Returns ranked list of users with full user details (email, externalUserId)
|
|
39778
|
+
* and transaction metrics. Ideal for leaderboards, engagement analysis,
|
|
39779
|
+
* and identifying power users.
|
|
39780
|
+
*
|
|
39781
|
+
* @param request - Ranking request with filters, sorting, and limit
|
|
39782
|
+
* @returns Promise resolving to ranked user list with transaction metrics
|
|
39783
|
+
*
|
|
39784
|
+
* @example Top 50 users by transaction count
|
|
39785
|
+
* ```typescript
|
|
39786
|
+
* const ranking = await getUserRanking({
|
|
39787
|
+
* sortBy: 'totalTransactions',
|
|
39788
|
+
* sortOrder: 'DESC',
|
|
39789
|
+
* limit: 50
|
|
39790
|
+
* });
|
|
39791
|
+
*
|
|
39792
|
+
* ranking.results.forEach((user, index) => {
|
|
39793
|
+
* console.log(`#${index + 1}: ${user.email || user.externalUserId}`);
|
|
39794
|
+
* console.log(` Transactions: ${user.totalTransactions}`);
|
|
39795
|
+
* console.log(` Token spent: ${user.tokenSpent}`);
|
|
39796
|
+
* });
|
|
39797
|
+
* ```
|
|
39798
|
+
*
|
|
39799
|
+
* @example Top STAMP spenders
|
|
39800
|
+
* ```typescript
|
|
39801
|
+
* const ranking = await getUserRanking({
|
|
39802
|
+
* filters: { tokenType: 'STAMP' },
|
|
39803
|
+
* sortBy: 'tokenSpent',
|
|
39804
|
+
* sortOrder: 'DESC',
|
|
39805
|
+
* limit: 20
|
|
39806
|
+
* });
|
|
39807
|
+
* ```
|
|
39808
|
+
*/
|
|
39809
|
+
const getUserRanking = react.useCallback(async (request = {}) => {
|
|
39810
|
+
if (!isInitialized || !sdk) {
|
|
39811
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
39812
|
+
}
|
|
39813
|
+
try {
|
|
39814
|
+
const result = await sdk.analytics.getUserRanking(request);
|
|
39815
|
+
return result;
|
|
39816
|
+
}
|
|
39817
|
+
catch (error) {
|
|
39818
|
+
console.error('Failed to fetch user ranking:', error);
|
|
39819
|
+
throw error;
|
|
39820
|
+
}
|
|
39821
|
+
}, [sdk, isInitialized]);
|
|
39822
|
+
/**
|
|
39823
|
+
* Retrieves business transaction ranking with enriched business data
|
|
39824
|
+
*
|
|
39825
|
+
* Returns ranked list of businesses with transaction metrics for
|
|
39826
|
+
* partner analytics and performance dashboards.
|
|
39827
|
+
*
|
|
39828
|
+
* @param request - Ranking request with filters, sorting, and limit
|
|
39829
|
+
* @returns Promise resolving to ranked business list
|
|
39830
|
+
*
|
|
39831
|
+
* @example Top businesses by transaction count
|
|
39832
|
+
* ```typescript
|
|
39833
|
+
* const ranking = await getBusinessRanking({
|
|
39834
|
+
* sortBy: 'totalTransactions',
|
|
39835
|
+
* sortOrder: 'DESC',
|
|
39836
|
+
* limit: 20
|
|
39837
|
+
* });
|
|
39838
|
+
*
|
|
39839
|
+
* ranking.results.forEach((business, index) => {
|
|
39840
|
+
* console.log(`#${index + 1}: ${business.businessId}`);
|
|
39841
|
+
* console.log(` Transactions: ${business.totalTransactions}`);
|
|
39842
|
+
* console.log(` Token spent: ${business.tokenSpent}`);
|
|
39843
|
+
* });
|
|
39844
|
+
* ```
|
|
39845
|
+
*/
|
|
39846
|
+
const getBusinessRanking = react.useCallback(async (request = {}) => {
|
|
39847
|
+
if (!isInitialized || !sdk) {
|
|
39848
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
39849
|
+
}
|
|
39850
|
+
try {
|
|
39851
|
+
const result = await sdk.analytics.getBusinessRanking(request);
|
|
39852
|
+
return result;
|
|
39853
|
+
}
|
|
39854
|
+
catch (error) {
|
|
39855
|
+
console.error('Failed to fetch business ranking:', error);
|
|
39856
|
+
throw error;
|
|
39857
|
+
}
|
|
39858
|
+
}, [sdk, isInitialized]);
|
|
39859
|
+
/**
|
|
39860
|
+
* Retrieves monthly user retention analytics
|
|
39861
|
+
*
|
|
39862
|
+
* Returns monthly retention data with active, new, and returning users
|
|
39863
|
+
* along with retention rates. Useful for churn analysis and engagement trends.
|
|
39864
|
+
*
|
|
39865
|
+
* @param request - Retention request with monthsBack and filters
|
|
39866
|
+
* @returns Promise resolving to monthly retention data
|
|
39867
|
+
*
|
|
39868
|
+
* @example Get 12 months of retention data
|
|
39869
|
+
* ```typescript
|
|
39870
|
+
* const retention = await getRetentionAnalytics({
|
|
39871
|
+
* monthsBack: 12
|
|
39872
|
+
* });
|
|
39873
|
+
*
|
|
39874
|
+
* retention.results.forEach(month => {
|
|
39875
|
+
* console.log(`${month.month}:`);
|
|
39876
|
+
* console.log(` Active: ${month.activeUsers}`);
|
|
39877
|
+
* console.log(` New: ${month.newUsers}`);
|
|
39878
|
+
* console.log(` Returning: ${month.returningUsers}`);
|
|
39879
|
+
* console.log(` Retention Rate: ${month.retentionRate.toFixed(1)}%`);
|
|
39880
|
+
* });
|
|
39881
|
+
* ```
|
|
39882
|
+
*/
|
|
39883
|
+
const getRetentionAnalytics = react.useCallback(async (request = {}) => {
|
|
39884
|
+
if (!isInitialized || !sdk) {
|
|
39885
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
39886
|
+
}
|
|
39887
|
+
try {
|
|
39888
|
+
const result = await sdk.analytics.getRetentionAnalytics(request);
|
|
39889
|
+
return result;
|
|
39890
|
+
}
|
|
39891
|
+
catch (error) {
|
|
39892
|
+
console.error('Failed to fetch retention analytics:', error);
|
|
39893
|
+
throw error;
|
|
39894
|
+
}
|
|
39895
|
+
}, [sdk, isInitialized]);
|
|
38122
39896
|
return {
|
|
38123
39897
|
getTransactionAnalytics,
|
|
39898
|
+
getCampaignClaimAnalytics,
|
|
39899
|
+
getUserAnalytics,
|
|
39900
|
+
getUserRanking,
|
|
39901
|
+
getBusinessRanking,
|
|
39902
|
+
getRetentionAnalytics,
|
|
38124
39903
|
isAvailable: isInitialized && !!sdk?.analytics,
|
|
38125
39904
|
};
|
|
38126
39905
|
};
|
|
@@ -38496,6 +40275,277 @@ const useEvents = () => {
|
|
|
38496
40275
|
};
|
|
38497
40276
|
};
|
|
38498
40277
|
|
|
40278
|
+
/**
|
|
40279
|
+
* React hook for TriggerSource operations in the PERS SDK
|
|
40280
|
+
*
|
|
40281
|
+
* Manages trigger sources which are physical or digital activation points for campaigns:
|
|
40282
|
+
* - **QR_CODE**: Scannable QR codes at physical locations
|
|
40283
|
+
* - **NFC_TAG**: NFC tap points for contactless interactions
|
|
40284
|
+
* - **GPS_GEOFENCE**: Location-based triggers with radius detection
|
|
40285
|
+
* - **API_WEBHOOK**: External system integration triggers
|
|
40286
|
+
* - **TRANSACTION**: Purchase/payment based triggers
|
|
40287
|
+
*
|
|
40288
|
+
* TriggerSources are standalone entities that can be created, managed, and then
|
|
40289
|
+
* assigned to campaigns. This separation allows reuse across multiple campaigns.
|
|
40290
|
+
*
|
|
40291
|
+
* **Admin Only**: All create, update, and delete operations require admin authentication.
|
|
40292
|
+
*
|
|
40293
|
+
* @returns TriggerSource hook with CRUD operations
|
|
40294
|
+
*
|
|
40295
|
+
* @example Basic TriggerSource Operations
|
|
40296
|
+
* ```typescript
|
|
40297
|
+
* function TriggerSourceManager() {
|
|
40298
|
+
* const {
|
|
40299
|
+
* getAll,
|
|
40300
|
+
* getById,
|
|
40301
|
+
* create,
|
|
40302
|
+
* update,
|
|
40303
|
+
* remove
|
|
40304
|
+
* } = useTriggerSources();
|
|
40305
|
+
*
|
|
40306
|
+
* // List all QR code trigger sources
|
|
40307
|
+
* const loadQRSources = async () => {
|
|
40308
|
+
* const { data: sources } = await getAll({ type: 'QR_CODE' });
|
|
40309
|
+
* console.log('QR Sources:', sources);
|
|
40310
|
+
* };
|
|
40311
|
+
*
|
|
40312
|
+
* // Create a new QR code for a store
|
|
40313
|
+
* const createStoreQR = async () => {
|
|
40314
|
+
* const source = await create({
|
|
40315
|
+
* type: 'QR_CODE',
|
|
40316
|
+
* name: 'Store Entrance QR',
|
|
40317
|
+
* description: 'Scan at the entrance',
|
|
40318
|
+
* businessId: 'business-123',
|
|
40319
|
+
* coordsLatitude: 47.6062,
|
|
40320
|
+
* coordsLongitude: -122.3321
|
|
40321
|
+
* });
|
|
40322
|
+
* console.log('Created:', source.id);
|
|
40323
|
+
* };
|
|
40324
|
+
* }
|
|
40325
|
+
* ```
|
|
40326
|
+
*
|
|
40327
|
+
* @example GPS Geofence Trigger
|
|
40328
|
+
* ```typescript
|
|
40329
|
+
* const { create } = useTriggerSources();
|
|
40330
|
+
*
|
|
40331
|
+
* // Create a GPS geofence around a location
|
|
40332
|
+
* const geofence = await create({
|
|
40333
|
+
* type: 'GPS_GEOFENCE',
|
|
40334
|
+
* name: 'Downtown Area',
|
|
40335
|
+
* coordsLatitude: 47.6062,
|
|
40336
|
+
* coordsLongitude: -122.3321,
|
|
40337
|
+
* metadata: { radiusMeters: 100 }
|
|
40338
|
+
* });
|
|
40339
|
+
* ```
|
|
40340
|
+
*/
|
|
40341
|
+
const useTriggerSources = () => {
|
|
40342
|
+
const { sdk, isInitialized, isAuthenticated } = usePersSDK();
|
|
40343
|
+
/**
|
|
40344
|
+
* Get trigger sources with optional filters and pagination
|
|
40345
|
+
*
|
|
40346
|
+
* Retrieves trigger sources (QR codes, NFC tags, GPS geofences, webhooks, etc.)
|
|
40347
|
+
* that can be used to activate campaigns. Supports filtering by type, business,
|
|
40348
|
+
* campaign association, and active status.
|
|
40349
|
+
*
|
|
40350
|
+
* @param options - Filter and pagination options
|
|
40351
|
+
* @returns Promise resolving to paginated trigger sources
|
|
40352
|
+
*
|
|
40353
|
+
* @example
|
|
40354
|
+
* ```typescript
|
|
40355
|
+
* // Get all QR code trigger sources
|
|
40356
|
+
* const { data: qrSources } = await getAll({ type: 'QR_CODE' });
|
|
40357
|
+
*
|
|
40358
|
+
* // Get trigger sources for a specific business
|
|
40359
|
+
* const { data: businessSources, pagination } = await getAll({
|
|
40360
|
+
* businessId: 'business-123',
|
|
40361
|
+
* active: true,
|
|
40362
|
+
* page: 1,
|
|
40363
|
+
* limit: 20
|
|
40364
|
+
* });
|
|
40365
|
+
*
|
|
40366
|
+
* // Get trigger sources assigned to a campaign
|
|
40367
|
+
* const { data: campaignSources } = await getAll({
|
|
40368
|
+
* campaignId: 'campaign-456'
|
|
40369
|
+
* });
|
|
40370
|
+
* ```
|
|
40371
|
+
*/
|
|
40372
|
+
const getAll = react.useCallback(async (options) => {
|
|
40373
|
+
if (!isInitialized || !sdk) {
|
|
40374
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
40375
|
+
}
|
|
40376
|
+
try {
|
|
40377
|
+
const result = await sdk.triggerSources.getAll(options);
|
|
40378
|
+
return result;
|
|
40379
|
+
}
|
|
40380
|
+
catch (error) {
|
|
40381
|
+
console.error('Failed to fetch trigger sources:', error);
|
|
40382
|
+
throw error;
|
|
40383
|
+
}
|
|
40384
|
+
}, [sdk, isInitialized]);
|
|
40385
|
+
/**
|
|
40386
|
+
* Get trigger source by ID
|
|
40387
|
+
*
|
|
40388
|
+
* Retrieves detailed information for a specific trigger source including
|
|
40389
|
+
* its type, location, metadata, and configuration.
|
|
40390
|
+
*
|
|
40391
|
+
* @param triggerSourceId - UUID of the trigger source
|
|
40392
|
+
* @returns Promise resolving to trigger source details
|
|
40393
|
+
* @throws {PersApiError} When trigger source with specified ID is not found
|
|
40394
|
+
*
|
|
40395
|
+
* @example
|
|
40396
|
+
* ```typescript
|
|
40397
|
+
* const source = await getById('source-123');
|
|
40398
|
+
*
|
|
40399
|
+
* console.log('Trigger Source:', source.name);
|
|
40400
|
+
* console.log('Type:', source.type);
|
|
40401
|
+
* console.log('Active:', source.isActive);
|
|
40402
|
+
*
|
|
40403
|
+
* if (source.coordsLatitude && source.coordsLongitude) {
|
|
40404
|
+
* console.log('Location:', source.coordsLatitude, source.coordsLongitude);
|
|
40405
|
+
* }
|
|
40406
|
+
* ```
|
|
40407
|
+
*/
|
|
40408
|
+
const getById = react.useCallback(async (triggerSourceId) => {
|
|
40409
|
+
if (!isInitialized || !sdk) {
|
|
40410
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
40411
|
+
}
|
|
40412
|
+
try {
|
|
40413
|
+
const result = await sdk.triggerSources.getById(triggerSourceId);
|
|
40414
|
+
return result;
|
|
40415
|
+
}
|
|
40416
|
+
catch (error) {
|
|
40417
|
+
console.error('Failed to fetch trigger source:', error);
|
|
40418
|
+
throw error;
|
|
40419
|
+
}
|
|
40420
|
+
}, [sdk, isInitialized]);
|
|
40421
|
+
/**
|
|
40422
|
+
* Admin: Create a new trigger source
|
|
40423
|
+
*
|
|
40424
|
+
* Creates a new trigger source (QR code, NFC tag, GPS geofence, webhook, or
|
|
40425
|
+
* transaction-based trigger) that can be assigned to campaigns. Requires
|
|
40426
|
+
* administrator privileges.
|
|
40427
|
+
*
|
|
40428
|
+
* @param triggerSource - Trigger source creation data
|
|
40429
|
+
* @returns Promise resolving to created trigger source
|
|
40430
|
+
* @throws {PersApiError} When not authenticated as admin or validation fails
|
|
40431
|
+
*
|
|
40432
|
+
* @example
|
|
40433
|
+
* ```typescript
|
|
40434
|
+
* // Create a QR code trigger source
|
|
40435
|
+
* const qrSource = await create({
|
|
40436
|
+
* type: 'QR_CODE',
|
|
40437
|
+
* name: 'Store Entrance QR',
|
|
40438
|
+
* description: 'QR code at main entrance',
|
|
40439
|
+
* businessId: 'business-123',
|
|
40440
|
+
* coordsLatitude: 47.6062,
|
|
40441
|
+
* coordsLongitude: -122.3321
|
|
40442
|
+
* });
|
|
40443
|
+
*
|
|
40444
|
+
* // Create an NFC tag trigger source
|
|
40445
|
+
* const nfcSource = await create({
|
|
40446
|
+
* type: 'NFC_TAG',
|
|
40447
|
+
* name: 'Product Display NFC',
|
|
40448
|
+
* metadata: { productId: 'SKU-12345' }
|
|
40449
|
+
* });
|
|
40450
|
+
* ```
|
|
40451
|
+
*/
|
|
40452
|
+
const create = react.useCallback(async (triggerSource) => {
|
|
40453
|
+
if (!isInitialized || !sdk) {
|
|
40454
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
40455
|
+
}
|
|
40456
|
+
if (!isAuthenticated) {
|
|
40457
|
+
throw new Error('SDK not authenticated. create requires admin authentication.');
|
|
40458
|
+
}
|
|
40459
|
+
try {
|
|
40460
|
+
const result = await sdk.triggerSources.create(triggerSource);
|
|
40461
|
+
return result;
|
|
40462
|
+
}
|
|
40463
|
+
catch (error) {
|
|
40464
|
+
console.error('Failed to create trigger source:', error);
|
|
40465
|
+
throw error;
|
|
40466
|
+
}
|
|
40467
|
+
}, [sdk, isInitialized, isAuthenticated]);
|
|
40468
|
+
/**
|
|
40469
|
+
* Admin: Update a trigger source
|
|
40470
|
+
*
|
|
40471
|
+
* Updates an existing trigger source's configuration. All fields are optional;
|
|
40472
|
+
* only provided fields will be updated. Requires administrator privileges.
|
|
40473
|
+
*
|
|
40474
|
+
* @param triggerSourceId - UUID of the trigger source to update
|
|
40475
|
+
* @param triggerSource - Updated trigger source data (partial)
|
|
40476
|
+
* @returns Promise resolving to updated trigger source
|
|
40477
|
+
* @throws {PersApiError} When not authenticated as admin or trigger source not found
|
|
40478
|
+
*
|
|
40479
|
+
* @example
|
|
40480
|
+
* ```typescript
|
|
40481
|
+
* // Update trigger source name and location
|
|
40482
|
+
* const updated = await update('source-123', {
|
|
40483
|
+
* name: 'Updated Store Entrance QR',
|
|
40484
|
+
* description: 'New description',
|
|
40485
|
+
* coordsLatitude: 47.6063,
|
|
40486
|
+
* coordsLongitude: -122.3322
|
|
40487
|
+
* });
|
|
40488
|
+
* ```
|
|
40489
|
+
*/
|
|
40490
|
+
const update = react.useCallback(async (triggerSourceId, triggerSource) => {
|
|
40491
|
+
if (!isInitialized || !sdk) {
|
|
40492
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
40493
|
+
}
|
|
40494
|
+
if (!isAuthenticated) {
|
|
40495
|
+
throw new Error('SDK not authenticated. update requires admin authentication.');
|
|
40496
|
+
}
|
|
40497
|
+
try {
|
|
40498
|
+
const result = await sdk.triggerSources.update(triggerSourceId, triggerSource);
|
|
40499
|
+
return result;
|
|
40500
|
+
}
|
|
40501
|
+
catch (error) {
|
|
40502
|
+
console.error('Failed to update trigger source:', error);
|
|
40503
|
+
throw error;
|
|
40504
|
+
}
|
|
40505
|
+
}, [sdk, isInitialized, isAuthenticated]);
|
|
40506
|
+
/**
|
|
40507
|
+
* Admin: Delete a trigger source
|
|
40508
|
+
*
|
|
40509
|
+
* Soft deletes a trigger source, making it inactive. The trigger source will
|
|
40510
|
+
* be removed from any campaigns it was assigned to. Requires administrator
|
|
40511
|
+
* privileges.
|
|
40512
|
+
*
|
|
40513
|
+
* @param triggerSourceId - UUID of the trigger source to delete
|
|
40514
|
+
* @returns Promise resolving to success status
|
|
40515
|
+
* @throws {PersApiError} When not authenticated as admin or trigger source not found
|
|
40516
|
+
*
|
|
40517
|
+
* @example
|
|
40518
|
+
* ```typescript
|
|
40519
|
+
* const success = await remove('source-123');
|
|
40520
|
+
* console.log('Trigger source deleted:', success);
|
|
40521
|
+
* ```
|
|
40522
|
+
*/
|
|
40523
|
+
const remove = react.useCallback(async (triggerSourceId) => {
|
|
40524
|
+
if (!isInitialized || !sdk) {
|
|
40525
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
40526
|
+
}
|
|
40527
|
+
if (!isAuthenticated) {
|
|
40528
|
+
throw new Error('SDK not authenticated. remove requires admin authentication.');
|
|
40529
|
+
}
|
|
40530
|
+
try {
|
|
40531
|
+
const result = await sdk.triggerSources.delete(triggerSourceId);
|
|
40532
|
+
return result;
|
|
40533
|
+
}
|
|
40534
|
+
catch (error) {
|
|
40535
|
+
console.error('Failed to delete trigger source:', error);
|
|
40536
|
+
throw error;
|
|
40537
|
+
}
|
|
40538
|
+
}, [sdk, isInitialized, isAuthenticated]);
|
|
40539
|
+
return {
|
|
40540
|
+
getAll,
|
|
40541
|
+
getById,
|
|
40542
|
+
create,
|
|
40543
|
+
update,
|
|
40544
|
+
remove,
|
|
40545
|
+
isAvailable: isInitialized && !!sdk?.triggerSources,
|
|
40546
|
+
};
|
|
40547
|
+
};
|
|
40548
|
+
|
|
38499
40549
|
// ==========================================
|
|
38500
40550
|
// TOKEN UTILITY FUNCTIONS
|
|
38501
40551
|
// ==========================================
|
|
@@ -38577,12 +40627,22 @@ exports.MEMBERSHIP_ROLE_HIERARCHY = MEMBERSHIP_ROLE_HIERARCHY;
|
|
|
38577
40627
|
exports.NativeTokenTypes = NativeTokenTypes;
|
|
38578
40628
|
exports.PersApiError = PersApiError;
|
|
38579
40629
|
exports.PersSDKProvider = PersSDKProvider;
|
|
40630
|
+
exports.QUERY_OPERATOR_SQL_MAP = QUERY_OPERATOR_SQL_MAP;
|
|
38580
40631
|
exports.ReactNativeDPoPProvider = ReactNativeDPoPProvider;
|
|
38581
40632
|
exports.ReactNativeHttpClient = ReactNativeHttpClient;
|
|
38582
40633
|
exports.ReactNativeSecureStorage = ReactNativeSecureStorage;
|
|
40634
|
+
exports.SOURCE_LOGIC_TYPES = SOURCE_LOGIC_TYPES;
|
|
40635
|
+
exports.SOURCE_LOGIC_TYPE_VALUES = SOURCE_LOGIC_TYPE_VALUES;
|
|
38583
40636
|
exports.SigningStatus = SigningStatus;
|
|
38584
40637
|
exports.TRANSACTION_FORMATS = TRANSACTION_FORMATS;
|
|
38585
40638
|
exports.TRANSACTION_FORMAT_DESCRIPTIONS = TRANSACTION_FORMAT_DESCRIPTIONS;
|
|
40639
|
+
exports.TRIGGER_SOURCE_TYPES = TRIGGER_SOURCE_TYPES;
|
|
40640
|
+
exports.TRIGGER_SOURCE_TYPE_VALUES = TRIGGER_SOURCE_TYPE_VALUES;
|
|
40641
|
+
exports.VALID_CAMPAIGN_CLAIM_RELATIONS = VALID_CAMPAIGN_CLAIM_RELATIONS;
|
|
40642
|
+
exports.VALID_CAMPAIGN_RELATIONS = VALID_CAMPAIGN_RELATIONS;
|
|
40643
|
+
exports.VALID_REDEMPTION_REDEEM_RELATIONS = VALID_REDEMPTION_REDEEM_RELATIONS;
|
|
40644
|
+
exports.VALID_RELATIONS = VALID_RELATIONS;
|
|
40645
|
+
exports.VALID_TRANSACTION_RELATIONS = VALID_TRANSACTION_RELATIONS;
|
|
38586
40646
|
exports.apiPublicKeyTestPrefix = apiPublicKeyTestPrefix;
|
|
38587
40647
|
exports.buildBurnRequest = buildBurnRequest;
|
|
38588
40648
|
exports.buildMintRequest = buildMintRequest;
|
|
@@ -38604,6 +40664,11 @@ exports.hasMinimumRole = hasMinimumRole;
|
|
|
38604
40664
|
exports.initializeReactNativePolyfills = initializeReactNativePolyfills;
|
|
38605
40665
|
exports.isPaginatedResponse = isPaginatedResponse;
|
|
38606
40666
|
exports.isUserIdentifierObject = isUserIdentifierObject;
|
|
40667
|
+
exports.isValidCampaignClaimRelation = isValidCampaignClaimRelation;
|
|
40668
|
+
exports.isValidCampaignRelation = isValidCampaignRelation;
|
|
40669
|
+
exports.isValidRedemptionRedeemRelation = isValidRedemptionRedeemRelation;
|
|
40670
|
+
exports.isValidRelation = isValidRelation;
|
|
40671
|
+
exports.isValidTransactionRelation = isValidTransactionRelation;
|
|
38607
40672
|
exports.normalizeToPaginated = normalizeToPaginated;
|
|
38608
40673
|
exports.registerIdentifierType = registerIdentifierType;
|
|
38609
40674
|
exports.testnetPrefix = testnetPrefix;
|
|
@@ -38624,6 +40689,7 @@ exports.useTokenBalances = useTokenBalances;
|
|
|
38624
40689
|
exports.useTokens = useTokens;
|
|
38625
40690
|
exports.useTransactionSigner = useTransactionSigner;
|
|
38626
40691
|
exports.useTransactions = useTransactions;
|
|
40692
|
+
exports.useTriggerSources = useTriggerSources;
|
|
38627
40693
|
exports.useUserStatus = useUserStatus;
|
|
38628
40694
|
exports.useUsers = useUsers;
|
|
38629
40695
|
exports.useWeb3 = useWeb3;
|