insert-affiliate-react-native-sdk 1.5.0 → 1.5.1
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/dist/DeepLinkIapProvider.d.ts +1 -1
- package/dist/DeepLinkIapProvider.js +138 -28
- package/dist/useDeepLinkIapProvider.d.ts +1 -1
- package/package.json +1 -1
- package/readme.md +150 -59
- package/src/DeepLinkIapProvider.tsx +167 -33
|
@@ -15,7 +15,7 @@ type T_DEEPLINK_IAP_CONTEXT = {
|
|
|
15
15
|
trackEvent: (eventName: string) => Promise<void>;
|
|
16
16
|
setShortCode: (shortCode: string) => Promise<void>;
|
|
17
17
|
setInsertAffiliateIdentifier: (referringLink: string) => Promise<void | string>;
|
|
18
|
-
initialize: (code: string | null) => Promise<void>;
|
|
18
|
+
initialize: (code: string | null, verboseLogging?: boolean) => Promise<void>;
|
|
19
19
|
isInitialized: boolean;
|
|
20
20
|
};
|
|
21
21
|
export declare const DeepLinkIapContext: React.Context<T_DEEPLINK_IAP_CONTEXT>;
|
|
@@ -58,7 +58,7 @@ exports.DeepLinkIapContext = (0, react_1.createContext)({
|
|
|
58
58
|
trackEvent: (eventName) => __awaiter(void 0, void 0, void 0, function* () { }),
|
|
59
59
|
setShortCode: (shortCode) => __awaiter(void 0, void 0, void 0, function* () { }),
|
|
60
60
|
setInsertAffiliateIdentifier: (referringLink) => __awaiter(void 0, void 0, void 0, function* () { }),
|
|
61
|
-
initialize: (code) => __awaiter(void 0, void 0, void 0, function* () { }),
|
|
61
|
+
initialize: (code, verboseLogging) => __awaiter(void 0, void 0, void 0, function* () { }),
|
|
62
62
|
isInitialized: false,
|
|
63
63
|
});
|
|
64
64
|
const DeepLinkIapProvider = ({ children, }) => {
|
|
@@ -66,8 +66,15 @@ const DeepLinkIapProvider = ({ children, }) => {
|
|
|
66
66
|
const [userId, setUserId] = (0, react_1.useState)('');
|
|
67
67
|
const [companyCode, setCompanyCode] = (0, react_1.useState)(null);
|
|
68
68
|
const [isInitialized, setIsInitialized] = (0, react_1.useState)(false);
|
|
69
|
+
const [verboseLogging, setVerboseLogging] = (0, react_1.useState)(false);
|
|
69
70
|
// MARK: Initialize the SDK
|
|
70
|
-
const initialize = (
|
|
71
|
+
const initialize = (companyCode_1, ...args_1) => __awaiter(void 0, [companyCode_1, ...args_1], void 0, function* (companyCode, verboseLogging = false) {
|
|
72
|
+
setVerboseLogging(verboseLogging);
|
|
73
|
+
if (verboseLogging) {
|
|
74
|
+
console.log('[Insert Affiliate] [VERBOSE] Starting SDK initialization...');
|
|
75
|
+
console.log('[Insert Affiliate] [VERBOSE] Company code provided:', companyCode ? 'Yes' : 'No');
|
|
76
|
+
console.log('[Insert Affiliate] [VERBOSE] Verbose logging enabled');
|
|
77
|
+
}
|
|
71
78
|
if (isInitialized) {
|
|
72
79
|
console.error('[Insert Affiliate] SDK is already initialized.');
|
|
73
80
|
return;
|
|
@@ -77,10 +84,17 @@ const DeepLinkIapProvider = ({ children, }) => {
|
|
|
77
84
|
yield saveValueInAsync(ASYNC_KEYS.COMPANY_CODE, companyCode);
|
|
78
85
|
setIsInitialized(true);
|
|
79
86
|
console.log(`[Insert Affiliate] SDK initialized with company code: ${companyCode}`);
|
|
87
|
+
if (verboseLogging) {
|
|
88
|
+
console.log('[Insert Affiliate] [VERBOSE] Company code saved to AsyncStorage');
|
|
89
|
+
console.log('[Insert Affiliate] [VERBOSE] SDK marked as initialized');
|
|
90
|
+
}
|
|
80
91
|
}
|
|
81
92
|
else {
|
|
82
93
|
console.warn('[Insert Affiliate] SDK initialized without a company code.');
|
|
83
94
|
setIsInitialized(true);
|
|
95
|
+
if (verboseLogging) {
|
|
96
|
+
console.log('[Insert Affiliate] [VERBOSE] No company code provided, SDK initialized in limited mode');
|
|
97
|
+
}
|
|
84
98
|
}
|
|
85
99
|
});
|
|
86
100
|
// EFFECT TO FETCH USER ID AND REF LINK
|
|
@@ -88,28 +102,43 @@ const DeepLinkIapProvider = ({ children, }) => {
|
|
|
88
102
|
(0, react_1.useEffect)(() => {
|
|
89
103
|
const fetchAsyncEssentials = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
90
104
|
try {
|
|
105
|
+
verboseLog('Loading stored data from AsyncStorage...');
|
|
91
106
|
const uId = yield getValueFromAsync(ASYNC_KEYS.USER_ID);
|
|
92
107
|
const refLink = yield getValueFromAsync(ASYNC_KEYS.REFERRER_LINK);
|
|
108
|
+
const companyCodeFromStorage = yield getValueFromAsync(ASYNC_KEYS.COMPANY_CODE);
|
|
109
|
+
verboseLog(`User ID found: ${uId ? 'Yes' : 'No'}`);
|
|
110
|
+
verboseLog(`Referrer link found: ${refLink ? 'Yes' : 'No'}`);
|
|
111
|
+
verboseLog(`Company code found: ${companyCodeFromStorage ? 'Yes' : 'No'}`);
|
|
93
112
|
if (uId && refLink) {
|
|
94
113
|
setUserId(uId);
|
|
95
114
|
setReferrerLink(refLink);
|
|
115
|
+
verboseLog('User ID and referrer link restored from storage');
|
|
116
|
+
}
|
|
117
|
+
if (companyCodeFromStorage) {
|
|
118
|
+
setCompanyCode(companyCodeFromStorage);
|
|
119
|
+
verboseLog('Company code restored from storage');
|
|
96
120
|
}
|
|
97
121
|
}
|
|
98
122
|
catch (error) {
|
|
99
123
|
errorLog(`ERROR ~ fetchAsyncEssentials: ${error}`);
|
|
124
|
+
verboseLog(`Error loading from AsyncStorage: ${error}`);
|
|
100
125
|
}
|
|
101
126
|
});
|
|
102
127
|
fetchAsyncEssentials();
|
|
103
128
|
}, []);
|
|
104
129
|
function generateThenSetUserID() {
|
|
105
130
|
return __awaiter(this, void 0, void 0, function* () {
|
|
131
|
+
verboseLog('Getting or generating user ID...');
|
|
106
132
|
let userId = yield getValueFromAsync(ASYNC_KEYS.USER_ID);
|
|
107
133
|
if (!userId) {
|
|
134
|
+
verboseLog('No existing user ID found, generating new one...');
|
|
108
135
|
userId = generateUserID();
|
|
109
136
|
setUserId(userId);
|
|
110
137
|
yield saveValueInAsync(ASYNC_KEYS.USER_ID, userId);
|
|
138
|
+
verboseLog(`Generated and saved new user ID: ${userId}`);
|
|
111
139
|
}
|
|
112
140
|
else {
|
|
141
|
+
verboseLog(`Found existing user ID: ${userId}`);
|
|
113
142
|
setUserId(userId);
|
|
114
143
|
}
|
|
115
144
|
return userId;
|
|
@@ -140,6 +169,29 @@ const DeepLinkIapProvider = ({ children, }) => {
|
|
|
140
169
|
const clearAsyncStorage = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
141
170
|
yield async_storage_1.default.clear();
|
|
142
171
|
});
|
|
172
|
+
// Helper function to get company code from state or storage
|
|
173
|
+
const getActiveCompanyCode = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
174
|
+
verboseLog('Getting active company code...');
|
|
175
|
+
let activeCompanyCode = companyCode;
|
|
176
|
+
verboseLog(`Company code in React state: ${activeCompanyCode || 'empty'}`);
|
|
177
|
+
if (!activeCompanyCode || (activeCompanyCode.trim() === '' && activeCompanyCode !== null)) {
|
|
178
|
+
verboseLog('Company code not in state, checking AsyncStorage...');
|
|
179
|
+
activeCompanyCode = yield getValueFromAsync(ASYNC_KEYS.COMPANY_CODE);
|
|
180
|
+
verboseLog(`Company code in AsyncStorage: ${activeCompanyCode || 'empty'}`);
|
|
181
|
+
if (activeCompanyCode) {
|
|
182
|
+
// Update state for future use
|
|
183
|
+
setCompanyCode(activeCompanyCode);
|
|
184
|
+
verboseLog('Updated React state with company code from storage');
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return activeCompanyCode;
|
|
188
|
+
});
|
|
189
|
+
// Helper function for verbose logging
|
|
190
|
+
const verboseLog = (message) => {
|
|
191
|
+
if (verboseLogging) {
|
|
192
|
+
console.log(`[Insert Affiliate] [VERBOSE] ${message}`);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
143
195
|
// Helper function to log errors
|
|
144
196
|
const errorLog = (message, type) => {
|
|
145
197
|
switch (type) {
|
|
@@ -207,12 +259,32 @@ const DeepLinkIapProvider = ({ children, }) => {
|
|
|
207
259
|
;
|
|
208
260
|
});
|
|
209
261
|
// MARK: Return Insert Affiliate Identifier
|
|
262
|
+
// Instead of just reading React state
|
|
210
263
|
const returnInsertAffiliateIdentifier = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
211
264
|
try {
|
|
212
|
-
|
|
265
|
+
verboseLog('Getting insert affiliate identifier...');
|
|
266
|
+
verboseLog(`React state - referrerLink: ${referrerLink || 'empty'}, userId: ${userId || 'empty'}`);
|
|
267
|
+
// Try React state first
|
|
268
|
+
if (referrerLink && userId) {
|
|
269
|
+
const identifier = `${referrerLink}-${userId}`;
|
|
270
|
+
verboseLog(`Found identifier in React state: ${identifier}`);
|
|
271
|
+
return identifier;
|
|
272
|
+
}
|
|
273
|
+
verboseLog('React state empty, checking AsyncStorage...');
|
|
274
|
+
// Fallback to async storage if React state is empty
|
|
275
|
+
const storedLink = yield getValueFromAsync(ASYNC_KEYS.REFERRER_LINK);
|
|
276
|
+
const storedUserId = yield getValueFromAsync(ASYNC_KEYS.USER_ID);
|
|
277
|
+
verboseLog(`AsyncStorage - storedLink: ${storedLink || 'empty'}, storedUserId: ${storedUserId || 'empty'}`);
|
|
278
|
+
if (storedLink && storedUserId) {
|
|
279
|
+
const identifier = `${storedLink}-${storedUserId}`;
|
|
280
|
+
verboseLog(`Found identifier in AsyncStorage: ${identifier}`);
|
|
281
|
+
return identifier;
|
|
282
|
+
}
|
|
283
|
+
verboseLog('No affiliate identifier found in state or storage');
|
|
284
|
+
return null;
|
|
213
285
|
}
|
|
214
286
|
catch (error) {
|
|
215
|
-
|
|
287
|
+
verboseLog(`Error getting affiliate identifier: ${error}`);
|
|
216
288
|
return null;
|
|
217
289
|
}
|
|
218
290
|
});
|
|
@@ -220,64 +292,77 @@ const DeepLinkIapProvider = ({ children, }) => {
|
|
|
220
292
|
function setInsertAffiliateIdentifier(referringLink) {
|
|
221
293
|
return __awaiter(this, void 0, void 0, function* () {
|
|
222
294
|
console.log('[Insert Affiliate] Setting affiliate identifier.');
|
|
295
|
+
verboseLog(`Input referringLink: ${referringLink}`);
|
|
223
296
|
try {
|
|
297
|
+
verboseLog('Generating or retrieving user ID...');
|
|
224
298
|
const customerID = yield generateThenSetUserID();
|
|
225
299
|
console.log('[Insert Affiliate] Completed generateThenSetUserID within setInsertAffiliateIdentifier.');
|
|
300
|
+
verboseLog(`Customer ID: ${customerID}`);
|
|
226
301
|
if (!referringLink) {
|
|
227
302
|
console.warn('[Insert Affiliate] Referring link is invalid.');
|
|
228
|
-
|
|
303
|
+
verboseLog('Referring link is empty or invalid, storing as-is');
|
|
229
304
|
yield storeInsertAffiliateIdentifier({ link: referringLink });
|
|
230
|
-
return `${
|
|
305
|
+
return `${referringLink}-${customerID}`;
|
|
231
306
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
307
|
+
// Get company code from state or storage
|
|
308
|
+
verboseLog('Getting company code...');
|
|
309
|
+
const activeCompanyCode = yield getActiveCompanyCode();
|
|
310
|
+
verboseLog(`Active company code: ${activeCompanyCode || 'Not found'}`);
|
|
311
|
+
if (!activeCompanyCode) {
|
|
312
|
+
console.error('[Insert Affiliate] Company code is not set. Please initialize the SDK with a valid company code.');
|
|
313
|
+
verboseLog('Company code missing, cannot proceed with API call');
|
|
314
|
+
return;
|
|
241
315
|
}
|
|
242
316
|
// Check if referring link is already a short code, if so save it and stop here.
|
|
317
|
+
verboseLog('Checking if referring link is already a short code...');
|
|
243
318
|
if (isShortCode(referringLink)) {
|
|
244
319
|
console.log('[Insert Affiliate] Referring link is already a short code.');
|
|
245
|
-
|
|
320
|
+
verboseLog('Link is already a short code, storing directly');
|
|
246
321
|
yield storeInsertAffiliateIdentifier({ link: referringLink });
|
|
247
|
-
return `${
|
|
322
|
+
return `${referringLink}-${customerID}`;
|
|
248
323
|
}
|
|
324
|
+
verboseLog('Link is not a short code, will convert via API');
|
|
249
325
|
// If the code is not already a short code, encode it raedy to send to our endpoint to return the short code. Save it before making the call in case something goes wrong
|
|
250
326
|
// Encode the referring link
|
|
327
|
+
verboseLog('Encoding referring link for API call...');
|
|
251
328
|
const encodedAffiliateLink = encodeURIComponent(referringLink);
|
|
252
329
|
if (!encodedAffiliateLink) {
|
|
253
330
|
console.error('[Insert Affiliate] Failed to encode affiliate link.');
|
|
254
|
-
|
|
331
|
+
verboseLog('Failed to encode link, storing original');
|
|
255
332
|
yield storeInsertAffiliateIdentifier({ link: referringLink });
|
|
256
|
-
return `${
|
|
333
|
+
return `${referringLink}-${customerID}`;
|
|
257
334
|
}
|
|
258
335
|
// Create the request URL
|
|
259
|
-
const urlString = `https://api.insertaffiliate.com/V1/convert-deep-link-to-short-link?companyId=${
|
|
336
|
+
const urlString = `https://api.insertaffiliate.com/V1/convert-deep-link-to-short-link?companyId=${activeCompanyCode}&deepLinkUrl=${encodedAffiliateLink}`;
|
|
260
337
|
console.log('[Insert Affiliate] urlString .', urlString);
|
|
338
|
+
verboseLog('Making API request to convert deep link to short code...');
|
|
261
339
|
const response = yield axios_1.default.get(urlString, {
|
|
262
340
|
headers: {
|
|
263
341
|
'Content-Type': 'application/json',
|
|
264
342
|
},
|
|
265
343
|
});
|
|
344
|
+
verboseLog(`API response status: ${response.status}`);
|
|
266
345
|
// Call to the backend for the short code and save the resolse in valid
|
|
267
346
|
if (response.status === 200 && response.data.shortLink) {
|
|
268
347
|
const shortLink = response.data.shortLink;
|
|
269
348
|
console.log('[Insert Affiliate] Short link received:', shortLink);
|
|
349
|
+
verboseLog(`Successfully converted to short link: ${shortLink}`);
|
|
350
|
+
verboseLog('Storing short link to AsyncStorage...');
|
|
351
|
+
yield storeInsertAffiliateIdentifier({ link: shortLink });
|
|
352
|
+
verboseLog('Short link stored successfully');
|
|
270
353
|
return `${shortLink}-${customerID}`;
|
|
271
354
|
}
|
|
272
355
|
else {
|
|
273
356
|
console.warn('[Insert Affiliate] Unexpected response format.');
|
|
274
|
-
|
|
357
|
+
verboseLog(`Unexpected API response. Status: ${response.status}, Data: ${JSON.stringify(response.data)}`);
|
|
358
|
+
verboseLog('Storing original link as fallback');
|
|
275
359
|
yield storeInsertAffiliateIdentifier({ link: referringLink });
|
|
276
|
-
return `${
|
|
360
|
+
return `${referringLink}-${customerID}`;
|
|
277
361
|
}
|
|
278
362
|
}
|
|
279
363
|
catch (error) {
|
|
280
364
|
console.error('[Insert Affiliate] Error:', error);
|
|
365
|
+
verboseLog(`Error in setInsertAffiliateIdentifier: ${error}`);
|
|
281
366
|
}
|
|
282
367
|
});
|
|
283
368
|
}
|
|
@@ -285,8 +370,11 @@ const DeepLinkIapProvider = ({ children, }) => {
|
|
|
285
370
|
function storeInsertAffiliateIdentifier(_a) {
|
|
286
371
|
return __awaiter(this, arguments, void 0, function* ({ link }) {
|
|
287
372
|
console.log(`[Insert Affiliate] Storing affiliate identifier: ${link}`);
|
|
373
|
+
verboseLog(`Updating React state with referrer link: ${link}`);
|
|
288
374
|
setReferrerLink(link);
|
|
375
|
+
verboseLog(`Saving referrer link to AsyncStorage...`);
|
|
289
376
|
yield saveValueInAsync(ASYNC_KEYS.REFERRER_LINK, link);
|
|
377
|
+
verboseLog(`Referrer link saved to AsyncStorage successfully`);
|
|
290
378
|
});
|
|
291
379
|
}
|
|
292
380
|
const validatePurchaseWithIapticAPI = (jsonIapPurchase, iapticAppId, iapticAppName, iapticPublicKey) => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -350,23 +438,29 @@ const DeepLinkIapProvider = ({ children, }) => {
|
|
|
350
438
|
}
|
|
351
439
|
});
|
|
352
440
|
const storeExpectedStoreTransaction = (purchaseToken) => __awaiter(void 0, void 0, void 0, function* () {
|
|
353
|
-
|
|
441
|
+
verboseLog(`Storing expected store transaction with token: ${purchaseToken}`);
|
|
442
|
+
const activeCompanyCode = yield getActiveCompanyCode();
|
|
443
|
+
if (!activeCompanyCode) {
|
|
354
444
|
console.error("[Insert Affiliate] Company code is not set. Please initialize the SDK with a valid company code.");
|
|
445
|
+
verboseLog("Cannot store transaction: no company code available");
|
|
355
446
|
return;
|
|
356
447
|
}
|
|
357
448
|
const shortCode = yield returnInsertAffiliateIdentifier();
|
|
358
449
|
if (!shortCode) {
|
|
359
450
|
console.error("[Insert Affiliate] No affiliate identifier found. Please set one before tracking events.");
|
|
451
|
+
verboseLog("Cannot store transaction: no affiliate identifier available");
|
|
360
452
|
return;
|
|
361
453
|
}
|
|
454
|
+
verboseLog(`Company code: ${activeCompanyCode}, Short code: ${shortCode}`);
|
|
362
455
|
// Build JSON payload
|
|
363
456
|
const payload = {
|
|
364
457
|
UUID: purchaseToken,
|
|
365
|
-
companyCode,
|
|
458
|
+
companyCode: activeCompanyCode,
|
|
366
459
|
shortCode,
|
|
367
460
|
storedDate: new Date().toISOString(), // ISO8601 format
|
|
368
461
|
};
|
|
369
462
|
console.log("[Insert Affiliate] Storing expected transaction: ", payload);
|
|
463
|
+
verboseLog("Making API call to store expected transaction...");
|
|
370
464
|
try {
|
|
371
465
|
const response = yield fetch("https://api.insertaffiliate.com/v1/api/app-store-webhook/create-expected-transaction", {
|
|
372
466
|
method: "POST",
|
|
@@ -375,47 +469,63 @@ const DeepLinkIapProvider = ({ children, }) => {
|
|
|
375
469
|
},
|
|
376
470
|
body: JSON.stringify(payload),
|
|
377
471
|
});
|
|
472
|
+
verboseLog(`API response status: ${response.status}`);
|
|
378
473
|
if (response.ok) {
|
|
379
474
|
console.info("[Insert Affiliate] Expected transaction stored successfully.");
|
|
475
|
+
verboseLog("Expected transaction stored successfully on server");
|
|
380
476
|
}
|
|
381
477
|
else {
|
|
382
478
|
const errorText = yield response.text();
|
|
383
479
|
console.error(`[Insert Affiliate] Failed to store expected transaction with status code: ${response.status}. Response: ${errorText}`);
|
|
480
|
+
verboseLog(`API error response: ${errorText}`);
|
|
384
481
|
}
|
|
385
482
|
}
|
|
386
483
|
catch (error) {
|
|
387
484
|
console.error(`[Insert Affiliate] Error storing expected transaction: ${error}`);
|
|
485
|
+
verboseLog(`Network error storing transaction: ${error}`);
|
|
388
486
|
}
|
|
389
487
|
});
|
|
390
488
|
// MARK: Track Event
|
|
391
489
|
const trackEvent = (eventName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
392
490
|
try {
|
|
393
|
-
|
|
491
|
+
verboseLog(`Tracking event: ${eventName}`);
|
|
492
|
+
const activeCompanyCode = yield getActiveCompanyCode();
|
|
493
|
+
if (!activeCompanyCode) {
|
|
394
494
|
console.error("[Insert Affiliate] Company code is not set. Please initialize the SDK with a valid company code.");
|
|
495
|
+
verboseLog("Cannot track event: no company code available");
|
|
395
496
|
return Promise.resolve();
|
|
396
497
|
}
|
|
397
|
-
console.log("track event called with - companyCode: ",
|
|
498
|
+
console.log("track event called with - companyCode: ", activeCompanyCode);
|
|
398
499
|
if (!referrerLink || !userId) {
|
|
399
500
|
console.warn('[Insert Affiliate] No affiliate identifier found. Please set one before tracking events.');
|
|
501
|
+
verboseLog("Cannot track event: no affiliate identifier available");
|
|
400
502
|
return Promise.resolve();
|
|
401
503
|
}
|
|
504
|
+
const deepLinkParam = `${referrerLink}-${userId}`;
|
|
505
|
+
verboseLog(`Deep link param: ${deepLinkParam}`);
|
|
402
506
|
const payload = {
|
|
403
507
|
eventName,
|
|
404
|
-
deepLinkParam:
|
|
405
|
-
companyId:
|
|
508
|
+
deepLinkParam: deepLinkParam,
|
|
509
|
+
companyId: activeCompanyCode,
|
|
406
510
|
};
|
|
511
|
+
verboseLog(`Track event payload: ${JSON.stringify(payload)}`);
|
|
512
|
+
verboseLog("Making API call to track event...");
|
|
407
513
|
const response = yield axios_1.default.post('https://api.insertaffiliate.com/v1/trackEvent', payload, {
|
|
408
514
|
headers: { 'Content-Type': 'application/json' },
|
|
409
515
|
});
|
|
516
|
+
verboseLog(`Track event API response status: ${response.status}`);
|
|
410
517
|
if (response.status === 200) {
|
|
411
518
|
console.log('[Insert Affiliate] Event tracked successfully');
|
|
519
|
+
verboseLog("Event tracked successfully on server");
|
|
412
520
|
}
|
|
413
521
|
else {
|
|
414
522
|
console.error(`[Insert Affiliate] Failed to track event with status code: ${response.status}`);
|
|
523
|
+
verboseLog(`Track event API error: status ${response.status}, response: ${JSON.stringify(response.data)}`);
|
|
415
524
|
}
|
|
416
525
|
}
|
|
417
526
|
catch (error) {
|
|
418
527
|
console.error('[Insert Affiliate] Error tracking event:', error);
|
|
528
|
+
verboseLog(`Network error tracking event: ${error}`);
|
|
419
529
|
return Promise.reject(error);
|
|
420
530
|
}
|
|
421
531
|
});
|
|
@@ -10,7 +10,7 @@ declare const useDeepLinkIapProvider: () => {
|
|
|
10
10
|
trackEvent: (eventName: string) => Promise<void>;
|
|
11
11
|
setShortCode: (shortCode: string) => Promise<void>;
|
|
12
12
|
setInsertAffiliateIdentifier: (referringLink: string) => Promise<void | string>;
|
|
13
|
-
initialize: (code: string | null) => Promise<void>;
|
|
13
|
+
initialize: (code: string | null, verboseLogging?: boolean) => Promise<void>;
|
|
14
14
|
isInitialized: boolean;
|
|
15
15
|
};
|
|
16
16
|
export default useDeepLinkIapProvider;
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -15,9 +15,9 @@ The **InsertAffiliateReactNative SDK** is designed for React Native applications
|
|
|
15
15
|
To get started with the InsertAffiliateReactNative SDK:
|
|
16
16
|
|
|
17
17
|
1. [Install the SDK](#installation)
|
|
18
|
-
2. [
|
|
18
|
+
2. [Set up the provider in Index.js and initialize the SDK in App.tsx](#basic-usage)
|
|
19
19
|
3. [Set up in-app purchases (Required)](#in-app-purchase-setup-required)
|
|
20
|
-
4. [Set up deep linking (Required)](#deep-link-setup-required)
|
|
20
|
+
4. [Set up deep linking in Index.js (Required)](#deep-link-setup-required)
|
|
21
21
|
|
|
22
22
|
## Installation
|
|
23
23
|
|
|
@@ -28,45 +28,109 @@ To integrate the InsertAffiliateReactNative SDK into your app:
|
|
|
28
28
|
npm install insert-affiliate-react-native-sdk
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
## Architecture Overview
|
|
32
|
+
|
|
33
|
+
The SDK uses a clean, two-file architecture:
|
|
34
|
+
|
|
35
|
+
- **`index.js`** (Entry Point): Provider wrapper and deep link handling
|
|
36
|
+
- **`App.tsx`** (UI Logic): SDK initialization and your app components
|
|
37
|
+
|
|
38
|
+
This separation ensures clean code organization and proper initialization timing.
|
|
39
|
+
|
|
31
40
|
## Basic Usage
|
|
32
41
|
|
|
33
42
|
Follow the steps below to install the SDK.
|
|
34
43
|
|
|
35
|
-
|
|
44
|
+
### Step 1: Entry Point in `Index.js`
|
|
45
|
+
```javascript
|
|
46
|
+
import React from 'react';
|
|
47
|
+
import {AppRegistry} from 'react-native';
|
|
48
|
+
import App from './App';
|
|
49
|
+
import {name as appName} from './app.json';
|
|
50
|
+
import {DeepLinkIapProvider} from 'insert-affiliate-react-native-sdk';
|
|
51
|
+
|
|
52
|
+
const RootComponent = () => {
|
|
53
|
+
return (
|
|
54
|
+
<DeepLinkIapProvider>
|
|
55
|
+
<App />
|
|
56
|
+
</DeepLinkIapProvider>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
AppRegistry.registerComponent(appName, () => RootComponent);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
#### Step 2: SDK initialization in `App.tsx`
|
|
36
64
|
|
|
37
65
|
First, wrap your with our provider and call the `initialize` method early in your app's lifecycle:
|
|
38
66
|
|
|
39
67
|
```javascript
|
|
40
68
|
const Child = () => {
|
|
41
|
-
const {
|
|
42
|
-
referrerLink,
|
|
43
|
-
subscriptions,
|
|
44
|
-
iapLoading,
|
|
45
|
-
validatePurchaseWithIapticAPI,
|
|
46
|
-
userId,
|
|
47
|
-
userPurchase,
|
|
48
|
-
trackEvent,
|
|
49
|
-
initialize,
|
|
50
|
-
isInitialized,
|
|
51
|
-
} = useDeepLinkIapProvider();
|
|
69
|
+
const { initialize, isInitialized } = useDeepLinkIapProvider();
|
|
52
70
|
|
|
53
71
|
useEffect(() => {
|
|
54
|
-
|
|
72
|
+
if (!isInitialized) {
|
|
73
|
+
initialize("{{ your-company-code }}");
|
|
74
|
+
}
|
|
55
75
|
}, [initialize, isInitialized]);
|
|
56
|
-
|
|
57
|
-
// ...
|
|
58
76
|
}
|
|
59
77
|
|
|
60
78
|
const App = () => {
|
|
61
|
-
return
|
|
62
|
-
<DeepLinkIapProvider>
|
|
63
|
-
<Child />
|
|
64
|
-
</DeepLinkIapProvider>
|
|
65
|
-
);
|
|
79
|
+
return <Child />;
|
|
66
80
|
};
|
|
67
81
|
```
|
|
68
82
|
- Replace `{{ your_company_code }}` with the unique company code associated with your Insert Affiliate account. You can find this code in your dashboard under [Settings](http://app.insertaffiliate.com/settings).
|
|
69
83
|
|
|
84
|
+
### Verbose Logging (Optional)
|
|
85
|
+
|
|
86
|
+
For debugging and troubleshooting, you can enable verbose logging to get detailed insights into the SDK's operations:
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
const Child = () => {
|
|
90
|
+
const { initialize, isInitialized } = useDeepLinkIapProvider();
|
|
91
|
+
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (!isInitialized) {
|
|
94
|
+
// Enable verbose logging (second parameter)
|
|
95
|
+
initialize("{{ your-company-code }}", true);
|
|
96
|
+
}
|
|
97
|
+
}, [initialize, isInitialized]);
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**When verbose logging is enabled, you'll see detailed logs with the `[Insert Affiliate] [VERBOSE]` prefix that show:**
|
|
102
|
+
|
|
103
|
+
- **Initialization Process**: SDK startup, company code validation, AsyncStorage operations
|
|
104
|
+
- **Data Management**: User ID generation, referrer link storage, company code state management
|
|
105
|
+
- **Deep Link Processing**: Input validation, short code detection, API conversion process
|
|
106
|
+
- **API Communication**: Request/response details for all server calls
|
|
107
|
+
- **Event Tracking**: Event parameters, payload construction, success/failure status
|
|
108
|
+
- **Purchase Operations**: Transaction storage, token validation, webhook processing
|
|
109
|
+
|
|
110
|
+
**Example verbose output:**
|
|
111
|
+
```
|
|
112
|
+
[Insert Affiliate] [VERBOSE] Starting SDK initialization...
|
|
113
|
+
[Insert Affiliate] [VERBOSE] Company code provided: Yes
|
|
114
|
+
[Insert Affiliate] [VERBOSE] Verbose logging enabled
|
|
115
|
+
[Insert Affiliate] SDK initialized with company code: your-company-code
|
|
116
|
+
[Insert Affiliate] [VERBOSE] Company code saved to AsyncStorage
|
|
117
|
+
[Insert Affiliate] [VERBOSE] SDK marked as initialized
|
|
118
|
+
[Insert Affiliate] [VERBOSE] Loading stored data from AsyncStorage...
|
|
119
|
+
[Insert Affiliate] [VERBOSE] User ID found: Yes
|
|
120
|
+
[Insert Affiliate] [VERBOSE] Referrer link found: Yes
|
|
121
|
+
[Insert Affiliate] [VERBOSE] Company code found: Yes
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Benefits of verbose logging:**
|
|
125
|
+
- **Debug Deep Linking Issues**: See exactly what links are being processed and how they're converted
|
|
126
|
+
- **Monitor API Communication**: Track all server requests, responses, and error details
|
|
127
|
+
- **Identify Storage Problems**: Understand AsyncStorage read/write operations and state sync
|
|
128
|
+
- **Performance Insights**: Monitor async operation timing and identify bottlenecks
|
|
129
|
+
- **Integration Troubleshooting**: Quickly identify configuration or setup issues
|
|
130
|
+
|
|
131
|
+
⚠️ **Important**: Disable verbose logging in production builds to avoid exposing sensitive debugging information and to optimize performance.
|
|
132
|
+
|
|
133
|
+
|
|
70
134
|
## In-App Purchase Setup [Required]
|
|
71
135
|
Insert Affiliate requires a Receipt Verification platform to validate in-app purchases. You must choose **one** of our supported partners:
|
|
72
136
|
- [RevenueCat](https://www.revenuecat.com/)
|
|
@@ -79,10 +143,12 @@ Insert Affiliate requires a Receipt Verification platform to validate in-app pur
|
|
|
79
143
|
First, complete the [RevenueCat SDK installation](https://www.revenuecat.com/docs/getting-started/installation/reactnative). Then modify your `App.tsx`:
|
|
80
144
|
|
|
81
145
|
```javascript
|
|
82
|
-
import {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
146
|
+
import React, {useEffect} from 'react';
|
|
147
|
+
import {AppRegistry} from 'react-native';
|
|
148
|
+
import branch from 'react-native-branch';
|
|
149
|
+
import App from './App';
|
|
150
|
+
import {name as appName} from './app.json';
|
|
151
|
+
import {useDeepLinkIapProvider, DeepLinkIapProvider} from 'insert-affiliate-react-native-sdk';
|
|
86
152
|
|
|
87
153
|
// ... //
|
|
88
154
|
const {
|
|
@@ -195,10 +261,7 @@ const Child = () => {
|
|
|
195
261
|
|
|
196
262
|
const App = () => {
|
|
197
263
|
return (
|
|
198
|
-
|
|
199
|
-
<DeepLinkIapProvider>
|
|
200
|
-
<Child />
|
|
201
|
-
</DeepLinkIapProvider>
|
|
264
|
+
<Child />
|
|
202
265
|
);
|
|
203
266
|
};
|
|
204
267
|
|
|
@@ -238,7 +301,7 @@ Ensure you import the necessary dependencies, including `Platform` and `useDeepL
|
|
|
238
301
|
|
|
239
302
|
```javascript
|
|
240
303
|
import { Platform } from 'react-native';
|
|
241
|
-
import {
|
|
304
|
+
import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
|
|
242
305
|
import { requestSubscription } from 'react-native-iap';
|
|
243
306
|
|
|
244
307
|
const { returnUserAccountTokenAndStoreExpectedTransaction } = useDeepLinkIapProvider();
|
|
@@ -322,38 +385,33 @@ To set up deep linking with Branch.io, follow these steps:
|
|
|
322
385
|
|
|
323
386
|
1. Create a deep link in Branch and pass it to our dashboard when an affiliate signs up.
|
|
324
387
|
- Example: [Create Affiliate](https://docs.insertaffiliate.com/create-affiliate).
|
|
325
|
-
2. Modify Your Deep Link Handling in `
|
|
326
|
-
|
|
388
|
+
2. Modify Your Deep Link Handling in `Index.js`
|
|
389
|
+
- After setting up your Branch integration, add the following code to your app:
|
|
327
390
|
|
|
328
391
|
|
|
329
392
|
#### Example with RevenueCat
|
|
330
393
|
```javascript
|
|
331
|
-
import { DeepLinkIapProvider
|
|
332
|
-
import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
|
|
394
|
+
import {useDeepLinkIapProvider, DeepLinkIapProvider} from 'insert-affiliate-react-native-sdk';
|
|
333
395
|
|
|
334
396
|
//...
|
|
397
|
+
const DeepLinkHandler = () => {
|
|
335
398
|
const {setInsertAffiliateIdentifier} = useDeepLinkIapProvider();
|
|
336
399
|
|
|
337
400
|
useEffect(() => {
|
|
338
|
-
if (!isInitialized) return;
|
|
339
|
-
|
|
340
401
|
const branchSubscription = branch.subscribe(async ({error, params}) => {
|
|
341
402
|
if (error) {
|
|
342
403
|
console.error('Error from Branch:', error);
|
|
343
404
|
return;
|
|
344
405
|
}
|
|
345
406
|
|
|
346
|
-
if (!params) {
|
|
347
|
-
return
|
|
348
|
-
}
|
|
349
407
|
if (params['+clicked_branch_link']) {
|
|
350
408
|
const referringLink = params['~referring_link'];
|
|
351
409
|
if (referringLink) {
|
|
352
410
|
try {
|
|
353
|
-
|
|
411
|
+
let insertAffiliateIdentifier = await setInsertAffiliateIdentifier(referringLink);
|
|
354
412
|
|
|
355
413
|
if (insertAffiliateIdentifier) {
|
|
356
|
-
await Purchases.setAttributes({"insert_affiliate" :
|
|
414
|
+
await Purchases.setAttributes({"insert_affiliate" : insertAffiliateIdentifier});
|
|
357
415
|
}
|
|
358
416
|
|
|
359
417
|
} catch (err) {
|
|
@@ -363,35 +421,68 @@ import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
|
|
|
363
421
|
}
|
|
364
422
|
});
|
|
365
423
|
|
|
366
|
-
// Cleanup the subscription on component unmount
|
|
367
424
|
return () => {
|
|
368
425
|
branchSubscription();
|
|
369
426
|
};
|
|
370
|
-
}, [setInsertAffiliateIdentifier
|
|
427
|
+
}, [setInsertAffiliateIdentifier]);
|
|
428
|
+
|
|
429
|
+
return <App />;
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
const RootComponent = () => {
|
|
433
|
+
return (
|
|
434
|
+
<DeepLinkIapProvider>
|
|
435
|
+
<DeepLinkHandler />
|
|
436
|
+
</DeepLinkIapProvider>
|
|
437
|
+
);
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
AppRegistry.registerComponent(appName, () => RootComponent);
|
|
441
|
+
|
|
371
442
|
//...
|
|
372
443
|
```
|
|
373
444
|
|
|
374
445
|
#### Example with Iaptic / App Store Direct Integration / Google Play Direct Integration
|
|
375
446
|
```javascript
|
|
376
447
|
import branch from 'react-native-branch';
|
|
377
|
-
import { DeepLinkIapProvider
|
|
378
|
-
const {setInsertAffiliateIdentifier} = useDeepLinkIapProvider();
|
|
448
|
+
import {useDeepLinkIapProvider, DeepLinkIapProvider} from 'insert-affiliate-react-native-sdk';
|
|
379
449
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
450
|
+
const DeepLinkHandler = () => {
|
|
451
|
+
const {setInsertAffiliateIdentifier} = useDeepLinkIapProvider();
|
|
452
|
+
|
|
453
|
+
React.useEffect(() => {
|
|
454
|
+
const branchSubscription = branch.subscribe(async ({error, params}) => {
|
|
455
|
+
if (error) {
|
|
456
|
+
console.error('Error from Branch:', error);
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (params['+clicked_branch_link']) {
|
|
461
|
+
const referringLink = params['~referring_link'];
|
|
462
|
+
if (referringLink) {
|
|
463
|
+
try {
|
|
464
|
+
await setInsertAffiliateIdentifier(referringLink);
|
|
465
|
+
console.log('Affiliate identifier set successfully.');
|
|
466
|
+
} catch (err) {
|
|
467
|
+
console.error('Error setting affiliate identifier:', err);
|
|
468
|
+
}
|
|
391
469
|
}
|
|
392
|
-
|
|
393
|
-
});
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
return () => branchSubscription();
|
|
474
|
+
}, [setInsertAffiliateIdentifier]);
|
|
394
475
|
|
|
476
|
+
return <App />;
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
const RootComponent = () => {
|
|
480
|
+
return (
|
|
481
|
+
<DeepLinkIapProvider>
|
|
482
|
+
<DeepLinkHandler />
|
|
483
|
+
</DeepLinkIapProvider>
|
|
484
|
+
);
|
|
485
|
+
};
|
|
395
486
|
```
|
|
396
487
|
|
|
397
488
|
## Additional Features
|
|
@@ -31,7 +31,7 @@ type T_DEEPLINK_IAP_CONTEXT = {
|
|
|
31
31
|
setInsertAffiliateIdentifier: (
|
|
32
32
|
referringLink: string
|
|
33
33
|
) => Promise<void | string>;
|
|
34
|
-
initialize: (code: string | null) => Promise<void>;
|
|
34
|
+
initialize: (code: string | null, verboseLogging?: boolean) => Promise<void>;
|
|
35
35
|
isInitialized: boolean;
|
|
36
36
|
};
|
|
37
37
|
|
|
@@ -75,7 +75,7 @@ export const DeepLinkIapContext = createContext<T_DEEPLINK_IAP_CONTEXT>({
|
|
|
75
75
|
trackEvent: async (eventName: string) => {},
|
|
76
76
|
setShortCode: async (shortCode: string) => {},
|
|
77
77
|
setInsertAffiliateIdentifier: async (referringLink: string) => {},
|
|
78
|
-
initialize: async (code: string | null) => {},
|
|
78
|
+
initialize: async (code: string | null, verboseLogging?: boolean) => {},
|
|
79
79
|
isInitialized: false,
|
|
80
80
|
});
|
|
81
81
|
|
|
@@ -86,9 +86,18 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
86
86
|
const [userId, setUserId] = useState<string>('');
|
|
87
87
|
const [companyCode, setCompanyCode] = useState<string | null>(null);
|
|
88
88
|
const [isInitialized, setIsInitialized] = useState<boolean>(false);
|
|
89
|
+
const [verboseLogging, setVerboseLogging] = useState<boolean>(false);
|
|
89
90
|
|
|
90
91
|
// MARK: Initialize the SDK
|
|
91
|
-
const initialize = async (companyCode: string | null): Promise<void> => {
|
|
92
|
+
const initialize = async (companyCode: string | null, verboseLogging: boolean = false): Promise<void> => {
|
|
93
|
+
setVerboseLogging(verboseLogging);
|
|
94
|
+
|
|
95
|
+
if (verboseLogging) {
|
|
96
|
+
console.log('[Insert Affiliate] [VERBOSE] Starting SDK initialization...');
|
|
97
|
+
console.log('[Insert Affiliate] [VERBOSE] Company code provided:', companyCode ? 'Yes' : 'No');
|
|
98
|
+
console.log('[Insert Affiliate] [VERBOSE] Verbose logging enabled');
|
|
99
|
+
}
|
|
100
|
+
|
|
92
101
|
if (isInitialized) {
|
|
93
102
|
console.error('[Insert Affiliate] SDK is already initialized.');
|
|
94
103
|
return;
|
|
@@ -101,11 +110,18 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
101
110
|
console.log(
|
|
102
111
|
`[Insert Affiliate] SDK initialized with company code: ${companyCode}`
|
|
103
112
|
);
|
|
113
|
+
if (verboseLogging) {
|
|
114
|
+
console.log('[Insert Affiliate] [VERBOSE] Company code saved to AsyncStorage');
|
|
115
|
+
console.log('[Insert Affiliate] [VERBOSE] SDK marked as initialized');
|
|
116
|
+
}
|
|
104
117
|
} else {
|
|
105
118
|
console.warn(
|
|
106
119
|
'[Insert Affiliate] SDK initialized without a company code.'
|
|
107
120
|
);
|
|
108
121
|
setIsInitialized(true);
|
|
122
|
+
if (verboseLogging) {
|
|
123
|
+
console.log('[Insert Affiliate] [VERBOSE] No company code provided, SDK initialized in limited mode');
|
|
124
|
+
}
|
|
109
125
|
}
|
|
110
126
|
};
|
|
111
127
|
|
|
@@ -114,15 +130,28 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
114
130
|
useEffect(() => {
|
|
115
131
|
const fetchAsyncEssentials = async () => {
|
|
116
132
|
try {
|
|
133
|
+
verboseLog('Loading stored data from AsyncStorage...');
|
|
117
134
|
const uId = await getValueFromAsync(ASYNC_KEYS.USER_ID);
|
|
118
135
|
const refLink = await getValueFromAsync(ASYNC_KEYS.REFERRER_LINK);
|
|
136
|
+
const companyCodeFromStorage = await getValueFromAsync(ASYNC_KEYS.COMPANY_CODE);
|
|
137
|
+
|
|
138
|
+
verboseLog(`User ID found: ${uId ? 'Yes' : 'No'}`);
|
|
139
|
+
verboseLog(`Referrer link found: ${refLink ? 'Yes' : 'No'}`);
|
|
140
|
+
verboseLog(`Company code found: ${companyCodeFromStorage ? 'Yes' : 'No'}`);
|
|
119
141
|
|
|
120
142
|
if (uId && refLink) {
|
|
121
143
|
setUserId(uId);
|
|
122
144
|
setReferrerLink(refLink);
|
|
145
|
+
verboseLog('User ID and referrer link restored from storage');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (companyCodeFromStorage) {
|
|
149
|
+
setCompanyCode(companyCodeFromStorage);
|
|
150
|
+
verboseLog('Company code restored from storage');
|
|
123
151
|
}
|
|
124
152
|
} catch (error) {
|
|
125
153
|
errorLog(`ERROR ~ fetchAsyncEssentials: ${error}`);
|
|
154
|
+
verboseLog(`Error loading from AsyncStorage: ${error}`);
|
|
126
155
|
}
|
|
127
156
|
};
|
|
128
157
|
|
|
@@ -130,12 +159,17 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
130
159
|
}, []);
|
|
131
160
|
|
|
132
161
|
async function generateThenSetUserID() {
|
|
162
|
+
verboseLog('Getting or generating user ID...');
|
|
133
163
|
let userId = await getValueFromAsync(ASYNC_KEYS.USER_ID);
|
|
164
|
+
|
|
134
165
|
if (!userId) {
|
|
166
|
+
verboseLog('No existing user ID found, generating new one...');
|
|
135
167
|
userId = generateUserID();
|
|
136
168
|
setUserId(userId);
|
|
137
169
|
await saveValueInAsync(ASYNC_KEYS.USER_ID, userId);
|
|
170
|
+
verboseLog(`Generated and saved new user ID: ${userId}`);
|
|
138
171
|
} else {
|
|
172
|
+
verboseLog(`Found existing user ID: ${userId}`);
|
|
139
173
|
setUserId(userId);
|
|
140
174
|
}
|
|
141
175
|
|
|
@@ -173,6 +207,33 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
173
207
|
await AsyncStorage.clear();
|
|
174
208
|
};
|
|
175
209
|
|
|
210
|
+
// Helper function to get company code from state or storage
|
|
211
|
+
const getActiveCompanyCode = async (): Promise<string | null> => {
|
|
212
|
+
verboseLog('Getting active company code...');
|
|
213
|
+
let activeCompanyCode = companyCode;
|
|
214
|
+
verboseLog(`Company code in React state: ${activeCompanyCode || 'empty'}`);
|
|
215
|
+
|
|
216
|
+
if (!activeCompanyCode || (activeCompanyCode.trim() === '' && activeCompanyCode !== null)) {
|
|
217
|
+
verboseLog('Company code not in state, checking AsyncStorage...');
|
|
218
|
+
activeCompanyCode = await getValueFromAsync(ASYNC_KEYS.COMPANY_CODE);
|
|
219
|
+
verboseLog(`Company code in AsyncStorage: ${activeCompanyCode || 'empty'}`);
|
|
220
|
+
|
|
221
|
+
if (activeCompanyCode) {
|
|
222
|
+
// Update state for future use
|
|
223
|
+
setCompanyCode(activeCompanyCode);
|
|
224
|
+
verboseLog('Updated React state with company code from storage');
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return activeCompanyCode;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// Helper function for verbose logging
|
|
231
|
+
const verboseLog = (message: string) => {
|
|
232
|
+
if (verboseLogging) {
|
|
233
|
+
console.log(`[Insert Affiliate] [VERBOSE] ${message}`);
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
176
237
|
// Helper function to log errors
|
|
177
238
|
const errorLog = (message: string, type?: 'error' | 'warn' | 'log') => {
|
|
178
239
|
switch (type) {
|
|
@@ -243,11 +304,37 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
243
304
|
};
|
|
244
305
|
|
|
245
306
|
// MARK: Return Insert Affiliate Identifier
|
|
307
|
+
// Instead of just reading React state
|
|
246
308
|
const returnInsertAffiliateIdentifier = async (): Promise<string | null> => {
|
|
247
309
|
try {
|
|
248
|
-
|
|
310
|
+
verboseLog('Getting insert affiliate identifier...');
|
|
311
|
+
verboseLog(`React state - referrerLink: ${referrerLink || 'empty'}, userId: ${userId || 'empty'}`);
|
|
312
|
+
|
|
313
|
+
// Try React state first
|
|
314
|
+
if (referrerLink && userId) {
|
|
315
|
+
const identifier = `${referrerLink}-${userId}`;
|
|
316
|
+
verboseLog(`Found identifier in React state: ${identifier}`);
|
|
317
|
+
return identifier;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
verboseLog('React state empty, checking AsyncStorage...');
|
|
321
|
+
|
|
322
|
+
// Fallback to async storage if React state is empty
|
|
323
|
+
const storedLink = await getValueFromAsync(ASYNC_KEYS.REFERRER_LINK);
|
|
324
|
+
const storedUserId = await getValueFromAsync(ASYNC_KEYS.USER_ID);
|
|
325
|
+
|
|
326
|
+
verboseLog(`AsyncStorage - storedLink: ${storedLink || 'empty'}, storedUserId: ${storedUserId || 'empty'}`);
|
|
327
|
+
|
|
328
|
+
if (storedLink && storedUserId) {
|
|
329
|
+
const identifier = `${storedLink}-${storedUserId}`;
|
|
330
|
+
verboseLog(`Found identifier in AsyncStorage: ${identifier}`);
|
|
331
|
+
return identifier;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
verboseLog('No affiliate identifier found in state or storage');
|
|
335
|
+
return null;
|
|
249
336
|
} catch (error) {
|
|
250
|
-
|
|
337
|
+
verboseLog(`Error getting affiliate identifier: ${error}`);
|
|
251
338
|
return null;
|
|
252
339
|
}
|
|
253
340
|
};
|
|
@@ -258,85 +345,102 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
258
345
|
referringLink: string
|
|
259
346
|
): Promise<void | string> {
|
|
260
347
|
console.log('[Insert Affiliate] Setting affiliate identifier.');
|
|
348
|
+
verboseLog(`Input referringLink: ${referringLink}`);
|
|
261
349
|
|
|
262
350
|
try {
|
|
351
|
+
verboseLog('Generating or retrieving user ID...');
|
|
263
352
|
const customerID = await generateThenSetUserID();
|
|
264
353
|
console.log(
|
|
265
354
|
'[Insert Affiliate] Completed generateThenSetUserID within setInsertAffiliateIdentifier.'
|
|
266
355
|
);
|
|
356
|
+
verboseLog(`Customer ID: ${customerID}`);
|
|
267
357
|
|
|
268
358
|
if (!referringLink) {
|
|
269
359
|
console.warn('[Insert Affiliate] Referring link is invalid.');
|
|
270
|
-
|
|
360
|
+
verboseLog('Referring link is empty or invalid, storing as-is');
|
|
271
361
|
await storeInsertAffiliateIdentifier({ link: referringLink });
|
|
272
|
-
return `${
|
|
362
|
+
return `${referringLink}-${customerID}`;
|
|
273
363
|
}
|
|
274
364
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
365
|
+
// Get company code from state or storage
|
|
366
|
+
verboseLog('Getting company code...');
|
|
367
|
+
const activeCompanyCode = await getActiveCompanyCode();
|
|
368
|
+
verboseLog(`Active company code: ${activeCompanyCode || 'Not found'}`);
|
|
369
|
+
|
|
370
|
+
if (!activeCompanyCode) {
|
|
371
|
+
console.error(
|
|
372
|
+
'[Insert Affiliate] Company code is not set. Please initialize the SDK with a valid company code.'
|
|
278
373
|
);
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
setCompanyCode(companyCodeFromStorage);
|
|
282
|
-
} else {
|
|
283
|
-
console.error(
|
|
284
|
-
'[Insert Affiliate] Company code is not set. Please initialize the SDK with a valid company code.'
|
|
285
|
-
);
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
374
|
+
verboseLog('Company code missing, cannot proceed with API call');
|
|
375
|
+
return;
|
|
288
376
|
}
|
|
289
377
|
|
|
290
378
|
// Check if referring link is already a short code, if so save it and stop here.
|
|
379
|
+
verboseLog('Checking if referring link is already a short code...');
|
|
291
380
|
if (isShortCode(referringLink)) {
|
|
292
381
|
console.log(
|
|
293
382
|
'[Insert Affiliate] Referring link is already a short code.'
|
|
294
383
|
);
|
|
295
|
-
|
|
384
|
+
verboseLog('Link is already a short code, storing directly');
|
|
296
385
|
await storeInsertAffiliateIdentifier({ link: referringLink });
|
|
297
|
-
return `${
|
|
386
|
+
return `${referringLink}-${customerID}`;
|
|
298
387
|
}
|
|
299
388
|
|
|
389
|
+
verboseLog('Link is not a short code, will convert via API');
|
|
390
|
+
|
|
300
391
|
// If the code is not already a short code, encode it raedy to send to our endpoint to return the short code. Save it before making the call in case something goes wrong
|
|
301
392
|
// Encode the referring link
|
|
393
|
+
verboseLog('Encoding referring link for API call...');
|
|
302
394
|
const encodedAffiliateLink = encodeURIComponent(referringLink);
|
|
303
395
|
if (!encodedAffiliateLink) {
|
|
304
396
|
console.error('[Insert Affiliate] Failed to encode affiliate link.');
|
|
305
|
-
|
|
306
|
-
let heldReferrerLinkBeforeAsyncStateUpdate = referrerLink;
|
|
397
|
+
verboseLog('Failed to encode link, storing original');
|
|
307
398
|
await storeInsertAffiliateIdentifier({ link: referringLink });
|
|
308
|
-
return `${
|
|
399
|
+
return `${referringLink}-${customerID}`;
|
|
309
400
|
}
|
|
310
401
|
|
|
311
402
|
// Create the request URL
|
|
312
|
-
const urlString = `https://api.insertaffiliate.com/V1/convert-deep-link-to-short-link?companyId=${
|
|
403
|
+
const urlString = `https://api.insertaffiliate.com/V1/convert-deep-link-to-short-link?companyId=${activeCompanyCode}&deepLinkUrl=${encodedAffiliateLink}`;
|
|
313
404
|
console.log('[Insert Affiliate] urlString .', urlString);
|
|
405
|
+
verboseLog('Making API request to convert deep link to short code...');
|
|
406
|
+
|
|
314
407
|
const response = await axios.get(urlString, {
|
|
315
408
|
headers: {
|
|
316
409
|
'Content-Type': 'application/json',
|
|
317
410
|
},
|
|
318
411
|
});
|
|
412
|
+
|
|
413
|
+
verboseLog(`API response status: ${response.status}`);
|
|
319
414
|
|
|
320
415
|
// Call to the backend for the short code and save the resolse in valid
|
|
321
416
|
if (response.status === 200 && response.data.shortLink) {
|
|
322
417
|
const shortLink = response.data.shortLink;
|
|
323
418
|
console.log('[Insert Affiliate] Short link received:', shortLink);
|
|
419
|
+
verboseLog(`Successfully converted to short link: ${shortLink}`);
|
|
420
|
+
verboseLog('Storing short link to AsyncStorage...');
|
|
421
|
+
await storeInsertAffiliateIdentifier({ link: shortLink });
|
|
422
|
+
verboseLog('Short link stored successfully');
|
|
324
423
|
return `${shortLink}-${customerID}`;
|
|
325
424
|
} else {
|
|
326
425
|
console.warn('[Insert Affiliate] Unexpected response format.');
|
|
327
|
-
|
|
426
|
+
verboseLog(`Unexpected API response. Status: ${response.status}, Data: ${JSON.stringify(response.data)}`);
|
|
427
|
+
verboseLog('Storing original link as fallback');
|
|
328
428
|
await storeInsertAffiliateIdentifier({ link: referringLink });
|
|
329
|
-
return `${
|
|
429
|
+
return `${referringLink}-${customerID}`;
|
|
330
430
|
}
|
|
331
431
|
} catch (error) {
|
|
332
432
|
console.error('[Insert Affiliate] Error:', error);
|
|
433
|
+
verboseLog(`Error in setInsertAffiliateIdentifier: ${error}`);
|
|
333
434
|
}
|
|
334
435
|
};
|
|
335
436
|
|
|
336
437
|
async function storeInsertAffiliateIdentifier({ link }: { link: string }) {
|
|
337
438
|
console.log(`[Insert Affiliate] Storing affiliate identifier: ${link}`);
|
|
439
|
+
verboseLog(`Updating React state with referrer link: ${link}`);
|
|
338
440
|
setReferrerLink(link);
|
|
441
|
+
verboseLog(`Saving referrer link to AsyncStorage...`);
|
|
339
442
|
await saveValueInAsync(ASYNC_KEYS.REFERRER_LINK, link);
|
|
443
|
+
verboseLog(`Referrer link saved to AsyncStorage successfully`);
|
|
340
444
|
}
|
|
341
445
|
|
|
342
446
|
const validatePurchaseWithIapticAPI = async (
|
|
@@ -419,26 +523,34 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
419
523
|
};
|
|
420
524
|
|
|
421
525
|
const storeExpectedStoreTransaction = async (purchaseToken: string): Promise<void> => {
|
|
422
|
-
|
|
526
|
+
verboseLog(`Storing expected store transaction with token: ${purchaseToken}`);
|
|
527
|
+
|
|
528
|
+
const activeCompanyCode = await getActiveCompanyCode();
|
|
529
|
+
if (!activeCompanyCode) {
|
|
423
530
|
console.error("[Insert Affiliate] Company code is not set. Please initialize the SDK with a valid company code.");
|
|
531
|
+
verboseLog("Cannot store transaction: no company code available");
|
|
424
532
|
return;
|
|
425
533
|
}
|
|
426
534
|
|
|
427
535
|
const shortCode = await returnInsertAffiliateIdentifier();
|
|
428
536
|
if (!shortCode) {
|
|
429
537
|
console.error("[Insert Affiliate] No affiliate identifier found. Please set one before tracking events.");
|
|
538
|
+
verboseLog("Cannot store transaction: no affiliate identifier available");
|
|
430
539
|
return;
|
|
431
540
|
}
|
|
432
541
|
|
|
542
|
+
verboseLog(`Company code: ${activeCompanyCode}, Short code: ${shortCode}`);
|
|
543
|
+
|
|
433
544
|
// Build JSON payload
|
|
434
545
|
const payload = {
|
|
435
546
|
UUID: purchaseToken,
|
|
436
|
-
companyCode,
|
|
547
|
+
companyCode: activeCompanyCode,
|
|
437
548
|
shortCode,
|
|
438
549
|
storedDate: new Date().toISOString(), // ISO8601 format
|
|
439
550
|
};
|
|
440
551
|
|
|
441
552
|
console.log("[Insert Affiliate] Storing expected transaction: ", payload);
|
|
553
|
+
verboseLog("Making API call to store expected transaction...");
|
|
442
554
|
|
|
443
555
|
try {
|
|
444
556
|
const response = await fetch("https://api.insertaffiliate.com/v1/api/app-store-webhook/create-expected-transaction", {
|
|
@@ -449,40 +561,57 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
449
561
|
body: JSON.stringify(payload),
|
|
450
562
|
});
|
|
451
563
|
|
|
564
|
+
verboseLog(`API response status: ${response.status}`);
|
|
565
|
+
|
|
452
566
|
if (response.ok) {
|
|
453
567
|
console.info("[Insert Affiliate] Expected transaction stored successfully.");
|
|
568
|
+
verboseLog("Expected transaction stored successfully on server");
|
|
454
569
|
} else {
|
|
455
570
|
const errorText = await response.text();
|
|
456
571
|
console.error(`[Insert Affiliate] Failed to store expected transaction with status code: ${response.status}. Response: ${errorText}`);
|
|
572
|
+
verboseLog(`API error response: ${errorText}`);
|
|
457
573
|
}
|
|
458
574
|
} catch (error) {
|
|
459
575
|
console.error(`[Insert Affiliate] Error storing expected transaction: ${error}`);
|
|
576
|
+
verboseLog(`Network error storing transaction: ${error}`);
|
|
460
577
|
}
|
|
461
578
|
};
|
|
462
579
|
|
|
463
580
|
// MARK: Track Event
|
|
464
581
|
const trackEvent = async (eventName: string): Promise<void> => {
|
|
465
582
|
try {
|
|
466
|
-
|
|
583
|
+
verboseLog(`Tracking event: ${eventName}`);
|
|
584
|
+
|
|
585
|
+
const activeCompanyCode = await getActiveCompanyCode();
|
|
586
|
+
if (!activeCompanyCode) {
|
|
467
587
|
console.error("[Insert Affiliate] Company code is not set. Please initialize the SDK with a valid company code.");
|
|
588
|
+
verboseLog("Cannot track event: no company code available");
|
|
468
589
|
return Promise.resolve();
|
|
469
590
|
}
|
|
470
591
|
|
|
471
|
-
console.log("track event called with - companyCode: ",
|
|
592
|
+
console.log("track event called with - companyCode: ", activeCompanyCode);
|
|
472
593
|
|
|
473
594
|
if (!referrerLink || !userId) {
|
|
474
595
|
console.warn(
|
|
475
596
|
'[Insert Affiliate] No affiliate identifier found. Please set one before tracking events.'
|
|
476
597
|
);
|
|
598
|
+
verboseLog("Cannot track event: no affiliate identifier available");
|
|
477
599
|
return Promise.resolve();
|
|
478
600
|
}
|
|
479
601
|
|
|
602
|
+
const deepLinkParam = `${referrerLink}-${userId}`;
|
|
603
|
+
verboseLog(`Deep link param: ${deepLinkParam}`);
|
|
604
|
+
|
|
480
605
|
const payload = {
|
|
481
606
|
eventName,
|
|
482
|
-
deepLinkParam:
|
|
483
|
-
companyId:
|
|
607
|
+
deepLinkParam: deepLinkParam,
|
|
608
|
+
companyId: activeCompanyCode,
|
|
484
609
|
};
|
|
485
610
|
|
|
611
|
+
verboseLog(`Track event payload: ${JSON.stringify(payload)}`);
|
|
612
|
+
|
|
613
|
+
verboseLog("Making API call to track event...");
|
|
614
|
+
|
|
486
615
|
const response = await axios.post(
|
|
487
616
|
'https://api.insertaffiliate.com/v1/trackEvent',
|
|
488
617
|
payload,
|
|
@@ -491,15 +620,20 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
491
620
|
}
|
|
492
621
|
);
|
|
493
622
|
|
|
623
|
+
verboseLog(`Track event API response status: ${response.status}`);
|
|
624
|
+
|
|
494
625
|
if (response.status === 200) {
|
|
495
626
|
console.log('[Insert Affiliate] Event tracked successfully');
|
|
627
|
+
verboseLog("Event tracked successfully on server");
|
|
496
628
|
} else {
|
|
497
629
|
console.error(
|
|
498
630
|
`[Insert Affiliate] Failed to track event with status code: ${response.status}`
|
|
499
631
|
);
|
|
632
|
+
verboseLog(`Track event API error: status ${response.status}, response: ${JSON.stringify(response.data)}`);
|
|
500
633
|
}
|
|
501
634
|
} catch (error) {
|
|
502
635
|
console.error('[Insert Affiliate] Error tracking event:', error);
|
|
636
|
+
verboseLog(`Network error tracking event: ${error}`);
|
|
503
637
|
return Promise.reject(error);
|
|
504
638
|
}
|
|
505
639
|
};
|