@capillarytech/react-native-hydra-lib 1.7.0-beta.7 → 1.7.0-beta.9
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/android/build.gradle +8 -7
- package/android/src/main/java/com/hydralib/delegates/NonHydraNotificationActivity.kt +22 -10
- package/android/src/main/java/com/hydralib/eventemitter/HydraEventEmitter.kt +34 -4
- package/android/src/main/java/com/hydralib/gamification/GamificationBannerViewManager.kt +34 -3
- package/android/src/main/java/com/hydralib/gamification/GamificationEmbedViewManager.kt +25 -4
- package/android/src/main/java/com/hydralib/gamification/GamificationLoyaltyViewManager.kt +41 -6
- package/android/src/main/java/com/hydralib/hydrasdk/HydraCore.kt +60 -5
- package/android/src/main/java/com/hydralib/hydrasdk/HydraInAppMessages.kt +68 -41
- package/android/src/main/java/com/hydralib/hydrasdk/HydraInbox.kt +2 -2
- package/android/src/main/java/com/hydralib/hydrasdk/HydraPushNotification.kt +1 -1
- package/android/src/newarch/HydraLibModule.kt +8 -0
- package/android/src/oldarch/HydraLibModule.kt +10 -0
- package/ios/Delegates/HydraApplicationDelegate.swift +8 -0
- package/ios/GamificationViews/GamificationBannerViewComponentView.mm +39 -2
- package/ios/GamificationViews/GamificationEmbedViewComponentView.mm +33 -2
- package/ios/GamificationViews/GamificationLoyaltyViewComponentView.mm +41 -1
- package/ios/HydraLib.mm +8 -0
- package/ios/HydraSDK/HydraInAppMessages.swift +35 -8
- package/ios/HydraSDK/HydraInbox.swift +36 -9
- package/ios/HydraSDK/HydraInboxUI.swift +5 -1
- package/ios/HydraSDK/HydraPushNotification.swift +2 -2
- package/ios/HydraSDK/HydraSDKCore.swift +156 -82
- package/ios/Utils/HydraExtensions.swift +1 -1
- package/lib/commonjs/NativeHydraLib.ts +2 -0
- package/lib/commonjs/hydra-apis/Hydra.js +7 -0
- package/lib/commonjs/hydra-apis/Hydra.js.map +1 -1
- package/lib/commonjs/index.js +7 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/models/ThemeMode.js +14 -0
- package/lib/commonjs/models/ThemeMode.js.map +1 -0
- package/lib/module/NativeHydraLib.ts +2 -0
- package/lib/module/hydra-apis/Hydra.js +7 -0
- package/lib/module/hydra-apis/Hydra.js.map +1 -1
- package/lib/module/index.js +2 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/models/ThemeMode.js +10 -0
- package/lib/module/models/ThemeMode.js.map +1 -0
- package/lib/typescript/commonjs/src/NativeHydraLib.d.ts +2 -0
- package/lib/typescript/commonjs/src/NativeHydraLib.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/hydra-apis/Hydra.d.ts +3 -0
- package/lib/typescript/commonjs/src/hydra-apis/Hydra.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +2 -1
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/models/ThemeMode.d.ts +7 -0
- package/lib/typescript/commonjs/src/models/ThemeMode.d.ts.map +1 -0
- package/lib/typescript/module/src/NativeHydraLib.d.ts +2 -0
- package/lib/typescript/module/src/NativeHydraLib.d.ts.map +1 -1
- package/lib/typescript/module/src/hydra-apis/Hydra.d.ts +3 -0
- package/lib/typescript/module/src/hydra-apis/Hydra.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +2 -1
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/models/ThemeMode.d.ts +7 -0
- package/lib/typescript/module/src/models/ThemeMode.d.ts.map +1 -0
- package/package.json +1 -1
- package/sbom.spdx.json +4 -4
- package/scripts/HydraPods.rb +1 -1
- package/src/NativeHydraLib.ts +2 -0
- package/src/hydra-apis/Hydra.ts +10 -0
- package/src/index.tsx +2 -0
- package/src/models/ThemeMode.ts +6 -0
|
@@ -129,6 +129,14 @@ class HydraLibModule(reactContext: ReactApplicationContext) :
|
|
|
129
129
|
HydraCore.isGamificationSuppressed(promise)
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
override fun setThemeMode(mode: String, promise: Promise?) {
|
|
133
|
+
HydraCore.setThemeMode(mode, promise)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
override fun getThemeMode(promise: Promise?) {
|
|
137
|
+
HydraCore.getThemeMode(promise)
|
|
138
|
+
}
|
|
139
|
+
|
|
132
140
|
override fun openExternalUrl(url: String, promise: Promise?) {
|
|
133
141
|
HydraPushNotification.openExternalUrl(url, promise)
|
|
134
142
|
}
|
|
@@ -151,6 +151,16 @@ class HydraLibModule internal constructor(context: ReactApplicationContext) :
|
|
|
151
151
|
HydraCore.isGamificationSuppressed(promise)
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
@ReactMethod(isBlockingSynchronousMethod = false)
|
|
155
|
+
fun setThemeMode(mode: String, promise: Promise?) {
|
|
156
|
+
HydraCore.setThemeMode(mode, promise)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@ReactMethod(isBlockingSynchronousMethod = false)
|
|
160
|
+
fun getThemeMode(promise: Promise?) {
|
|
161
|
+
HydraCore.getThemeMode(promise)
|
|
162
|
+
}
|
|
163
|
+
|
|
154
164
|
@ReactMethod(isBlockingSynchronousMethod = false)
|
|
155
165
|
fun openExternalUrl(url: String, promise: Promise?) {
|
|
156
166
|
HydraPushNotification.openExternalUrl(url, promise)
|
|
@@ -32,6 +32,14 @@ import HydraCore
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
fileprivate func setupNavigationController(_ application: UIApplication) {
|
|
35
|
+
// Wrapping the app's rootViewController in a UINavigationController is only
|
|
36
|
+
// needed to push the Hydra NotificationCenter (see HydraInboxUI). Apps that
|
|
37
|
+
// don't enable InboxUI keep their own root view controller untouched.
|
|
38
|
+
guard HydraSDKCore.isInboxUIEnabled() else {
|
|
39
|
+
Logger.info("HydraApplicationDelegate: setupNavigationController: enable_inbox_ui is false, skipping navigation controller setup")
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
|
|
35
43
|
//Create and set NavigationController as rootController, will be required to show NotificationCenter
|
|
36
44
|
let storyboard = UIStoryboard(name: Bundle.main.infoDictionary?["UILaunchStoryboardName"] as? String ?? "LaunchScreen", bundle: nil)
|
|
37
45
|
let viewController = storyboard.instantiateInitialViewController()
|
|
@@ -53,12 +53,37 @@ using namespace facebook::react;
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
- (void)gamificationDataReloaded {
|
|
56
|
+
// Always dispatch to main: the SDK may post this from a background queue,
|
|
57
|
+
// and createGamificationBannerView is a UIKit/MainActor call.
|
|
56
58
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
59
|
+
// Fabric keeps unmounted component views alive in its recycle pool, and a pooled view is
|
|
60
|
+
// still a registered observer here. It must NOT rebuild: every successful
|
|
61
|
+
// createGamificationBannerView records an impression against the entry point's display count
|
|
62
|
+
// (conditions.showCount.count), so an off-screen pooled view would silently burn the cap and
|
|
63
|
+
// the banner would vanish for real users far sooner than configured. A mounted view always
|
|
64
|
+
// has a superview; a pooled one never does (Fabric asserts this when enqueueing).
|
|
65
|
+
if (self.superview == nil) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
57
68
|
self->_needsBannerView = YES;
|
|
58
69
|
[self attachBannerViewIfPossible];
|
|
59
70
|
});
|
|
60
71
|
}
|
|
61
72
|
|
|
73
|
+
// Fabric recycles component views. RCTViewComponentView's own prepareForRecycle resets the event
|
|
74
|
+
// emitter and react subviews but NOT `contentView`, and setContentView: re-adds it to the container
|
|
75
|
+
// view — so without this a recycled instance keeps the previous mount's banner view (a live
|
|
76
|
+
// WKWebView showing an already-rendered campaign). updateProps would then see `contentView != nil`
|
|
77
|
+
// with an unchanged bannerId and never ask the SDK again, bypassing the frequency-cap/visibility
|
|
78
|
+
// check entirely and displaying stale content the SDK has decided to hide.
|
|
79
|
+
- (void)prepareForRecycle {
|
|
80
|
+
self.contentView = nil;
|
|
81
|
+
_bannerId = nil;
|
|
82
|
+
_needsBannerView = NO;
|
|
83
|
+
_retryPending = NO;
|
|
84
|
+
[super prepareForRecycle];
|
|
85
|
+
}
|
|
86
|
+
|
|
62
87
|
- (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps {
|
|
63
88
|
const auto &newProps = *std::static_pointer_cast<const GamificationBannerViewProps>(props);
|
|
64
89
|
|
|
@@ -87,7 +112,11 @@ using namespace facebook::react;
|
|
|
87
112
|
if (!_needsBannerView || _bannerId.length == 0) {
|
|
88
113
|
return;
|
|
89
114
|
}
|
|
90
|
-
|
|
115
|
+
// Only WIDTH has to be laid out: the SDK ignores our bounds entirely (it measures the window)
|
|
116
|
+
// and seeds the real height back through onHeight. Requiring a non-empty rect would wedge a
|
|
117
|
+
// surface that has legitimately collapsed to height 0 — it could never rebuild when fresh data
|
|
118
|
+
// arrives, because its own bounds would stay empty forever.
|
|
119
|
+
if (self.bounds.size.width <= 0) {
|
|
91
120
|
return;
|
|
92
121
|
}
|
|
93
122
|
|
|
@@ -99,7 +128,15 @@ using namespace facebook::react;
|
|
|
99
128
|
_needsBannerView = NO;
|
|
100
129
|
_retryPending = NO;
|
|
101
130
|
} else {
|
|
102
|
-
NSLog(@"[GamificationBanner] SDK returned nil — scheduling long fallback");
|
|
131
|
+
NSLog(@"[GamificationBanner] SDK returned nil — collapsing and scheduling long fallback");
|
|
132
|
+
// nil means "do not render this banner now" — hidden, frequency-capped, or no resolved URL.
|
|
133
|
+
// Drop anything already attached so a previously loaded webview can't outlive that decision.
|
|
134
|
+
// The SDK has already pushed height 0 through onHeight, so the JS side collapses with us.
|
|
135
|
+
self.contentView = nil;
|
|
136
|
+
// Don't retry aggressively: the SDK may have entry points loaded but
|
|
137
|
+
// reward/program data not yet ready. The HydraGamificationDataReloaded
|
|
138
|
+
// notification fires when everything is ready and will call us again.
|
|
139
|
+
// This 5-second fallback only fires if that notification is missed.
|
|
103
140
|
[self scheduleFallbackRetry];
|
|
104
141
|
}
|
|
105
142
|
}
|
|
@@ -56,11 +56,34 @@ using namespace facebook::react;
|
|
|
56
56
|
// Always dispatch to main: the SDK may post this from a background queue,
|
|
57
57
|
// and createGamificationEmbedView is a UIKit/MainActor call.
|
|
58
58
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
59
|
+
// Fabric keeps unmounted component views alive in its recycle pool, and a pooled view is
|
|
60
|
+
// still a registered observer here. It must NOT rebuild: every successful
|
|
61
|
+
// createGamificationEmbedView records an impression against the entry point's display count
|
|
62
|
+
// (conditions.showCount.count), so an off-screen pooled view would silently burn the cap and
|
|
63
|
+
// the embed would vanish for real users far sooner than configured. A mounted view always
|
|
64
|
+
// has a superview; a pooled one never does (Fabric asserts this when enqueueing).
|
|
65
|
+
if (self.superview == nil) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
59
68
|
self->_needsEmbedView = YES;
|
|
60
69
|
[self attachEmbedViewIfPossible];
|
|
61
70
|
});
|
|
62
71
|
}
|
|
63
72
|
|
|
73
|
+
// Fabric recycles component views. RCTViewComponentView's own prepareForRecycle resets the event
|
|
74
|
+
// emitter and react subviews but NOT `contentView`, and setContentView: re-adds it to the container
|
|
75
|
+
// view — so without this a recycled instance keeps the previous mount's EmbedView (a live WKWebView
|
|
76
|
+
// showing an already-rendered campaign). updateProps would then see `contentView != nil` with an
|
|
77
|
+
// unchanged embedId and never ask the SDK again, bypassing the frequency-cap/visibility check
|
|
78
|
+
// entirely and displaying stale content the SDK has decided to hide.
|
|
79
|
+
- (void)prepareForRecycle {
|
|
80
|
+
self.contentView = nil;
|
|
81
|
+
_embedId = nil;
|
|
82
|
+
_needsEmbedView = NO;
|
|
83
|
+
_retryPending = NO;
|
|
84
|
+
[super prepareForRecycle];
|
|
85
|
+
}
|
|
86
|
+
|
|
64
87
|
- (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps {
|
|
65
88
|
const auto &newProps = *std::static_pointer_cast<const GamificationEmbedViewProps>(props);
|
|
66
89
|
|
|
@@ -89,7 +112,11 @@ using namespace facebook::react;
|
|
|
89
112
|
if (!_needsEmbedView || _embedId.length == 0) {
|
|
90
113
|
return;
|
|
91
114
|
}
|
|
92
|
-
|
|
115
|
+
// Only WIDTH has to be laid out: the SDK ignores our bounds entirely (it measures the window)
|
|
116
|
+
// and seeds the real height back through onHeight. Requiring a non-empty rect would wedge a
|
|
117
|
+
// surface that has legitimately collapsed to height 0 — it could never rebuild when fresh data
|
|
118
|
+
// arrives, because its own bounds would stay empty forever.
|
|
119
|
+
if (self.bounds.size.width <= 0) {
|
|
93
120
|
return;
|
|
94
121
|
}
|
|
95
122
|
|
|
@@ -101,7 +128,11 @@ using namespace facebook::react;
|
|
|
101
128
|
_needsEmbedView = NO;
|
|
102
129
|
_retryPending = NO;
|
|
103
130
|
} else {
|
|
104
|
-
NSLog(@"[GamificationEmbed] SDK returned nil — scheduling long fallback");
|
|
131
|
+
NSLog(@"[GamificationEmbed] SDK returned nil — collapsing and scheduling long fallback");
|
|
132
|
+
// nil means "do not render this embed now" — hidden, frequency-capped, or no resolved URL.
|
|
133
|
+
// Drop anything already attached so a previously loaded webview can't outlive that decision.
|
|
134
|
+
// The SDK has already pushed height 0 through onHeight, so the JS side collapses with us.
|
|
135
|
+
self.contentView = nil;
|
|
105
136
|
// Don't retry aggressively: the SDK may have entry points loaded but
|
|
106
137
|
// reward/program data not yet ready. The HydraGamificationDataReloaded
|
|
107
138
|
// notification fires when everything is ready and will call us again.
|
|
@@ -53,12 +53,37 @@ using namespace facebook::react;
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
- (void)gamificationDataReloaded {
|
|
56
|
+
// Always dispatch to main: the SDK may post this from a background queue,
|
|
57
|
+
// and createGamificationLoyaltyView is a UIKit/MainActor call.
|
|
56
58
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
59
|
+
// Fabric keeps unmounted component views alive in its recycle pool, and a pooled view is
|
|
60
|
+
// still a registered observer here. It must NOT rebuild: every successful
|
|
61
|
+
// createGamificationLoyaltyView records an impression against the entry point's display count
|
|
62
|
+
// (conditions.showCount.count), so an off-screen pooled view would silently burn the cap and
|
|
63
|
+
// the widget would vanish for real users far sooner than configured. A mounted view always
|
|
64
|
+
// has a superview; a pooled one never does (Fabric asserts this when enqueueing).
|
|
65
|
+
if (self.superview == nil) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
57
68
|
self->_needsLoyaltyView = YES;
|
|
58
69
|
[self attachLoyaltyViewIfPossible];
|
|
59
70
|
});
|
|
60
71
|
}
|
|
61
72
|
|
|
73
|
+
// Fabric recycles component views. RCTViewComponentView's own prepareForRecycle resets the event
|
|
74
|
+
// emitter and react subviews but NOT `contentView`, and setContentView: re-adds it to the container
|
|
75
|
+
// view — so without this a recycled instance keeps the previous mount's loyalty view (a live
|
|
76
|
+
// WKWebView showing an already-rendered campaign). updateProps would then see `contentView != nil`
|
|
77
|
+
// with an unchanged loyaltyId and never ask the SDK again, bypassing the frequency-cap/visibility
|
|
78
|
+
// check entirely and displaying stale content the SDK has decided to hide.
|
|
79
|
+
- (void)prepareForRecycle {
|
|
80
|
+
self.contentView = nil;
|
|
81
|
+
_loyaltyId = nil;
|
|
82
|
+
_needsLoyaltyView = NO;
|
|
83
|
+
_retryPending = NO;
|
|
84
|
+
[super prepareForRecycle];
|
|
85
|
+
}
|
|
86
|
+
|
|
62
87
|
- (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps {
|
|
63
88
|
const auto &newProps = *std::static_pointer_cast<const GamificationLoyaltyViewProps>(props);
|
|
64
89
|
|
|
@@ -85,16 +110,31 @@ using namespace facebook::react;
|
|
|
85
110
|
if (!_needsLoyaltyView || _loyaltyId.length == 0) {
|
|
86
111
|
return;
|
|
87
112
|
}
|
|
88
|
-
|
|
113
|
+
// Only WIDTH has to be laid out: the SDK ignores our bounds entirely (it measures the window)
|
|
114
|
+
// and seeds the real height back through onHeight. Requiring a non-empty rect would wedge a
|
|
115
|
+
// surface that has legitimately collapsed to height 0 — it could never rebuild when fresh data
|
|
116
|
+
// arrives, because its own bounds would stay empty forever.
|
|
117
|
+
if (self.bounds.size.width <= 0) {
|
|
89
118
|
return;
|
|
90
119
|
}
|
|
91
120
|
|
|
121
|
+
NSLog(@"[GamificationLoyalty] trying createGamificationLoyaltyView(loyaltyId=%@)", _loyaltyId);
|
|
92
122
|
UIView *loyaltyView = [[HydraSDKCore shared] createGamificationLoyaltyViewWithLoyaltyId:_loyaltyId];
|
|
93
123
|
if (loyaltyView) {
|
|
124
|
+
NSLog(@"[GamificationLoyalty] loyalty view created OK");
|
|
94
125
|
self.contentView = loyaltyView;
|
|
95
126
|
_needsLoyaltyView = NO;
|
|
96
127
|
_retryPending = NO;
|
|
97
128
|
} else {
|
|
129
|
+
NSLog(@"[GamificationLoyalty] SDK returned nil — collapsing and scheduling long fallback");
|
|
130
|
+
// nil means "do not render this now" — hidden, frequency-capped, or no resolved URL.
|
|
131
|
+
// Drop anything already attached so a previously loaded webview can't outlive that decision.
|
|
132
|
+
// The SDK has already pushed height 0 through onHeight, so the JS side collapses with us.
|
|
133
|
+
self.contentView = nil;
|
|
134
|
+
// Don't retry aggressively: the SDK may have entry points loaded but
|
|
135
|
+
// reward/program data not yet ready. The HydraGamificationDataReloaded
|
|
136
|
+
// notification fires when everything is ready and will call us again.
|
|
137
|
+
// This 5-second fallback only fires if that notification is missed.
|
|
98
138
|
[self scheduleFallbackRetry];
|
|
99
139
|
}
|
|
100
140
|
}
|
package/ios/HydraLib.mm
CHANGED
|
@@ -202,6 +202,14 @@ RCT_EXPORT_METHOD(reportMessageRating:(nonnull NSDictionary *)message rating:(do
|
|
|
202
202
|
[[HydraSDKCore shared] isGamificationSuppressed:resolve reject:reject];
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
+
- (void)setThemeMode:(nonnull NSString *)mode resolve:(nonnull RCTPromiseResolveBlock)resolve reject:(nonnull RCTPromiseRejectBlock)reject {
|
|
206
|
+
[[HydraSDKCore shared] setThemeMode:mode resolve:resolve reject:reject];
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
- (void)getThemeMode:(nonnull RCTPromiseResolveBlock)resolve reject:(nonnull RCTPromiseRejectBlock)reject {
|
|
210
|
+
[[HydraSDKCore shared] getThemeMode:resolve reject:reject];
|
|
211
|
+
}
|
|
212
|
+
|
|
205
213
|
|
|
206
214
|
|
|
207
215
|
#ifdef RCT_NEW_ARCH_ENABLED
|
|
@@ -60,22 +60,49 @@ import React
|
|
|
60
60
|
// }
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
// NOTE: these four methods do not yet call into a corresponding HydraCore/HydraInAppMessage
|
|
64
|
+
// report API (unlike the Android side, which calls HydraInAppUIHelper...reportInAppMessage*).
|
|
65
|
+
// The logging/resolve/reject below only makes failures visible and stops the RN promise
|
|
66
|
+
// from hanging forever — it does not report the click/dismiss/rating/feedback to the SDK.
|
|
67
|
+
|
|
63
68
|
@objc public func reportMessageClicked(_ message: [String: Any]?, resolve : RCTPromiseResolveBlock?, reject : RCTPromiseRejectBlock?) -> Void{
|
|
64
|
-
|
|
65
|
-
Logger.
|
|
69
|
+
guard let payload = message?["nativeJsonPayload"] as? [String: Any] else {
|
|
70
|
+
Logger.error("HydraInAppMessages: reportMessageClicked: message is nil or missing nativeJsonPayload")
|
|
71
|
+
reject?("Error", "message is nil or missing nativeJsonPayload", nil)
|
|
72
|
+
return
|
|
66
73
|
}
|
|
74
|
+
Logger.debug("HydraInAppMessages.reportMessageClicked payload = \(payload)")
|
|
75
|
+
resolve?(true)
|
|
67
76
|
}
|
|
68
|
-
|
|
77
|
+
|
|
69
78
|
@objc public func reportMessageDismissed(_ message: [String: Any]?, resolve : RCTPromiseResolveBlock?, reject : RCTPromiseRejectBlock?) -> Void{
|
|
70
|
-
|
|
79
|
+
guard let payload = message?["nativeJsonPayload"] as? [String: Any] else {
|
|
80
|
+
Logger.error("HydraInAppMessages: reportMessageDismissed: message is nil or missing nativeJsonPayload")
|
|
81
|
+
reject?("Error", "message is nil or missing nativeJsonPayload", nil)
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
Logger.debug("HydraInAppMessages.reportMessageDismissed payload = \(payload)")
|
|
85
|
+
resolve?(true)
|
|
71
86
|
}
|
|
72
|
-
|
|
87
|
+
|
|
73
88
|
@objc public func reportMessageRating(_ message: [String: Any]?, rating: Double, resolve : RCTPromiseResolveBlock?, reject : RCTPromiseRejectBlock?) -> Void{
|
|
74
|
-
|
|
89
|
+
guard let payload = message?["nativeJsonPayload"] as? [String: Any] else {
|
|
90
|
+
Logger.error("HydraInAppMessages: reportMessageRating: message is nil or missing nativeJsonPayload")
|
|
91
|
+
reject?("Error", "message is nil or missing nativeJsonPayload", nil)
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
Logger.debug("HydraInAppMessages.reportMessageRating payload = \(payload), rating = \(rating)")
|
|
95
|
+
resolve?(true)
|
|
75
96
|
}
|
|
76
|
-
|
|
97
|
+
|
|
77
98
|
@objc public func reportMessageFeedback(_ message: [String: Any]?, feedback: String, feedbackOptions: [String], resolve : RCTPromiseResolveBlock?, reject : RCTPromiseRejectBlock?) -> Void{
|
|
78
|
-
|
|
99
|
+
guard let payload = message?["nativeJsonPayload"] as? [String: Any] else {
|
|
100
|
+
Logger.error("HydraInAppMessages: reportMessageFeedback: message is nil or missing nativeJsonPayload")
|
|
101
|
+
reject?("Error", "message is nil or missing nativeJsonPayload", nil)
|
|
102
|
+
return
|
|
103
|
+
}
|
|
104
|
+
Logger.debug("HydraInAppMessages.reportMessageFeedback payload = \(payload), feedback = \(feedback), feedbackOptions = \(feedbackOptions)")
|
|
105
|
+
resolve?(true)
|
|
79
106
|
}
|
|
80
107
|
}
|
|
81
108
|
|
|
@@ -32,13 +32,18 @@ import React
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
@objc public func getInboxMessages(_ resolve : RCTPromiseResolveBlock?, reject : RCTPromiseRejectBlock? ){
|
|
35
|
-
self.inboxCore
|
|
35
|
+
guard let inboxCore = self.inboxCore else {
|
|
36
|
+
Logger.error("HydraInbox: getInboxMessages: inboxCore is nil, InboxCore not initialized")
|
|
37
|
+
reject?("Error", "InboxCore not initialized", nil)
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
inboxCore.getNotifications(){
|
|
36
41
|
(rawNotifications) -> Void in
|
|
37
42
|
let notifications = rawNotifications.map{$0.toDict()}
|
|
38
43
|
resolve?(notifications)
|
|
39
44
|
Logger.debug("HydraInbox: getInboxMessages: notifications = \(String(describing: notifications))")
|
|
40
45
|
}
|
|
41
|
-
|
|
46
|
+
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
fileprivate func updateBadgeCount() {
|
|
@@ -49,15 +54,25 @@ import React
|
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
@objc public func getUnreadInboxMessagesCount(_ resolve : RCTPromiseResolveBlock?, reject : RCTPromiseRejectBlock? ){
|
|
52
|
-
inboxCore
|
|
57
|
+
guard let inboxCore = self.inboxCore else {
|
|
58
|
+
Logger.error("HydraInbox: getUnreadInboxMessagesCount: inboxCore is nil, InboxCore not initialized")
|
|
59
|
+
reject?("Error", "InboxCore not initialized", nil)
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
inboxCore.getUnreadNotificationCount(){
|
|
53
63
|
(count) -> Void in
|
|
54
64
|
resolve?(count)
|
|
55
65
|
Logger.debug("HydraInbox: getUnreadInboxMessagesCount: count = \(count)")
|
|
56
66
|
}
|
|
57
67
|
}
|
|
58
|
-
|
|
68
|
+
|
|
59
69
|
@objc public func deleteAllInboxMessages(_ resolve : RCTPromiseResolveBlock?, reject : RCTPromiseRejectBlock? ){
|
|
60
|
-
inboxCore
|
|
70
|
+
guard let inboxCore = self.inboxCore else {
|
|
71
|
+
Logger.error("HydraInbox: deleteAllInboxMessages: inboxCore is nil, InboxCore not initialized")
|
|
72
|
+
reject?("Error", "InboxCore not initialized", nil)
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
inboxCore.handleDeleteAllNotifications(){
|
|
61
76
|
(isDeleted) -> Void in
|
|
62
77
|
if isDeleted {
|
|
63
78
|
self.updateBadgeCount()
|
|
@@ -66,26 +81,38 @@ import React
|
|
|
66
81
|
Logger.debug("HydraInbox: deleteAllInboxMessages: deleted = \(isDeleted)")
|
|
67
82
|
}
|
|
68
83
|
}
|
|
69
|
-
|
|
84
|
+
|
|
70
85
|
@objc public func deleteInboxMessage(_ inboxMessage: [String: Any] ,resolve : RCTPromiseResolveBlock?, reject : RCTPromiseRejectBlock? ){
|
|
86
|
+
guard let inboxCore = self.inboxCore else {
|
|
87
|
+
Logger.error("HydraInbox: deleteInboxMessage: inboxCore is nil, InboxCore not initialized")
|
|
88
|
+
reject?("Error", "InboxCore not initialized", nil)
|
|
89
|
+
return
|
|
90
|
+
}
|
|
71
91
|
let payload = HydraNotificationPayload.generate(from: inboxMessage)
|
|
72
|
-
inboxCore
|
|
92
|
+
inboxCore.handleNotification(notification: payload, action: .delete){
|
|
73
93
|
(isDeleted) -> Void in
|
|
74
94
|
if isDeleted {
|
|
75
95
|
self.updateBadgeCount()
|
|
76
96
|
}
|
|
77
97
|
resolve?(isDeleted)
|
|
98
|
+
Logger.debug("HydraInbox: deleteInboxMessage: deleted = \(isDeleted)")
|
|
78
99
|
}
|
|
79
100
|
}
|
|
80
|
-
|
|
101
|
+
|
|
81
102
|
@objc public func markInboxMessageAsRead(_ inboxMessage: [String: Any] ,resolve : RCTPromiseResolveBlock?, reject : RCTPromiseRejectBlock? ){
|
|
103
|
+
guard let inboxCore = self.inboxCore else {
|
|
104
|
+
Logger.error("HydraInbox: markInboxMessageAsRead: inboxCore is nil, InboxCore not initialized")
|
|
105
|
+
reject?("Error", "InboxCore not initialized", nil)
|
|
106
|
+
return
|
|
107
|
+
}
|
|
82
108
|
let payload = HydraNotificationPayload.generate(from: inboxMessage)
|
|
83
|
-
inboxCore
|
|
109
|
+
inboxCore.handleNotification(notification: payload, action: .read){
|
|
84
110
|
(isRead) -> Void in
|
|
85
111
|
if isRead {
|
|
86
112
|
self.updateBadgeCount()
|
|
87
113
|
}
|
|
88
114
|
resolve?(isRead)
|
|
115
|
+
Logger.debug("HydraInbox: markInboxMessageAsRead: read = \(isRead)")
|
|
89
116
|
}
|
|
90
117
|
}
|
|
91
118
|
}
|
|
@@ -72,13 +72,17 @@ import React
|
|
|
72
72
|
@objc public func showNotificationCenter(_ resolve : RCTPromiseResolveBlock?, reject : RCTPromiseRejectBlock? ){
|
|
73
73
|
if self.inboxUICore != nil{
|
|
74
74
|
DispatchQueue.main.async{
|
|
75
|
-
guard let notificationCenter = self.inboxUICore?.getNotificationCenter() else {
|
|
75
|
+
guard let notificationCenter = self.inboxUICore?.getNotificationCenter() else {
|
|
76
|
+
Logger.error("HydraInboxUI: showNotificationCenter: getNotificationCenter() returned nil, cannot push notification center")
|
|
77
|
+
return
|
|
78
|
+
}
|
|
76
79
|
self.navigationController?.pushViewController(notificationCenter, animated: true)
|
|
77
80
|
self.hydraNotificationController = notificationCenter
|
|
78
81
|
}
|
|
79
82
|
resolve?(true)
|
|
80
83
|
return
|
|
81
84
|
}
|
|
85
|
+
Logger.error("HydraInboxUI: showNotificationCenter: inboxUICore is nil, InboxUI not initialized")
|
|
82
86
|
resolve?(false)
|
|
83
87
|
}
|
|
84
88
|
|
|
@@ -61,7 +61,7 @@ import HydraInAppMessage
|
|
|
61
61
|
|
|
62
62
|
@objc public func getFCMToken(_ resolve : RCTPromiseResolveBlock?, reject : RCTPromiseRejectBlock? ){
|
|
63
63
|
guard fcmToken != nil else{
|
|
64
|
-
Logger.
|
|
64
|
+
Logger.error("HydraPushNotification: getFCMToken: Did not receive the token yet")
|
|
65
65
|
reject?( "TOKEN_NOT_AVAILABLE", "Did not receive the token yet", nil)
|
|
66
66
|
return
|
|
67
67
|
}
|
|
@@ -234,7 +234,7 @@ import HydraInAppMessage
|
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
@objc public func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: any Error) {
|
|
237
|
-
Logger.
|
|
237
|
+
Logger.error("HydraPushNotification: application:didFailToRegisterForRemoteNotificationsWithError error = \(error.localizedDescription)")
|
|
238
238
|
// if HydraSDKCore.shared.hydra == nil{
|
|
239
239
|
// DispatchQueue.main.asyncAfter(deadline: .now() + 0.3){
|
|
240
240
|
// self.application(application, didFailToRegisterForRemoteNotificationsWithError: error)
|