Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class RNUsercentricsModuleTest {
putString("version", "1.2.3")
putInt("networkMode", 1)
putInt("initTimeoutMillis", 10000)
putString("controllerId", "a".repeat(64))
}

private val bannerSettingsMap = mapOf(
Expand Down Expand Up @@ -128,6 +129,7 @@ class RNUsercentricsModuleTest {
assertEquals("1.2.3", usercentricsProxy.initializeOptionsArgument?.version)
assertEquals(NetworkMode.EU, usercentricsProxy.initializeOptionsArgument?.networkMode)
assertEquals(10000L, usercentricsProxy.initializeOptionsArgument?.initTimeoutMillis)
assertEquals("a".repeat(64), usercentricsProxy.initializeOptionsArgument?.controllerId)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ internal fun ReadableMap.usercentricsOptionsFromMap(): UsercentricsOptions {
options.initTimeoutMillis = it.toLong()
}

getString("controllerId")?.let {
options.controllerId = it
}

Comment thread
islameldesoky95 marked this conversation as resolved.
getMap("bannerCustomization")?.let {
options.bannerCustomization = it.bannerInitCustomizationFromMap()
}
Expand Down
4 changes: 4 additions & 0 deletions ios/Extensions/UsercentricsOptions+Dict.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ public extension UsercentricsOptions {
options.initTimeoutMillis = Int64(initTimeoutMillis)
}

if let controllerId = dictionary["controllerId"] as? String {
options.controllerId = controllerId
}

if let bannerCustomizationDict = dictionary["bannerCustomization"] as? NSDictionary {
options.bannerCustomization = BannerInitCustomization(from: bannerCustomizationDict)
}
Expand Down
2 changes: 2 additions & 0 deletions sample/ios/sampleTests/UsercentricsOptionsDictTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class UsercentricsOptionsDictTests: XCTestCase {
"version": "1.2.3",
"networkMode": 1,
"initTimeoutMillis": 1500,
"controllerId": String(repeating: "a", count: 64),
]


Expand All @@ -28,6 +29,7 @@ class UsercentricsOptionsDictTests: XCTestCase {
XCTAssertEqual(1000, usercentricsOptionsFromDict.timeoutMillis)
XCTAssertEqual(.eu, usercentricsOptionsFromDict.networkMode)
XCTAssertEqual(1500, usercentricsOptionsFromDict.initTimeoutMillis)
XCTAssertEqual(String(repeating: "a", count: 64), usercentricsOptionsFromDict.controllerId)
}

func testInitializeWithoutSettingsIdShouldNotInitialize() {
Expand Down
15 changes: 15 additions & 0 deletions src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,21 @@ describe('Test Usercentrics Module', () => {
expect(call).toBe(options)
})

test('testConfigureBridgeWithControllerId', () => {
const controllerId = "a".repeat(64);
const options = new UsercentricsOptions({
settingsId: "abc",
ruleSetId: "qwer",
controllerId
});

Usercentrics.configure(options);
const calls = RNUsercentricsModule.configure.mock.calls;
const call = calls[calls.length - 1][0];
expect(call).toBe(options);
expect(call.controllerId).toBe(controllerId);
})

test('testConfigureBridgeWithBannerCustomization', () => {
const bannerCustomization = new BannerInitCustomization({
paddingTop: 16,
Expand Down
17 changes: 17 additions & 0 deletions src/models/UsercentricsOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@ export class UsercentricsOptions {
networkMode?: NetworkMode;
consentMediation?: Boolean;
initTimeoutMillis?: number;
/**
* Optional controllerId to inject at SDK initialisation.
*
* Use this to preserve user identity across login/logout flows that clear local consent
* storage. Store the controllerId (via `Usercentrics.getControllerId()`) server-side after
* the first successful init, then pass it here on every subsequent login. The SDK will skip
* generating a new ID and use this value instead. It is persisted to local storage, so
* subsequent re-initialisations without this option continue to use it.
*
* The value must be a 64-character lowercase hexadecimal string (the format produced
* internally by the SDK). Invalid values are ignored with a warning log and the SDK falls
* back to its normal ID resolution (stored → generated).
Comment thread
islameldesoky95 marked this conversation as resolved.
Comment thread
islameldesoky95 marked this conversation as resolved.
*/
controllerId?: string;
Comment thread
islameldesoky95 marked this conversation as resolved.
/**
* @deprecated bannerCustomization is deprecated and will be removed in a future release.
* Configure banner appearance via the Usercentrics dashboard instead.
Expand All @@ -26,6 +40,7 @@ export class UsercentricsOptions {
networkMode = undefined,
consentMediation = undefined,
initTimeoutMillis = undefined,
controllerId = undefined,
bannerCustomization = undefined
}: {
settingsId?: string,
Expand All @@ -37,6 +52,7 @@ export class UsercentricsOptions {
networkMode?: NetworkMode,
consentMediation?: Boolean,
initTimeoutMillis?: number,
controllerId?: string,
bannerCustomization?: BannerInitCustomization
}) {
this.settingsId = settingsId;
Expand All @@ -48,6 +64,7 @@ export class UsercentricsOptions {
this.networkMode = networkMode
this.consentMediation = consentMediation
this.initTimeoutMillis = initTimeoutMillis
this.controllerId = controllerId
this.bannerCustomization = bannerCustomization
}
}
Loading