insert-affiliate-react-native-sdk 1.6.5 → 1.7.0
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 +4 -2
- package/dist/DeepLinkIapProvider.js +75 -6
- package/dist/useDeepLinkIapProvider.d.ts +4 -2
- package/dist/useDeepLinkIapProvider.js +3 -1
- package/package.json +1 -1
- package/readme.md +83 -1
- package/src/DeepLinkIapProvider.tsx +91 -8
- package/src/useDeepLinkIapProvider.tsx +4 -0
|
@@ -10,7 +10,9 @@ type T_DEEPLINK_IAP_CONTEXT = {
|
|
|
10
10
|
referrerLink: string;
|
|
11
11
|
userId: string;
|
|
12
12
|
OfferCode: string | null;
|
|
13
|
-
returnInsertAffiliateIdentifier: () => Promise<string | null>;
|
|
13
|
+
returnInsertAffiliateIdentifier: (ignoreTimeout?: boolean) => Promise<string | null>;
|
|
14
|
+
isAffiliateAttributionValid: () => Promise<boolean>;
|
|
15
|
+
getAffiliateStoredDate: () => Promise<Date | null>;
|
|
14
16
|
validatePurchaseWithIapticAPI: (jsonIapPurchase: CustomPurchase, iapticAppId: string, iapticAppName: string, iapticPublicKey: string) => Promise<boolean>;
|
|
15
17
|
returnUserAccountTokenAndStoreExpectedTransaction: () => Promise<string | null>;
|
|
16
18
|
storeExpectedStoreTransaction: (purchaseToken: string) => Promise<void>;
|
|
@@ -19,7 +21,7 @@ type T_DEEPLINK_IAP_CONTEXT = {
|
|
|
19
21
|
setInsertAffiliateIdentifier: (referringLink: string) => Promise<void | string>;
|
|
20
22
|
setInsertAffiliateIdentifierChangeCallback: (callback: InsertAffiliateIdentifierChangeCallback | null) => void;
|
|
21
23
|
handleInsertLinks: (url: string) => Promise<boolean>;
|
|
22
|
-
initialize: (code: string | null, verboseLogging?: boolean, insertLinksEnabled?: boolean, insertLinksClipboardEnabled?: boolean) => Promise<void>;
|
|
24
|
+
initialize: (code: string | null, verboseLogging?: boolean, insertLinksEnabled?: boolean, insertLinksClipboardEnabled?: boolean, affiliateAttributionActiveTime?: number) => Promise<void>;
|
|
23
25
|
isInitialized: boolean;
|
|
24
26
|
};
|
|
25
27
|
export declare const DeepLinkIapContext: React.Context<T_DEEPLINK_IAP_CONTEXT>;
|
|
@@ -51,13 +51,16 @@ const ASYNC_KEYS = {
|
|
|
51
51
|
COMPANY_CODE: '@app_company_code',
|
|
52
52
|
USER_ACCOUNT_TOKEN: '@app_user_account_token',
|
|
53
53
|
IOS_OFFER_CODE: '@app_ios_offer_code',
|
|
54
|
+
AFFILIATE_STORED_DATE: '@app_affiliate_stored_date',
|
|
54
55
|
};
|
|
55
56
|
// STARTING CONTEXT IMPLEMENTATION
|
|
56
57
|
exports.DeepLinkIapContext = (0, react_1.createContext)({
|
|
57
58
|
referrerLink: '',
|
|
58
59
|
userId: '',
|
|
59
60
|
OfferCode: null,
|
|
60
|
-
returnInsertAffiliateIdentifier: () => __awaiter(void 0, void 0, void 0, function* () { return ''; }),
|
|
61
|
+
returnInsertAffiliateIdentifier: (ignoreTimeout) => __awaiter(void 0, void 0, void 0, function* () { return ''; }),
|
|
62
|
+
isAffiliateAttributionValid: () => __awaiter(void 0, void 0, void 0, function* () { return false; }),
|
|
63
|
+
getAffiliateStoredDate: () => __awaiter(void 0, void 0, void 0, function* () { return null; }),
|
|
61
64
|
validatePurchaseWithIapticAPI: (jsonIapPurchase, iapticAppId, iapticAppName, iapticPublicKey) => __awaiter(void 0, void 0, void 0, function* () { return false; }),
|
|
62
65
|
returnUserAccountTokenAndStoreExpectedTransaction: () => __awaiter(void 0, void 0, void 0, function* () { return ''; }),
|
|
63
66
|
storeExpectedStoreTransaction: (purchaseToken) => __awaiter(void 0, void 0, void 0, function* () { }),
|
|
@@ -66,7 +69,7 @@ exports.DeepLinkIapContext = (0, react_1.createContext)({
|
|
|
66
69
|
setInsertAffiliateIdentifier: (referringLink) => __awaiter(void 0, void 0, void 0, function* () { }),
|
|
67
70
|
setInsertAffiliateIdentifierChangeCallback: (callback) => { },
|
|
68
71
|
handleInsertLinks: (url) => __awaiter(void 0, void 0, void 0, function* () { return false; }),
|
|
69
|
-
initialize: (code, verboseLogging, insertLinksEnabled, insertLinksClipboardEnabled) => __awaiter(void 0, void 0, void 0, function* () { }),
|
|
72
|
+
initialize: (code, verboseLogging, insertLinksEnabled, insertLinksClipboardEnabled, affiliateAttributionActiveTime) => __awaiter(void 0, void 0, void 0, function* () { }),
|
|
70
73
|
isInitialized: false,
|
|
71
74
|
});
|
|
72
75
|
const DeepLinkIapProvider = ({ children, }) => {
|
|
@@ -78,12 +81,16 @@ const DeepLinkIapProvider = ({ children, }) => {
|
|
|
78
81
|
const [insertLinksEnabled, setInsertLinksEnabled] = (0, react_1.useState)(false);
|
|
79
82
|
const [insertLinksClipboardEnabled, setInsertLinksClipboardEnabled] = (0, react_1.useState)(false);
|
|
80
83
|
const [OfferCode, setOfferCode] = (0, react_1.useState)(null);
|
|
84
|
+
const [affiliateAttributionActiveTime, setAffiliateAttributionActiveTime] = (0, react_1.useState)(null);
|
|
81
85
|
const insertAffiliateIdentifierChangeCallbackRef = (0, react_1.useRef)(null);
|
|
82
86
|
// MARK: Initialize the SDK
|
|
83
|
-
const initialize = (companyCode_1, ...args_1) => __awaiter(void 0, [companyCode_1, ...args_1], void 0, function* (companyCode, verboseLogging = false, insertLinksEnabled = false, insertLinksClipboardEnabled = false) {
|
|
87
|
+
const initialize = (companyCode_1, ...args_1) => __awaiter(void 0, [companyCode_1, ...args_1], void 0, function* (companyCode, verboseLogging = false, insertLinksEnabled = false, insertLinksClipboardEnabled = false, affiliateAttributionActiveTime) {
|
|
84
88
|
setVerboseLogging(verboseLogging);
|
|
85
89
|
setInsertLinksEnabled(insertLinksEnabled);
|
|
86
90
|
setInsertLinksClipboardEnabled(insertLinksClipboardEnabled);
|
|
91
|
+
if (affiliateAttributionActiveTime !== undefined) {
|
|
92
|
+
setAffiliateAttributionActiveTime(affiliateAttributionActiveTime);
|
|
93
|
+
}
|
|
87
94
|
if (verboseLogging) {
|
|
88
95
|
console.log('[Insert Affiliate] [VERBOSE] Starting SDK initialization...');
|
|
89
96
|
console.log('[Insert Affiliate] [VERBOSE] Company code provided:', companyCode ? 'Yes' : 'No');
|
|
@@ -1057,10 +1064,18 @@ const DeepLinkIapProvider = ({ children, }) => {
|
|
|
1057
1064
|
;
|
|
1058
1065
|
});
|
|
1059
1066
|
// MARK: Return Insert Affiliate Identifier
|
|
1060
|
-
|
|
1061
|
-
const returnInsertAffiliateIdentifier = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
1067
|
+
const returnInsertAffiliateIdentifier = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (ignoreTimeout = false) {
|
|
1062
1068
|
try {
|
|
1063
|
-
verboseLog(
|
|
1069
|
+
verboseLog(`Getting insert affiliate identifier (ignoreTimeout: ${ignoreTimeout})...`);
|
|
1070
|
+
// If timeout is enabled and we're not ignoring it, check validity first
|
|
1071
|
+
if (!ignoreTimeout && affiliateAttributionActiveTime) {
|
|
1072
|
+
const isValid = yield isAffiliateAttributionValid();
|
|
1073
|
+
if (!isValid) {
|
|
1074
|
+
verboseLog('Attribution has expired, returning null');
|
|
1075
|
+
return null;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
// Now get the actual identifier
|
|
1064
1079
|
verboseLog(`React state - referrerLink: ${referrerLink || 'empty'}, userId: ${userId || 'empty'}`);
|
|
1065
1080
|
// Try React state first
|
|
1066
1081
|
if (referrerLink && userId) {
|
|
@@ -1092,6 +1107,48 @@ const DeepLinkIapProvider = ({ children, }) => {
|
|
|
1092
1107
|
return null;
|
|
1093
1108
|
}
|
|
1094
1109
|
});
|
|
1110
|
+
// MARK: Attribution Timeout Functions
|
|
1111
|
+
// Check if the current affiliate attribution is still valid based on timeout
|
|
1112
|
+
const isAffiliateAttributionValid = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
1113
|
+
try {
|
|
1114
|
+
// If no timeout is set, attribution is always valid
|
|
1115
|
+
if (!affiliateAttributionActiveTime) {
|
|
1116
|
+
verboseLog('No attribution timeout set, attribution is valid');
|
|
1117
|
+
return true;
|
|
1118
|
+
}
|
|
1119
|
+
const storedDate = yield getAffiliateStoredDate();
|
|
1120
|
+
if (!storedDate) {
|
|
1121
|
+
verboseLog('No stored date found, attribution is invalid');
|
|
1122
|
+
return false;
|
|
1123
|
+
}
|
|
1124
|
+
const now = new Date();
|
|
1125
|
+
const timeDifferenceSeconds = Math.floor((now.getTime() - storedDate.getTime()) / 1000);
|
|
1126
|
+
const isValid = timeDifferenceSeconds <= affiliateAttributionActiveTime;
|
|
1127
|
+
verboseLog(`Attribution timeout check: stored=${storedDate.toISOString()}, now=${now.toISOString()}, diff=${timeDifferenceSeconds}s, timeout=${affiliateAttributionActiveTime}s, valid=${isValid}`);
|
|
1128
|
+
return isValid;
|
|
1129
|
+
}
|
|
1130
|
+
catch (error) {
|
|
1131
|
+
verboseLog(`Error checking attribution validity: ${error}`);
|
|
1132
|
+
return false;
|
|
1133
|
+
}
|
|
1134
|
+
});
|
|
1135
|
+
// Get the date when the affiliate identifier was stored
|
|
1136
|
+
const getAffiliateStoredDate = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
1137
|
+
try {
|
|
1138
|
+
const storedDateString = yield getValueFromAsync(ASYNC_KEYS.AFFILIATE_STORED_DATE);
|
|
1139
|
+
if (!storedDateString) {
|
|
1140
|
+
verboseLog('No affiliate stored date found');
|
|
1141
|
+
return null;
|
|
1142
|
+
}
|
|
1143
|
+
const storedDate = new Date(storedDateString);
|
|
1144
|
+
verboseLog(`Retrieved affiliate stored date: ${storedDate.toISOString()}`);
|
|
1145
|
+
return storedDate;
|
|
1146
|
+
}
|
|
1147
|
+
catch (error) {
|
|
1148
|
+
verboseLog(`Error getting affiliate stored date: ${error}`);
|
|
1149
|
+
return null;
|
|
1150
|
+
}
|
|
1151
|
+
});
|
|
1095
1152
|
// MARK: Insert Affiliate Identifier
|
|
1096
1153
|
function setInsertAffiliateIdentifier(referringLink) {
|
|
1097
1154
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1174,10 +1231,20 @@ const DeepLinkIapProvider = ({ children, }) => {
|
|
|
1174
1231
|
function storeInsertAffiliateIdentifier(_a) {
|
|
1175
1232
|
return __awaiter(this, arguments, void 0, function* ({ link }) {
|
|
1176
1233
|
console.log(`[Insert Affiliate] Storing affiliate identifier: ${link}`);
|
|
1234
|
+
// Check if we're trying to store the same link (prevent duplicate storage)
|
|
1235
|
+
const existingLink = yield getValueFromAsync(ASYNC_KEYS.REFERRER_LINK);
|
|
1236
|
+
if (existingLink === link) {
|
|
1237
|
+
verboseLog(`Link ${link} is already stored, skipping duplicate storage`);
|
|
1238
|
+
return;
|
|
1239
|
+
}
|
|
1177
1240
|
verboseLog(`Updating React state with referrer link: ${link}`);
|
|
1178
1241
|
setReferrerLink(link);
|
|
1179
1242
|
verboseLog(`Saving referrer link to AsyncStorage...`);
|
|
1180
1243
|
yield saveValueInAsync(ASYNC_KEYS.REFERRER_LINK, link);
|
|
1244
|
+
// Store the current date/time when the affiliate identifier is stored
|
|
1245
|
+
const currentDate = new Date().toISOString();
|
|
1246
|
+
verboseLog(`Saving affiliate stored date: ${currentDate}`);
|
|
1247
|
+
yield saveValueInAsync(ASYNC_KEYS.AFFILIATE_STORED_DATE, currentDate);
|
|
1181
1248
|
verboseLog(`Referrer link saved to AsyncStorage successfully`);
|
|
1182
1249
|
// Automatically fetch and store offer code for any affiliate identifier
|
|
1183
1250
|
verboseLog('Attempting to fetch offer code for stored affiliate identifier...');
|
|
@@ -1426,6 +1493,8 @@ const DeepLinkIapProvider = ({ children, }) => {
|
|
|
1426
1493
|
OfferCode,
|
|
1427
1494
|
setShortCode,
|
|
1428
1495
|
returnInsertAffiliateIdentifier,
|
|
1496
|
+
isAffiliateAttributionValid,
|
|
1497
|
+
getAffiliateStoredDate,
|
|
1429
1498
|
storeExpectedStoreTransaction,
|
|
1430
1499
|
returnUserAccountTokenAndStoreExpectedTransaction,
|
|
1431
1500
|
validatePurchaseWithIapticAPI,
|
|
@@ -6,13 +6,15 @@ declare const useDeepLinkIapProvider: () => {
|
|
|
6
6
|
}, iapticAppId: string, iapticAppName: string, iapticPublicKey: string) => Promise<boolean>;
|
|
7
7
|
storeExpectedStoreTransaction: (purchaseToken: string) => Promise<void>;
|
|
8
8
|
returnUserAccountTokenAndStoreExpectedTransaction: () => Promise<string | null>;
|
|
9
|
-
returnInsertAffiliateIdentifier: () => Promise<string | null>;
|
|
9
|
+
returnInsertAffiliateIdentifier: (ignoreTimeout?: boolean) => Promise<string | null>;
|
|
10
|
+
isAffiliateAttributionValid: () => Promise<boolean>;
|
|
11
|
+
getAffiliateStoredDate: () => Promise<Date | null>;
|
|
10
12
|
trackEvent: (eventName: string) => Promise<void>;
|
|
11
13
|
setShortCode: (shortCode: string) => Promise<void>;
|
|
12
14
|
setInsertAffiliateIdentifier: (referringLink: string) => Promise<void | string>;
|
|
13
15
|
setInsertAffiliateIdentifierChangeCallback: (callback: import("./DeepLinkIapProvider").InsertAffiliateIdentifierChangeCallback | null) => void;
|
|
14
16
|
handleInsertLinks: (url: string) => Promise<boolean>;
|
|
15
|
-
initialize: (code: string | null, verboseLogging?: boolean, insertLinksEnabled?: boolean, insertLinksClipboardEnabled?: boolean) => Promise<void>;
|
|
17
|
+
initialize: (code: string | null, verboseLogging?: boolean, insertLinksEnabled?: boolean, insertLinksClipboardEnabled?: boolean, affiliateAttributionActiveTime?: number) => Promise<void>;
|
|
16
18
|
isInitialized: boolean;
|
|
17
19
|
OfferCode: string | null;
|
|
18
20
|
};
|
|
@@ -3,7 +3,7 @@ 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, storeExpectedStoreTransaction, returnUserAccountTokenAndStoreExpectedTransaction, returnInsertAffiliateIdentifier, trackEvent, setShortCode, setInsertAffiliateIdentifier, setInsertAffiliateIdentifierChangeCallback, handleInsertLinks, initialize, isInitialized, OfferCode, } = (0, react_1.useContext)(DeepLinkIapProvider_1.DeepLinkIapContext);
|
|
6
|
+
const { referrerLink, userId, validatePurchaseWithIapticAPI, storeExpectedStoreTransaction, returnUserAccountTokenAndStoreExpectedTransaction, returnInsertAffiliateIdentifier, isAffiliateAttributionValid, getAffiliateStoredDate, trackEvent, setShortCode, setInsertAffiliateIdentifier, setInsertAffiliateIdentifierChangeCallback, handleInsertLinks, initialize, isInitialized, OfferCode, } = (0, react_1.useContext)(DeepLinkIapProvider_1.DeepLinkIapContext);
|
|
7
7
|
return {
|
|
8
8
|
referrerLink,
|
|
9
9
|
userId,
|
|
@@ -11,6 +11,8 @@ const useDeepLinkIapProvider = () => {
|
|
|
11
11
|
storeExpectedStoreTransaction,
|
|
12
12
|
returnUserAccountTokenAndStoreExpectedTransaction,
|
|
13
13
|
returnInsertAffiliateIdentifier,
|
|
14
|
+
isAffiliateAttributionValid,
|
|
15
|
+
getAffiliateStoredDate,
|
|
14
16
|
trackEvent,
|
|
15
17
|
setShortCode,
|
|
16
18
|
setInsertAffiliateIdentifier,
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -172,7 +172,8 @@ const Child = () => {
|
|
|
172
172
|
"{{ your-company-code }}",
|
|
173
173
|
false, // Enable for debugging
|
|
174
174
|
true, // Enables Insert Links
|
|
175
|
-
true
|
|
175
|
+
true, // Enable Insert Links Clipboard access to avoid permission prompt
|
|
176
|
+
604800 // Optional: Attribution timeout in seconds (7 days)
|
|
176
177
|
);
|
|
177
178
|
}
|
|
178
179
|
}, [initialize, isInitialized]);
|
|
@@ -1227,3 +1228,84 @@ Short codes must meet the following criteria:
|
|
|
1227
1228
|
onPress={() => setShortCode('JOIN_123')}
|
|
1228
1229
|
/>
|
|
1229
1230
|
```
|
|
1231
|
+
|
|
1232
|
+
### Attribution Timeout
|
|
1233
|
+
|
|
1234
|
+
You can configure how long an affiliate link attribution remains active after being clicked. This allows you to control the attribution window for commissions.
|
|
1235
|
+
|
|
1236
|
+
#### Basic Usage
|
|
1237
|
+
|
|
1238
|
+
When initializing the SDK, you can specify the attribution timeout in seconds:
|
|
1239
|
+
|
|
1240
|
+
```javascript
|
|
1241
|
+
const Child = () => {
|
|
1242
|
+
const { initialize, isInitialized } = useDeepLinkIapProvider();
|
|
1243
|
+
|
|
1244
|
+
useEffect(() => {
|
|
1245
|
+
if (!isInitialized) {
|
|
1246
|
+
// Set attribution timeout to 7 days (7 * 24 * 60 * 60 = 604800 seconds)
|
|
1247
|
+
initialize(
|
|
1248
|
+
"{{ your-company-code }}",
|
|
1249
|
+
false, // verbose logging
|
|
1250
|
+
false, // insert links enabled
|
|
1251
|
+
false, // insert links clipboard enabled
|
|
1252
|
+
604800 // attribution timeout in seconds
|
|
1253
|
+
);
|
|
1254
|
+
}
|
|
1255
|
+
}, [initialize, isInitialized]);
|
|
1256
|
+
}
|
|
1257
|
+
```
|
|
1258
|
+
|
|
1259
|
+
**When to use `affiliateAttributionActiveTime`:**
|
|
1260
|
+
- Set to a number in seconds to define how long affiliate attributions remain active
|
|
1261
|
+
- Set to `null` or omit to disable attribution timeout (attribution never expires)
|
|
1262
|
+
- Common values: 86400 (1 day), 604800 (7 days), 2592000 (30 days)
|
|
1263
|
+
|
|
1264
|
+
#### Common Timeout Values
|
|
1265
|
+
|
|
1266
|
+
```javascript
|
|
1267
|
+
// 1 day
|
|
1268
|
+
initialize("your-company-code", false, false, false, 86400);
|
|
1269
|
+
|
|
1270
|
+
// 7 days (default for many platforms)
|
|
1271
|
+
initialize("your-company-code", false, false, false, 604800);
|
|
1272
|
+
|
|
1273
|
+
// 30 days
|
|
1274
|
+
initialize("your-company-code", false, false, false, 2592000);
|
|
1275
|
+
|
|
1276
|
+
// No timeout (attribution never expires)
|
|
1277
|
+
initialize("your-company-code", false, false, false); // or pass null/undefined
|
|
1278
|
+
```
|
|
1279
|
+
|
|
1280
|
+
#### Advanced Usage
|
|
1281
|
+
|
|
1282
|
+
The SDK provides methods to work with attribution timeouts:
|
|
1283
|
+
|
|
1284
|
+
```javascript
|
|
1285
|
+
const {
|
|
1286
|
+
returnInsertAffiliateIdentifier,
|
|
1287
|
+
isAffiliateAttributionValid,
|
|
1288
|
+
getAffiliateStoredDate
|
|
1289
|
+
} = useDeepLinkIapProvider();
|
|
1290
|
+
|
|
1291
|
+
// Get affiliate identifier (respects timeout)
|
|
1292
|
+
const identifier = await returnInsertAffiliateIdentifier();
|
|
1293
|
+
|
|
1294
|
+
// Get affiliate identifier ignoring timeout
|
|
1295
|
+
const rawIdentifier = await returnInsertAffiliateIdentifier(true);
|
|
1296
|
+
|
|
1297
|
+
// Check if attribution is still valid
|
|
1298
|
+
const isValid = await isAffiliateAttributionValid();
|
|
1299
|
+
|
|
1300
|
+
// Get the date when affiliate was first stored
|
|
1301
|
+
const storedDate = await getAffiliateStoredDate();
|
|
1302
|
+
```
|
|
1303
|
+
|
|
1304
|
+
#### How It Works
|
|
1305
|
+
|
|
1306
|
+
1. **Attribution Storage**: When an affiliate link is clicked and processed, the SDK stores both the affiliate identifier and the current timestamp
|
|
1307
|
+
2. **Timeout Check**: When `returnInsertAffiliateIdentifier()` is called, the SDK checks if the stored attribution is still within the timeout window
|
|
1308
|
+
3. **Expired Attribution**: If the attribution has expired, the method returns `null` instead of the affiliate identifier
|
|
1309
|
+
4. **Bypass Option**: You can bypass the timeout check by passing `true` to `returnInsertAffiliateIdentifier(true)`
|
|
1310
|
+
|
|
1311
|
+
This ensures that affiliates are only credited for purchases made within the specified attribution window, providing fair and accurate commission tracking.
|
|
@@ -22,7 +22,9 @@ type T_DEEPLINK_IAP_CONTEXT = {
|
|
|
22
22
|
referrerLink: string;
|
|
23
23
|
userId: string;
|
|
24
24
|
OfferCode: string | null;
|
|
25
|
-
returnInsertAffiliateIdentifier: () => Promise<string | null>;
|
|
25
|
+
returnInsertAffiliateIdentifier: (ignoreTimeout?: boolean) => Promise<string | null>;
|
|
26
|
+
isAffiliateAttributionValid: () => Promise<boolean>;
|
|
27
|
+
getAffiliateStoredDate: () => Promise<Date | null>;
|
|
26
28
|
validatePurchaseWithIapticAPI: (
|
|
27
29
|
jsonIapPurchase: CustomPurchase,
|
|
28
30
|
iapticAppId: string,
|
|
@@ -40,7 +42,7 @@ type T_DEEPLINK_IAP_CONTEXT = {
|
|
|
40
42
|
) => Promise<void | string>;
|
|
41
43
|
setInsertAffiliateIdentifierChangeCallback: (callback: InsertAffiliateIdentifierChangeCallback | null) => void;
|
|
42
44
|
handleInsertLinks: (url: string) => Promise<boolean>;
|
|
43
|
-
initialize: (code: string | null, verboseLogging?: boolean, insertLinksEnabled?: boolean, insertLinksClipboardEnabled?: boolean) => Promise<void>;
|
|
45
|
+
initialize: (code: string | null, verboseLogging?: boolean, insertLinksEnabled?: boolean, insertLinksClipboardEnabled?: boolean, affiliateAttributionActiveTime?: number) => Promise<void>;
|
|
44
46
|
isInitialized: boolean;
|
|
45
47
|
};
|
|
46
48
|
|
|
@@ -67,6 +69,7 @@ const ASYNC_KEYS = {
|
|
|
67
69
|
COMPANY_CODE: '@app_company_code',
|
|
68
70
|
USER_ACCOUNT_TOKEN: '@app_user_account_token',
|
|
69
71
|
IOS_OFFER_CODE: '@app_ios_offer_code',
|
|
72
|
+
AFFILIATE_STORED_DATE: '@app_affiliate_stored_date',
|
|
70
73
|
};
|
|
71
74
|
|
|
72
75
|
// STARTING CONTEXT IMPLEMENTATION
|
|
@@ -74,7 +77,9 @@ export const DeepLinkIapContext = createContext<T_DEEPLINK_IAP_CONTEXT>({
|
|
|
74
77
|
referrerLink: '',
|
|
75
78
|
userId: '',
|
|
76
79
|
OfferCode: null,
|
|
77
|
-
returnInsertAffiliateIdentifier: async () => '',
|
|
80
|
+
returnInsertAffiliateIdentifier: async (ignoreTimeout?: boolean) => '',
|
|
81
|
+
isAffiliateAttributionValid: async () => false,
|
|
82
|
+
getAffiliateStoredDate: async () => null,
|
|
78
83
|
validatePurchaseWithIapticAPI: async (
|
|
79
84
|
jsonIapPurchase: CustomPurchase,
|
|
80
85
|
iapticAppId: string,
|
|
@@ -88,7 +93,7 @@ export const DeepLinkIapContext = createContext<T_DEEPLINK_IAP_CONTEXT>({
|
|
|
88
93
|
setInsertAffiliateIdentifier: async (referringLink: string) => {},
|
|
89
94
|
setInsertAffiliateIdentifierChangeCallback: (callback: InsertAffiliateIdentifierChangeCallback | null) => {},
|
|
90
95
|
handleInsertLinks: async (url: string) => false,
|
|
91
|
-
initialize: async (code: string | null, verboseLogging?: boolean, insertLinksEnabled?: boolean, insertLinksClipboardEnabled?: boolean) => {},
|
|
96
|
+
initialize: async (code: string | null, verboseLogging?: boolean, insertLinksEnabled?: boolean, insertLinksClipboardEnabled?: boolean, affiliateAttributionActiveTime?: number) => {},
|
|
92
97
|
isInitialized: false,
|
|
93
98
|
});
|
|
94
99
|
|
|
@@ -103,13 +108,17 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
103
108
|
const [insertLinksEnabled, setInsertLinksEnabled] = useState<boolean>(false);
|
|
104
109
|
const [insertLinksClipboardEnabled, setInsertLinksClipboardEnabled] = useState<boolean>(false);
|
|
105
110
|
const [OfferCode, setOfferCode] = useState<string | null>(null);
|
|
111
|
+
const [affiliateAttributionActiveTime, setAffiliateAttributionActiveTime] = useState<number | null>(null);
|
|
106
112
|
const insertAffiliateIdentifierChangeCallbackRef = useRef<InsertAffiliateIdentifierChangeCallback | null>(null);
|
|
107
113
|
|
|
108
114
|
// MARK: Initialize the SDK
|
|
109
|
-
const initialize = async (companyCode: string | null, verboseLogging: boolean = false, insertLinksEnabled: boolean = false, insertLinksClipboardEnabled: boolean = false): Promise<void> => {
|
|
115
|
+
const initialize = async (companyCode: string | null, verboseLogging: boolean = false, insertLinksEnabled: boolean = false, insertLinksClipboardEnabled: boolean = false, affiliateAttributionActiveTime?: number): Promise<void> => {
|
|
110
116
|
setVerboseLogging(verboseLogging);
|
|
111
117
|
setInsertLinksEnabled(insertLinksEnabled);
|
|
112
118
|
setInsertLinksClipboardEnabled(insertLinksClipboardEnabled);
|
|
119
|
+
if (affiliateAttributionActiveTime !== undefined) {
|
|
120
|
+
setAffiliateAttributionActiveTime(affiliateAttributionActiveTime);
|
|
121
|
+
}
|
|
113
122
|
|
|
114
123
|
if (verboseLogging) {
|
|
115
124
|
console.log('[Insert Affiliate] [VERBOSE] Starting SDK initialization...');
|
|
@@ -1210,10 +1219,20 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
1210
1219
|
};
|
|
1211
1220
|
|
|
1212
1221
|
// MARK: Return Insert Affiliate Identifier
|
|
1213
|
-
|
|
1214
|
-
const returnInsertAffiliateIdentifier = async (): Promise<string | null> => {
|
|
1222
|
+
const returnInsertAffiliateIdentifier = async (ignoreTimeout: boolean = false): Promise<string | null> => {
|
|
1215
1223
|
try {
|
|
1216
|
-
verboseLog(
|
|
1224
|
+
verboseLog(`Getting insert affiliate identifier (ignoreTimeout: ${ignoreTimeout})...`);
|
|
1225
|
+
|
|
1226
|
+
// If timeout is enabled and we're not ignoring it, check validity first
|
|
1227
|
+
if (!ignoreTimeout && affiliateAttributionActiveTime) {
|
|
1228
|
+
const isValid = await isAffiliateAttributionValid();
|
|
1229
|
+
if (!isValid) {
|
|
1230
|
+
verboseLog('Attribution has expired, returning null');
|
|
1231
|
+
return null;
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
// Now get the actual identifier
|
|
1217
1236
|
verboseLog(`React state - referrerLink: ${referrerLink || 'empty'}, userId: ${userId || 'empty'}`);
|
|
1218
1237
|
|
|
1219
1238
|
// Try React state first
|
|
@@ -1252,6 +1271,54 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
1252
1271
|
}
|
|
1253
1272
|
};
|
|
1254
1273
|
|
|
1274
|
+
// MARK: Attribution Timeout Functions
|
|
1275
|
+
|
|
1276
|
+
// Check if the current affiliate attribution is still valid based on timeout
|
|
1277
|
+
const isAffiliateAttributionValid = async (): Promise<boolean> => {
|
|
1278
|
+
try {
|
|
1279
|
+
// If no timeout is set, attribution is always valid
|
|
1280
|
+
if (!affiliateAttributionActiveTime) {
|
|
1281
|
+
verboseLog('No attribution timeout set, attribution is valid');
|
|
1282
|
+
return true;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
const storedDate = await getAffiliateStoredDate();
|
|
1286
|
+
if (!storedDate) {
|
|
1287
|
+
verboseLog('No stored date found, attribution is invalid');
|
|
1288
|
+
return false;
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
const now = new Date();
|
|
1292
|
+
const timeDifferenceSeconds = Math.floor((now.getTime() - storedDate.getTime()) / 1000);
|
|
1293
|
+
const isValid = timeDifferenceSeconds <= affiliateAttributionActiveTime;
|
|
1294
|
+
|
|
1295
|
+
verboseLog(`Attribution timeout check: stored=${storedDate.toISOString()}, now=${now.toISOString()}, diff=${timeDifferenceSeconds}s, timeout=${affiliateAttributionActiveTime}s, valid=${isValid}`);
|
|
1296
|
+
|
|
1297
|
+
return isValid;
|
|
1298
|
+
} catch (error) {
|
|
1299
|
+
verboseLog(`Error checking attribution validity: ${error}`);
|
|
1300
|
+
return false;
|
|
1301
|
+
}
|
|
1302
|
+
};
|
|
1303
|
+
|
|
1304
|
+
// Get the date when the affiliate identifier was stored
|
|
1305
|
+
const getAffiliateStoredDate = async (): Promise<Date | null> => {
|
|
1306
|
+
try {
|
|
1307
|
+
const storedDateString = await getValueFromAsync(ASYNC_KEYS.AFFILIATE_STORED_DATE);
|
|
1308
|
+
if (!storedDateString) {
|
|
1309
|
+
verboseLog('No affiliate stored date found');
|
|
1310
|
+
return null;
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
const storedDate = new Date(storedDateString);
|
|
1314
|
+
verboseLog(`Retrieved affiliate stored date: ${storedDate.toISOString()}`);
|
|
1315
|
+
return storedDate;
|
|
1316
|
+
} catch (error) {
|
|
1317
|
+
verboseLog(`Error getting affiliate stored date: ${error}`);
|
|
1318
|
+
return null;
|
|
1319
|
+
}
|
|
1320
|
+
};
|
|
1321
|
+
|
|
1255
1322
|
// MARK: Insert Affiliate Identifier
|
|
1256
1323
|
|
|
1257
1324
|
async function setInsertAffiliateIdentifier(
|
|
@@ -1349,10 +1416,24 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
1349
1416
|
|
|
1350
1417
|
async function storeInsertAffiliateIdentifier({ link }: { link: string }) {
|
|
1351
1418
|
console.log(`[Insert Affiliate] Storing affiliate identifier: ${link}`);
|
|
1419
|
+
|
|
1420
|
+
// Check if we're trying to store the same link (prevent duplicate storage)
|
|
1421
|
+
const existingLink = await getValueFromAsync(ASYNC_KEYS.REFERRER_LINK);
|
|
1422
|
+
if (existingLink === link) {
|
|
1423
|
+
verboseLog(`Link ${link} is already stored, skipping duplicate storage`);
|
|
1424
|
+
return;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1352
1427
|
verboseLog(`Updating React state with referrer link: ${link}`);
|
|
1353
1428
|
setReferrerLink(link);
|
|
1354
1429
|
verboseLog(`Saving referrer link to AsyncStorage...`);
|
|
1355
1430
|
await saveValueInAsync(ASYNC_KEYS.REFERRER_LINK, link);
|
|
1431
|
+
|
|
1432
|
+
// Store the current date/time when the affiliate identifier is stored
|
|
1433
|
+
const currentDate = new Date().toISOString();
|
|
1434
|
+
verboseLog(`Saving affiliate stored date: ${currentDate}`);
|
|
1435
|
+
await saveValueInAsync(ASYNC_KEYS.AFFILIATE_STORED_DATE, currentDate);
|
|
1436
|
+
|
|
1356
1437
|
verboseLog(`Referrer link saved to AsyncStorage successfully`);
|
|
1357
1438
|
|
|
1358
1439
|
// Automatically fetch and store offer code for any affiliate identifier
|
|
@@ -1658,6 +1739,8 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
|
|
|
1658
1739
|
OfferCode,
|
|
1659
1740
|
setShortCode,
|
|
1660
1741
|
returnInsertAffiliateIdentifier,
|
|
1742
|
+
isAffiliateAttributionValid,
|
|
1743
|
+
getAffiliateStoredDate,
|
|
1661
1744
|
storeExpectedStoreTransaction,
|
|
1662
1745
|
returnUserAccountTokenAndStoreExpectedTransaction,
|
|
1663
1746
|
validatePurchaseWithIapticAPI,
|
|
@@ -9,6 +9,8 @@ const useDeepLinkIapProvider = () => {
|
|
|
9
9
|
storeExpectedStoreTransaction,
|
|
10
10
|
returnUserAccountTokenAndStoreExpectedTransaction,
|
|
11
11
|
returnInsertAffiliateIdentifier,
|
|
12
|
+
isAffiliateAttributionValid,
|
|
13
|
+
getAffiliateStoredDate,
|
|
12
14
|
trackEvent,
|
|
13
15
|
setShortCode,
|
|
14
16
|
setInsertAffiliateIdentifier,
|
|
@@ -26,6 +28,8 @@ const useDeepLinkIapProvider = () => {
|
|
|
26
28
|
storeExpectedStoreTransaction,
|
|
27
29
|
returnUserAccountTokenAndStoreExpectedTransaction,
|
|
28
30
|
returnInsertAffiliateIdentifier,
|
|
31
|
+
isAffiliateAttributionValid,
|
|
32
|
+
getAffiliateStoredDate,
|
|
29
33
|
trackEvent,
|
|
30
34
|
setShortCode,
|
|
31
35
|
setInsertAffiliateIdentifier,
|