insert-affiliate-react-native-sdk 1.4.0 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/DeepLinkIapProvider.d.ts +2 -0
- package/dist/DeepLinkIapProvider.js +92 -17
- package/dist/useDeepLinkIapProvider.d.ts +2 -0
- package/dist/useDeepLinkIapProvider.js +3 -1
- package/package.json +1 -1
- package/readme.md +105 -7
- package/src/DeepLinkIapProvider.tsx +95 -1
- package/src/useDeepLinkIapProvider.tsx +4 -0
|
@@ -10,6 +10,8 @@ type T_DEEPLINK_IAP_CONTEXT = {
|
|
|
10
10
|
userId: string;
|
|
11
11
|
returnInsertAffiliateIdentifier: () => Promise<string | null>;
|
|
12
12
|
validatePurchaseWithIapticAPI: (jsonIapPurchase: CustomPurchase, iapticAppId: string, iapticAppName: string, iapticPublicKey: string) => Promise<boolean>;
|
|
13
|
+
returnUserAccountTokenAndStoreExpectedTransaction: () => Promise<string | null>;
|
|
14
|
+
storeExpectedStoreTransaction: (purchaseToken: string) => Promise<void>;
|
|
13
15
|
trackEvent: (eventName: string) => Promise<void>;
|
|
14
16
|
setShortCode: (shortCode: string) => Promise<void>;
|
|
15
17
|
setInsertAffiliateIdentifier: (referringLink: string) => Promise<void | string>;
|
|
@@ -15,23 +15,13 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) ||
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
35
25
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
26
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
27
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -55,6 +45,7 @@ const ASYNC_KEYS = {
|
|
|
55
45
|
USER_PURCHASE: '@app_user_purchase',
|
|
56
46
|
USER_ID: '@app_user_id',
|
|
57
47
|
COMPANY_CODE: '@app_company_code',
|
|
48
|
+
USER_ACCOUNT_TOKEN: '@app_user_account_token',
|
|
58
49
|
};
|
|
59
50
|
// STARTING CONTEXT IMPLEMENTATION
|
|
60
51
|
exports.DeepLinkIapContext = (0, react_1.createContext)({
|
|
@@ -62,6 +53,8 @@ exports.DeepLinkIapContext = (0, react_1.createContext)({
|
|
|
62
53
|
userId: '',
|
|
63
54
|
returnInsertAffiliateIdentifier: () => __awaiter(void 0, void 0, void 0, function* () { return ''; }),
|
|
64
55
|
validatePurchaseWithIapticAPI: (jsonIapPurchase, iapticAppId, iapticAppName, iapticPublicKey) => __awaiter(void 0, void 0, void 0, function* () { return false; }),
|
|
56
|
+
returnUserAccountTokenAndStoreExpectedTransaction: () => __awaiter(void 0, void 0, void 0, function* () { return ''; }),
|
|
57
|
+
storeExpectedStoreTransaction: (purchaseToken) => __awaiter(void 0, void 0, void 0, function* () { }),
|
|
65
58
|
trackEvent: (eventName) => __awaiter(void 0, void 0, void 0, function* () { }),
|
|
66
59
|
setShortCode: (shortCode) => __awaiter(void 0, void 0, void 0, function* () { }),
|
|
67
60
|
setInsertAffiliateIdentifier: (referringLink) => __awaiter(void 0, void 0, void 0, function* () { }),
|
|
@@ -178,6 +171,41 @@ const DeepLinkIapProvider = ({ children, }) => {
|
|
|
178
171
|
yield storeInsertAffiliateIdentifier({ link: capitalisedShortCode });
|
|
179
172
|
});
|
|
180
173
|
}
|
|
174
|
+
function getOrCreateUserAccountToken() {
|
|
175
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
176
|
+
let userAccountToken = yield getValueFromAsync(ASYNC_KEYS.USER_ACCOUNT_TOKEN);
|
|
177
|
+
if (!userAccountToken) {
|
|
178
|
+
userAccountToken = UUID();
|
|
179
|
+
yield saveValueInAsync(ASYNC_KEYS.USER_ACCOUNT_TOKEN, userAccountToken);
|
|
180
|
+
}
|
|
181
|
+
return userAccountToken;
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
;
|
|
185
|
+
const returnUserAccountTokenAndStoreExpectedTransaction = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
186
|
+
try {
|
|
187
|
+
const shortCode = yield returnInsertAffiliateIdentifier();
|
|
188
|
+
if (!shortCode) {
|
|
189
|
+
console.log('[Insert Affiliate] No affiliate stored - not saving expected transaction.');
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
const userAccountToken = yield getOrCreateUserAccountToken();
|
|
193
|
+
console.log('[Insert Affiliate] User account token:', userAccountToken);
|
|
194
|
+
if (!userAccountToken) {
|
|
195
|
+
console.error('[Insert Affiliate] Failed to generate user account token.');
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
yield storeExpectedStoreTransaction(userAccountToken);
|
|
200
|
+
return userAccountToken;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
console.error('[Insert Affiliate] Error in returnUserAccountTokenAndStoreExpectedTransaction:', error);
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
;
|
|
208
|
+
});
|
|
181
209
|
// MARK: Return Insert Affiliate Identifier
|
|
182
210
|
const returnInsertAffiliateIdentifier = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
183
211
|
try {
|
|
@@ -321,6 +349,44 @@ const DeepLinkIapProvider = ({ children, }) => {
|
|
|
321
349
|
return false;
|
|
322
350
|
}
|
|
323
351
|
});
|
|
352
|
+
const storeExpectedStoreTransaction = (purchaseToken) => __awaiter(void 0, void 0, void 0, function* () {
|
|
353
|
+
if (!companyCode || (companyCode.trim() === '' && companyCode !== null)) {
|
|
354
|
+
console.error("[Insert Affiliate] Company code is not set. Please initialize the SDK with a valid company code.");
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
const shortCode = yield returnInsertAffiliateIdentifier();
|
|
358
|
+
if (!shortCode) {
|
|
359
|
+
console.error("[Insert Affiliate] No affiliate identifier found. Please set one before tracking events.");
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
// Build JSON payload
|
|
363
|
+
const payload = {
|
|
364
|
+
UUID: purchaseToken,
|
|
365
|
+
companyCode,
|
|
366
|
+
shortCode,
|
|
367
|
+
storedDate: new Date().toISOString(), // ISO8601 format
|
|
368
|
+
};
|
|
369
|
+
console.log("[Insert Affiliate] Storing expected transaction: ", payload);
|
|
370
|
+
try {
|
|
371
|
+
const response = yield fetch("https://api.insertaffiliate.com/v1/api/app-store-webhook/create-expected-transaction", {
|
|
372
|
+
method: "POST",
|
|
373
|
+
headers: {
|
|
374
|
+
"Content-Type": "application/json",
|
|
375
|
+
},
|
|
376
|
+
body: JSON.stringify(payload),
|
|
377
|
+
});
|
|
378
|
+
if (response.ok) {
|
|
379
|
+
console.info("[Insert Affiliate] Expected transaction stored successfully.");
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
const errorText = yield response.text();
|
|
383
|
+
console.error(`[Insert Affiliate] Failed to store expected transaction with status code: ${response.status}. Response: ${errorText}`);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
catch (error) {
|
|
387
|
+
console.error(`[Insert Affiliate] Error storing expected transaction: ${error}`);
|
|
388
|
+
}
|
|
389
|
+
});
|
|
324
390
|
// MARK: Track Event
|
|
325
391
|
const trackEvent = (eventName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
326
392
|
try {
|
|
@@ -352,6 +418,8 @@ const DeepLinkIapProvider = ({ children, }) => {
|
|
|
352
418
|
userId,
|
|
353
419
|
setShortCode,
|
|
354
420
|
returnInsertAffiliateIdentifier,
|
|
421
|
+
storeExpectedStoreTransaction,
|
|
422
|
+
returnUserAccountTokenAndStoreExpectedTransaction,
|
|
355
423
|
validatePurchaseWithIapticAPI,
|
|
356
424
|
trackEvent,
|
|
357
425
|
setInsertAffiliateIdentifier,
|
|
@@ -360,3 +428,10 @@ const DeepLinkIapProvider = ({ children, }) => {
|
|
|
360
428
|
} }, children));
|
|
361
429
|
};
|
|
362
430
|
exports.default = DeepLinkIapProvider;
|
|
431
|
+
function UUID() {
|
|
432
|
+
// Generate a random UUID (version 4)
|
|
433
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
434
|
+
const r = (Math.random() * 16) | 0, v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
435
|
+
return v.toString(16);
|
|
436
|
+
});
|
|
437
|
+
}
|
|
@@ -4,6 +4,8 @@ declare const useDeepLinkIapProvider: () => {
|
|
|
4
4
|
validatePurchaseWithIapticAPI: (jsonIapPurchase: {
|
|
5
5
|
[key: string]: any;
|
|
6
6
|
}, iapticAppId: string, iapticAppName: string, iapticPublicKey: string) => Promise<boolean>;
|
|
7
|
+
storeExpectedStoreTransaction: (purchaseToken: string) => Promise<void>;
|
|
8
|
+
returnUserAccountTokenAndStoreExpectedTransaction: () => Promise<string | null>;
|
|
7
9
|
returnInsertAffiliateIdentifier: () => Promise<string | null>;
|
|
8
10
|
trackEvent: (eventName: string) => Promise<void>;
|
|
9
11
|
setShortCode: (shortCode: string) => Promise<void>;
|
|
@@ -3,11 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const react_1 = require("react");
|
|
4
4
|
const DeepLinkIapProvider_1 = require("./DeepLinkIapProvider");
|
|
5
5
|
const useDeepLinkIapProvider = () => {
|
|
6
|
-
const { referrerLink, userId, validatePurchaseWithIapticAPI, returnInsertAffiliateIdentifier, trackEvent, setShortCode, setInsertAffiliateIdentifier, initialize, isInitialized } = (0, react_1.useContext)(DeepLinkIapProvider_1.DeepLinkIapContext);
|
|
6
|
+
const { referrerLink, userId, validatePurchaseWithIapticAPI, storeExpectedStoreTransaction, returnUserAccountTokenAndStoreExpectedTransaction, returnInsertAffiliateIdentifier, trackEvent, setShortCode, setInsertAffiliateIdentifier, initialize, isInitialized } = (0, react_1.useContext)(DeepLinkIapProvider_1.DeepLinkIapContext);
|
|
7
7
|
return {
|
|
8
8
|
referrerLink,
|
|
9
9
|
userId,
|
|
10
10
|
validatePurchaseWithIapticAPI,
|
|
11
|
+
storeExpectedStoreTransaction,
|
|
12
|
+
returnUserAccountTokenAndStoreExpectedTransaction,
|
|
11
13
|
returnInsertAffiliateIdentifier,
|
|
12
14
|
trackEvent,
|
|
13
15
|
setShortCode,
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -71,6 +71,8 @@ const App = () => {
|
|
|
71
71
|
Insert Affiliate requires a Receipt Verification platform to validate in-app purchases. You must choose **one** of our supported partners:
|
|
72
72
|
- [RevenueCat](https://www.revenuecat.com/)
|
|
73
73
|
- [Iaptic](https://www.iaptic.com/account)
|
|
74
|
+
- [App Store Direct Integration](#app-store-direct-integration)
|
|
75
|
+
- [Google Play Store Direct Integration](#google-play-store-direct-integration)
|
|
74
76
|
|
|
75
77
|
### Option 1: RevenueCat Integration
|
|
76
78
|
#### Step 1. Code Setup
|
|
@@ -156,7 +158,7 @@ const Child = () => {
|
|
|
156
158
|
// ***...***
|
|
157
159
|
// Fetch & Load your subscription/purchases and handling the IAP purchase here as per the Iaptic Documentation...
|
|
158
160
|
// ***...***
|
|
159
|
-
|
|
161
|
+
|
|
160
162
|
// Initialize the Insert Affiliate SDK at the earliest possible moment
|
|
161
163
|
useEffect(() => {
|
|
162
164
|
if (!isInitialized) {
|
|
@@ -164,7 +166,6 @@ const Child = () => {
|
|
|
164
166
|
}
|
|
165
167
|
}, [initialize, isInitialized]);
|
|
166
168
|
|
|
167
|
-
|
|
168
169
|
// Validate the purchase with Iaptic through Insert Affiliate's SDK for Affiliate Tracking
|
|
169
170
|
useEffect(() => {
|
|
170
171
|
if (currentPurchase) {
|
|
@@ -211,18 +212,114 @@ export default App;
|
|
|
211
212
|
- Replace `{{ your_iaptic_public_key }}` with your **Iaptic Public Key**. You can find this [here](https://www.iaptic.com/settings).
|
|
212
213
|
- 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).
|
|
213
214
|
|
|
215
|
+
### Option 3: App Store Direct Integration
|
|
216
|
+
|
|
217
|
+
Our direct App Store integration is currently in beta and currently supports subscriptions only. **Consumables and one-off purchases are not yet supported** due to App Store server-to-server notification limitations.
|
|
218
|
+
|
|
219
|
+
We plan to release support for consumables and one-off purchases soon. In the meantime, you can use a receipt verification platform from the other integration options.
|
|
220
|
+
|
|
221
|
+
#### Apple App Store Notification Setup
|
|
222
|
+
To proceed, visit [our docs](https://docs.insertaffiliate.com/direct-store-purchase-integration#1-apple-app-store-server-notifications) and complete the required setup steps to set up App Store Server to Server Notifications.
|
|
223
|
+
|
|
224
|
+
#### Implementing Purchases
|
|
225
|
+
|
|
226
|
+
##### 1. Import Required Modules
|
|
227
|
+
|
|
228
|
+
Ensure you import the necessary dependencies, including `Platform` and `useDeepLinkIapProvider` from the SDK.
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
import { Platform } from 'react-native';
|
|
232
|
+
import { DeepLinkIapProvider, useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
|
|
233
|
+
import { requestSubscription } from 'react-native-iap';
|
|
234
|
+
|
|
235
|
+
const { returnUserAccountTokenAndStoreExpectedTransaction } = useDeepLinkIapProvider();
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
##### 2. Handle the Purchase
|
|
240
|
+
When a user initiates a subscription, retrieve the appAccountToken and pass it to the requestSubscription call:
|
|
241
|
+
|
|
242
|
+
```javascript
|
|
243
|
+
const handleBuySubscription = async (product: SubscriptionAndroid | Subscription) => {
|
|
244
|
+
try {
|
|
245
|
+
let appAccountToken = null;
|
|
246
|
+
|
|
247
|
+
// Step 1: Retrieve the appAccountToken for iOS
|
|
248
|
+
if (Platform.OS === 'ios') {
|
|
249
|
+
appAccountToken = await returnUserAccountTokenAndStoreExpectedTransaction();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Step 2: Request the subscription and pass the token for tracking
|
|
253
|
+
await requestSubscription({
|
|
254
|
+
sku: product?.productId,
|
|
255
|
+
...(appAccountToken ? { applicationUsername: appAccountToken } : {}),
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
} catch (error) {
|
|
259
|
+
console.error("Error processing subscription:", error);
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
### Option 4: Google Play Store Direct Integration
|
|
267
|
+
Our direct Google Play Store integration is currently in beta.
|
|
268
|
+
|
|
269
|
+
#### Real Time Developer Notifications (RTDN) Setup
|
|
270
|
+
|
|
271
|
+
Visit [our docs](https://docs.insertaffiliate.com/direct-google-play-store-purchase-integration) and complete the required set up steps for Google Play's Real Time Developer Notifications.
|
|
272
|
+
|
|
273
|
+
#### Implementing Purchases
|
|
274
|
+
|
|
275
|
+
##### 1. Import Required Modules
|
|
276
|
+
|
|
277
|
+
Ensure you import the necessary dependencies, including `Platform` and `useDeepLinkIapProvider` from the SDK.
|
|
278
|
+
|
|
279
|
+
```javascript
|
|
280
|
+
import React, {useEffect, useState} from 'react';
|
|
281
|
+
import { Platform } from 'react-native';
|
|
282
|
+
import { DeepLinkIapProvider, useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
|
|
283
|
+
import { currentPurchase, requestSubscription } from 'react-native-iap';
|
|
284
|
+
|
|
285
|
+
const { storeExpectedStoreTransaction } = useDeepLinkIapProvider();
|
|
286
|
+
|
|
287
|
+
useEffect(() => {
|
|
288
|
+
if (currentPurchase) {
|
|
289
|
+
if (Platform.OS === 'android' && currentPurchase.purchaseToken) {
|
|
290
|
+
// Step 1: Store the expected transaction for Google Play purchases
|
|
291
|
+
storeExpectedStoreTransaction(
|
|
292
|
+
currentPurchase.purchaseToken
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}, [currentPurchase, storeExpectedStoreTransaction]);
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
|
|
214
301
|
## Deep Link Setup [Required]
|
|
215
302
|
|
|
216
|
-
|
|
303
|
+
Insert Affiliate requires a Deep Linking platform to create links for your affiliates. Our platform works with **any** deep linking provider, and you only need to follow these steps:
|
|
304
|
+
1. **Create a deep link** in your chosen third-party platform and pass it to our dashboard when an affiliate signs up.
|
|
305
|
+
2. **Handle deep link clicks** in your app by passing the clicked link:
|
|
306
|
+
```javascript
|
|
307
|
+
await setInsertAffiliateIdentifier(referringLink)
|
|
308
|
+
```
|
|
309
|
+
3. **Integrate with a Receipt Verification platform** by using the result from `setInsertAffiliateIdentifier` to log in or set your application’s username. Examples below include [**Iaptic**](https://github.com/Insert-Affiliate/InsertAffiliateReactNativeSDK?tab=readme-ov-file#example-with-iaptic) and [**RevenueCat**](https://github.com/Insert-Affiliate/InsertAffiliateReactNativeSDK?tab=readme-ov-file#example-with-revenuecat)
|
|
217
310
|
|
|
218
|
-
|
|
311
|
+
### Deep Linking with Branch.io
|
|
312
|
+
To set up deep linking with Branch.io, follow these steps:
|
|
219
313
|
|
|
220
|
-
|
|
314
|
+
1. Create a deep link in Branch and pass it to our dashboard when an affiliate signs up.
|
|
315
|
+
- Example: [Create Affiliate](https://docs.insertaffiliate.com/create-affiliate).
|
|
316
|
+
2. Modify Your Deep Link Handling in `App.tsx`
|
|
317
|
+
- After setting up your Branch integration, add the following code to initialise our SDK in your app:
|
|
221
318
|
|
|
222
|
-
After setting up your Branch integration, add the following code to your ```App.tsx```
|
|
223
319
|
|
|
224
320
|
#### Example with RevenueCat
|
|
225
321
|
```javascript
|
|
322
|
+
import { DeepLinkIapProvider, useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
|
|
226
323
|
import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
|
|
227
324
|
|
|
228
325
|
//...
|
|
@@ -265,10 +362,11 @@ import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
|
|
|
265
362
|
//...
|
|
266
363
|
```
|
|
267
364
|
|
|
268
|
-
#### Example with Iaptic
|
|
365
|
+
#### Example with Iaptic / App Store Direct Integration / Google Play Direct Integration
|
|
269
366
|
```javascript
|
|
270
367
|
import branch from 'react-native-branch';
|
|
271
368
|
import { DeepLinkIapProvider, useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
|
|
369
|
+
const {setInsertAffiliateIdentifier} = useDeepLinkIapProvider();
|
|
272
370
|
|
|
273
371
|
branch.subscribe(async ({ error, params }) => {
|
|
274
372
|
if (error) {
|
|
@@ -22,6 +22,10 @@ type T_DEEPLINK_IAP_CONTEXT = {
|
|
|
22
22
|
iapticAppName: string,
|
|
23
23
|
iapticPublicKey: string
|
|
24
24
|
) => Promise<boolean>;
|
|
25
|
+
returnUserAccountTokenAndStoreExpectedTransaction: () => Promise<string | null>;
|
|
26
|
+
storeExpectedStoreTransaction: (
|
|
27
|
+
purchaseToken: string
|
|
28
|
+
) => Promise<void>;
|
|
25
29
|
trackEvent: (eventName: string) => Promise<void>;
|
|
26
30
|
setShortCode: (shortCode: string) => Promise<void>;
|
|
27
31
|
setInsertAffiliateIdentifier: (
|
|
@@ -52,6 +56,7 @@ const ASYNC_KEYS = {
|
|
|
52
56
|
USER_PURCHASE: '@app_user_purchase',
|
|
53
57
|
USER_ID: '@app_user_id',
|
|
54
58
|
COMPANY_CODE: '@app_company_code',
|
|
59
|
+
USER_ACCOUNT_TOKEN: '@app_user_account_token',
|
|
55
60
|
};
|
|
56
61
|
|
|
57
62
|
// STARTING CONTEXT IMPLEMENTATION
|
|
@@ -65,6 +70,8 @@ export const DeepLinkIapContext = createContext<T_DEEPLINK_IAP_CONTEXT>({
|
|
|
65
70
|
iapticAppName: string,
|
|
66
71
|
iapticPublicKey: string
|
|
67
72
|
) => false,
|
|
73
|
+
returnUserAccountTokenAndStoreExpectedTransaction: async () => '',
|
|
74
|
+
storeExpectedStoreTransaction: async (purchaseToken: string) => {},
|
|
68
75
|
trackEvent: async (eventName: string) => {},
|
|
69
76
|
setShortCode: async (shortCode: string) => {},
|
|
70
77
|
setInsertAffiliateIdentifier: async (referringLink: string) => {},
|
|
@@ -200,10 +207,44 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
200
207
|
await storeInsertAffiliateIdentifier({ link: capitalisedShortCode });
|
|
201
208
|
}
|
|
202
209
|
|
|
210
|
+
async function getOrCreateUserAccountToken(): Promise<string> {
|
|
211
|
+
let userAccountToken = await getValueFromAsync(ASYNC_KEYS.USER_ACCOUNT_TOKEN);
|
|
212
|
+
|
|
213
|
+
if (!userAccountToken) {
|
|
214
|
+
userAccountToken = UUID();
|
|
215
|
+
await saveValueInAsync(ASYNC_KEYS.USER_ACCOUNT_TOKEN, userAccountToken);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return userAccountToken;
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const returnUserAccountTokenAndStoreExpectedTransaction = async (): Promise<string | null> => {
|
|
222
|
+
try {
|
|
223
|
+
const shortCode = await returnInsertAffiliateIdentifier();
|
|
224
|
+
if (!shortCode) {
|
|
225
|
+
console.log('[Insert Affiliate] No affiliate stored - not saving expected transaction.');
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const userAccountToken = await getOrCreateUserAccountToken();
|
|
230
|
+
console.log('[Insert Affiliate] User account token:', userAccountToken);
|
|
231
|
+
|
|
232
|
+
if (!userAccountToken) {
|
|
233
|
+
console.error('[Insert Affiliate] Failed to generate user account token.');
|
|
234
|
+
return null;
|
|
235
|
+
} else {
|
|
236
|
+
await storeExpectedStoreTransaction(userAccountToken);
|
|
237
|
+
return userAccountToken;
|
|
238
|
+
}
|
|
239
|
+
} catch (error) {
|
|
240
|
+
console.error('[Insert Affiliate] Error in returnUserAccountTokenAndStoreExpectedTransaction:', error);
|
|
241
|
+
return null;
|
|
242
|
+
};
|
|
243
|
+
};
|
|
244
|
+
|
|
203
245
|
// MARK: Return Insert Affiliate Identifier
|
|
204
246
|
const returnInsertAffiliateIdentifier = async (): Promise<string | null> => {
|
|
205
247
|
try {
|
|
206
|
-
|
|
207
248
|
return `${referrerLink}-${userId}`;
|
|
208
249
|
} catch (error) {
|
|
209
250
|
errorLog(`ERROR ~ returnInsertAffiliateIdentifier: ${error}`);
|
|
@@ -377,6 +418,48 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
377
418
|
}
|
|
378
419
|
};
|
|
379
420
|
|
|
421
|
+
const storeExpectedStoreTransaction = async (purchaseToken: string): Promise<void> => {
|
|
422
|
+
if (!companyCode || (companyCode.trim() === '' && companyCode !== null)) {
|
|
423
|
+
console.error("[Insert Affiliate] Company code is not set. Please initialize the SDK with a valid company code.");
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const shortCode = await returnInsertAffiliateIdentifier();
|
|
428
|
+
if (!shortCode) {
|
|
429
|
+
console.error("[Insert Affiliate] No affiliate identifier found. Please set one before tracking events.");
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Build JSON payload
|
|
434
|
+
const payload = {
|
|
435
|
+
UUID: purchaseToken,
|
|
436
|
+
companyCode,
|
|
437
|
+
shortCode,
|
|
438
|
+
storedDate: new Date().toISOString(), // ISO8601 format
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
console.log("[Insert Affiliate] Storing expected transaction: ", payload);
|
|
442
|
+
|
|
443
|
+
try {
|
|
444
|
+
const response = await fetch("https://api.insertaffiliate.com/v1/api/app-store-webhook/create-expected-transaction", {
|
|
445
|
+
method: "POST",
|
|
446
|
+
headers: {
|
|
447
|
+
"Content-Type": "application/json",
|
|
448
|
+
},
|
|
449
|
+
body: JSON.stringify(payload),
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
if (response.ok) {
|
|
453
|
+
console.info("[Insert Affiliate] Expected transaction stored successfully.");
|
|
454
|
+
} else {
|
|
455
|
+
const errorText = await response.text();
|
|
456
|
+
console.error(`[Insert Affiliate] Failed to store expected transaction with status code: ${response.status}. Response: ${errorText}`);
|
|
457
|
+
}
|
|
458
|
+
} catch (error) {
|
|
459
|
+
console.error(`[Insert Affiliate] Error storing expected transaction: ${error}`);
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
|
|
380
463
|
// MARK: Track Event
|
|
381
464
|
const trackEvent = async (eventName: string): Promise<void> => {
|
|
382
465
|
try {
|
|
@@ -420,6 +503,8 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
420
503
|
userId,
|
|
421
504
|
setShortCode,
|
|
422
505
|
returnInsertAffiliateIdentifier,
|
|
506
|
+
storeExpectedStoreTransaction,
|
|
507
|
+
returnUserAccountTokenAndStoreExpectedTransaction,
|
|
423
508
|
validatePurchaseWithIapticAPI,
|
|
424
509
|
trackEvent,
|
|
425
510
|
setInsertAffiliateIdentifier,
|
|
@@ -433,3 +518,12 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
433
518
|
};
|
|
434
519
|
|
|
435
520
|
export default DeepLinkIapProvider;
|
|
521
|
+
function UUID(): string {
|
|
522
|
+
// Generate a random UUID (version 4)
|
|
523
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
524
|
+
const r = (Math.random() * 16) | 0,
|
|
525
|
+
v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
526
|
+
return v.toString(16);
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
|
|
@@ -6,6 +6,8 @@ const useDeepLinkIapProvider = () => {
|
|
|
6
6
|
referrerLink,
|
|
7
7
|
userId,
|
|
8
8
|
validatePurchaseWithIapticAPI,
|
|
9
|
+
storeExpectedStoreTransaction,
|
|
10
|
+
returnUserAccountTokenAndStoreExpectedTransaction,
|
|
9
11
|
returnInsertAffiliateIdentifier,
|
|
10
12
|
trackEvent,
|
|
11
13
|
setShortCode,
|
|
@@ -18,6 +20,8 @@ const useDeepLinkIapProvider = () => {
|
|
|
18
20
|
referrerLink,
|
|
19
21
|
userId,
|
|
20
22
|
validatePurchaseWithIapticAPI,
|
|
23
|
+
storeExpectedStoreTransaction,
|
|
24
|
+
returnUserAccountTokenAndStoreExpectedTransaction,
|
|
21
25
|
returnInsertAffiliateIdentifier,
|
|
22
26
|
trackEvent,
|
|
23
27
|
setShortCode,
|