insert-affiliate-react-native-sdk 1.5.1 → 1.6.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.
@@ -0,0 +1,8 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "WebFetch(domain:github.com)"
5
+ ],
6
+ "deny": []
7
+ }
8
+ }
@@ -16,6 +16,7 @@ type T_DEEPLINK_IAP_CONTEXT = {
16
16
  setShortCode: (shortCode: string) => Promise<void>;
17
17
  setInsertAffiliateIdentifier: (referringLink: string) => Promise<void | string>;
18
18
  initialize: (code: string | null, verboseLogging?: boolean) => Promise<void>;
19
+ fetchAndConditionallyOpenUrl: (affiliateIdentifier: string, offerCodeUrlId: string) => Promise<boolean>;
19
20
  isInitialized: boolean;
20
21
  };
21
22
  export declare const DeepLinkIapContext: React.Context<T_DEEPLINK_IAP_CONTEXT>;
@@ -59,6 +59,7 @@ exports.DeepLinkIapContext = (0, react_1.createContext)({
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
61
  initialize: (code, verboseLogging) => __awaiter(void 0, void 0, void 0, function* () { }),
62
+ fetchAndConditionallyOpenUrl: (affiliateIdentifier, offerCodeUrlId) => __awaiter(void 0, void 0, void 0, function* () { return false; }),
62
63
  isInitialized: false,
63
64
  });
64
65
  const DeepLinkIapProvider = ({ children, }) => {
@@ -529,6 +530,87 @@ const DeepLinkIapProvider = ({ children, }) => {
529
530
  return Promise.reject(error);
530
531
  }
531
532
  });
533
+ const fetchAndConditionallyOpenUrl = (affiliateIdentifier, offerCodeUrlId) => __awaiter(void 0, void 0, void 0, function* () {
534
+ try {
535
+ verboseLog(`Attempting to fetch and conditionally open URL for affiliate: ${affiliateIdentifier}, offerCodeUrlId: ${offerCodeUrlId}`);
536
+ if (react_native_1.Platform.OS !== 'ios') {
537
+ console.warn("[Insert Affiliate] Offer codes are only supported on iOS");
538
+ verboseLog("Offer codes are only supported on iOS");
539
+ return false;
540
+ }
541
+ const offerCode = yield fetchOfferCode(affiliateIdentifier);
542
+ if (offerCode && offerCode.length > 0) {
543
+ yield openRedeemURL(offerCode, offerCodeUrlId);
544
+ return true;
545
+ }
546
+ else {
547
+ verboseLog("No valid offer code found");
548
+ return false;
549
+ }
550
+ }
551
+ catch (error) {
552
+ console.error('[Insert Affiliate] Error fetching and opening offer code URL:', error);
553
+ verboseLog(`Error fetching and opening offer code URL: ${error}`);
554
+ return false;
555
+ }
556
+ });
557
+ const fetchOfferCode = (affiliateLink) => __awaiter(void 0, void 0, void 0, function* () {
558
+ try {
559
+ const encodedAffiliateLink = encodeURIComponent(affiliateLink);
560
+ const url = `https://api.insertaffiliate.com/v1/affiliateReturnOfferCode/${encodedAffiliateLink}`;
561
+ verboseLog(`Fetching offer code from: ${url}`);
562
+ const response = yield axios_1.default.get(url);
563
+ if (response.status === 200) {
564
+ const offerCode = response.data;
565
+ // Check for specific error strings from API
566
+ if (typeof offerCode === 'string' && (offerCode.includes("errorofferCodeNotFound") ||
567
+ offerCode.includes("errorAffiliateoffercodenotfoundinanycompany") ||
568
+ offerCode.includes("errorAffiliateoffercodenotfoundinanycompanyAffiliatelinkwas") ||
569
+ offerCode.includes("Routenotfound"))) {
570
+ console.warn(`[Insert Affiliate] Offer code not found or invalid: ${offerCode}`);
571
+ verboseLog(`Offer code not found or invalid: ${offerCode}`);
572
+ return null;
573
+ }
574
+ const cleanedOfferCode = cleanOfferCode(offerCode);
575
+ verboseLog(`Successfully fetched and cleaned offer code: ${cleanedOfferCode}`);
576
+ return cleanedOfferCode;
577
+ }
578
+ else {
579
+ console.error(`[Insert Affiliate] Failed to fetch offer code. Status code: ${response.status}, Response: ${JSON.stringify(response.data)}`);
580
+ verboseLog(`Failed to fetch offer code. Status code: ${response.status}, Response: ${JSON.stringify(response.data)}`);
581
+ return null;
582
+ }
583
+ }
584
+ catch (error) {
585
+ console.error('[Insert Affiliate] Error fetching offer code:', error);
586
+ verboseLog(`Error fetching offer code: ${error}`);
587
+ return null;
588
+ }
589
+ });
590
+ const openRedeemURL = (offerCode, offerCodeUrlId) => __awaiter(void 0, void 0, void 0, function* () {
591
+ try {
592
+ const redeemUrl = `https://apps.apple.com/redeem?ctx=offercodes&id=${offerCodeUrlId}&code=${offerCode}`;
593
+ verboseLog(`Opening redeem URL: ${redeemUrl}`);
594
+ const canOpen = yield react_native_1.Linking.canOpenURL(redeemUrl);
595
+ if (canOpen) {
596
+ yield react_native_1.Linking.openURL(redeemUrl);
597
+ console.log('[Insert Affiliate] Successfully opened redeem URL');
598
+ verboseLog('Successfully opened redeem URL');
599
+ }
600
+ else {
601
+ console.error(`[Insert Affiliate] Could not launch redeem URL: ${redeemUrl}`);
602
+ verboseLog(`Could not launch redeem URL: ${redeemUrl}`);
603
+ }
604
+ }
605
+ catch (error) {
606
+ console.error('[Insert Affiliate] Error opening redeem URL:', error);
607
+ verboseLog(`Error opening redeem URL: ${error}`);
608
+ }
609
+ });
610
+ const cleanOfferCode = (offerCode) => {
611
+ // Remove special characters, keep only alphanumeric
612
+ return offerCode.replace(/[^a-zA-Z0-9]/g, '');
613
+ };
532
614
  return (react_1.default.createElement(exports.DeepLinkIapContext.Provider, { value: {
533
615
  referrerLink,
534
616
  userId,
@@ -541,6 +623,7 @@ const DeepLinkIapProvider = ({ children, }) => {
541
623
  setInsertAffiliateIdentifier,
542
624
  initialize,
543
625
  isInitialized,
626
+ fetchAndConditionallyOpenUrl,
544
627
  } }, children));
545
628
  };
546
629
  exports.default = DeepLinkIapProvider;
@@ -12,5 +12,6 @@ declare const useDeepLinkIapProvider: () => {
12
12
  setInsertAffiliateIdentifier: (referringLink: string) => Promise<void | string>;
13
13
  initialize: (code: string | null, verboseLogging?: boolean) => Promise<void>;
14
14
  isInitialized: boolean;
15
+ fetchAndConditionallyOpenUrl: (affiliateIdentifier: string, offerCodeUrlId: string) => Promise<boolean>;
15
16
  };
16
17
  export default useDeepLinkIapProvider;
@@ -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, initialize, isInitialized } = (0, react_1.useContext)(DeepLinkIapProvider_1.DeepLinkIapContext);
6
+ const { referrerLink, userId, validatePurchaseWithIapticAPI, storeExpectedStoreTransaction, returnUserAccountTokenAndStoreExpectedTransaction, returnInsertAffiliateIdentifier, trackEvent, setShortCode, setInsertAffiliateIdentifier, initialize, isInitialized, fetchAndConditionallyOpenUrl } = (0, react_1.useContext)(DeepLinkIapProvider_1.DeepLinkIapContext);
7
7
  return {
8
8
  referrerLink,
9
9
  userId,
@@ -15,7 +15,8 @@ const useDeepLinkIapProvider = () => {
15
15
  setShortCode,
16
16
  setInsertAffiliateIdentifier,
17
17
  initialize,
18
- isInitialized
18
+ isInitialized,
19
+ fetchAndConditionallyOpenUrl
19
20
  };
20
21
  };
21
22
  exports.default = useDeepLinkIapProvider;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "insert-affiliate-react-native-sdk",
3
- "version": "1.5.1",
3
+ "version": "1.6.1",
4
4
  "description": "A package for connecting with the Insert Affiliate Platform to add app based affiliate marketing.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/readme.md CHANGED
@@ -498,7 +498,7 @@ At this stage, we cannot guarantee that this feature is fully resistant to tampe
498
498
 
499
499
  #### Using `trackEvent`
500
500
 
501
- To track an event, use the `trackEvent` function. Make sure to set an affiliate identifier first; otherwise, event tracking wont work. Heres an example:
501
+ To track an event, use the `trackEvent` function. Make sure to set an affiliate identifier first; otherwise, event tracking won't work. Here's an example:
502
502
 
503
503
  ```javascript
504
504
  const {
@@ -520,7 +520,127 @@ const {
520
520
  />
521
521
  ```
522
522
 
523
- ### 2. Short Codes (Beta)
523
+ ### 2. Offer Codes
524
+
525
+ Offer Codes allow you to automatically present a discount to users who access an affiliate's link or enter a short code. This provides affiliates with a compelling incentive to promote your app, as discounts are automatically applied during the redemption flow [(learn more)](https://docs.insertaffiliate.com/offer-codes).
526
+
527
+ **Note: Offer Codes are currently only supported on iOS.**
528
+
529
+ You'll need your Offer Code URL ID, which can be created and retrieved from App Store Connect. Instructions to retrieve your Offer Code URL ID are available [here](https://docs.insertaffiliate.com/offer-codes#create-the-codes-within-app-store-connect).
530
+
531
+ To fetch an Offer Code and conditionally redirect the user to redeem it, pass the affiliate identifier (deep link or short code) to:
532
+
533
+ ```javascript
534
+ const { fetchAndConditionallyOpenUrl } = useDeepLinkIapProvider();
535
+
536
+ await fetchAndConditionallyOpenUrl("your_affiliate_identifier", "your_offer_code_url_id");
537
+ ```
538
+
539
+ #### Branch.io Example
540
+
541
+ ```javascript
542
+ import React, { useEffect } from 'react';
543
+ import branch from 'react-native-branch';
544
+ import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
545
+
546
+ const DeepLinkHandler = () => {
547
+ const { fetchAndConditionallyOpenUrl } = useDeepLinkIapProvider();
548
+
549
+ useEffect(() => {
550
+ const branchSubscription = branch.subscribe(async ({ error, params }) => {
551
+ if (error) {
552
+ console.error('Error from Branch:', error);
553
+ return;
554
+ }
555
+
556
+ if (params['+clicked_branch_link']) {
557
+ const referringLink = params['~referring_link'];
558
+ if (referringLink) {
559
+ try {
560
+ await fetchAndConditionallyOpenUrl(
561
+ referringLink,
562
+ "{{ your_offer_code_url_id }}"
563
+ );
564
+
565
+ // Other code required for Insert Affiliate in the other listed steps...
566
+ } catch (err) {
567
+ console.error('Error with offer code:', err);
568
+ }
569
+ }
570
+ }
571
+ });
572
+
573
+ return () => branchSubscription();
574
+ }, [fetchAndConditionallyOpenUrl]);
575
+
576
+ return <App />;
577
+ };
578
+ ```
579
+
580
+ #### Short Code Example
581
+
582
+ ```javascript
583
+ import React, { useState } from 'react';
584
+ import { View, TextInput, Button, StyleSheet } from 'react-native';
585
+ import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
586
+
587
+ const ShortCodeInputWidget = () => {
588
+ const [shortCode, setShortCode] = useState('');
589
+ const { setShortCode: setInsertAffiliateShortCode, fetchAndConditionallyOpenUrl } = useDeepLinkIapProvider();
590
+
591
+ const handleShortCodeSubmission = async () => {
592
+ const trimmedCode = shortCode.trim();
593
+
594
+ if (trimmedCode.length > 0) {
595
+ try {
596
+ // Set the short code for affiliate tracking
597
+ await setInsertAffiliateShortCode(trimmedCode);
598
+
599
+ // Fetch and conditionally open offer code URL
600
+ await fetchAndConditionallyOpenUrl(
601
+ trimmedCode,
602
+ "{{ your_offer_code_url_id }}"
603
+ );
604
+ } catch (error) {
605
+ console.error('Error handling short code:', error);
606
+ }
607
+ }
608
+ };
609
+
610
+ return (
611
+ <View style={styles.container}>
612
+ <TextInput
613
+ style={styles.input}
614
+ value={shortCode}
615
+ onChangeText={setShortCode}
616
+ placeholder="Enter your code"
617
+ placeholderTextColor="#ABC123"
618
+ />
619
+ <Button
620
+ title="Apply Code"
621
+ onPress={handleShortCodeSubmission}
622
+ />
623
+ </View>
624
+ );
625
+ };
626
+
627
+ const styles = StyleSheet.create({
628
+ container: {
629
+ padding: 20,
630
+ },
631
+ input: {
632
+ borderWidth: 1,
633
+ borderColor: '#ddd',
634
+ padding: 10,
635
+ marginBottom: 10,
636
+ borderRadius: 5,
637
+ },
638
+ });
639
+
640
+ export default ShortCodeInputWidget;
641
+ ```
642
+
643
+ ### 3. Short Codes (Beta)
524
644
 
525
645
  #### What are Short Codes?
526
646
 
@@ -1,5 +1,5 @@
1
1
  import React, { createContext, useEffect, useState } from 'react';
2
- import { Platform } from 'react-native';
2
+ import { Platform, Linking } from 'react-native';
3
3
  import axios from 'axios';
4
4
  import AsyncStorage from '@react-native-async-storage/async-storage';
5
5
 
@@ -32,6 +32,10 @@ type T_DEEPLINK_IAP_CONTEXT = {
32
32
  referringLink: string
33
33
  ) => Promise<void | string>;
34
34
  initialize: (code: string | null, verboseLogging?: boolean) => Promise<void>;
35
+ fetchAndConditionallyOpenUrl: (
36
+ affiliateIdentifier: string,
37
+ offerCodeUrlId: string
38
+ ) => Promise<boolean>;
35
39
  isInitialized: boolean;
36
40
  };
37
41
 
@@ -76,6 +80,10 @@ export const DeepLinkIapContext = createContext<T_DEEPLINK_IAP_CONTEXT>({
76
80
  setShortCode: async (shortCode: string) => {},
77
81
  setInsertAffiliateIdentifier: async (referringLink: string) => {},
78
82
  initialize: async (code: string | null, verboseLogging?: boolean) => {},
83
+ fetchAndConditionallyOpenUrl: async (
84
+ affiliateIdentifier: string,
85
+ offerCodeUrlId: string
86
+ ) => false,
79
87
  isInitialized: false,
80
88
  });
81
89
 
@@ -638,6 +646,101 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
638
646
  }
639
647
  };
640
648
 
649
+ const fetchAndConditionallyOpenUrl = async (
650
+ affiliateIdentifier: string,
651
+ offerCodeUrlId: string
652
+ ): Promise<boolean> => {
653
+ try {
654
+ verboseLog(`Attempting to fetch and conditionally open URL for affiliate: ${affiliateIdentifier}, offerCodeUrlId: ${offerCodeUrlId}`);
655
+
656
+ if (Platform.OS !== 'ios') {
657
+ console.warn("[Insert Affiliate] Offer codes are only supported on iOS");
658
+ verboseLog("Offer codes are only supported on iOS");
659
+ return false;
660
+ }
661
+
662
+ const offerCode = await fetchOfferCode(affiliateIdentifier);
663
+
664
+ if (offerCode && offerCode.length > 0) {
665
+ await openRedeemURL(offerCode, offerCodeUrlId);
666
+ return true;
667
+ } else {
668
+ verboseLog("No valid offer code found");
669
+ return false;
670
+ }
671
+ } catch (error) {
672
+ console.error('[Insert Affiliate] Error fetching and opening offer code URL:', error);
673
+ verboseLog(`Error fetching and opening offer code URL: ${error}`);
674
+ return false;
675
+ }
676
+ };
677
+
678
+ const fetchOfferCode = async (affiliateLink: string): Promise<string | null> => {
679
+ try {
680
+
681
+
682
+ const encodedAffiliateLink = encodeURIComponent(affiliateLink);
683
+ const url = `https://api.insertaffiliate.com/v1/affiliateReturnOfferCode/${encodedAffiliateLink}`;
684
+
685
+ verboseLog(`Fetching offer code from: ${url}`);
686
+
687
+ const response = await axios.get(url);
688
+
689
+ if (response.status === 200) {
690
+ const offerCode = response.data;
691
+
692
+ // Check for specific error strings from API
693
+ if (typeof offerCode === 'string' && (
694
+ offerCode.includes("errorofferCodeNotFound") ||
695
+ offerCode.includes("errorAffiliateoffercodenotfoundinanycompany") ||
696
+ offerCode.includes("errorAffiliateoffercodenotfoundinanycompanyAffiliatelinkwas") ||
697
+ offerCode.includes("Routenotfound")
698
+ )) {
699
+ console.warn(`[Insert Affiliate] Offer code not found or invalid: ${offerCode}`);
700
+ verboseLog(`Offer code not found or invalid: ${offerCode}`);
701
+ return null;
702
+ }
703
+
704
+ const cleanedOfferCode = cleanOfferCode(offerCode);
705
+ verboseLog(`Successfully fetched and cleaned offer code: ${cleanedOfferCode}`);
706
+ return cleanedOfferCode;
707
+ } else {
708
+ console.error(`[Insert Affiliate] Failed to fetch offer code. Status code: ${response.status}, Response: ${JSON.stringify(response.data)}`);
709
+ verboseLog(`Failed to fetch offer code. Status code: ${response.status}, Response: ${JSON.stringify(response.data)}`);
710
+ return null;
711
+ }
712
+ } catch (error) {
713
+ console.error('[Insert Affiliate] Error fetching offer code:', error);
714
+ verboseLog(`Error fetching offer code: ${error}`);
715
+ return null;
716
+ }
717
+ };
718
+
719
+ const openRedeemURL = async (offerCode: string, offerCodeUrlId: string): Promise<void> => {
720
+ try {
721
+ const redeemUrl = `https://apps.apple.com/redeem?ctx=offercodes&id=${offerCodeUrlId}&code=${offerCode}`;
722
+ verboseLog(`Opening redeem URL: ${redeemUrl}`);
723
+
724
+ const canOpen = await Linking.canOpenURL(redeemUrl);
725
+ if (canOpen) {
726
+ await Linking.openURL(redeemUrl);
727
+ console.log('[Insert Affiliate] Successfully opened redeem URL');
728
+ verboseLog('Successfully opened redeem URL');
729
+ } else {
730
+ console.error(`[Insert Affiliate] Could not launch redeem URL: ${redeemUrl}`);
731
+ verboseLog(`Could not launch redeem URL: ${redeemUrl}`);
732
+ }
733
+ } catch (error) {
734
+ console.error('[Insert Affiliate] Error opening redeem URL:', error);
735
+ verboseLog(`Error opening redeem URL: ${error}`);
736
+ }
737
+ };
738
+
739
+ const cleanOfferCode = (offerCode: string): string => {
740
+ // Remove special characters, keep only alphanumeric
741
+ return offerCode.replace(/[^a-zA-Z0-9]/g, '');
742
+ };
743
+
641
744
  return (
642
745
  <DeepLinkIapContext.Provider
643
746
  value={{
@@ -652,6 +755,7 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
652
755
  setInsertAffiliateIdentifier,
653
756
  initialize,
654
757
  isInitialized,
758
+ fetchAndConditionallyOpenUrl,
655
759
  }}
656
760
  >
657
761
  {children}
@@ -13,7 +13,8 @@ const useDeepLinkIapProvider = () => {
13
13
  setShortCode,
14
14
  setInsertAffiliateIdentifier,
15
15
  initialize,
16
- isInitialized
16
+ isInitialized,
17
+ fetchAndConditionallyOpenUrl
17
18
  } = useContext(DeepLinkIapContext);
18
19
 
19
20
  return {
@@ -27,7 +28,8 @@ const useDeepLinkIapProvider = () => {
27
28
  setShortCode,
28
29
  setInsertAffiliateIdentifier,
29
30
  initialize,
30
- isInitialized
31
+ isInitialized,
32
+ fetchAndConditionallyOpenUrl
31
33
  };
32
34
  };
33
35