From be8fa00b3c03ec6633293a46fa517e4b5bfb0780 Mon Sep 17 00:00:00 2001 From: Asad Raza Date: Mon, 14 Sep 2026 17:52:55 +0100 Subject: [PATCH] feat(banner): add notifySubscriptionLapsed bridge method Exposes the native SDK's subscription-lapse API through the React Native bridge on Android and iOS. Co-Authored-By: Claude Sonnet 5 --- .../reactnative/RNUsercentricsModule.kt | 9 ++++++++ .../reactnative/RNUsercentricsModuleSpec.kt | 3 +++ ios/Manager/UsercentricsManager.swift | 5 +++++ ios/RNUsercentricsModule.mm | 3 +++ ios/RNUsercentricsModule.swift | 8 +++++++ ios/RNUsercentricsModuleSpec.h | 3 +++ .../Fake/FakeUsercentricsManager.swift | 9 ++++++++ sample/src/screens/Home.tsx | 12 ++++++++++ src/NativeUsercentrics.ts | 1 + src/Usercentrics.tsx | 8 +++++++ src/__tests__/index.test.ts | 22 +++++++++++++++++++ src/fabric/NativeUsercentricsModule.ts | 1 + 12 files changed, 84 insertions(+) diff --git a/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt b/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt index 08760ff..ef2857a 100644 --- a/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt +++ b/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt @@ -277,6 +277,15 @@ internal class RNUsercentricsModule( }) } + @ReactMethod + override fun notifySubscriptionLapsed(promise: Promise) { + usercentricsProxy.instance.notifySubscriptionLapsed({ + promise.resolve(null) + }, { + promise.reject(it) + }) + } + @ReactMethod override fun addListener(eventName: String) { if (eventName != ON_GPP_SECTION_CHANGE_EVENT) return diff --git a/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt b/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt index 8aa52d7..52e17da 100644 --- a/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt +++ b/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt @@ -39,6 +39,9 @@ abstract class RNUsercentricsModuleSpec internal constructor(context: ReactAppli @ReactMethod abstract fun notifySubscribeSuccess(promise: Promise) + @ReactMethod + abstract fun notifySubscriptionLapsed(promise: Promise) + @ReactMethod abstract fun getConsents(promise: Promise) diff --git a/ios/Manager/UsercentricsManager.swift b/ios/Manager/UsercentricsManager.swift index b108a9c..b18cdca 100644 --- a/ios/Manager/UsercentricsManager.swift +++ b/ios/Manager/UsercentricsManager.swift @@ -15,6 +15,7 @@ public protocol UsercentricsManager { func notifyLoginSuccess(onSuccess: @escaping (() -> Void), onError: @escaping ((Error) -> Void)) func notifySubscribeSuccess(onSuccess: @escaping (() -> Void), onError: @escaping ((Error) -> Void)) + func notifySubscriptionLapsed(onSuccess: @escaping (() -> Void), onError: @escaping ((Error) -> Void)) func showSecondLayer(bannerSettings: BannerSettings?, dismissViewHandler: @escaping (UsercentricsConsentUserResponse) -> Void) @@ -81,6 +82,10 @@ final class UsercentricsManagerImplementation: UsercentricsManager { UsercentricsCore.shared.notifySubscribeSuccess(onSuccess: onSuccess, onError: onError) } + func notifySubscriptionLapsed(onSuccess: @escaping (() -> Void), onError: @escaping ((Error) -> Void)) { + UsercentricsCore.shared.notifySubscriptionLapsed(onSuccess: onSuccess, onError: onError) + } + func showSecondLayer(bannerSettings: BannerSettings?, dismissViewHandler: @escaping (UsercentricsConsentUserResponse) -> Void) { UsercentricsBanner(bannerSettings: bannerSettings).showSecondLayer(completionHandler: dismissViewHandler) diff --git a/ios/RNUsercentricsModule.mm b/ios/RNUsercentricsModule.mm index 7487ec7..f572565 100644 --- a/ios/RNUsercentricsModule.mm +++ b/ios/RNUsercentricsModule.mm @@ -114,4 +114,7 @@ @interface RCT_EXTERN_MODULE(RNUsercentricsModule, NSObject) RCT_EXTERN_METHOD(notifySubscribeSuccess:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(notifySubscriptionLapsed:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) @end diff --git a/ios/RNUsercentricsModule.swift b/ios/RNUsercentricsModule.swift index d4783f3..f341d1d 100644 --- a/ios/RNUsercentricsModule.swift +++ b/ios/RNUsercentricsModule.swift @@ -290,6 +290,14 @@ class RNUsercentricsModule: RCTEventEmitter { } } + @objc func notifySubscriptionLapsed(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + usercentricsManager.notifySubscriptionLapsed { + resolve(nil) + } onError: { error in + reject("usercentrics_reactNative_notifySubscriptionLapsed_error", error.localizedDescription, error) + } + } + private static let onGppSectionChangeEvent = "onGppSectionChange" private static let onLoginClickedEvent = "onLoginClicked" private static let onSubscribeClickedEvent = "onSubscribeClicked" diff --git a/ios/RNUsercentricsModuleSpec.h b/ios/RNUsercentricsModuleSpec.h index 47f99e4..84a22a5 100644 --- a/ios/RNUsercentricsModuleSpec.h +++ b/ios/RNUsercentricsModuleSpec.h @@ -36,6 +36,9 @@ NS_ASSUME_NONNULL_BEGIN - (void)notifySubscribeSuccess:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)notifySubscriptionLapsed:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + // Data Retrieval - (void)getConsents:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; diff --git a/sample/ios/sampleTests/Fake/FakeUsercentricsManager.swift b/sample/ios/sampleTests/Fake/FakeUsercentricsManager.swift index 6db7021..0f5d251 100644 --- a/sample/ios/sampleTests/Fake/FakeUsercentricsManager.swift +++ b/sample/ios/sampleTests/Fake/FakeUsercentricsManager.swift @@ -272,4 +272,13 @@ final class FakeUsercentricsManager: UsercentricsManager { } onSuccess() } + + var notifySubscriptionLapsedError: Error? + func notifySubscriptionLapsed(onSuccess: @escaping (() -> Void), onError: @escaping ((Error) -> Void)) { + if let notifySubscriptionLapsedError = notifySubscriptionLapsedError { + onError(notifySubscriptionLapsedError) + return + } + onSuccess() + } } diff --git a/sample/src/screens/Home.tsx b/sample/src/screens/Home.tsx index 01ce7b9..7dd07cf 100644 --- a/sample/src/screens/Home.tsx +++ b/sample/src/screens/Home.tsx @@ -73,6 +73,17 @@ export const HomeScreen = ({ navigation }: { navigation: any }) => { }; }, []); + async function notifySubscriptionLapsed() { + try { + await Usercentrics.notifySubscriptionLapsed(); + console.log('[Usercentrics] notifySubscriptionLapsed done'); + Alert.alert('notifySubscriptionLapsed', 'Subscription reset'); + } catch (e) { + console.error('[Usercentrics] notifySubscriptionLapsed failed:', e); + Alert.alert('notifySubscriptionLapsed failed', String(e)); + } + } + async function showSecondLayer() { try { const response = await Usercentrics.showSecondLayer({ @@ -129,6 +140,7 @@ export const HomeScreen = ({ navigation }: { navigation: any }) => {