diff --git a/android/src/main/java/com/usercentrics/reactnative/extensions/BannerInitCustomizationExtensions.kt b/android/src/main/java/com/usercentrics/reactnative/extensions/BannerInitCustomizationExtensions.kt new file mode 100644 index 0000000..f79a708 --- /dev/null +++ b/android/src/main/java/com/usercentrics/reactnative/extensions/BannerInitCustomizationExtensions.kt @@ -0,0 +1,45 @@ +package com.usercentrics.reactnative.extensions + +import com.facebook.react.bridge.ReadableMap +import com.usercentrics.sdk.BannerInitCustomization +import com.usercentrics.sdk.PurposeListStyle + +internal fun ReadableMap.bannerInitCustomizationFromMap(): BannerInitCustomization { + return BannerInitCustomization( + paddingTop = getIntOrNull("paddingTop"), + paddingBottom = getIntOrNull("paddingBottom"), + paddingStart = getIntOrNull("paddingStart"), + paddingEnd = getIntOrNull("paddingEnd"), + lineSpacingMultiplier = getFloatOrNull("lineSpacingMultiplier"), + titleFontSize = getIntOrNull("titleFontSize"), + bodyFontSize = getIntOrNull("bodyFontSize"), + linkFontSize = getIntOrNull("linkFontSize"), + titleFontBold = getBooleanOrNull("titleFontBold"), + headerPaddingTop = getIntOrNull("headerPaddingTop"), + headerPaddingSides = getIntOrNull("headerPaddingSides"), + headerPaddingBetweenElements = getIntOrNull("headerPaddingBetweenElements"), + buttonBorderColor = getString("buttonBorderColor"), + buttonBorderWidth = getIntOrNull("buttonBorderWidth"), + purposeListStyle = getString("purposeListStyle")?.purposeListStyleFromEnumString(), + stickyHeader = getBooleanOrNull("stickyHeader"), + hideLanguageSwitcher = getBooleanOrNull("hideLanguageSwitcher"), + buttonHeightDp = getIntOrNull("buttonHeightDp"), + buttonHorizontalPaddingDp = getIntOrNull("buttonHorizontalPaddingDp"), + buttonSpacingDp = getIntOrNull("buttonSpacingDp"), + linkUnderline = getBooleanOrNull("linkUnderline"), + showSecondLayerCloseButton = getBooleanOrNull("showSecondLayerCloseButton"), + tabFontSize = getIntOrNull("tabFontSize"), + tabActiveColor = getString("tabActiveColor"), + denyAllButtonBackground = getString("denyAllButtonBackground"), + acceptAllButtonBackground = getString("acceptAllButtonBackground"), + linkColor = getString("linkColor"), + ) +} + +internal fun String.purposeListStyleFromEnumString(): PurposeListStyle? { + return when (this) { + "BOXED" -> PurposeListStyle.BOXED + "FLAT" -> PurposeListStyle.FLAT + else -> null + } +} diff --git a/android/src/main/java/com/usercentrics/reactnative/extensions/BannerSettingsExtensions.kt b/android/src/main/java/com/usercentrics/reactnative/extensions/BannerSettingsExtensions.kt index b328c98..3f19ae3 100644 --- a/android/src/main/java/com/usercentrics/reactnative/extensions/BannerSettingsExtensions.kt +++ b/android/src/main/java/com/usercentrics/reactnative/extensions/BannerSettingsExtensions.kt @@ -26,6 +26,7 @@ internal fun ReadableMap.bannerSettingsFromMap(context: Context): BannerSettings secondLayerStyleSettings = rawSecondLayerStyleSettings?.secondLayerStyleSettingsFromMap(context), generalStyleSettings = rawGeneralStyleSettings?.generalStyleSettingsFromMap(context), variantName = getString("variantName"), + initCustomization = getMap("initCustomization")?.bannerInitCustomizationFromMap(), ) } diff --git a/android/src/main/java/com/usercentrics/reactnative/extensions/ReadableMapExtensions.kt b/android/src/main/java/com/usercentrics/reactnative/extensions/ReadableMapExtensions.kt index 3cb9e86..a02561d 100644 --- a/android/src/main/java/com/usercentrics/reactnative/extensions/ReadableMapExtensions.kt +++ b/android/src/main/java/com/usercentrics/reactnative/extensions/ReadableMapExtensions.kt @@ -29,6 +29,10 @@ internal fun ReadableMap.getBooleanOrNull(key: String): Boolean? { } } +internal fun ReadableMap.getFloatOrNull(key: String): Float? { + return getDoubleOrNull(key)?.toFloat() +} + internal fun List<*>.serialize(): WritableArray { val array = Arguments.createArray() forEach { value -> diff --git a/android/src/main/java/com/usercentrics/reactnative/extensions/UserOptionsExtensions.kt b/android/src/main/java/com/usercentrics/reactnative/extensions/UserOptionsExtensions.kt index 13ba25a..f4508ac 100644 --- a/android/src/main/java/com/usercentrics/reactnative/extensions/UserOptionsExtensions.kt +++ b/android/src/main/java/com/usercentrics/reactnative/extensions/UserOptionsExtensions.kt @@ -56,5 +56,9 @@ internal fun ReadableMap.usercentricsOptionsFromMap(): UsercentricsOptions { options.initTimeoutMillis = it.toLong() } + getMap("bannerCustomization")?.let { + options.bannerCustomization = it.bannerInitCustomizationFromMap() + } + return options } diff --git a/android/src/test/java/com/usercentrics/reactnative/extensions/BannerInitCustomizationExtensionsTest.kt b/android/src/test/java/com/usercentrics/reactnative/extensions/BannerInitCustomizationExtensionsTest.kt new file mode 100644 index 0000000..4b9fb80 --- /dev/null +++ b/android/src/test/java/com/usercentrics/reactnative/extensions/BannerInitCustomizationExtensionsTest.kt @@ -0,0 +1,107 @@ +package com.usercentrics.reactnative.extensions + +import com.facebook.react.bridge.JavaOnlyMap +import com.usercentrics.sdk.PurposeListStyle +import org.junit.Assert.* +import org.junit.Test + +class BannerInitCustomizationExtensionsTest { + + @Test + fun `bannerInitCustomizationFromMap maps all fields`() { + val map = JavaOnlyMap().apply { + putInt("paddingTop", 16) + putInt("paddingBottom", 16) + putInt("paddingStart", 8) + putInt("paddingEnd", 8) + putDouble("lineSpacingMultiplier", 1.2) + putInt("titleFontSize", 18) + putInt("bodyFontSize", 14) + putInt("linkFontSize", 14) + putBoolean("titleFontBold", true) + putInt("headerPaddingTop", 12) + putInt("headerPaddingSides", 12) + putInt("headerPaddingBetweenElements", 4) + putString("buttonBorderColor", "#004dcf") + putInt("buttonBorderWidth", 1) + putString("purposeListStyle", "FLAT") + putBoolean("stickyHeader", true) + putBoolean("hideLanguageSwitcher", false) + putInt("buttonHeightDp", 48) + putInt("buttonHorizontalPaddingDp", 16) + putInt("buttonSpacingDp", 8) + putBoolean("linkUnderline", true) + putBoolean("showSecondLayerCloseButton", true) + putInt("tabFontSize", 14) + putString("tabActiveColor", "#004dcf") + putString("denyAllButtonBackground", "#ffffff") + putString("acceptAllButtonBackground", "#004dcf") + putString("linkColor", "#004dcf") + } + + val customization = map.bannerInitCustomizationFromMap() + + assertEquals(16, customization.paddingTop) + assertEquals(16, customization.paddingBottom) + assertEquals(8, customization.paddingStart) + assertEquals(8, customization.paddingEnd) + assertEquals(1.2f, customization.lineSpacingMultiplier) + assertEquals(18, customization.titleFontSize) + assertEquals(14, customization.bodyFontSize) + assertEquals(14, customization.linkFontSize) + assertEquals(true, customization.titleFontBold) + assertEquals(12, customization.headerPaddingTop) + assertEquals(12, customization.headerPaddingSides) + assertEquals(4, customization.headerPaddingBetweenElements) + assertEquals("#004dcf", customization.buttonBorderColor) + assertEquals(1, customization.buttonBorderWidth) + assertEquals(PurposeListStyle.FLAT, customization.purposeListStyle) + assertEquals(true, customization.stickyHeader) + assertEquals(false, customization.hideLanguageSwitcher) + assertEquals(48, customization.buttonHeightDp) + assertEquals(16, customization.buttonHorizontalPaddingDp) + assertEquals(8, customization.buttonSpacingDp) + assertEquals(true, customization.linkUnderline) + assertEquals(true, customization.showSecondLayerCloseButton) + assertEquals(14, customization.tabFontSize) + assertEquals("#004dcf", customization.tabActiveColor) + assertEquals("#ffffff", customization.denyAllButtonBackground) + assertEquals("#004dcf", customization.acceptAllButtonBackground) + assertEquals("#004dcf", customization.linkColor) + } + + @Test + fun `bannerInitCustomizationFromMap omits unset fields instead of defaulting`() { + val map = JavaOnlyMap() + + val customization = map.bannerInitCustomizationFromMap() + + assertNull(customization.paddingTop) + assertNull(customization.buttonBorderColor) + assertNull(customization.purposeListStyle) + assertNull(customization.stickyHeader) + } + + @Test + fun `purposeListStyleFromEnumString maps known values and returns null otherwise`() { + assertEquals(PurposeListStyle.BOXED, "BOXED".purposeListStyleFromEnumString()) + assertEquals(PurposeListStyle.FLAT, "FLAT".purposeListStyleFromEnumString()) + assertNull("UNKNOWN".purposeListStyleFromEnumString()) + } + + @Test + fun `usercentricsOptionsFromMap maps nested bannerCustomization`() { + val map = JavaOnlyMap().apply { + putString("settingsId", "123") + putMap("bannerCustomization", JavaOnlyMap().apply { + putInt("paddingTop", 16) + putString("purposeListStyle", "FLAT") + }) + } + + val options = map.usercentricsOptionsFromMap() + + assertEquals(16, options.bannerCustomization?.paddingTop) + assertEquals(PurposeListStyle.FLAT, options.bannerCustomization?.purposeListStyle) + } +} diff --git a/ios/Extensions/BannerInitCustomization+Dict.swift b/ios/Extensions/BannerInitCustomization+Dict.swift new file mode 100644 index 0000000..6f3b318 --- /dev/null +++ b/ios/Extensions/BannerInitCustomization+Dict.swift @@ -0,0 +1,53 @@ +import Foundation +import Usercentrics + +extension BannerInitCustomization { + convenience init?(from dictionary: NSDictionary?) { + guard let dictionary = dictionary else { return nil } + + self.init( + paddingTop: (dictionary["paddingTop"] as? Int32).map { KotlinInt(value: $0) }, + paddingBottom: (dictionary["paddingBottom"] as? Int32).map { KotlinInt(value: $0) }, + paddingStart: (dictionary["paddingStart"] as? Int32).map { KotlinInt(value: $0) }, + paddingEnd: (dictionary["paddingEnd"] as? Int32).map { KotlinInt(value: $0) }, + lineSpacingMultiplier: (dictionary["lineSpacingMultiplier"] as? Double).map { KotlinFloat(value: Float($0)) }, + titleFontSize: (dictionary["titleFontSize"] as? Int32).map { KotlinInt(value: $0) }, + bodyFontSize: (dictionary["bodyFontSize"] as? Int32).map { KotlinInt(value: $0) }, + linkFontSize: (dictionary["linkFontSize"] as? Int32).map { KotlinInt(value: $0) }, + titleFontBold: (dictionary["titleFontBold"] as? Bool).map { KotlinBoolean(value: $0) }, + headerPaddingTop: (dictionary["headerPaddingTop"] as? Int32).map { KotlinInt(value: $0) }, + headerPaddingSides: (dictionary["headerPaddingSides"] as? Int32).map { KotlinInt(value: $0) }, + headerPaddingBetweenElements: (dictionary["headerPaddingBetweenElements"] as? Int32).map { KotlinInt(value: $0) }, + buttonBorderColor: dictionary["buttonBorderColor"] as? String, + buttonBorderWidth: (dictionary["buttonBorderWidth"] as? Int32).map { KotlinInt(value: $0) }, + purposeListStyle: PurposeListStyle.from(enumString: dictionary["purposeListStyle"] as? String), + stickyHeader: (dictionary["stickyHeader"] as? Bool).map { KotlinBoolean(value: $0) }, + hideLanguageSwitcher: (dictionary["hideLanguageSwitcher"] as? Bool).map { KotlinBoolean(value: $0) }, + buttonHeightDp: (dictionary["buttonHeightDp"] as? Int32).map { KotlinInt(value: $0) }, + buttonHorizontalPaddingDp: (dictionary["buttonHorizontalPaddingDp"] as? Int32).map { KotlinInt(value: $0) }, + buttonSpacingDp: (dictionary["buttonSpacingDp"] as? Int32).map { KotlinInt(value: $0) }, + linkUnderline: (dictionary["linkUnderline"] as? Bool).map { KotlinBoolean(value: $0) }, + showSecondLayerCloseButton: (dictionary["showSecondLayerCloseButton"] as? Bool).map { KotlinBoolean(value: $0) }, + tabFontSize: (dictionary["tabFontSize"] as? Int32).map { KotlinInt(value: $0) }, + tabActiveColor: dictionary["tabActiveColor"] as? String, + denyAllButtonBackground: dictionary["denyAllButtonBackground"] as? String, + acceptAllButtonBackground: dictionary["acceptAllButtonBackground"] as? String, + linkColor: dictionary["linkColor"] as? String + ) + } +} + +extension PurposeListStyle { + static func from(enumString: String?) -> PurposeListStyle? { + guard let enumString = enumString else { return nil } + + switch enumString { + case "BOXED": + return .boxed + case "FLAT": + return .flat + default: + return nil + } + } +} diff --git a/ios/Extensions/BannerSettings+Dict.swift b/ios/Extensions/BannerSettings+Dict.swift index 60308ee..6e0aea1 100644 --- a/ios/Extensions/BannerSettings+Dict.swift +++ b/ios/Extensions/BannerSettings+Dict.swift @@ -1,4 +1,5 @@ import Foundation +import Usercentrics import UsercentricsUI import UIKit @@ -16,10 +17,14 @@ extension BannerSettings { let secondLayerStyleSettingsDict = dictionary["secondLayerStyleSettings"] as? NSDictionary let secondLayerSettings = SecondLayerStyleSettings(from: secondLayerStyleSettingsDict, bannerFontHolder: bannerFontHolder) + let initCustomizationDict = dictionary["initCustomization"] as? NSDictionary + let initCustomization = BannerInitCustomization(from: initCustomizationDict) + self.init(generalStyleSettings: generalStyleSettings, firstLayerStyleSettings: firstLayerSettings, secondLayerStyleSettings: secondLayerSettings, - variantName: dictionary["variantName"] as? String) + variantName: dictionary["variantName"] as? String, + initCustomization: initCustomization) } } diff --git a/ios/Extensions/UsercentricsOptions+Dict.swift b/ios/Extensions/UsercentricsOptions+Dict.swift index 5b52682..42788e2 100644 --- a/ios/Extensions/UsercentricsOptions+Dict.swift +++ b/ios/Extensions/UsercentricsOptions+Dict.swift @@ -41,6 +41,10 @@ public extension UsercentricsOptions { options.initTimeoutMillis = Int64(initTimeoutMillis) } + if let bannerCustomizationDict = dictionary["bannerCustomization"] as? NSDictionary { + options.bannerCustomization = BannerInitCustomization(from: bannerCustomizationDict) + } + return options } } diff --git a/sample/ios/Podfile.lock b/sample/ios/Podfile.lock index cf9073a..ca6531e 100644 --- a/sample/ios/Podfile.lock +++ b/sample/ios/Podfile.lock @@ -2816,7 +2816,7 @@ SPEC CHECKSUMS: hermes-engine: 35c763d57c9832d0eef764316ca1c4d043581394 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 - RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669 + RCT-Folly: 59ec0ac1f2f39672a0c6e6cecdd39383b764646f RCTDeprecation: c0ed3249a97243002615517dff789bf4666cf585 RCTRequired: 58719f5124f9267b5f9649c08bf23d9aea845b23 RCTTypeSafety: 4aefa8328ab1f86da273f08517f1f6b343f6c2cc @@ -2850,7 +2850,7 @@ SPEC CHECKSUMS: React-Mapbuffer: e4a65db5f4df53369f39558c0cf2f480f6d3d6c7 React-microtasksnativemodule: 86334c5c06315e0bccb7b6e6f2c905e92f98b615 react-native-safe-area-context: eda63a662750758c1fdd7e719c9f1026c8d161cb - react-native-usercentrics: 04e3b7f3afa0f0d105c316b1d6f4aea5b5fbfe0c + react-native-usercentrics: 61e591b5b3d23360ec528b086e374cf53bbaeba0 react-native-webview: 83c663c5bdf1357d3e7c00986260cb888ea0e328 React-NativeModulesApple: 8c7eb6057b00c191a11ad5ced41826ec5a0e4d78 React-oscompat: 93b5535ea7f7dff46aaee4f78309a70979bdde9d diff --git a/sample/ios/sampleTests/BannerInitCustomizationDictTests.swift b/sample/ios/sampleTests/BannerInitCustomizationDictTests.swift new file mode 100644 index 0000000..5e477aa --- /dev/null +++ b/sample/ios/sampleTests/BannerInitCustomizationDictTests.swift @@ -0,0 +1,104 @@ +import XCTest + +@testable import Usercentrics +@testable import react_native_usercentrics + +class BannerInitCustomizationDictTests: XCTestCase { + + func testFromDictWithAllValuesSet() { + let dict: NSDictionary = [ + "paddingTop": 16, + "paddingBottom": 16, + "paddingStart": 8, + "paddingEnd": 8, + "lineSpacingMultiplier": 1.2, + "titleFontSize": 18, + "bodyFontSize": 14, + "linkFontSize": 14, + "titleFontBold": true, + "headerPaddingTop": 12, + "headerPaddingSides": 12, + "headerPaddingBetweenElements": 4, + "buttonBorderColor": "#004dcf", + "buttonBorderWidth": 1, + "purposeListStyle": "FLAT", + "stickyHeader": true, + "hideLanguageSwitcher": false, + "buttonHeightDp": 48, + "buttonHorizontalPaddingDp": 16, + "buttonSpacingDp": 8, + "linkUnderline": true, + "showSecondLayerCloseButton": true, + "tabFontSize": 14, + "tabActiveColor": "#004dcf", + "denyAllButtonBackground": "#ffffff", + "acceptAllButtonBackground": "#004dcf", + "linkColor": "#004dcf", + ] + + let customization = BannerInitCustomization(from: dict)! + + XCTAssertEqual(16, customization.paddingTop?.int32Value) + XCTAssertEqual(16, customization.paddingBottom?.int32Value) + XCTAssertEqual(8, customization.paddingStart?.int32Value) + XCTAssertEqual(8, customization.paddingEnd?.int32Value) + XCTAssertEqual(1.2, customization.lineSpacingMultiplier?.floatValue ?? -1, accuracy: 0.0001) + XCTAssertEqual(18, customization.titleFontSize?.int32Value) + XCTAssertEqual(14, customization.bodyFontSize?.int32Value) + XCTAssertEqual(14, customization.linkFontSize?.int32Value) + XCTAssertEqual(true, customization.titleFontBold?.boolValue) + XCTAssertEqual(12, customization.headerPaddingTop?.int32Value) + XCTAssertEqual(12, customization.headerPaddingSides?.int32Value) + XCTAssertEqual(4, customization.headerPaddingBetweenElements?.int32Value) + XCTAssertEqual("#004dcf", customization.buttonBorderColor) + XCTAssertEqual(1, customization.buttonBorderWidth?.int32Value) + XCTAssertEqual(.flat, customization.purposeListStyle) + XCTAssertEqual(true, customization.stickyHeader?.boolValue) + XCTAssertEqual(false, customization.hideLanguageSwitcher?.boolValue) + XCTAssertEqual(48, customization.buttonHeightDp?.int32Value) + XCTAssertEqual(16, customization.buttonHorizontalPaddingDp?.int32Value) + XCTAssertEqual(8, customization.buttonSpacingDp?.int32Value) + XCTAssertEqual(true, customization.linkUnderline?.boolValue) + XCTAssertEqual(true, customization.showSecondLayerCloseButton?.boolValue) + XCTAssertEqual(14, customization.tabFontSize?.int32Value) + XCTAssertEqual("#004dcf", customization.tabActiveColor) + XCTAssertEqual("#ffffff", customization.denyAllButtonBackground) + XCTAssertEqual("#004dcf", customization.acceptAllButtonBackground) + XCTAssertEqual("#004dcf", customization.linkColor) + } + + func testFromDictWithNoValuesSetOmitsFields() { + let dict: NSDictionary = [:] + let customization = BannerInitCustomization(from: dict)! + + XCTAssertNil(customization.paddingTop) + XCTAssertNil(customization.buttonBorderColor) + XCTAssertNil(customization.purposeListStyle) + } + + func testFromNilDictionaryReturnsNil() { + XCTAssertNil(BannerInitCustomization(from: nil)) + } + + func testPurposeListStyleFromEnumString() { + XCTAssertEqual(.boxed, PurposeListStyle.from(enumString: "BOXED")) + XCTAssertEqual(.flat, PurposeListStyle.from(enumString: "FLAT")) + XCTAssertNil(PurposeListStyle.from(enumString: "UNKNOWN")) + XCTAssertNil(PurposeListStyle.from(enumString: nil)) + } + + func testUsercentricsOptionsBannerCustomizationFromDict() { + let dict: NSDictionary = [ + "settingsId": "123", + "bannerCustomization": [ + "paddingTop": 16, + "purposeListStyle": "FLAT", + ], + ] + + let options = UsercentricsOptions.initialize(from: dict)! + + XCTAssertEqual(16, options.bannerCustomization?.paddingTop?.int32Value) + XCTAssertEqual(.flat, options.bannerCustomization?.purposeListStyle) + } +} diff --git a/sample/ios/sampleTests/BannerSettingsDictTests.swift b/sample/ios/sampleTests/BannerSettingsDictTests.swift index 52619e2..1771da9 100644 --- a/sample/ios/sampleTests/BannerSettingsDictTests.swift +++ b/sample/ios/sampleTests/BannerSettingsDictTests.swift @@ -1,5 +1,6 @@ import XCTest +import Usercentrics import UsercentricsUI @testable import react_native_usercentrics @@ -28,4 +29,18 @@ class BannerSettingsDictTests: XCTestCase { XCTAssertNil(settings?.generalStyleSettings?.logo) XCTAssertNil(settings?.generalStyleSettings?.font) } + + func testFromDictWithInitCustomization() { + let dict: NSDictionary = [ + "initCustomization": [ + "paddingTop": 16, + "purposeListStyle": "FLAT", + ] + ] + let settings = BannerSettings(from: dict) + + XCTAssertNotNil(settings?.initCustomization) + XCTAssertEqual(16, settings?.initCustomization?.paddingTop?.int32Value) + XCTAssertEqual(.flat, settings?.initCustomization?.purposeListStyle) + } } diff --git a/src/__tests__/index.test.ts b/src/__tests__/index.test.ts index 144c49d..3c23bc3 100644 --- a/src/__tests__/index.test.ts +++ b/src/__tests__/index.test.ts @@ -1,7 +1,9 @@ import {NativeModules} from 'react-native'; import { + BannerInitCustomization, BannerSettings, NetworkMode, + PurposeListStyle, TCFData, TCFDecisionUILayer, UsercentricsConsentType, @@ -87,6 +89,50 @@ describe('Test Usercentrics Module', () => { expect(call).toBe(options) }) + test('testConfigureBridgeWithBannerCustomization', () => { + const bannerCustomization = new BannerInitCustomization({ + paddingTop: 16, + paddingBottom: 16, + paddingStart: 8, + paddingEnd: 8, + lineSpacingMultiplier: 1.2, + titleFontSize: 18, + bodyFontSize: 14, + linkFontSize: 14, + titleFontBold: true, + headerPaddingTop: 12, + headerPaddingSides: 12, + headerPaddingBetweenElements: 4, + buttonBorderColor: "#004dcf", + buttonBorderWidth: 1, + purposeListStyle: PurposeListStyle.flat, + stickyHeader: true, + hideLanguageSwitcher: false, + buttonHeightDp: 48, + buttonHorizontalPaddingDp: 16, + buttonSpacingDp: 8, + linkUnderline: true, + showSecondLayerCloseButton: true, + tabFontSize: 14, + tabActiveColor: "#004dcf", + denyAllButtonBackground: "#ffffff", + acceptAllButtonBackground: "#004dcf", + linkColor: "#004dcf" + }); + + const options = new UsercentricsOptions({ + settingsId: "abc", + ruleSetId: "qwer", + bannerCustomization + }); + + Usercentrics.configure(options); + const calls = RNUsercentricsModule.configure.mock.calls; + const call = calls[calls.length - 1][0]; + expect(call).toBe(options); + expect(call.bannerCustomization).toBe(bannerCustomization); + }) + test('testStatus', async () => { const readyStatus = new UsercentricsReadyStatus( true, @@ -178,6 +224,36 @@ describe('Test Usercentrics Module', () => { expect(call).toBe(bannerSettings) }) + test('testShowFirstLayerWithInitCustomization', async () => { + const response = new UsercentricsConsentUserResponse( + "abc", + UsercentricsUserInteraction.acceptAll, + [] + ) + + RNUsercentricsModule.showFirstLayer.mockImplementationOnce( + (): Promise => Promise.resolve(response) + ) + + const initCustomization = new BannerInitCustomization({ + paddingTop: 16, + buttonBorderColor: "#004dcf", + purposeListStyle: PurposeListStyle.flat + }); + + const bannerSettings: BannerSettings = { + initCustomization + } + + const data = await Usercentrics.showFirstLayer(bannerSettings) + expect(data).toBe(response); + + const calls = RNUsercentricsModule.showFirstLayer.mock.calls; + const call = calls[calls.length - 1][0]; + expect(call).toBe(bannerSettings); + expect(call.initCustomization).toBe(initCustomization); + }) + test('testRestoreUserSession', async () => { const readyStatus = new UsercentricsReadyStatus( true, diff --git a/src/models/BannerInitCustomization.tsx b/src/models/BannerInitCustomization.tsx new file mode 100644 index 0000000..dae6380 --- /dev/null +++ b/src/models/BannerInitCustomization.tsx @@ -0,0 +1,125 @@ +export enum PurposeListStyle { + boxed = "BOXED", + flat = "FLAT" +} + +/** + * @deprecated BannerInitCustomization is deprecated and will be removed in a future release. + * Configure banner appearance via the Usercentrics dashboard instead. + */ +export class BannerInitCustomization { + + paddingTop?: number; + paddingBottom?: number; + paddingStart?: number; + paddingEnd?: number; + lineSpacingMultiplier?: number; + titleFontSize?: number; + bodyFontSize?: number; + linkFontSize?: number; + titleFontBold?: boolean; + headerPaddingTop?: number; + headerPaddingSides?: number; + headerPaddingBetweenElements?: number; + buttonBorderColor?: string; + buttonBorderWidth?: number; + purposeListStyle?: PurposeListStyle; + stickyHeader?: boolean; + hideLanguageSwitcher?: boolean; + buttonHeightDp?: number; + buttonHorizontalPaddingDp?: number; + buttonSpacingDp?: number; + linkUnderline?: boolean; + showSecondLayerCloseButton?: boolean; + tabFontSize?: number; + tabActiveColor?: string; + denyAllButtonBackground?: string; + acceptAllButtonBackground?: string; + linkColor?: string; + + constructor({ + paddingTop = undefined, + paddingBottom = undefined, + paddingStart = undefined, + paddingEnd = undefined, + lineSpacingMultiplier = undefined, + titleFontSize = undefined, + bodyFontSize = undefined, + linkFontSize = undefined, + titleFontBold = undefined, + headerPaddingTop = undefined, + headerPaddingSides = undefined, + headerPaddingBetweenElements = undefined, + buttonBorderColor = undefined, + buttonBorderWidth = undefined, + purposeListStyle = undefined, + stickyHeader = undefined, + hideLanguageSwitcher = undefined, + buttonHeightDp = undefined, + buttonHorizontalPaddingDp = undefined, + buttonSpacingDp = undefined, + linkUnderline = undefined, + showSecondLayerCloseButton = undefined, + tabFontSize = undefined, + tabActiveColor = undefined, + denyAllButtonBackground = undefined, + acceptAllButtonBackground = undefined, + linkColor = undefined + }: { + paddingTop?: number, + paddingBottom?: number, + paddingStart?: number, + paddingEnd?: number, + lineSpacingMultiplier?: number, + titleFontSize?: number, + bodyFontSize?: number, + linkFontSize?: number, + titleFontBold?: boolean, + headerPaddingTop?: number, + headerPaddingSides?: number, + headerPaddingBetweenElements?: number, + buttonBorderColor?: string, + buttonBorderWidth?: number, + purposeListStyle?: PurposeListStyle, + stickyHeader?: boolean, + hideLanguageSwitcher?: boolean, + buttonHeightDp?: number, + buttonHorizontalPaddingDp?: number, + buttonSpacingDp?: number, + linkUnderline?: boolean, + showSecondLayerCloseButton?: boolean, + tabFontSize?: number, + tabActiveColor?: string, + denyAllButtonBackground?: string, + acceptAllButtonBackground?: string, + linkColor?: string + } = {}) { + this.paddingTop = paddingTop; + this.paddingBottom = paddingBottom; + this.paddingStart = paddingStart; + this.paddingEnd = paddingEnd; + this.lineSpacingMultiplier = lineSpacingMultiplier; + this.titleFontSize = titleFontSize; + this.bodyFontSize = bodyFontSize; + this.linkFontSize = linkFontSize; + this.titleFontBold = titleFontBold; + this.headerPaddingTop = headerPaddingTop; + this.headerPaddingSides = headerPaddingSides; + this.headerPaddingBetweenElements = headerPaddingBetweenElements; + this.buttonBorderColor = buttonBorderColor; + this.buttonBorderWidth = buttonBorderWidth; + this.purposeListStyle = purposeListStyle; + this.stickyHeader = stickyHeader; + this.hideLanguageSwitcher = hideLanguageSwitcher; + this.buttonHeightDp = buttonHeightDp; + this.buttonHorizontalPaddingDp = buttonHorizontalPaddingDp; + this.buttonSpacingDp = buttonSpacingDp; + this.linkUnderline = linkUnderline; + this.showSecondLayerCloseButton = showSecondLayerCloseButton; + this.tabFontSize = tabFontSize; + this.tabActiveColor = tabActiveColor; + this.denyAllButtonBackground = denyAllButtonBackground; + this.acceptAllButtonBackground = acceptAllButtonBackground; + this.linkColor = linkColor; + } +} diff --git a/src/models/BannerSettings.tsx b/src/models/BannerSettings.tsx index 8faf749..4f268a9 100644 --- a/src/models/BannerSettings.tsx +++ b/src/models/BannerSettings.tsx @@ -1,5 +1,5 @@ import {ImageResolvedAssetSource} from "react-native"; -import {FirstLayerStyleSettings, SecondLayerStyleSettings} from "."; +import {BannerInitCustomization, FirstLayerStyleSettings, SecondLayerStyleSettings} from "."; export class BannerLogo { @@ -107,11 +107,17 @@ export class BannerSettings { secondLayerStyleSettings?: SecondLayerStyleSettings; generalStyleSettings?: GeneralStyleSettings; variantName?: String + /** + * @deprecated initCustomization is deprecated and will be removed in a future release. + * Configure banner appearance via the Usercentrics dashboard instead. + */ + initCustomization?: BannerInitCustomization; - constructor(firstLayerStyleSettings?: FirstLayerStyleSettings, secondLayerStyleSettings?: SecondLayerStyleSettings, generalStyleSettings?: GeneralStyleSettings, variantName?: String) { + constructor(firstLayerStyleSettings?: FirstLayerStyleSettings, secondLayerStyleSettings?: SecondLayerStyleSettings, generalStyleSettings?: GeneralStyleSettings, variantName?: String, initCustomization?: BannerInitCustomization) { this.firstLayerStyleSettings = firstLayerStyleSettings; this.secondLayerStyleSettings = secondLayerStyleSettings; this.generalStyleSettings = generalStyleSettings; this.variantName = variantName; + this.initCustomization = initCustomization; } } diff --git a/src/models/UsercentricsOptions.tsx b/src/models/UsercentricsOptions.tsx index f257894..f88855c 100644 --- a/src/models/UsercentricsOptions.tsx +++ b/src/models/UsercentricsOptions.tsx @@ -1,4 +1,4 @@ -import {NetworkMode, UsercentricsLoggerLevel} from "."; +import {BannerInitCustomization, NetworkMode, UsercentricsLoggerLevel} from "."; export class UsercentricsOptions { settingsId?: string; @@ -10,6 +10,11 @@ export class UsercentricsOptions { networkMode?: NetworkMode; consentMediation?: Boolean; initTimeoutMillis?: number; + /** + * @deprecated bannerCustomization is deprecated and will be removed in a future release. + * Configure banner appearance via the Usercentrics dashboard instead. + */ + bannerCustomization?: BannerInitCustomization; constructor({ settingsId = "", @@ -20,7 +25,8 @@ export class UsercentricsOptions { version = undefined, networkMode = undefined, consentMediation = undefined, - initTimeoutMillis = undefined + initTimeoutMillis = undefined, + bannerCustomization = undefined }: { settingsId?: string, ruleSetId?: string, @@ -30,7 +36,8 @@ export class UsercentricsOptions { version?: string, networkMode?: NetworkMode, consentMediation?: Boolean, - initTimeoutMillis?: number + initTimeoutMillis?: number, + bannerCustomization?: BannerInitCustomization }) { this.settingsId = settingsId; this.ruleSetId = ruleSetId; @@ -41,5 +48,6 @@ export class UsercentricsOptions { this.networkMode = networkMode this.consentMediation = consentMediation this.initTimeoutMillis = initTimeoutMillis + this.bannerCustomization = bannerCustomization } } diff --git a/src/models/index.tsx b/src/models/index.tsx index 1a103fa..4b30ad3 100644 --- a/src/models/index.tsx +++ b/src/models/index.tsx @@ -1,3 +1,4 @@ +export * from './BannerInitCustomization'; export * from './BannerSettings'; export * from './CCPAData'; export * from './FirstLayerSettings';