Skip to content

feat(MSDK-4088): Support PL-5714 new COP restriction fields across TS, Android and iOS#218

Open
uc-brunosilva wants to merge 1 commit into
masterfrom
bugfix/MSDK-4088-pur-vendor-consents-not-set-on-save
Open

feat(MSDK-4088): Support PL-5714 new COP restriction fields across TS, Android and iOS#218
uc-brunosilva wants to merge 1 commit into
masterfrom
bugfix/MSDK-4088-pur-vendor-consents-not-set-on-save

Conversation

@uc-brunosilva
Copy link
Copy Markdown
Collaborator

@uc-brunosilva uc-brunosilva commented Jun 5, 2026

Summary

Adds support for the new PL-5714 JSON schema fields across all three bridge layers.

New class: ConsentOrPayRestriction{id: number, value: 'FLEXIBLE'|'MANDATORY'} with isFlexible() helper

Updated: TCF2ChangedPurposes — new consentOrPay?: ConsentOrPayRestriction[] field
Updated: TCF2Settings — new specialFeaturesConsentOrPay?: ConsentOrPayRestriction[] field

Both Android and iOS bridges serialize the new fields. Old publisherRestrictions and specialFeatures maps are kept for backwards compatibility.

Part of the PUR model fix tracked in MSDK-4088. Native SDK changes are in mobile-sdk PR #2401.

Test plan

  • TypeScript: ConsentOrPayRestriction exported correctly, new fields present on TCF2Settings and TCF2ChangedPurposes
  • Android: UsercentricsCMPDataExtensions serializes specialFeaturesConsentOrPay and changedPurposes.consentOrPay
  • iOS: UsercentricsCMPData+Dict serializes both new fields
  • Existing tests pass

🤖 Generated with Claude Code

Summary by CodeRabbit

New Features

  • Added comprehensive Consent-or-Pay restrictions support for enhanced management of consent preferences with greater flexibility
  • Extended consent management capabilities to include special features with full Consent-or-Pay configuration options
  • Implemented automatic detection mechanism for flexible Consent-or-Pay restrictions to streamline workflows
  • Enhanced overall data serialization and consistency across Android, iOS, and web platforms

…, Android and iOS

Adds ConsentOrPayRestriction class and two new PL-5714 fields:
- TCF2ChangedPurposes.consentOrPay — array of {id, value: FLEXIBLE|MANDATORY}
- TCF2Settings.specialFeaturesConsentOrPay — same format

Both Android and iOS bridges now serialize these fields alongside the legacy
publisherRestrictions/specialFeatures maps for backwards compatibility.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented Jun 5, 2026

CodeAnt AI is reviewing your PR.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 5, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR extends the React Native SDK's TCF2 settings model across TypeScript, iOS, and Android by introducing ConsentOrPayRestriction data with specialFeaturesConsentOrPay and consentOrPay fields. The TypeScript model defines the shape; iOS and Android serialization layers then bridge these fields to their respective native implementations.

Changes

Consent-or-Pay Restrictions Data Flow

Layer / File(s) Summary
TypeScript Model Definitions
src/models/TCF2Settings.tsx
New ConsentOrPayRestriction class with id, value, and isFlexible() method. TCF2Settings gains optional specialFeaturesConsentOrPay array; TCF2ChangedPurposes gains optional consentOrPay array, both wired through constructors.
iOS Serialization Bridge
ios/Extensions/UsercentricsCMPData+Dict.swift
TCF2Settings.toDictionary() and TCF2ChangedPurposes.toDictionary() updated to serialize the new restriction fields. New ConsentOrPayRestriction.toDictionary() helper converts restrictions to dictionaries.
Android Serialization Bridge
android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt
ConsentOrPayRestriction import added. TCF2Settings.serialize() and TCF2ChangedPurposes.serialize() updated to serialize restriction fields. New ConsentOrPayRestriction.serialize() helper converts restrictions to maps.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • Usercentrics/react-native-sdk#212: Both PRs extend the React Native bridge's TCF2Settings Android/iOS/TS serialization to include Consent-or-Pay data—main PR adds specialFeaturesConsentOrPay / consentOrPay restriction items, while the retrieved PR adds a consentOrPay configuration payload—so they overlap directly in the same TCF2Settings mapping code paths.

Suggested labels

size:M

Suggested reviewers

  • rodrigo-leal-usercentrics
  • uc-brunosouza
  • islameldesoky95

Poem

A hopping journey, three paths aligned,
TypeScript, iOS, Android in mind,
ConsentOrPay restrictions take their place,
Serialization flows with timely grace,
Bridges built for data to embrace. 🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding support for new Consent-or-Pay restriction fields across TypeScript, Android, and iOS platforms.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bugfix/MSDK-4088-pur-vendor-consents-not-set-on-save

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Support PL-5714 consent-or-pay restriction fields across platforms

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add ConsentOrPayRestriction class with isFlexible() helper method
• Support new PL-5714 fields in TCF2Settings and TCF2ChangedPurposes
• Serialize specialFeaturesConsentOrPay in Android and iOS bridges
• Serialize consentOrPay array in TCF2ChangedPurposes across all platforms
Diagram
flowchart LR
  A["PL-5714 Schema"] -->|"New Fields"| B["ConsentOrPayRestriction"]
  B -->|"Added to"| C["TCF2Settings"]
  B -->|"Added to"| D["TCF2ChangedPurposes"]
  C -->|"Serialized by"| E["Android Bridge"]
  C -->|"Serialized by"| F["iOS Bridge"]
  D -->|"Serialized by"| E
  D -->|"Serialized by"| F
  E -->|"TypeScript Model"| G["TCF2Settings.tsx"]
  F -->|"TypeScript Model"| G

Loading

Grey Divider

File Changes

1. src/models/TCF2Settings.tsx ✨ Enhancement +20/-0

Add ConsentOrPayRestriction model and new PL-5714 fields

• Add new ConsentOrPayRestriction class with id, value properties and isFlexible() method
• Add specialFeaturesConsentOrPay?: ConsentOrPayRestriction[] field to TCF2Settings
• Add consentOrPay?: ConsentOrPayRestriction[] field to TCF2ChangedPurposes
• Update constructors to accept and initialize new fields

src/models/TCF2Settings.tsx


2. android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt ✨ Enhancement +9/-1

Serialize new consent-or-pay fields in Android bridge

• Import ConsentOrPayRestriction class from native SDK
• Add serialization of specialFeaturesConsentOrPay in TCF2Settings.serialize()
• Add serialization of consentOrPay array in TCF2ChangedPurposes.serialize()
• Add new ConsentOrPayRestriction.serialize() extension function

android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt


3. ios/Extensions/UsercentricsCMPData+Dict.swift ✨ Enhancement +12/-1

Serialize new consent-or-pay fields in iOS bridge

• Add serialization of specialFeaturesConsentOrPay in TCF2Settings.toDictionary()
• Add serialization of consentOrPay array in TCF2ChangedPurposes.toDictionary()
• Add new ConsentOrPayRestriction.toDictionary() extension function

ios/Extensions/UsercentricsCMPData+Dict.swift


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Jun 5, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0)

Context used
✅ Tickets: MSDK-4088

Grey Divider


Remediation recommended

1. Null vs missing divergence 🐞 Bug ≡ Correctness
Description
For the new COP restriction arrays, iOS always inserts the key and will bridge a missing value as
null, while Android omits the key entirely when the value is null. This creates different JS shapes
for the same API depending on platform (e.g.,
specialFeaturesConsentOrPay/changedPurposes.consentOrPay being null on iOS vs undefined on
Android), which can break consumers relying on consistent presence/absence semantics.
Code

ios/Extensions/UsercentricsCMPData+Dict.swift[241]

+            "specialFeaturesConsentOrPay": self.specialFeaturesConsentOrPay?.map { $0.toDictionary() } as Any,
Evidence
iOS explicitly boxes optionals into Any, which preserves nil as a value that bridges to JS null,
while Android’s toWritableMap() drops null values (no null handling in the when). The new
field additions follow these respective patterns, introducing platform-dependent JS shapes for the
same newly-added keys.

ios/Extensions/UsercentricsCMPData+Dict.swift[235-243]
ios/Extensions/UsercentricsCMPData+Dict.swift[497-505]
android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt[190-255]
android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt[446-460]
android/src/main/java/com/usercentrics/reactnative/extensions/ReadableMapExtensions.kt[74-113]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New optional COP restriction fields serialize differently on iOS vs Android:
- iOS puts the key with a boxed optional (`... as Any`), which bridges to `NSNull`/`null` in JS when the optional is nil.
- Android omits null entries entirely because `toWritableMap()` has no null branch.

This makes the JS API shape inconsistent across platforms.

## Issue Context
React Native consumers commonly distinguish between `undefined` (missing) and `null` (explicit empty). The TS models define these fields as optional (`?:`), which typically implies `undefined`/missing rather than `null`.

## Fix Focus Areas
- ios/Extensions/UsercentricsCMPData+Dict.swift[235-243]
- ios/Extensions/UsercentricsCMPData+Dict.swift[497-514]
- android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt[190-255]
- android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt[446-460]
- android/src/main/java/com/usercentrics/reactnative/extensions/ReadableMapExtensions.kt[74-113]

## Suggested fix
Pick one behavior and implement it on both platforms (recommended: omit keys when nil to match Android + TS `?:`).

### iOS
Build the dictionary mutably and only insert these keys when non-nil, e.g.
- if `specialFeaturesConsentOrPay != nil`, set the array
- if `consentOrPay != nil`, set the array
Otherwise do not include the key.

### Android (optional)
If you prefer explicit nulls, add `putNull` support in `toWritableMap()` for null values, and pass `null` for missing optionals. Otherwise keep Android as-is and adjust iOS to omit keys.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

2. Restriction value too loosely typed 🐞 Bug ⚙ Maintainability
Description
The new ConsentOrPayRestriction model types value as a generic string, allowing invalid values
to compile and propagate even though downstream logic expects specific values like
FLEXIBLE/MANDATORY. This reduces type-safety for SDK consumers and forces runtime normalization in
isFlexible().
Code

src/models/TCF2Settings.tsx[R223-235]

+export class ConsentOrPayRestriction {
+    id: number
+    value: string
+
+    constructor(id: number, value: string) {
+        this.id = id
+        this.value = value
+    }
+
+    isFlexible(): boolean {
+        return this.value?.toUpperCase() === 'FLEXIBLE'
    }
}
Evidence
The new TS class explicitly declares value as string and accepts value: string in the
constructor, so invalid values are not prevented at compile time.

src/models/TCF2Settings.tsx[223-235]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ConsentOrPayRestriction.value` is declared as `string`, which allows arbitrary values and weakens the contract for consumers.

## Issue Context
The model adds a helper `isFlexible()` that assumes a restricted set of string values.

## Fix Focus Areas
- src/models/TCF2Settings.tsx[223-235]

## Suggested fix
Define a constrained type and use it:
- `export type ConsentOrPayRestrictionValue = 'FLEXIBLE' | 'MANDATORY'`
- Change `value: string` -> `value: ConsentOrPayRestrictionValue`
- Change constructor parameter type accordingly.
Optionally keep `isFlexible()` case-insensitive if backend might send lowercase, but still store/normalize to the union (e.g., normalize in constructor).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@pantoaibot
Copy link
Copy Markdown

pantoaibot Bot commented Jun 5, 2026

PR Summary:

Add support for new Consent-or-Pay (COP) restriction fields (ConsentOrPayRestriction) across TypeScript models and native (Android/iOS) serialization so COP special-feature restrictions are passed through the bridge.

Changes:

  • TypeScript (src/models/TCF2Settings.tsx)
    • Added optional field specialFeaturesConsentOrPay?: ConsentOrPayRestriction[] to TCF2Settings.
    • Extended constructor to accept specialFeaturesConsentOrPay (optional) and assign it.
    • Added consentOrPay?: ConsentOrPayRestriction[] to TCF2ChangedPurposes and include it in constructor.
    • Introduced new ConsentOrPayRestriction class (id: number, value: string) with helper isFlexible().
  • Android (UsercentricsCMPDataExtensions.kt)
    • Imported ConsentOrPayRestriction type.
    • Added "specialFeaturesConsentOrPay" mapping into UsercentricsSettings.serialize() to serialize the new list.
    • Added consentOrPay mapping to TCF2ChangedPurposes serialization.
    • Implemented ConsentOrPayRestriction.serialize() helper to convert to Map and included it where needed.
  • iOS (UsercentricsCMPData+Dict.swift)
    • Added "specialFeaturesConsentOrPay" to settings dictionary serialization (maps to array of dictionaries).
    • Added consentOrPay mapping to TCF2ChangedPurposes.toDictionary().
    • Added ConsentOrPayRestriction.toDictionary() extension to serialize id/value pairs.

Notes and compatibility:

  • All additions are optional fields; existing consumers should continue to work without changes.
  • No dependency or performance changes introduced.

Reviewed by Panto AI

Comment on lines +457 to +460
private fun ConsentOrPayRestriction.serialize(): Map<String, Any?> = mapOf(
"id" to id,
"value" to value,
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[VALIDATION] ConsentOrPayRestriction.serialize() returns id and value directly. Ensure the SDK's ConsentOrPayRestriction.value is a JSON-friendly type (String). If the SDK defines value as an enum, explicitly serialize it to a string (e.g. value.name or value.toString().uppercase()) so the JS side receives the expected 'FLEXIBLE'|'MANDATORY' strings. Also consider normalizing casing (uppercase) to match the TypeScript expectation.

private fun ConsentOrPayRestriction.serialize(): Map<String, Any?> = mapOf(
    "id" to id,
    "value" to value.toString().uppercase(),
)

"resurfacePeriod": self.resurfacePeriod,
"consentOrPay": self.consentOrPay?.toDictionary() as Any,
"mandatoryLabel": self.mandatoryLabel,
"specialFeaturesConsentOrPay": self.specialFeaturesConsentOrPay?.map { $0.toDictionary() } as Any,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[REFACTORING] You added "specialFeaturesConsentOrPay": self.specialFeaturesConsentOrPay?.map { $0.toDictionary() } as Any. Ensure the resulting array elements are JSON-serializable types (String/Int/Bool/NSDictionary). If ConsentOrPayRestriction.value is an enum on the native SDK, convert it to rawValue or String(describing:) in toDictionary() so the JS bridge receives plain strings (matching the TS 'FLEXIBLE'|'MANDATORY' expectation).

extension ConsentOrPayRestriction {
    func toDictionary() -> [String: Any] {
        return [
            "id": self.id,
            "value": (self.value as? CustomStringConvertible)?.description ?? String(describing: self.value),
        ]
    }
}

selectedATPIds: number[]
consentOrPay?: TCF2ConsentOrPaySettings
mandatoryLabel: string
specialFeaturesConsentOrPay?: ConsentOrPayRestriction[]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[REFACTORING] You introduced specialFeaturesConsentOrPay?: ConsentOrPayRestriction[] and the ConsentOrPayRestriction class with value: string. For stronger type-safety, change the value type to a string literal union: value: 'FLEXIBLE' | 'MANDATORY'. This prevents invalid values being created in TypeScript consumers. Also remove the unnecessary optional-chaining in isFlexible(): use return this.value.toUpperCase() === 'FLEXIBLE' (value is non-nullable if typed as the union).

export class ConsentOrPayRestriction {
    id: number
    value: 'FLEXIBLE' | 'MANDATORY'

    constructor(id: number, value: 'FLEXIBLE' | 'MANDATORY') {
        this.id = id
        this.value = value
    }

    isFlexible(): boolean {
        return this.value.toUpperCase() === 'FLEXIBLE'
    }
}

@pantoaibot
Copy link
Copy Markdown

pantoaibot Bot commented Jun 5, 2026

Reviewed up to commit:3de3c6bb9cd5691cc494d9215a431450771e6097

Additional Suggestion
Others - Update native/unit mocks and expected snapshots to include the new fields: Android GetCMPDataMock.expectedSettings (and related expectedTCF2Settings) must include specialFeaturesConsentOrPay and changedPurposes.consentOrPay entries. Without updates tests will fail. See android/src/androidTest/mock/GetCMPDataMock.kt referenced in this PR for locations to update.
// android/src/androidTest/java/com/usercentrics/reactnative/mock/GetCMPDataMock.kt

import com.usercentrics.sdk.v2.settings.data.ConsentOrPayRestriction

// when creating fakeTCF2Settings
private val fakeTCF2Settings = TCF2Settings(
    // ...existing args...
    changedPurposes = TCF2ChangedPurposes(
        purposes = listOf(1, 2, 3),
        legIntPurposes = listOf(1, 2, 3),
        consentOrPay = listOf(
            ConsentOrPayRestriction(id = 1, value = "FLEXIBLE"),
            ConsentOrPayRestriction(id = 2, value = "MANDATORY"),
        ),
    ),
    // ...existing args...
    specialFeaturesConsentOrPay = listOf(
        ConsentOrPayRestriction(id = 1, value = "FLEXIBLE"),
    ),
)

// in expectedTCF2Settings
private val expectedTCF2Settings = hashMapOf(
    // ...existing expectations...
    "changedPurposes" to hashMapOf(
        "purposes" to listOf(1, 2, 3),
        "legIntPurposes" to listOf(1, 2, 3),
        "consentOrPay" to listOf(
            hashMapOf("id" to 1, "value" to "FLEXIBLE"),
            hashMapOf("id" to 2, "value" to "MANDATORY"),
        ),
    ),
    "specialFeaturesConsentOrPay" to listOf(
        hashMapOf("id" to 1, "value" to "FLEXIBLE"),
    ),
)
  • Update iOS sample/mock tests (e.g. sample/ios/sampleTests/Mock/CMPData+Mock.swift and any expected dictionary construction) to include specialFeaturesConsentOrPay and changedPurposes.consentOrPay to ensure test coverage matches the new serialization fields.
// sample/ios/sampleTests/Mock/CMPData+Mock.swift

extension TCF2ChangedPurposes {

  static func mock() -> TCF2ChangedPurposes {
    return .init(
      purposes: [1,2,3],
      legIntPurposes: [1,2,3],
      notAllowedPurposes: [1,2,3],
      consentOrPay: [ConsentOrPayRestriction(id: 1, value: .flexible)]
    )
  }
}

extension TCF2Settings {

  static func mock() -> TCF2Settings {
    return .init(
      /* existing args... */
      consentOrPay: nil,
      mandatoryLabel: "Mandatory",
      specialFeaturesConsentOrPay: [ConsentOrPayRestriction(id: 1, value: .flexible)]
    )
  }
}

Reviewed by Panto AI

@qodo-code-review
Copy link
Copy Markdown

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: test-android

Failed stage: Run SDK Unit Tests [❌]

Failed test name: ""

Failure summary:

The action failed because the Android module :react-native-usercentrics could not compile Kotlin
(:react-native-usercentrics:compileDebugKotlin).
- Kotlin compilation errors originate from
android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt,
starting at line 15.
- Primary error is an unresolved reference to ConsentOrPayRestriction (e.g.,
UsercentricsCMPDataExtensions.kt:15:46), which then causes many follow-on errors such as overload
resolution ambiguity, inability to infer parameter types, and additional unresolved references
(e.g., specialFeaturesConsentOrPay, consentOrPay, id, value, it).
- Gradle ultimately stops with:
Execution failed for task ':react-native-usercentrics:compileDebugKotlin' due to these compilation
errors, exiting with code 1.

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

251:  NODE_JS_VERSION: 20.19.5
252:  GRADLE_VERSION: 8.13
253:  JAVA_HOME: /Users/runner/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.19-10/arm64/Contents/Home
254:  JAVA_HOME_17_ARM64: /Users/runner/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.19-10/arm64/Contents/Home
255:  ##[endgroup]
256:  Downloading https://services.gradle.org/distributions/gradle-8.13-all.zip
257:  ......................10%......................20%......................30%......................40%......................50%......................60%......................70%.......................80%......................90%......................100%
258:  Welcome to Gradle 8.13!
259:  Here are the highlights of this release:
260:  - Daemon JVM auto-provisioning
261:  - Enhancements for Scala plugin and JUnit testing
262:  - Improvements for build authors and plugin developers
263:  For more details see https://docs.gradle.org/8.13/release-notes.html
264:  Starting a Gradle Daemon (subsequent builds will be faster)
265:  Configuration on demand is an incubating feature.
266:  > Task :gradle-plugin:react-native-gradle-plugin:checkKotlinGradlePluginConfigurationErrors SKIPPED
267:  > Task :gradle-plugin:shared:checkKotlinGradlePluginConfigurationErrors SKIPPED
268:  > Task :gradle-plugin:react-native-gradle-plugin:pluginDescriptors
...

276:  > Task :gradle-plugin:react-native-gradle-plugin:compileJava NO-SOURCE
277:  > Task :gradle-plugin:react-native-gradle-plugin:classes
278:  > Task :gradle-plugin:react-native-gradle-plugin:jar
279:  > Configure project :react-native-usercentrics
280:  WARNING: The option setting 'android.enableResourceOptimizations=false' is deprecated.
281:  The current default is 'true'.
282:  It will be removed in version 9.0 of the Android Gradle plugin.
283:  WARNING: The option setting 'android.defaults.buildfeatures.buildconfig=true' is deprecated.
284:  The current default is 'false'.
285:  It will be removed in version 10.0 of the Android Gradle plugin.
286:  To keep using this feature, add the following to your module-level build.gradle files:
287:  android.buildFeatures.buildConfig = true
288:  or from Android Studio, click: `Refactor` > `Migrate BuildConfig to Gradle Build Files`.
289:  w: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/build.gradle.kts:27:9: 'targetSdk: Int?' is deprecated. Will be removed from library DSL in v9.0. Use testOptions.targetSdk or/and lint.targetSdk instead
290:  w: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/build.gradle.kts:58:15: 'getter for buildDir: File!' is deprecated. Deprecated in Java
291:  > Task :react-native-usercentrics:checkKotlinGradlePluginConfigurationErrors SKIPPED
292:  > Task :react-native-usercentrics:generateCodegenSchemaFromJavaScript
...

300:  > Task :react-native-usercentrics:preDebugUnitTestBuild
301:  > Task :react-native-usercentrics:javaPreCompileDebug
302:  > Task :react-native-usercentrics:javaPreCompileDebugUnitTest FROM-CACHE
303:  > Task :react-native-usercentrics:parseDebugLocalResources
304:  > Task :react-native-usercentrics:koverFindJar
305:  > Task :react-native-usercentrics:preReleaseBuild
306:  > Task :react-native-usercentrics:generateReleaseBuildConfig
307:  > Task :react-native-usercentrics:generateReleaseResValues FROM-CACHE
308:  > Task :react-native-usercentrics:generateReleaseResources
309:  > Task :react-native-usercentrics:packageReleaseResources
310:  > Task :react-native-usercentrics:parseReleaseLocalResources FROM-CACHE
311:  > Task :react-native-usercentrics:generateReleaseRFile
312:  > Task :react-native-usercentrics:generateDebugRFile
313:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:15:46 Unresolved reference 'ConsentOrPayRestriction'.
314:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:30:37 Overload resolution ambiguity between candidates:
315:  > Task :react-native-usercentrics:compileDebugKotlin FAILED
316:  fun UsercentricsSettings.serialize(): WritableMap
317:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
318:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:31:39 Cannot infer type for this parameter. Specify it explicitly.
319:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:31:48 Overload resolution ambiguity between candidates:
320:  fun UsercentricsService.serialize(): WritableMap
321:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
322:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:32:43 Cannot infer type for this parameter. Specify it explicitly.
323:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:32:52 Overload resolution ambiguity between candidates:
324:  fun UsercentricsCategory.serialize(): WritableMap
325:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
326:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:34:45 Overload resolution ambiguity between candidates:
327:  fun UsercentricsLocation.serialize(): WritableMap
328:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
329:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:35:41 Overload resolution ambiguity between candidates:
330:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
331:  fun LegalBasisLocalization.serialize(): WritableMap
332:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:41:28 Overload resolution ambiguity between candidates:
333:  fun UsercentricsLabels.serialize(): Map<String, Any?>
334:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
335:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:45:38 Overload resolution ambiguity between candidates:
336:  fun SecondLayer.serialize(): WritableMap
337:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
338:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:47:25 Overload resolution ambiguity between candidates:
339:  fun TCF2Settings.serialize(): WritableMap
340:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
341:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:48:25 Overload resolution ambiguity between candidates:
342:  fun CCPASettings.serialize(): WritableMap
343:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
344:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:50:37 Overload resolution ambiguity between candidates:
345:  fun FirstLayer.serialize(): WritableMap
346:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
347:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:62:43 Overload resolution ambiguity between candidates:
348:  fun UsercentricsCustomization.serialize(): WritableMap
349:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
350:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:63:33 Overload resolution ambiguity between candidates:
351:  fun VariantsSettings?.serialize(): Any?
352:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
353:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:66:43 Cannot infer type for this parameter. Specify it explicitly.
354:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:66:43 Not enough information to infer type argument for 'R'.
355:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:66:52 Overload resolution ambiguity between candidates:
356:  fun PublishedApp.serialize(): Any
357:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
358:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:248:47 Overload resolution ambiguity between candidates:
359:  fun TCF2ChangedPurposes?.serialize(): Any?
360:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
361:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:251:41 Overload resolution ambiguity between candidates:
362:  fun ConsentOrPaySettings.serialize(): Map<String, Any?>
363:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
364:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:253:42 Unresolved reference 'specialFeaturesConsentOrPay'.
365:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:253:77 Unresolved reference 'it'.
366:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:304:27 Overload resolution ambiguity between candidates:
367:  fun CustomizationColor.serialize(): WritableMap
368:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
369:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:305:25 Overload resolution ambiguity between candidates:
370:  fun CustomizationFont.serialize(): WritableMap
371:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
372:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:404:42 Overload resolution ambiguity between candidates:
373:  fun ConsentDisclosureObject?.serialize(): Any?
374:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
375:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:453:27 Unresolved reference 'consentOrPay'.
376:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:453:47 Unresolved reference 'it'.
377:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:457:13 Unresolved reference 'ConsentOrPayRestriction'.
378:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:458:13 Unresolved reference 'id'.
379:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:459:16 Unresolved reference 'value'.
380:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:465:53 Cannot infer type for this parameter. Specify it explicitly.
381:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:465:62 Overload resolution ambiguity between candidates:
382:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
383:  fun AdTechProvider.serialize(): WritableMap
384:  e: file:///Users/runner/work/react-native-sdk/react-native-sdk/android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt:480:37 Overload resolution ambiguity between candidates:
385:  fun <ERROR TYPE REF: Symbol not found for ConsentOrPayRestriction>.serialize(): Map<String, Any?>
386:  fun TranslationAriaLabels.serialize(): WritableMap
387:  FAILURE: Build failed with an exception.
388:  > Task :react-native-usercentrics:generateDebugUnitTestStubRFile
389:  25 actionable tasks: 22 executed, 3 from cache
390:  * What went wrong:
391:  Execution failed for task ':react-native-usercentrics:compileDebugKotlin'.
392:  > A failure occurred while executing org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction
393:  > Compilation error. See log for more details
394:  * Try:
395:  > Run with --stacktrace option to get the stack trace.
396:  > Run with --info or --debug option to get more log output.
397:  > Run with --scan to get full insights.
398:  > Get more help at https://help.gradle.org.
399:  BUILD FAILED in 2m 39s
400:  ##[error]Process completed with exit code 1.
401:  ##[group]Run actions/upload-artifact@v4

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/models/TCF2Settings.tsx (1)

223-235: ⚡ Quick win

Consider using a union type for stricter type safety on the value field.

The value field is currently typed as string, but based on the PR objectives, it should only be 'FLEXIBLE' or 'MANDATORY'. Using a union type would provide compile-time safety and better autocomplete support.

🔧 Proposed enhancement for type safety
+export type ConsentOrPayValue = 'FLEXIBLE' | 'MANDATORY'
+
 export class ConsentOrPayRestriction {
     id: number
-    value: string
+    value: ConsentOrPayValue

-    constructor(id: number, value: string) {
+    constructor(id: number, value: ConsentOrPayValue) {
         this.id = id
         this.value = value
     }

     isFlexible(): boolean {
-        return this.value?.toUpperCase() === 'FLEXIBLE'
+        return this.value === 'FLEXIBLE'
     }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/models/TCF2Settings.tsx` around lines 223 - 235, Change the value field
and constructor parameter on class ConsentOrPayRestriction from type string to a
string literal union 'FLEXIBLE' | 'MANDATORY' (i.e., value: 'FLEXIBLE' |
'MANDATORY'), update the constructor signature accordingly, and simplify
isFlexible() to return this.value === 'FLEXIBLE' (remove the optional chaining
and toUpperCase). Also search for and update any call sites that construct
ConsentOrPayRestriction to pass one of the two allowed literals to match the new
type.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/models/TCF2Settings.tsx`:
- Around line 223-235: Change the value field and constructor parameter on class
ConsentOrPayRestriction from type string to a string literal union 'FLEXIBLE' |
'MANDATORY' (i.e., value: 'FLEXIBLE' | 'MANDATORY'), update the constructor
signature accordingly, and simplify isFlexible() to return this.value ===
'FLEXIBLE' (remove the optional chaining and toUpperCase). Also search for and
update any call sites that construct ConsentOrPayRestriction to pass one of the
two allowed literals to match the new type.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 69fe2d36-1aea-488b-9770-fdcae7838051

📥 Commits

Reviewing files that changed from the base of the PR and between 1ea68b5 and 3de3c6b.

📒 Files selected for processing (3)
  • android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt
  • ios/Extensions/UsercentricsCMPData+Dict.swift
  • src/models/TCF2Settings.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant