@usercentrics/react-native-sdk 2.0.3-rc2 → 2.2.2-RC1

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 (53) hide show
  1. package/README.md +2 -0
  2. package/android/build.gradle +1 -1
  3. package/android/src/androidTest/java/com/usercentrics/reactnativemodule/RNUsercentricsModuleTest.kt +15 -6
  4. package/android/src/androidTest/java/com/usercentrics/reactnativemodule/api/FakeUsercentricsProxy.kt +23 -1
  5. package/android/src/androidTest/java/com/usercentrics/reactnativemodule/mock/GetCMPDataMock.kt +2 -1
  6. package/android/src/androidTest/java/com/usercentrics/reactnativemodule/mock/GetConsentsMock.kt +19 -1
  7. package/android/src/androidTest/java/com/usercentrics/reactnativemodule/mock/GetTCFDataMock.kt +2 -0
  8. package/android/src/androidTest/java/com/usercentrics/reactnativemodule/mock/SaveDecisionsForTCFMock.kt +18 -1
  9. package/android/src/androidTest/java/com/usercentrics/reactnativemodule/mock/SaveDecisionsMock.kt +0 -1
  10. package/android/src/androidTest/java/com/usercentrics/reactnativemodule/mock/ShowFirstLayerMock.kt +27 -0
  11. package/android/src/main/java/com/usercentrics/reactnativeusercentrics/RNUsercentricsModule.kt +52 -0
  12. package/android/src/main/java/com/usercentrics/reactnativeusercentrics/api/UsercentricsProxy.kt +42 -1
  13. package/android/src/main/java/com/usercentrics/reactnativeusercentrics/extensions/FirstLayerOptionsExtensions.kt +160 -0
  14. package/android/src/main/java/com/usercentrics/reactnativeusercentrics/extensions/TCFDataExtensions.kt +1 -0
  15. package/android/src/main/java/com/usercentrics/reactnativeusercentrics/extensions/UsercentricsServiceConsentExtensions.kt +21 -0
  16. package/ios/Extensions/BannerSettings+Dict.swift +180 -0
  17. package/ios/Extensions/TCFData+Dict.swift +2 -1
  18. package/ios/Extensions/UIColor+Extensions.swift +52 -0
  19. package/ios/Extensions/UIFont+UsercentricsFontDict.swift +15 -0
  20. package/ios/Extensions/UIImage+UsercentricsLogoDict.swift +14 -0
  21. package/ios/Extensions/UsercentricsCMPData+Dict.swift +1 -1
  22. package/ios/Extensions/UsercentricsServiceConsents+Dict.swift +14 -0
  23. package/ios/Extensions/UsercentricsUISettings+Dict.swift +1 -0
  24. package/ios/Manager/UsercentricsManager.swift +43 -39
  25. package/ios/RNUsercentricsModule.m +8 -0
  26. package/ios/RNUsercentricsModule.swift +97 -36
  27. package/ios/RNUsercentricsModule.xcodeproj/project.pbxproj +16 -0
  28. package/lib/Usercentrics.d.ts +6 -1
  29. package/lib/Usercentrics.js +43 -16
  30. package/lib/Usercentrics.js.map +1 -1
  31. package/lib/models/BannerSettings.d.ts +6 -0
  32. package/lib/models/BannerSettings.js +7 -0
  33. package/lib/models/BannerSettings.js.map +1 -0
  34. package/lib/models/FirstLayerOptions.d.ts +82 -0
  35. package/lib/models/FirstLayerOptions.js +104 -0
  36. package/lib/models/FirstLayerOptions.js.map +1 -0
  37. package/lib/models/SecondLayerOptions.d.ts +6 -0
  38. package/lib/models/SecondLayerOptions.js +7 -0
  39. package/lib/models/SecondLayerOptions.js.map +1 -0
  40. package/lib/models/TCFData.d.ts +9 -8
  41. package/lib/models/TCFData.js +2 -1
  42. package/lib/models/TCFData.js.map +1 -1
  43. package/lib/models/UsercentricsServiceConsent.d.ts +9 -1
  44. package/lib/models/UsercentricsServiceConsent.js +10 -1
  45. package/lib/models/UsercentricsServiceConsent.js.map +1 -1
  46. package/lib/models/UsercentricsUIOptions.d.ts +2 -1
  47. package/lib/models/UsercentricsUIOptions.js +2 -1
  48. package/lib/models/UsercentricsUIOptions.js.map +1 -1
  49. package/lib/models/index.d.ts +3 -0
  50. package/lib/models/index.js +3 -0
  51. package/lib/models/index.js.map +1 -1
  52. package/package.json +2 -2
  53. package/react-native-usercentrics.podspec +0 -1
package/README.md CHANGED
@@ -30,6 +30,8 @@ The Usercentrics Apps SDK is a Consent Management Platform framework for mobile,
30
30
  ### Requirements
31
31
  * Android 5.0 (API 21) or higher with Kotlin 1.5 or higher
32
32
  * iOS 11 or higher
33
+ * React 17.0 or higher
34
+ * React Native 0.65 or higher
33
35
 
34
36
  ## Installation
35
37
 
@@ -1,4 +1,4 @@
1
- def usercentrics_version = "2.0.2"
1
+ def usercentrics_version = "2.2.1"
2
2
  version usercentrics_version
3
3
 
4
4
  buildscript {
@@ -2,10 +2,7 @@ package com.usercentrics.reactnativemodule
2
2
 
3
3
  import androidx.test.ext.junit.runners.AndroidJUnit4
4
4
  import androidx.test.platform.app.InstrumentationRegistry
5
- import com.facebook.react.bridge.JavaOnlyMap
6
- import com.facebook.react.bridge.ReactApplicationContext
7
- import com.facebook.react.bridge.WritableArray
8
- import com.facebook.react.bridge.WritableMap
5
+ import com.facebook.react.bridge.*
9
6
  import com.facebook.soloader.SoLoader
10
7
  import com.usercentrics.reactnativemodule.api.FakeUsercentricsProxy
11
8
  import com.usercentrics.reactnativemodule.fake.FakePromise
@@ -39,6 +36,14 @@ class RNUsercentricsModuleTest {
39
36
  putString("version", "1.2.3")
40
37
  }
41
38
 
39
+ private val usercentricsConsentHistoryEntries = listOf(
40
+ UsercentricsConsentHistoryEntry(
41
+ status = false,
42
+ UsercentricsConsentType.EXPLICIT,
43
+ 123
44
+ )
45
+ )
46
+
42
47
  private val usercentricsReadyStatus = UsercentricsReadyStatus(
43
48
  shouldShowCMP = false,
44
49
  consents = listOf(
@@ -47,7 +52,9 @@ class RNUsercentricsModuleTest {
47
52
  status = false,
48
53
  dataProcessor = "Facebook SDK",
49
54
  type = UsercentricsConsentType.EXPLICIT,
50
- version = "1.0.1"
55
+ version = "1.0.1",
56
+ isEssential = false,
57
+ history = usercentricsConsentHistoryEntries
51
58
  )
52
59
  )
53
60
  )
@@ -74,7 +81,9 @@ class RNUsercentricsModuleTest {
74
81
  status = false,
75
82
  dataProcessor = "Facebook SDK",
76
83
  type = UsercentricsConsentType.EXPLICIT,
77
- version = "1.0.1"
84
+ version = "1.0.1",
85
+ isEssential = false,
86
+ history = usercentricsConsentHistoryEntries
78
87
  )
79
88
  ),
80
89
  controllerId = "8620135313b043696b806868b20da905886a3a2598ddddc2b52973f9807d6b45",
@@ -1,11 +1,13 @@
1
1
  package com.usercentrics.reactnativemodule.api
2
2
 
3
+ import android.app.Activity
3
4
  import android.content.Context
4
5
  import android.content.Intent
6
+ import com.facebook.react.bridge.Promise
7
+ import com.facebook.react.bridge.ReadableMap
5
8
  import com.usercentrics.reactnativeusercentrics.api.UsercentricsProxy
6
9
  import com.usercentrics.sdk.*
7
10
  import com.usercentrics.sdk.errors.UsercentricsError
8
- import com.usercentrics.sdk.models.settings.UsercentricsConsent
9
11
 
10
12
  internal class FakeUsercentricsProxy(
11
13
  private val instanceAnswer: UsercentricsSDK? = null,
@@ -66,4 +68,24 @@ internal class FakeUsercentricsProxy(
66
68
  override fun reset() {
67
69
  resetCount++
68
70
  }
71
+
72
+ var showFirstLayerLayout: UsercentricsLayout? = null
73
+ var showFirstLayerBannerSettings: BannerSettings? = null
74
+ var showFirstLayerStyle: FirstLayerStyleSettings? = null
75
+
76
+ override fun showFirstLayer(
77
+ activity: Activity,
78
+ layout: UsercentricsLayout,
79
+ bannerSettings: BannerSettings?,
80
+ firstLayerStyleSettings: FirstLayerStyleSettings?,
81
+ promise: Promise
82
+ ) {
83
+ this.showFirstLayerLayout = layout
84
+ this.showFirstLayerBannerSettings = bannerSettings
85
+ this.showFirstLayerStyle = firstLayerStyleSettings
86
+ }
87
+
88
+ override fun showSecondLayer() {
89
+
90
+ }
69
91
  }
@@ -228,7 +228,8 @@ internal class GetCMPDataMock {
228
228
  hideButtonDeny = false,
229
229
  tabsServicesIsEnabled = true,
230
230
  isOverlayEnabled = true,
231
- title = ""
231
+ title = "",
232
+ hideTogglesForServices = false
232
233
  )
233
234
  private val fakeTCF2Settings = TCF2Settings(
234
235
  togglesSpecialFeaturesToggleOff = "Off",
@@ -1,17 +1,27 @@
1
1
  package com.usercentrics.reactnativemodule.mock
2
2
 
3
+ import com.usercentrics.sdk.UsercentricsConsentHistoryEntry
3
4
  import com.usercentrics.sdk.UsercentricsServiceConsent
4
5
  import com.usercentrics.sdk.models.settings.UsercentricsConsentType
5
6
 
6
7
  internal class GetConsentsMock {
7
8
  companion object {
9
+
8
10
  val fakeWithData = listOf(
9
11
  UsercentricsServiceConsent(
10
12
  templateId = "ocv9HNX_g",
11
13
  status = false,
12
14
  dataProcessor = "Facebook SDK",
13
15
  type = UsercentricsConsentType.EXPLICIT,
14
- version = "1.0.1"
16
+ version = "1.0.1",
17
+ history = listOf(
18
+ UsercentricsConsentHistoryEntry(
19
+ status = false,
20
+ UsercentricsConsentType.EXPLICIT,
21
+ 123
22
+ )
23
+ ),
24
+ isEssential = false
15
25
  )
16
26
  )
17
27
 
@@ -22,6 +32,14 @@ internal class GetConsentsMock {
22
32
  "type" to 0,
23
33
  "version" to "1.0.1",
24
34
  "dataProcessor" to "Facebook SDK",
35
+ "isEssential" to false,
36
+ "history" to listOf(
37
+ mapOf(
38
+ "timestampInMillis" to 123,
39
+ "type" to 0,
40
+ "status" to false
41
+ )
42
+ )
25
43
  )
26
44
  )
27
45
  }
@@ -92,6 +92,7 @@ internal class GetTCFDataMock {
92
92
  deviceStorage = null,
93
93
  usesCookies = false,
94
94
  cookieRefresh = null,
95
+ dataSharedOutsideEU = false
95
96
  )
96
97
  ),
97
98
  )
@@ -182,6 +183,7 @@ internal class GetTCFDataMock {
182
183
  "deviceStorageDisclosureUrl" to null,
183
184
  "usesCookies" to false,
184
185
  "cookieRefresh" to null,
186
+ "dataSharedOutsideEU" to false
185
187
  ),
186
188
  ),
187
189
  )
@@ -2,6 +2,7 @@ package com.usercentrics.reactnativemodule.mock
2
2
 
3
3
  import com.usercentrics.reactnativeusercentrics.extensions.toWritableMap
4
4
  import com.usercentrics.sdk.UserDecision
5
+ import com.usercentrics.sdk.UsercentricsConsentHistoryEntry
5
6
  import com.usercentrics.sdk.UsercentricsServiceConsent
6
7
  import com.usercentrics.sdk.models.settings.UsercentricsConsentType
7
8
  import com.usercentrics.sdk.services.tcf.TCFDecisionUILayer
@@ -18,7 +19,15 @@ internal class SaveDecisionsForTCFMock {
18
19
  status = true,
19
20
  dataProcessor = "Facebook SDK",
20
21
  type = UsercentricsConsentType.EXPLICIT,
21
- version = "1.0.1"
22
+ version = "1.0.1",
23
+ history = listOf(
24
+ UsercentricsConsentHistoryEntry(
25
+ status = false,
26
+ UsercentricsConsentType.EXPLICIT,
27
+ 123
28
+ )
29
+ ),
30
+ isEssential = false
22
31
  )
23
32
  )
24
33
 
@@ -62,6 +71,14 @@ internal class SaveDecisionsForTCFMock {
62
71
  "type" to 0,
63
72
  "version" to "1.0.1",
64
73
  "dataProcessor" to "Facebook SDK",
74
+ "isEssential" to false,
75
+ "history" to listOf(
76
+ mapOf(
77
+ "timestampInMillis" to 123,
78
+ "type" to 0,
79
+ "status" to false
80
+ )
81
+ )
65
82
  )
66
83
  )
67
84
  }
@@ -2,7 +2,6 @@ package com.usercentrics.reactnativemodule.mock
2
2
 
3
3
  import com.usercentrics.sdk.UserDecision
4
4
 
5
-
6
5
  internal class SaveDecisionsMock {
7
6
  companion object {
8
7
  val callDecisions = listOf(
@@ -0,0 +1,27 @@
1
+ package com.usercentrics.reactnativemodule.mock
2
+
3
+ import com.usercentrics.reactnativeusercentrics.extensions.toWritableMap
4
+
5
+ internal class ShowFirstLayerMock {
6
+ companion object {
7
+ val arguments = mapOf(
8
+ "layout" to "POPUP_CENTER",
9
+ "bannerSettings" to mapOf(
10
+ "font" to null,
11
+ "logo" to null,
12
+ ),
13
+ "styleSettings" to mapOf(
14
+ "headerImage" to null,
15
+ "title" to mapOf(
16
+ "alignment" to "END",
17
+ "textSize" to 20.0,
18
+ ),
19
+ "message" to mapOf(
20
+ "alignment" to "CENTER",
21
+ "textSize" to 16,
22
+ ),
23
+ "cornerRadius" to 50
24
+ ),
25
+ ).toWritableMap()
26
+ }
27
+ }
@@ -5,8 +5,11 @@ import android.content.Intent
5
5
  import com.facebook.react.bridge.*
6
6
  import com.usercentrics.reactnativeusercentrics.api.UsercentricsProxy
7
7
  import com.usercentrics.reactnativeusercentrics.extensions.*
8
+ import com.usercentrics.sdk.UsercentricsBanner
9
+ import com.usercentrics.sdk.UsercentricsLayout
8
10
  import com.usercentrics.sdk.models.settings.UsercentricsConsentType
9
11
  import com.usercentrics.sdk.services.tcf.TCFDecisionUILayer
12
+ import java.lang.Exception
10
13
 
11
14
  internal class RNUsercentricsModule(
12
15
  reactContext: ReactApplicationContext,
@@ -69,6 +72,55 @@ internal class RNUsercentricsModule(
69
72
  currentActivity?.startActivityForResult(intent, showCMPRequestCode)
70
73
  }
71
74
 
75
+ @ReactMethod
76
+ fun showFirstLayer(options: ReadableMap, promise: Promise) {
77
+ UiThreadUtil.runOnUiThread {
78
+ try {
79
+ val assetManager = currentActivity!!.assets
80
+
81
+ val layout = options.getString("layout")!!.usercentricsLayoutFromEnumString()
82
+ val bannerSettings =
83
+ options.getMap("bannerSettings")?.bannerSettingsFromMap(assetManager)
84
+ val styleSettings =
85
+ options.getMap("styleSettings")?.firstLayerStyleSettingsFromMap(assetManager)
86
+
87
+ usercentricsProxy.showFirstLayer(
88
+ currentActivity!!,
89
+ layout,
90
+ bannerSettings,
91
+ styleSettings,
92
+ promise
93
+ )
94
+
95
+ } catch (e: Exception) {
96
+ promise.reject(e)
97
+ }
98
+ }
99
+ }
100
+
101
+ @ReactMethod
102
+ fun showSecondLayer(options: ReadableMap, promise: Promise) {
103
+ UiThreadUtil.runOnUiThread {
104
+ try {
105
+ val assetManager = currentActivity!!.assets
106
+
107
+ val bannerSettings =
108
+ options.getMap("bannerSettings")?.bannerSettingsFromMap(assetManager)
109
+ val showCloseButton = options.getBoolean("showCloseButton")
110
+
111
+
112
+ UsercentricsBanner(currentActivity!!, bannerSettings).showSecondLayer(
113
+ showCloseButton
114
+ ) {
115
+ promise.resolve(it?.toWritableMap())
116
+ }
117
+
118
+ } catch (e: Exception) {
119
+ promise.reject(e)
120
+ }
121
+ }
122
+ }
123
+
72
124
  internal fun parseActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean {
73
125
  if (requestCode != showCMPRequestCode) return false
74
126
  assert(pendingPromise != null)
@@ -1,10 +1,18 @@
1
1
  package com.usercentrics.reactnativeusercentrics.api
2
2
 
3
+ import android.app.Activity
3
4
  import android.content.Context
4
5
  import android.content.Intent
5
6
  import android.util.Log
7
+ import com.facebook.react.bridge.Promise
8
+ import com.facebook.react.bridge.ReadableMap
9
+ import com.usercentrics.reactnativeusercentrics.extensions.bannerSettingsFromMap
10
+ import com.usercentrics.reactnativeusercentrics.extensions.firstLayerStyleSettingsFromMap
11
+ import com.usercentrics.reactnativeusercentrics.extensions.toWritableMap
12
+ import com.usercentrics.reactnativeusercentrics.extensions.usercentricsLayoutFromEnumString
6
13
  import com.usercentrics.sdk.*
7
14
  import com.usercentrics.sdk.errors.UsercentricsError
15
+ import java.lang.Exception
8
16
 
9
17
  interface UsercentricsProxy {
10
18
  val instance: UsercentricsSDK
@@ -23,6 +31,16 @@ interface UsercentricsProxy {
23
31
 
24
32
  fun parseResult(resultCode: Int, data: Intent?): UsercentricsConsentUserResponse?
25
33
 
34
+ fun showFirstLayer(
35
+ activity: Activity,
36
+ layout: UsercentricsLayout,
37
+ bannerSettings: BannerSettings?,
38
+ firstLayerStyleSettings: FirstLayerStyleSettings?,
39
+ promise: Promise
40
+ )
41
+
42
+ fun showSecondLayer()
43
+
26
44
  fun reset()
27
45
  }
28
46
 
@@ -32,7 +50,11 @@ internal class UsercentricsProxyImpl : UsercentricsProxy {
32
50
  get() = Usercentrics.instance
33
51
 
34
52
  override fun initialize(context: Context, options: UsercentricsOptions) {
35
- Usercentrics.initialize(context, options)
53
+ try {
54
+ Usercentrics.initialize(context, options)
55
+ } catch (e: Exception) {
56
+ e.printStackTrace()
57
+ }
36
58
  }
37
59
 
38
60
  override fun isReady(
@@ -55,6 +77,25 @@ internal class UsercentricsProxyImpl : UsercentricsProxy {
55
77
  .parseResult(resultCode, data)
56
78
  }
57
79
 
80
+ override fun showFirstLayer(
81
+ activity: Activity,
82
+ layout: UsercentricsLayout,
83
+ bannerSettings: BannerSettings?,
84
+ firstLayerStyleSettings: FirstLayerStyleSettings?,
85
+ promise: Promise
86
+ ) {
87
+ UsercentricsBanner(activity, bannerSettings).showFirstLayer(
88
+ layout,
89
+ firstLayerStyleSettings
90
+ ) {
91
+ promise.resolve(it?.toWritableMap())
92
+ }
93
+ }
94
+
95
+ override fun showSecondLayer() {
96
+
97
+ }
98
+
58
99
  override fun reset() = Usercentrics.reset()
59
100
 
60
101
  }
@@ -0,0 +1,160 @@
1
+ package com.usercentrics.reactnativeusercentrics.extensions
2
+
3
+ import android.content.res.AssetManager
4
+ import android.graphics.Color
5
+ import androidx.annotation.ColorInt
6
+ import com.facebook.react.bridge.ReadableMap
7
+ import com.usercentrics.sdk.*
8
+
9
+ internal fun String.usercentricsLayoutFromEnumString(): UsercentricsLayout {
10
+ return when (this) {
11
+ "FULL" -> UsercentricsLayout.Full
12
+ "SHEET" -> UsercentricsLayout.Sheet
13
+ "POPUP_BOTTOM" -> UsercentricsLayout.Popup(PopupPosition.BOTTOM)
14
+ "POPUP_CENTER" -> UsercentricsLayout.Popup(PopupPosition.CENTER)
15
+ else -> throw IllegalArgumentException("Invalid layout: $this")
16
+ }
17
+ }
18
+
19
+ internal fun ReadableMap.bannerSettingsFromMap(assetManager: AssetManager): BannerSettings {
20
+ val customFont = getMap("font")
21
+ val customLogo = getMap("logo")
22
+
23
+ return BannerSettings(
24
+ customFont?.usercentricsFontFromMap(assetManager),
25
+ customLogo?.usercentricsImageFromMap()
26
+ )
27
+ }
28
+
29
+ internal fun ReadableMap.firstLayerStyleSettingsFromMap(assetManager: AssetManager): FirstLayerStyleSettings {
30
+ return FirstLayerStyleSettings(
31
+ headerImage = getMap("headerImage")?.headerImageFromMap(),
32
+ title = getMap("title")?.titleFromMap(assetManager),
33
+ message = getMap("message")?.messageFromMap(assetManager),
34
+ buttonLayout = getMap("buttonLayout")?.buttonLayoutFromMap(assetManager),
35
+ backgroundColor = getString("backgroundColorHex")?.deserializeColor(),
36
+ overlayColor = getString("overlayColorHex")?.deserializeColor(),
37
+ cornerRadius = getIntOrNull("cornerRadius")
38
+ )
39
+ }
40
+
41
+ internal fun ReadableMap.headerImageFromMap(): HeaderImageSettings? {
42
+ val isHidden = getBooleanOrNull("isHidden") ?: false
43
+ if (isHidden) {
44
+ return HeaderImageSettings.Hidden
45
+ }
46
+
47
+ val image = getMap("image")?.usercentricsImageFromMap() ?: return null
48
+
49
+ val isExtended = getBooleanOrNull("isExtended") ?: false
50
+ return if (isExtended) {
51
+ HeaderImageSettings.ExtendedLogoSettings(image)
52
+ } else {
53
+ HeaderImageSettings.LogoSettings(
54
+ image = image,
55
+ alignment = getString("alignment")?.sectionAlignmentFromMap(),
56
+ heightInDp = getDoubleOrNull("height")?.toFloat()
57
+ )
58
+ }
59
+ }
60
+
61
+ internal fun ReadableMap.titleFromMap(assetManager: AssetManager): TitleSettings {
62
+ val font = getMap("font")?.usercentricsFontFromMap(assetManager)
63
+ return TitleSettings(
64
+ alignment = getString("alignment")?.sectionAlignmentFromMap(),
65
+ textColor = getString("textColorHex")?.deserializeColor(),
66
+ font = font?.font,
67
+ textSizeInSp = font?.sizeInSp
68
+ )
69
+ }
70
+
71
+ internal fun ReadableMap.messageFromMap(assetManager: AssetManager): MessageSettings {
72
+ val font = getMap("font")?.usercentricsFontFromMap(assetManager)
73
+
74
+ return MessageSettings(
75
+ font = font?.font,
76
+ textSizeInSp = font?.sizeInSp,
77
+ textColor = getString("textColorHex")?.deserializeColor(),
78
+ alignment = getString("alignment")?.sectionAlignmentFromMap(),
79
+ linkTextColor = getString("linkTextColorHex")?.deserializeColor(),
80
+ underlineLink = getBooleanOrNull("linkTextUnderline")
81
+ )
82
+ }
83
+
84
+ internal fun String.sectionAlignmentFromMap(): SectionAlignment {
85
+ return SectionAlignment.valueOf(this)
86
+ }
87
+
88
+ internal fun ReadableMap.buttonLayoutFromMap(
89
+ assetManager: AssetManager
90
+ ): ButtonLayout? {
91
+ val layout = getString("layout")
92
+ val buttons: List<List<ButtonSettings>> = getArray("buttons")?.let { buttonsArray ->
93
+ val buttonsList: MutableList<List<ButtonSettings>> = mutableListOf()
94
+
95
+ for (rowIndex in 0 until buttonsArray.size()) {
96
+ val listRow = mutableListOf<ButtonSettings>()
97
+ val row = buttonsArray.getArray(rowIndex)
98
+ for (rowElement in 0 until row.size()) {
99
+ val element = row.getMap(rowElement)
100
+ listRow.add(element.buttonSettingsFromMap(assetManager))
101
+ }
102
+ buttonsList.add(listRow)
103
+ }
104
+
105
+ return@let buttonsList.toList()
106
+ } ?: listOf()
107
+
108
+ when (layout) {
109
+ "ROW" -> {
110
+ return ButtonLayout.Row(
111
+ buttons.flatten()
112
+ )
113
+ }
114
+ "COLUMN" -> {
115
+ return ButtonLayout.Column(
116
+ buttons.flatten()
117
+ )
118
+ }
119
+ "GRID" -> {
120
+ return ButtonLayout.Grid(
121
+ buttons
122
+ )
123
+ }
124
+ }
125
+
126
+ return null
127
+ }
128
+
129
+ internal fun ReadableMap.buttonSettingsFromMap(
130
+ assetManager: AssetManager
131
+ ): ButtonSettings {
132
+ val font = getMap("font")?.usercentricsFontFromMap(assetManager)
133
+ return ButtonSettings(
134
+ type = getString("buttonType")!!.deserializeButtonType(),
135
+ isAllCaps = getBooleanOrNull("isAllCaps"),
136
+ font = font?.font,
137
+ textColor = getString("textColorHex")?.deserializeColor(),
138
+ backgroundColor = getString("backgroundColorHex")?.deserializeColor(),
139
+ cornerRadius = getIntOrNull("cornerRadius"),
140
+ textSizeInSp = font?.sizeInSp
141
+ )
142
+ }
143
+
144
+ internal fun String.deserializeButtonType(): ButtonType {
145
+ return ButtonType.valueOf(this)
146
+ }
147
+
148
+ @ColorInt
149
+ internal fun String.deserializeColor(): Int? {
150
+ val colorString: String =
151
+ if (!this.startsWith("#")) {
152
+ "#$this"
153
+ } else {
154
+ this
155
+ }
156
+
157
+ return runCatching {
158
+ Color.parseColor(colorString)
159
+ }.getOrNull()
160
+ }
@@ -93,5 +93,6 @@ private fun TCFVendor.serialize(): WritableMap {
93
93
  // "deviceStorage" to deviceStorage.serialize(),
94
94
  "usesCookies" to usesCookies,
95
95
  "cookieRefresh" to cookieRefresh,
96
+ "dataSharedOutsideEU" to dataSharedOutsideEU
96
97
  ).toWritableMap()
97
98
  }
@@ -1,8 +1,10 @@
1
1
  package com.usercentrics.reactnativeusercentrics.extensions
2
2
 
3
3
  import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.ReadableArray
4
5
  import com.facebook.react.bridge.WritableArray
5
6
  import com.facebook.react.bridge.WritableMap
7
+ import com.usercentrics.sdk.UsercentricsConsentHistoryEntry
6
8
  import com.usercentrics.sdk.UsercentricsServiceConsent
7
9
 
8
10
  internal fun List<UsercentricsServiceConsent>.toWritableArray(): WritableArray {
@@ -28,6 +30,25 @@ internal fun UsercentricsServiceConsent.toWritableMap(): WritableMap {
28
30
  }
29
31
  putString("version", version)
30
32
  putString("dataProcessor", dataProcessor)
33
+ putBoolean("isEssential", isEssential)
34
+ putArray("history", history.toWritableArray())
35
+ }
36
+ }
37
+
38
+ private fun List<UsercentricsConsentHistoryEntry>.toWritableArray(): ReadableArray? {
39
+ map {
40
+ Arguments.createMap().apply {
41
+ putBoolean("status", it.status)
42
+ putInt("type", it.type.ordinal)
43
+ putInt("timestampInMillis", it.timestampInMillis.toInt())
44
+ }
45
+ }.apply {
46
+ val array = Arguments.createArray()
47
+ forEach {
48
+ array.pushMap(it)
49
+ }
50
+
51
+ return array
31
52
  }
32
53
  }
33
54