@capillarytech/react-native-hydra-lib 1.7.0-beta.7 → 1.7.0-beta.8

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.
Files changed (60) hide show
  1. package/android/build.gradle +8 -7
  2. package/android/src/main/java/com/hydralib/delegates/NonHydraNotificationActivity.kt +22 -10
  3. package/android/src/main/java/com/hydralib/eventemitter/HydraEventEmitter.kt +34 -4
  4. package/android/src/main/java/com/hydralib/gamification/GamificationBannerViewManager.kt +34 -3
  5. package/android/src/main/java/com/hydralib/gamification/GamificationEmbedViewManager.kt +25 -4
  6. package/android/src/main/java/com/hydralib/gamification/GamificationLoyaltyViewManager.kt +41 -6
  7. package/android/src/main/java/com/hydralib/hydrasdk/HydraCore.kt +42 -5
  8. package/android/src/main/java/com/hydralib/hydrasdk/HydraInAppMessages.kt +68 -41
  9. package/android/src/main/java/com/hydralib/hydrasdk/HydraInbox.kt +2 -2
  10. package/android/src/main/java/com/hydralib/hydrasdk/HydraPushNotification.kt +1 -1
  11. package/android/src/newarch/HydraLibModule.kt +8 -0
  12. package/android/src/oldarch/HydraLibModule.kt +10 -0
  13. package/ios/Delegates/HydraApplicationDelegate.swift +8 -0
  14. package/ios/GamificationViews/GamificationBannerViewComponentView.mm +39 -2
  15. package/ios/GamificationViews/GamificationEmbedViewComponentView.mm +33 -2
  16. package/ios/GamificationViews/GamificationLoyaltyViewComponentView.mm +41 -1
  17. package/ios/HydraLib.mm +8 -0
  18. package/ios/HydraSDK/HydraInAppMessages.swift +35 -8
  19. package/ios/HydraSDK/HydraInbox.swift +36 -9
  20. package/ios/HydraSDK/HydraInboxUI.swift +5 -1
  21. package/ios/HydraSDK/HydraPushNotification.swift +2 -2
  22. package/ios/HydraSDK/HydraSDKCore.swift +156 -82
  23. package/ios/Utils/HydraExtensions.swift +1 -1
  24. package/lib/commonjs/NativeHydraLib.ts +2 -0
  25. package/lib/commonjs/hydra-apis/Hydra.js +7 -0
  26. package/lib/commonjs/hydra-apis/Hydra.js.map +1 -1
  27. package/lib/commonjs/index.js +7 -0
  28. package/lib/commonjs/index.js.map +1 -1
  29. package/lib/commonjs/models/ThemeMode.js +14 -0
  30. package/lib/commonjs/models/ThemeMode.js.map +1 -0
  31. package/lib/module/NativeHydraLib.ts +2 -0
  32. package/lib/module/hydra-apis/Hydra.js +7 -0
  33. package/lib/module/hydra-apis/Hydra.js.map +1 -1
  34. package/lib/module/index.js +2 -1
  35. package/lib/module/index.js.map +1 -1
  36. package/lib/module/models/ThemeMode.js +10 -0
  37. package/lib/module/models/ThemeMode.js.map +1 -0
  38. package/lib/typescript/commonjs/src/NativeHydraLib.d.ts +2 -0
  39. package/lib/typescript/commonjs/src/NativeHydraLib.d.ts.map +1 -1
  40. package/lib/typescript/commonjs/src/hydra-apis/Hydra.d.ts +3 -0
  41. package/lib/typescript/commonjs/src/hydra-apis/Hydra.d.ts.map +1 -1
  42. package/lib/typescript/commonjs/src/index.d.ts +2 -1
  43. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  44. package/lib/typescript/commonjs/src/models/ThemeMode.d.ts +7 -0
  45. package/lib/typescript/commonjs/src/models/ThemeMode.d.ts.map +1 -0
  46. package/lib/typescript/module/src/NativeHydraLib.d.ts +2 -0
  47. package/lib/typescript/module/src/NativeHydraLib.d.ts.map +1 -1
  48. package/lib/typescript/module/src/hydra-apis/Hydra.d.ts +3 -0
  49. package/lib/typescript/module/src/hydra-apis/Hydra.d.ts.map +1 -1
  50. package/lib/typescript/module/src/index.d.ts +2 -1
  51. package/lib/typescript/module/src/index.d.ts.map +1 -1
  52. package/lib/typescript/module/src/models/ThemeMode.d.ts +7 -0
  53. package/lib/typescript/module/src/models/ThemeMode.d.ts.map +1 -0
  54. package/package.json +1 -1
  55. package/sbom.spdx.json +2 -2
  56. package/scripts/HydraPods.rb +1 -1
  57. package/src/NativeHydraLib.ts +2 -0
  58. package/src/hydra-apis/Hydra.ts +10 -0
  59. package/src/index.tsx +2 -0
  60. package/src/models/ThemeMode.ts +6 -0
@@ -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
- if (CGRectIsEmpty(self.bounds)) {
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
- if (CGRectIsEmpty(self.bounds)) {
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
- if (CGRectIsEmpty(self.bounds)) {
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
- if let payload = message?["nativeJsonPayload"] as? [String: Any]{
65
- Logger.debug("HydraInAppMessages.reportMessageClicked payload = \(payload)")
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?.getNotifications(){
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?.getUnreadNotificationCount(){
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?.handleDeleteAllNotifications(){
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?.handleNotification(notification: payload, action: .delete){
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?.handleNotification(notification: payload, action: .read){
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 { return}
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.debug("HydraPushNotification: getFCMToken: Did not receive the token yet")
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.debug("HydraPushNotification: application:didFailToRegisterForRemoteNotificationsWithError error = \(error.localizedDescription)")
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)