From 7ed2e65be9cda02902d8e6b385f9dc478c623813 Mon Sep 17 00:00:00 2001 From: wesleyorbin Date: Fri, 24 Sep 2021 15:11:17 -0400 Subject: [PATCH] Release version 1.33.0 --- AppboyProject/AppboyProject.js | 3 +- .../android/app/src/main/AndroidManifest.xml | 1 + .../java/com/appboyproject/MainActivity.java | 6 ++ .../android/app/src/main/res/values/braze.xml | 10 +- AppboyProject/ios/Podfile.lock | 22 ++--- AppboyProject/package.json | 2 +- AppboyProject/yarn.lock | 8 +- CHANGELOG.md | 10 ++ __tests__/index.test.js | 14 +++ android/build.gradle | 10 +- .../appboy/reactbridge/AppboyReactBridge.java | 99 ++++++++++++------- android/src/main/res/values/braze.xml | 2 +- .../AppboyReactBridge/AppboyReactBridge.m | 71 ++++++++++--- index.d.ts | 14 +++ index.js | 76 ++++++++++---- package.json | 2 +- react-native-appboy-sdk.podspec | 2 +- 17 files changed, 255 insertions(+), 97 deletions(-) diff --git a/AppboyProject/AppboyProject.js b/AppboyProject/AppboyProject.js index e6b657e..d7ab01a 100644 --- a/AppboyProject/AppboyProject.js +++ b/AppboyProject/AppboyProject.js @@ -350,6 +350,7 @@ class AppboyProject extends Component { var testDate = new Date(); ReactAppboy.logCustomEvent(this.state.customEventText, {'stringKey': 'stringValue', 'intKey': 42, 'floatKey': 1.23, 'boolKey': true, 'dateKey': testDate}); ReactAppboy.logCustomEvent(this.state.customEventText + 'NoProps'); + ReactAppboy.logCustomEvent(this.state.customEventText, {'arrayKey': ['arrayVal1', 'arrayVal2', testDate, [testDate, 'nestedArrayval'], {'dictInArrayKey': testDate}], 'dictKey': {'dictKey1': 'dictVal1', 'dictKey2': testDate, 'dictKey3': {'nestedDictKey1': testDate}, 'dictKey4': ['nestedArrayVal1', 'nestedArrayVal2']}}); this._showToast('Event logged: ' + this.state.customEventText); } _setLanguagePress(event) { @@ -396,7 +397,7 @@ class AppboyProject extends Component { } _logPurchasePress(event) { var testDate = new Date(); - ReactAppboy.logPurchase('reactProductIdentifier', '1.2', 'USD', 2, {'stringKey': 'stringValue', 'intKey': 42, 'floatKey': 1.23, 'boolKey': true, 'dateKey': testDate}); + ReactAppboy.logPurchase('reactProductIdentifier', '1.2', 'USD', 2, {'stringKey': 'stringValue', 'intKey': 42, 'floatKey': 1.23, 'boolKey': true, 'dateKey': testDate, 'dictKey':{'dictKey1': 'dictVal1'}}); ReactAppboy.logPurchase('reactProductIdentifier' + 'NoProps', '1.2', 'USD', 2); this._showToast('Purchase logged'); } diff --git a/AppboyProject/android/app/src/main/AndroidManifest.xml b/AppboyProject/android/app/src/main/AndroidManifest.xml index 3f90d77..eefef38 100644 --- a/AppboyProject/android/app/src/main/AndroidManifest.xml +++ b/AppboyProject/android/app/src/main/AndroidManifest.xml @@ -24,6 +24,7 @@ android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" + android:launchMode="singleTask" android:windowSoftInputMode="adjustResize"> diff --git a/AppboyProject/android/app/src/main/java/com/appboyproject/MainActivity.java b/AppboyProject/android/app/src/main/java/com/appboyproject/MainActivity.java index a600dbd..72f8aee 100644 --- a/AppboyProject/android/app/src/main/java/com/appboyproject/MainActivity.java +++ b/AppboyProject/android/app/src/main/java/com/appboyproject/MainActivity.java @@ -72,6 +72,12 @@ public void afterInAppMessageViewClosed(IInAppMessage inAppMessage) { } BrazeInAppMessageManager.getInstance().setCustomInAppMessageManagerListener(new BrazeInAppMessageManagerListener()); } + @Override + public void onNewIntent(Intent intent) { + super.onNewIntent(intent); + setIntent(intent); + } + /** * Returns the name of the main component registered from JavaScript. * This is used to schedule rendering of the component. diff --git a/AppboyProject/android/app/src/main/res/values/braze.xml b/AppboyProject/android/app/src/main/res/values/braze.xml index 2cacd7c..83b4d2c 100644 --- a/AppboyProject/android/app/src/main/res/values/braze.xml +++ b/AppboyProject/android/app/src/main/res/values/braze.xml @@ -2,11 +2,11 @@ - 8220f3a6-2e82-4737-a83a-aab39eb1bcef - STAGING + 8220f3a6-2e82-4737-a83a-aab39eb1bcef + STAGING - true - 531790618696 + true + 531790618696 - true + true diff --git a/AppboyProject/ios/Podfile.lock b/AppboyProject/ios/Podfile.lock index aca60d1..897e2e1 100644 --- a/AppboyProject/ios/Podfile.lock +++ b/AppboyProject/ios/Podfile.lock @@ -1,17 +1,17 @@ PODS: - - Appboy-iOS-SDK (4.3.2): - - Appboy-iOS-SDK/UI (= 4.3.2) - - Appboy-iOS-SDK/ContentCards (4.3.2): + - Appboy-iOS-SDK (4.3.4): + - Appboy-iOS-SDK/UI (= 4.3.4) + - Appboy-iOS-SDK/ContentCards (4.3.4): - Appboy-iOS-SDK/Core - SDWebImage (< 6, >= 5.8.2) - - Appboy-iOS-SDK/Core (4.3.2) - - Appboy-iOS-SDK/InAppMessage (4.3.2): + - Appboy-iOS-SDK/Core (4.3.4) + - Appboy-iOS-SDK/InAppMessage (4.3.4): - Appboy-iOS-SDK/Core - SDWebImage (< 6, >= 5.8.2) - - Appboy-iOS-SDK/NewsFeed (4.3.2): + - Appboy-iOS-SDK/NewsFeed (4.3.4): - Appboy-iOS-SDK/Core - SDWebImage (< 6, >= 5.8.2) - - Appboy-iOS-SDK/UI (4.3.2): + - Appboy-iOS-SDK/UI (4.3.4): - Appboy-iOS-SDK/ContentCards - Appboy-iOS-SDK/Core - Appboy-iOS-SDK/InAppMessage @@ -199,8 +199,8 @@ PODS: - React-cxxreact (= 0.61.5) - React-jsi (= 0.61.5) - React-jsinspector (0.61.5) - - react-native-appboy-sdk (1.32.0): - - Appboy-iOS-SDK (~> 4.3.2) + - react-native-appboy-sdk (1.33.0): + - Appboy-iOS-SDK (~> 4.3.4) - React - React-RCTActionSheet (0.61.5): - React-Core/RCTActionSheetHeaders (= 0.61.5) @@ -334,7 +334,7 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/yoga" SPEC CHECKSUMS: - Appboy-iOS-SDK: 173d96a8e903e1dff8bbc200f2a95f39cac9af21 + Appboy-iOS-SDK: dd22a28a003c5a1331080ecec398eaa4d7ef4569 boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2 FBLazyVector: aaeaf388755e4f29cd74acbc9e3b8da6d807c37f @@ -350,7 +350,7 @@ SPEC CHECKSUMS: React-jsi: cb2cd74d7ccf4cffb071a46833613edc79cdf8f7 React-jsiexecutor: d5525f9ed5f782fdbacb64b9b01a43a9323d2386 React-jsinspector: fa0ecc501688c3c4c34f28834a76302233e29dc0 - react-native-appboy-sdk: 1aa507125262dc879e8cbad2ba119ce95b5e021d + react-native-appboy-sdk: f1a5fda43cad5f3e9ce01d81ed64edffcf5f4bed React-RCTActionSheet: 600b4d10e3aea0913b5a92256d2719c0cdd26d76 React-RCTAnimation: 791a87558389c80908ed06cc5dfc5e7920dfa360 React-RCTBlob: d89293cc0236d9cb0933d85e430b0bbe81ad1d72 diff --git a/AppboyProject/package.json b/AppboyProject/package.json index c0e18eb..6863cbc 100644 --- a/AppboyProject/package.json +++ b/AppboyProject/package.json @@ -13,7 +13,7 @@ "dependencies": { "react": "16.9.0", "react-native": "^0.61.5", - "react-native-appboy-sdk": "file:../" + "react-native-appboy-sdk": "file:.." }, "devDependencies": { "@babel/core": "^7.6.2", diff --git a/AppboyProject/yarn.lock b/AppboyProject/yarn.lock index c3f6f4f..f69ce79 100644 --- a/AppboyProject/yarn.lock +++ b/AppboyProject/yarn.lock @@ -5001,7 +5001,7 @@ react-is@^16.8.1, react-is@^16.8.4, react-is@^16.9.0: integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q== "react-native-appboy-sdk@file:..": - version "1.32.0" + version "1.33.0" react-native@^0.61.5: version "0.61.5" @@ -5914,9 +5914,9 @@ tmp@^0.0.33: os-tmpdir "~1.0.2" tmpl@1.0.x: - version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" - integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== to-fast-properties@^2.0.0: version "2.0.0" diff --git a/CHANGELOG.md b/CHANGELOG.md index de508e7..15fc3f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## 1.33.0 + +##### ⚠ Breaking +- Updated the native Android bridge to [Braze Android SDK 16.0.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#1600). +- Updated the native iOS bridge to [Braze iOS SDK 4.3.4](https://github.com/Appboy/appboy-ios-sdk/blob/master/CHANGELOG.md#434). + +##### Added +- Added `ReactAppboy.addToSubscriptionGroup()` and `ReactAppboy.removeFromSubscriptionGroup()` to manage SMS/Email Subscription Groups. +- Custom events and purchases now support nested properties. In addition to integers, floats, booleans, dates, or strings, a JSON object can be provided containing dictionaries of arrays or nested dictionaries. All properties combined can be up to 50 KB in total length. + ## 1.32.0 ##### ⚠ Breaking diff --git a/__tests__/index.test.js b/__tests__/index.test.js index c47118a..d5ec286 100644 --- a/__tests__/index.test.js +++ b/__tests__/index.test.js @@ -56,6 +56,8 @@ jest.mock('NativeModules', () => { setDoubleCustomUserAttribute: jest.fn(), incrementCustomUserAttribute: jest.fn(), setGender: jest.fn(), + addToSubscriptionGroup: jest.fn(), + removeFromSubscriptionGroup: jest.fn(), setPushNotificationSubscriptionType: jest.fn(), setEmailNotificationSubscriptionType: jest.fn(), addToCustomAttributeArray: jest.fn(), @@ -391,6 +393,18 @@ test('it calls AppboyReactBridge.setGender', () => { expect(NativeModules.AppboyReactBridge.setGender).toBeCalledWith(gender, testCallback); }); +test('it calls AppboyReactBridge.addToSubscriptionGroup', () => { + const groupId = "some_group_id"; + ReactAppboy.addToSubscriptionGroup(groupId, testCallback); + expect(NativeModules.AppboyReactBridge.addToSubscriptionGroup).toBeCalledWith(groupId, testCallback); +}); + +test('it calls AppboyReactBridge.removeFromSubscriptionGroup', () => { + const groupId = "some_group_id"; + ReactAppboy.removeFromSubscriptionGroup(groupId, testCallback); + expect(NativeModules.AppboyReactBridge.removeFromSubscriptionGroup).toBeCalledWith(groupId, testCallback); +}); + test('it calls AppboyReactBridge.setPushNotificationSubscriptionType', () => { const sub_type = "some_sub_type"; ReactAppboy.setPushNotificationSubscriptionType(sub_type, testCallback); diff --git a/android/build.gradle b/android/build.gradle index e49a6a9..1ada444 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -5,16 +5,16 @@ def safeExtGet(prop, fallback) { } android { - compileSdkVersion safeExtGet('compileSdkVersion', 30) - buildToolsVersion safeExtGet('buildToolsVersion', '30.0.2') + compileSdkVersion safeExtGet('compileSdkVersion', 31) + buildToolsVersion safeExtGet('buildToolsVersion', '31.0.0') defaultConfig { minSdkVersion safeExtGet('minSdkVersion', 16) - targetSdkVersion safeExtGet('targetSdkVersion', 30) + targetSdkVersion safeExtGet('targetSdkVersion', 31) versionCode 1 versionName '1.0' } - + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -22,6 +22,6 @@ android { } dependencies { - api 'com.appboy:android-sdk-ui:15.0.0' + api 'com.appboy:android-sdk-ui:16.0.0' api 'com.facebook.react:react-native:+' } diff --git a/android/src/main/java/com/appboy/reactbridge/AppboyReactBridge.java b/android/src/main/java/com/appboy/reactbridge/AppboyReactBridge.java index 087899b..ad59853 100644 --- a/android/src/main/java/com/appboy/reactbridge/AppboyReactBridge.java +++ b/android/src/main/java/com/appboy/reactbridge/AppboyReactBridge.java @@ -55,6 +55,7 @@ import java.util.Date; import java.util.List; import java.util.Map; +import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; public class AppboyReactBridge extends ReactContextBaseJavaModule { @@ -145,51 +146,51 @@ public void logCustomEvent(String eventName, ReadableMap eventProperties) { } private AppboyProperties populateEventPropertiesFromReadableMap(ReadableMap eventProperties) { - AppboyProperties properties = new AppboyProperties(); - ReadableMapKeySetIterator keySetIterator = eventProperties.keySetIterator(); if (eventProperties == JSONObject.NULL) { - return properties; + return new AppboyProperties(); } + return new AppboyProperties(new JSONObject(parseReadableMap(eventProperties))); + } + + private Map parseReadableMap(ReadableMap readableMap) { + ReadableMapKeySetIterator keySetIterator = readableMap.keySetIterator(); + Map parsedMap = readableMap.toHashMap(); while (keySetIterator.hasNextKey()) { String key = keySetIterator.nextKey(); - ReadableType readableType = eventProperties.getType(key); - switch (readableType) { - case String: - properties.addProperty(key, eventProperties.getString(key)); - break; - case Boolean: - properties.addProperty(key, eventProperties.getBoolean(key)); - break; - case Number: - try { - properties.addProperty(key, eventProperties.getDouble(key)); - } catch (Exception e) { - try { - properties.addProperty(key, eventProperties.getInt(key)); - } catch (Exception e2) { - AppboyLogger.e(TAG, "Could not parse ReadableType.Number from ReadableMap for key: " + key, e2); - } - } - break; - case Map: - try { - if (eventProperties.getMap(key).getString("type").equals("UNIX_timestamp")) { - double unixTimestamp = eventProperties.getMap(key).getDouble("value"); - properties.addProperty(key, new Date((long) unixTimestamp)); - } else { - AppboyLogger.w(TAG, "Unsupported ReadableMap type received for key: " + key); - } - } catch (Exception e) { - AppboyLogger.e(TAG, "Could not determine type from ReadableMap for key: " + key, e); - } - break; - default: - AppboyLogger.w(TAG, "Could not map ReadableType to an AppboyProperty value for key: " + key); - break; + ReadableType readableType = readableMap.getType(key); + if (readableType == readableType.Map) { + if (readableMap.getMap(key).hasKey("type") && + readableMap.getMap(key).getString("type").equals("UNIX_timestamp")) { + double unixTimestamp = readableMap.getMap(key).getDouble("value"); + parsedMap.put(key, new Date((long) unixTimestamp)); + } else { + parsedMap.put(key, parseReadableMap(readableMap.getMap(key))); + } + } else if (readableType == readableType.Array) { + parsedMap.put(key, parseReadableArray(readableMap.getArray(key))); + } + } + return parsedMap; + } + + private List parseReadableArray(ReadableArray readableArray) { + List parsedList = readableArray.toArrayList(); + for (int i = 0; i < readableArray.size(); i++) { + ReadableType readableType = readableArray.getType(i); + if (readableType == readableType.Map) { + if (readableArray.getMap(i).hasKey("type") && + readableArray.getMap(i).getString("type").equals("UNIX_timestamp")) { + double unixTimestamp = readableArray.getMap(i).getDouble("value"); + parsedList.set(i, new Date((long) unixTimestamp)); + } else { + parsedList.set(i, parseReadableMap(readableArray.getMap(i))); + } + } else if (readableType == readableType.Array) { + parsedList.set(i, parseReadableArray(readableArray.getArray(i))); } } - return properties; + return parsedList; } @ReactMethod @@ -437,6 +438,28 @@ public void onSuccess(@NonNull BrazeUser brazeUser) { }); } + @ReactMethod + public void addToSubscriptionGroup(String groupId, final Callback callback) { + Braze.getInstance(getReactApplicationContext()).getCurrentUser(new SimpleValueCallback() { + @Override + public void onSuccess(@NonNull BrazeUser brazeUser) { + boolean result = brazeUser.addToSubscriptionGroup(groupId); + reportResultWithCallback(callback, null, result); + } + }); + } + + @ReactMethod + public void removeFromSubscriptionGroup(String groupId, final Callback callback) { + Braze.getInstance(getReactApplicationContext()).getCurrentUser(new SimpleValueCallback() { + @Override + public void onSuccess(@NonNull BrazeUser brazeUser) { + boolean result = brazeUser.removeFromSubscriptionGroup(groupId); + reportResultWithCallback(callback, null, result); + } + }); + } + @ReactMethod public void setPushNotificationSubscriptionType(String subscriptionType, final Callback callback) { final NotificationSubscriptionType notificationSubscriptionType; diff --git a/android/src/main/res/values/braze.xml b/android/src/main/res/values/braze.xml index 51119c0..3927da9 100644 --- a/android/src/main/res/values/braze.xml +++ b/android/src/main/res/values/braze.xml @@ -1,5 +1,5 @@ - REACT + REACT diff --git a/iOS/AppboyReactBridge/AppboyReactBridge/AppboyReactBridge.m b/iOS/AppboyReactBridge/AppboyReactBridge/AppboyReactBridge.m index afdc330..53e8d65 100644 --- a/iOS/AppboyReactBridge/AppboyReactBridge/AppboyReactBridge.m +++ b/iOS/AppboyReactBridge/AppboyReactBridge/AppboyReactBridge.m @@ -115,29 +115,68 @@ - (void)reportResultWithCallback:(RCTResponseSenderBlock)callback andError:(NSSt RCT_EXPORT_METHOD(logCustomEvent:(NSString *)eventName withProperties:(nullable NSDictionary *)properties) { RCTLogInfo(@"[Appboy sharedInstance] logCustomEvent with eventName %@", eventName); - NSMutableDictionary *transformedProperties = [properties mutableCopy]; - for (NSString* key in properties) { - if ([properties[key] isKindOfClass:[NSDictionary class]]) { - NSDictionary* value = properties[key]; - NSString* type = value[@"type"]; + if (!properties) { + [[Appboy sharedInstance] logCustomEvent:eventName]; + return; + } + + [[Appboy sharedInstance] logCustomEvent:eventName withProperties:[self parseDictionary:properties]]; +} + +- (NSDictionary *)parseDictionary:(NSDictionary *)dictionary { + NSArray *keys = [dictionary allKeys]; + NSMutableDictionary *parsedDictionary = [dictionary mutableCopy]; + for (NSString *key in keys) { + if ([dictionary[key] isKindOfClass:[NSDictionary class]]){ + NSString* type = dictionary[key][@"type"]; if ([type isEqualToString:@"UNIX_timestamp"]) { - double timestamp = [value[@"value"] doubleValue]; + double timestamp = [dictionary[key][@"value"] doubleValue]; NSDate* nativeDate = [NSDate dateWithTimeIntervalSince1970:(timestamp / 1000.0)]; - [transformedProperties setObject:nativeDate forKey:key]; + [parsedDictionary setObject:nativeDate forKey:key]; } else { - [transformedProperties removeObjectForKey:key]; - RCTLogInfo(@"[Appboy sharedInstance] logCustomEvent property not supported %@", type); + NSDictionary *dictProperty = (NSDictionary *)dictionary[key]; + [parsedDictionary setObject:[self parseDictionary:dictProperty] forKey:key]; } + } else if ([dictionary[key] isKindOfClass:[NSArray class]]) { + NSArray *array = (NSArray *)dictionary[key]; + [parsedDictionary setObject:[self parseArray:array] forKey:key]; } } - [[Appboy sharedInstance] logCustomEvent:eventName withProperties:transformedProperties]; + return parsedDictionary; +} + +- (NSArray *)parseArray:(NSArray *)array { + NSMutableArray *parsedArray = [array mutableCopy]; + for (int i = 0; i < array.count; i++) { + if ([array[i] isKindOfClass:[NSDictionary class]]){ + NSString* type = array[i][@"type"]; + if ([type isEqualToString:@"UNIX_timestamp"]) { + double timestamp = [array[i][@"value"] doubleValue]; + NSDate* nativeDate = [NSDate dateWithTimeIntervalSince1970:(timestamp / 1000.0)]; + parsedArray[i] = nativeDate; + } else { + NSDictionary *dictionary = (NSDictionary *)array[i]; + parsedArray[i] = [self parseDictionary:dictionary]; + } + } else if ([array[i] isKindOfClass:[NSArray class]]) { + NSArray *arrayProperty = (NSArray *)array[i]; + parsedArray[i] = [self parseArray:arrayProperty]; + } + } + + return parsedArray; } RCT_EXPORT_METHOD(logPurchase:(NSString *)productIdentifier atPrice:(NSString *)price inCurrency:(NSString *)currencyCode withQuantity:(NSUInteger)quantity andProperties:(nullable NSDictionary *)properties) { RCTLogInfo(@"[Appboy sharedInstance] logPurchase with productIdentifier %@", productIdentifier); NSDecimalNumber *decimalPrice = [NSDecimalNumber decimalNumberWithString:price]; - [[Appboy sharedInstance] logPurchase:productIdentifier inCurrency:currencyCode atPrice:decimalPrice withQuantity:quantity andProperties:properties]; + if (!properties) { + [[Appboy sharedInstance] logPurchase:productIdentifier inCurrency:currencyCode atPrice:decimalPrice withQuantity:quantity]; + return; + } + + [[Appboy sharedInstance] logPurchase:productIdentifier inCurrency:currencyCode atPrice:decimalPrice withQuantity:quantity andProperties:[self parseDictionary:properties]]; } RCT_EXPORT_METHOD(setFirstName:(NSString *)firstName) { @@ -210,6 +249,16 @@ - (void)reportResultWithCallback:(RCTResponseSenderBlock)callback andError:(NSSt [Appboy sharedInstance].user.avatarImageURL = avatarImageURL; } +RCT_EXPORT_METHOD(addToSubscriptionGroup:(NSString *)groupId callback:(RCTResponseSenderBlock)callback) { + RCTLogInfo(@"[Appboy sharedInstance].user addtoSubscriptionGroup: = %@", groupId); + [self reportResultWithCallback:callback andError:nil andResult:@([[Appboy sharedInstance].user addToSubscriptionGroup:groupId])]; +} + +RCT_EXPORT_METHOD(removeFromSubscriptionGroup:(NSString *)groupId callback:(RCTResponseSenderBlock)callback) { + RCTLogInfo(@"[Appboy sharedInstance].user removeFromSubscriptionGroup: = %@", groupId); + [self reportResultWithCallback:callback andError:nil andResult:@([[Appboy sharedInstance].user removeFromSubscriptionGroup:groupId])]; +} + RCT_EXPORT_METHOD(setEmailNotificationSubscriptionType:(ABKNotificationSubscriptionType)emailNotificationSubscriptionType callback:(RCTResponseSenderBlock)callback) { RCTLogInfo(@"[Appboy sharedInstance].user.emailNotificationSubscriptionType = %@", @"enum"); [self reportResultWithCallback:callback andError:nil andResult:@([Appboy sharedInstance].user.emailNotificationSubscriptionType = emailNotificationSubscriptionType)]; diff --git a/index.d.ts b/index.d.ts index 7463e17..dd6ed88 100644 --- a/index.d.ts +++ b/index.d.ts @@ -170,6 +170,20 @@ export function registerAndroidPushToken(token: string): void; */ export function setGoogleAdvertisingId(googleAdvertisingId: string, adTrackingEnabled: boolean): void; +/** +* Adds the user to a subscription group. +* @param {string} groupId - The string UUID corresponding to the subscription group, provided by the Braze dashboard. +* @param {function(error, result)} callback - A callback that receives the function call result. +*/ +export function addToSubscriptionGroup(groupId: string, callback?: Callback): void + +/** +* Removes the user from a subscription group. +* @param {string} groupId - The string UUID corresponding to the subscription group, provided by the Braze dashboard. +* @param {function(error, result)} callback - A callback that receives the function call result. +*/ +export function removeFromSubscriptionGroup(groupId: string, callback?: Callback): void; + /** * Sets whether the user should be sent push campaigns. * @param {NotificationSubscriptionType} notificationSubscriptionType - Notification setting (explicitly diff --git a/index.js b/index.js index 26964ae..a6b23df 100644 --- a/index.js +++ b/index.js @@ -40,6 +40,44 @@ function callFunctionWithCallback(methodName, argsArray, callback) { methodName.apply(this, argsArray); } +function parseNestedProperties(object) { + if (object instanceof Array) { + for (let i = 0; i < object.length; i++) { + if (object[i] instanceof Date){ + var dateProp = object[i]; + object[i] = { + type: "UNIX_timestamp", + value: dateProp.valueOf() + } + } else { + parseNestedProperties(object[i]); + } + } + } else if (object instanceof Object) { + for (const key of keys(object)) { + if (object[key] instanceof Date) { + var dateProp = object[key]; + object[key] = { + type: "UNIX_timestamp", + value: dateProp.valueOf() + } + } else { + parseNestedProperties(object[key]); + } + } + } +} + +function keys(a) { + const keys = []; + for (let k in a) { + if (a.hasOwnProperty(k)) { + keys.push(k); + } + } + return keys; +} + var ReactAppboy = { /** * When launching an iOS application that has previously been force closed, React Native's Linking API doesn't @@ -177,15 +215,7 @@ var ReactAppboy = { */ logCustomEvent: function(eventName, eventProperties) { AppboyReactBridge.setSDKFlavor(); - for (var key in eventProperties) { - if (eventProperties[key] instanceof Date){ - var dateProp = eventProperties[key]; - eventProperties[key] = { - type: "UNIX_timestamp", - value: dateProp.valueOf() - } - } - } + parseNestedProperties(eventProperties); AppboyReactBridge.logCustomEvent(eventName, eventProperties); }, @@ -214,15 +244,7 @@ var ReactAppboy = { * Values can be numeric, boolean, Date, or strings 255 characters or shorter. */ logPurchase: function(productId, price, currencyCode, quantity, purchaseProperties) { - for (var key in purchaseProperties) { - if (purchaseProperties[key] instanceof Date){ - var dateProp = purchaseProperties[key]; - purchaseProperties[key] = { - type: "UNIX_timestamp", - value: dateProp.valueOf() - } - } - } + parseNestedProperties(purchaseProperties); AppboyReactBridge.logPurchase(productId, price, currencyCode, quantity, purchaseProperties); }, @@ -355,6 +377,24 @@ var ReactAppboy = { AppboyReactBridge.setDateOfBirth(year, month, day); }, + /** + * Adds the user to a subscription group. + * @param {string} groupId - The string UUID corresponding to the subscription group, provided by the Braze dashboard. + * @param {function(error, result)} callback - A callback that receives the function call result. + */ + addToSubscriptionGroup: function(groupId, callback) { + callFunctionWithCallback(AppboyReactBridge.addToSubscriptionGroup, [groupId], callback); + }, + + /** + * Removes the user from a subscription group. + * @param {string} groupId - The string UUID corresponding to the subscription group, provided by the Braze dashboard. + * @param {function(error, result)} callback - A callback that receives the function call result. + */ + removeFromSubscriptionGroup: function(groupId, callback) { + callFunctionWithCallback(AppboyReactBridge.removeFromSubscriptionGroup, [groupId], callback); + }, + /** * Sets whether the user should be sent push campaigns. * @param {NotificationSubscriptionTypes} notificationSubscriptionType - Notification setting (explicitly diff --git a/package.json b/package.json index d389043..a162604 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-appboy-sdk", - "version": "1.32.0", + "version": "1.33.0", "description": "Braze SDK for React Native.", "main": "index.js", "types": "index.d.ts", diff --git a/react-native-appboy-sdk.podspec b/react-native-appboy-sdk.podspec index 67c0d77..77b6a27 100644 --- a/react-native-appboy-sdk.podspec +++ b/react-native-appboy-sdk.podspec @@ -18,6 +18,6 @@ Pod::Spec.new do |s| s.preserve_paths = 'LICENSE.md', 'README.md', 'package.json', 'index.js' s.source_files = 'iOS/**/*.{h,m}' - s.dependency 'Appboy-iOS-SDK', '~> 4.3.2' + s.dependency 'Appboy-iOS-SDK', '~> 4.3.4' s.dependency 'React' end