From 054cfd53461551e74c956206f146b724df5447b7 Mon Sep 17 00:00:00 2001 From: islameldesoky1 Date: Thu, 12 Mar 2026 15:26:27 +0000 Subject: [PATCH 1/2] feat(MSDK-3297): pass unsavedVendorLIDecisions through denyAllForTCF on all layers --- .../reactnative/RNUsercentricsModule.kt | 4 +-- .../reactnative/RNUsercentricsModuleSpec.kt | 2 +- ios/RNUsercentricsModule.swift | 26 ++++++++++++------- src/NativeUsercentrics.ts | 3 ++- src/Usercentrics.tsx | 5 ++-- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt b/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt index 7f85c44..bfcc296 100644 --- a/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt +++ b/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt @@ -149,10 +149,10 @@ internal class RNUsercentricsModule( } @ReactMethod - override fun denyAllForTCF(fromLayer: Double, consentType: Double, unsavedPurposeLIDecisions: ReadableArray, promise: Promise) { + override fun denyAllForTCF(fromLayer: Double, consentType: Double, unsavedPurposeLIDecisions: ReadableArray, unsavedVendorLIDecisions: ReadableArray, promise: Promise) { promise.resolve( usercentricsProxy.instance.denyAllForTCF( - TCFDecisionUILayer.values()[fromLayer.toInt()], UsercentricsConsentType.values()[consentType.toInt()], unsavedPurposeLIDecisions.deserializePurposeLIDecisionsMap() + TCFDecisionUILayer.values()[fromLayer.toInt()], UsercentricsConsentType.values()[consentType.toInt()], unsavedPurposeLIDecisions.deserializePurposeLIDecisionsMap(), unsavedVendorLIDecisions.deserializePurposeLIDecisionsMap() ).toWritableArray() ) } diff --git a/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt b/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt index 6051bbf..63bdddb 100644 --- a/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt +++ b/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt @@ -73,7 +73,7 @@ abstract class RNUsercentricsModuleSpec internal constructor(context: ReactAppli abstract fun denyAll(consentType: Double, promise: Promise) @ReactMethod - abstract fun denyAllForTCF(fromLayer: Double, consentType: Double, unsavedPurposeLIDecisions: ReadableArray, promise: Promise) + abstract fun denyAllForTCF(fromLayer: Double, consentType: Double, unsavedPurposeLIDecisions: ReadableArray, unsavedVendorLIDecisions: ReadableArray, promise: Promise) @ReactMethod abstract fun saveDecisions(decisions: ReadableArray, consentType: Double, promise: Promise) diff --git a/ios/RNUsercentricsModule.swift b/ios/RNUsercentricsModule.swift index 5794cc3..45b6685 100644 --- a/ios/RNUsercentricsModule.swift +++ b/ios/RNUsercentricsModule.swift @@ -160,20 +160,26 @@ class RNUsercentricsModule: NSObject { @objc func denyAllForTCF(_ fromLayer: Double, consentType: Double, unsavedPurposeLIDecisions: [NSDictionary], + unsavedVendorLIDecisions: [NSDictionary], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { - var decisions: [KotlinInt: KotlinBoolean]? = nil - if !unsavedPurposeLIDecisions.isEmpty { - decisions = [:] - for dict in unsavedPurposeLIDecisions { - if let id = dict["id"] as? Int, - let consent = dict["legitimateInterestConsent"] as? Bool { - decisions?[KotlinInt(int: Int32(id))] = KotlinBoolean(bool: consent) - } + let services = usercentricsManager.denyAllForTCF( + fromLayer: .initialize(from: Int(fromLayer)), + consentType: .initialize(from: Int(consentType)), + unsavedPurposeLIDecisions: extractLIDecisionsMap(unsavedPurposeLIDecisions), + unsavedVendorLIDecisions: extractLIDecisionsMap(unsavedVendorLIDecisions) + ) + resolve(services.toListOfDictionary()) + } + + private func extractLIDecisionsMap(_ decisions: [NSDictionary]) -> [KotlinInt: KotlinBoolean]? { + guard !decisions.isEmpty else { return nil } + return decisions.reduce(into: [:]) { result, dict in + if let id = dict["id"] as? Int, + let consent = dict["legitimateInterestConsent"] as? Bool { + result[KotlinInt(int: Int32(id))] = KotlinBoolean(bool: consent) } } - let services = usercentricsManager.denyAllForTCF(fromLayer: .initialize(from: Int(fromLayer)), consentType: .initialize(from: Int(consentType)), unsavedPurposeLIDecisions: decisions) - resolve(services.toListOfDictionary()) } @objc func denyAll(_ consentType: Double, diff --git a/src/NativeUsercentrics.ts b/src/NativeUsercentrics.ts index e80fa4b..d2f8a16 100644 --- a/src/NativeUsercentrics.ts +++ b/src/NativeUsercentrics.ts @@ -12,6 +12,7 @@ import type { UserDecision, TCFUserDecisions, TCFUserDecisionOnPurpose, + TCFUserDecisionOnVendor, } from './models'; export interface Spec extends TurboModule { @@ -46,7 +47,7 @@ export interface Spec extends TurboModule { acceptAll(consentType: number): Promise>; acceptAllForTCF(fromLayer: number, consentType: number): Promise>; denyAll(consentType: number): Promise>; - denyAllForTCF(fromLayer: number, consentType: number, unsavedPurposeLIDecisions: Array): Promise>; + denyAllForTCF(fromLayer: number, consentType: number, unsavedPurposeLIDecisions: Array, unsavedVendorLIDecisions: Array): Promise>; saveDecisions(decisions: Array, consentType: number): Promise>; saveDecisionsForTCF( diff --git a/src/Usercentrics.tsx b/src/Usercentrics.tsx index e6923e1..35a9fa6 100644 --- a/src/Usercentrics.tsx +++ b/src/Usercentrics.tsx @@ -6,6 +6,7 @@ import { TCFData, TCFDecisionUILayer, TCFUserDecisionOnPurpose, + TCFUserDecisionOnVendor, TCFUserDecisions, UsercentricsAnalyticsEventType, UsercentricsCMPData, @@ -106,9 +107,9 @@ export const Usercentrics = { return RNUsercentricsModule.denyAll(consentType); }, - denyAllForTCF: async (fromLayer: TCFDecisionUILayer, consentType: UsercentricsConsentType, unsavedPurposeLIDecisions: TCFUserDecisionOnPurpose[] = []): Promise> => { + denyAllForTCF: async (fromLayer: TCFDecisionUILayer, consentType: UsercentricsConsentType, unsavedPurposeLIDecisions: TCFUserDecisionOnPurpose[] = [], unsavedVendorLIDecisions: TCFUserDecisionOnVendor[] = []): Promise> => { await RNUsercentricsModule.isReady(); - return RNUsercentricsModule.denyAllForTCF(fromLayer, consentType, unsavedPurposeLIDecisions); + return RNUsercentricsModule.denyAllForTCF(fromLayer, consentType, unsavedPurposeLIDecisions, unsavedVendorLIDecisions); }, saveDecisions: async (decisions: UserDecision[], consentType: UsercentricsConsentType): Promise> => { From 447550378cc2cae5c8afead9566cb246a3177194 Mon Sep 17 00:00:00 2001 From: islameldesoky1 Date: Thu, 12 Mar 2026 16:49:38 +0000 Subject: [PATCH 2/2] fix android and iOS tests --- ios/Manager/UsercentricsManager.swift | 6 +++--- ios/RNUsercentricsModule.mm | 1 + src/fabric/NativeUsercentricsModule.ts | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ios/Manager/UsercentricsManager.swift b/ios/Manager/UsercentricsManager.swift index 4818438..a872a55 100644 --- a/ios/Manager/UsercentricsManager.swift +++ b/ios/Manager/UsercentricsManager.swift @@ -28,7 +28,7 @@ public protocol UsercentricsManager { func acceptAllForTCF(fromLayer: TCFDecisionUILayer, consentType: UsercentricsConsentType) -> [UsercentricsServiceConsent] func acceptAll(consentType: UsercentricsConsentType) -> [UsercentricsServiceConsent] - func denyAllForTCF(fromLayer: TCFDecisionUILayer, consentType: UsercentricsConsentType, unsavedPurposeLIDecisions: [KotlinInt: KotlinBoolean]?) -> [UsercentricsServiceConsent] + func denyAllForTCF(fromLayer: TCFDecisionUILayer, consentType: UsercentricsConsentType, unsavedPurposeLIDecisions: [KotlinInt: KotlinBoolean]?, unsavedVendorLIDecisions: [KotlinInt: KotlinBoolean]?) -> [UsercentricsServiceConsent] func denyAll(consentType: UsercentricsConsentType) -> [UsercentricsServiceConsent] func saveDecisionsForTCF(tcfDecisions: TCFUserDecisions, @@ -112,8 +112,8 @@ final class UsercentricsManagerImplementation: UsercentricsManager { return UsercentricsCore.shared.acceptAll(consentType: consentType) } - func denyAllForTCF(fromLayer: TCFDecisionUILayer, consentType: UsercentricsConsentType, unsavedPurposeLIDecisions: [KotlinInt: KotlinBoolean]?) -> [UsercentricsServiceConsent] { - return UsercentricsCore.shared.denyAllForTCF(fromLayer: fromLayer, consentType: consentType, unsavedPurposeLIDecisions: unsavedPurposeLIDecisions) + func denyAllForTCF(fromLayer: TCFDecisionUILayer, consentType: UsercentricsConsentType, unsavedPurposeLIDecisions: [KotlinInt: KotlinBoolean]?, unsavedVendorLIDecisions: [KotlinInt: KotlinBoolean]?) -> [UsercentricsServiceConsent] { + return UsercentricsCore.shared.denyAllForTCF(fromLayer: fromLayer, consentType: consentType, unsavedPurposeLIDecisions: unsavedPurposeLIDecisions, unsavedVendorLIDecisions: unsavedVendorLIDecisions) } func denyAll(consentType: UsercentricsConsentType) -> [UsercentricsServiceConsent] { diff --git a/ios/RNUsercentricsModule.mm b/ios/RNUsercentricsModule.mm index 3a811ce..c5b532e 100644 --- a/ios/RNUsercentricsModule.mm +++ b/ios/RNUsercentricsModule.mm @@ -72,6 +72,7 @@ @interface RCT_EXTERN_MODULE(RNUsercentricsModule, NSObject) RCT_EXTERN_METHOD(denyAllForTCF:(double)fromLayer consentType:(double)consentType unsavedPurposeLIDecisions:(NSArray)unsavedPurposeLIDecisions + unsavedVendorLIDecisions:(NSArray)unsavedVendorLIDecisions resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) diff --git a/src/fabric/NativeUsercentricsModule.ts b/src/fabric/NativeUsercentricsModule.ts index 4ce54f5..c105c33 100644 --- a/src/fabric/NativeUsercentricsModule.ts +++ b/src/fabric/NativeUsercentricsModule.ts @@ -33,7 +33,7 @@ export interface Spec extends TurboModule { acceptAll(consentType: number): Promise>; acceptAllForTCF(fromLayer: number, consentType: number): Promise>; denyAll(consentType: number): Promise>; - denyAllForTCF(fromLayer: number, consentType: number, unsavedPurposeLIDecisions: Array): Promise>; + denyAllForTCF(fromLayer: number, consentType: number, unsavedPurposeLIDecisions: Array, unsavedVendorLIDecisions: Array): Promise>; saveDecisions(decisions: Array, consentType: number): Promise>; saveDecisionsForTCF(