Skip to content

Commit 6d52867

Browse files
authored
Merge pull request #50 from contentpass/chore-improvements
Minor improvements
2 parents 0ed49f5 + ff6233b commit 6d52867

File tree

10 files changed

+386
-158
lines changed

10 files changed

+386
-158
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@contentpass/react-native-contentpass": patch
3+
"@contentpass/react-native-contentpass-ui": patch
4+
"@contentpass/react-native-contentpass-cmp-onetrust": patch
5+
---
6+
7+
Clean up debug logs, fix consent layer theme and SDK version string. Add README documentation for all packages.

README.md

Lines changed: 15 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -1,150 +1,27 @@
1-
# @contentpass/react-native-contentpass
1+
# react-native-contentpass
22

3-
Contentpass React Native SDK enables easy integration of Contentpass functionality into your React Native applications.
3+
Monorepo for the Contentpass React Native SDK and related packages.
44

5-
## Installation
6-
Install the package using npm or Yarn:
5+
## Packages
76

8-
```sh
9-
npm install @contentpass/react-native-contentpass
10-
```
7+
| Package | Description |
8+
|---------|-------------|
9+
| [`@contentpass/react-native-contentpass`](./packages/react-native-contentpass) | Core SDK — authentication, subscription validation, and impression tracking. |
10+
| [`@contentpass/react-native-contentpass-ui`](./packages/react-native-contentpass-ui) | Pre-built UI components for the Contentpass consent layer. |
11+
| [`@contentpass/react-native-contentpass-cmp-onetrust`](./packages/react-native-contentpass-cmp-onetrust) | OneTrust CMP adapter for the Contentpass SDK. |
1112

12-
or
13+
## Examples
1314

14-
```sh
15-
yarn add @contentpass/react-native-contentpass
16-
```
17-
18-
### Peer Dependencies
19-
The following peer dependencies must also be installed:
20-
- [react](https://github.com/facebook/react) (Required for React Native projects.)
21-
- [react-native](https://github.com/facebook/react-native) (Core React Native framework)
22-
- [react-native-app-auth](https://github.com/FormidableLabs/react-native-app-auth) (Used for OAuth 2.0 authentication)
23-
- [react-native-encrypted-storage](https://github.com/emeraldsanto/react-native-encrypted-storage) (Ensures secure storage of authentication tokens)
24-
25-
Some dependencies require additional setup in the native code. Refer to their official guides:
26-
- [react-native-app-auth setup](https://commerce.nearform.com/open-source/react-native-app-auth/docs#setup)
27-
- [react-native-encrypted-storage setup](https://github.com/emeraldsanto/react-native-encrypted-storage?tab=readme-ov-file#installation)
28-
29-
### Expo support
30-
If you are using Expo, you need to run the following command to enable modifications to the `ios` and `android` directories:
31-
32-
```sh
33-
npx expo prebuild
34-
```
35-
36-
## Usage
37-
38-
### Initialization
39-
Wrap your app's root component with ContentpassSdkProvider. The provider requires a configuration object (contentpassConfig) with the following properties:
40-
- `propertyId` - Your unique property ID (ask Contentpass team for details)
41-
- `planId` - The ID of the plan you want to check the user's subscription status against (ask Contentpass team for details)
42-
- `issuer` - The OAuth 2.0 server URL (e.g. `https://my.contentpass.net`)
43-
- `redirectUrl` - the redirect URL of your app to which the OAuth2 server will redirect after the authentication
44-
- `samplingRate` - Optional: The rate at which the SDK will send impression events for unauthenticated users. Default is 0.05 (5%)
45-
- `logLevel` - Optional: The log level for the SDK. By default logger is disabled. Possible values are 'info', 'warn', 'error' and 'debug'
46-
47-
48-
```jsx
49-
import React from 'react';
50-
import { ContentpassSdkProvider } from '@contentpass/react-native-contentpass';
51-
52-
const contentpassConfig = {
53-
propertyId: 'property-id',
54-
planId: 'plan-id',
55-
issuer: 'https://my.contentpass.net',
56-
redirectUrl: 'com.yourapp://oauthredirect',
57-
samplingRate: 0.1,
58-
logLevel: 'info'
59-
};
60-
61-
const App = () => {
62-
return (
63-
<ContentpassSdkProvider contentpassConfig={contentpassConfig}>
64-
<YourApp />
65-
</ContentpassSdkProvider>
66-
);
67-
};
68-
69-
export default App;
70-
```
71-
72-
### SDK Methods
73-
The SDK exposes the following methods through the `useContentpassSdk` hook:
74-
75-
### authenticate
76-
Initiates the OAuth 2.0 authentication process via a modal interface. It validates the user’s active Contentpass subscriptions
77-
upon successful authentication.
78-
79-
### countImpression
80-
Tracks and increments the impression count for the current user. This method should be invoked whenever a user views a
81-
piece of content. It applies to all users, whether authenticated or unauthenticated.
82-
83-
### registerObserver
84-
Registers a callback function to listen for changes in the user’s authentication and subscription status. The observer function
85-
receives a state object describing the current status (see the exported [ContentpassState](./packages/react-native-contentpass/src/types/ContentpassState.ts) type).
86-
87-
### unregisterObserver
88-
Unregisters a previously registered observer. The observer will no longer receive updates.
89-
90-
### logout
91-
Logs the user out by clearing all stored authentication tokens.
92-
93-
### recoverFromError
94-
During background token refresh, an error state may occur due to poor or no internet connection. This is indicated by the
95-
`state` switching to `ERROR`. The state object includes a reference to the original exception that was thrown. As the SDK
96-
does not monitor the device's connection state, you must notify the SDK when the network connection has been reestablished
97-
or improved. The SDK will then refresh and revalidate the user's authentication tokens.
98-
99-
```jsx
100-
import React, { useEffect } from 'react';
101-
import { useContentpassSdk } from '@contentpass/react-native-contentpass';
102-
import { Button, View } from 'react-native';
103-
104-
const YourApp = () => {
105-
const {
106-
authenticate,
107-
countImpression,
108-
registerObserver,
109-
unregisterObserver,
110-
logout,
111-
recoverFromError
112-
} = useContentpassSdk();
113-
114-
useEffect(() => {
115-
const observer = (state) => {
116-
console.log('Contentpass state changed:', state);
117-
};
118-
119-
registerObserver(observer);
120-
121-
return () => {
122-
unregisterObserver(observer);
123-
};
124-
}, []);
125-
126-
return (
127-
<View>
128-
<Button onPress={authenticate} title={'Authenticate'} />
129-
<Button onPress={countImpression} title={'Count Impression'} />
130-
</View>
131-
);
132-
};
133-
```
134-
135-
## Integration with Sourcepoint SDK
136-
137-
See the [Sourcepoint SDK documentation](packages/react-native-contentpass/docs/SOURCEPOINT_SDK_INTEGRATION.md) for information on integrating the Contentpass SDK with the Sourcepoint SDK.
15+
| Example | Description |
16+
|---------|-------------|
17+
| [`examples/onetrust`](./examples/onetrust) | Integration using OneTrust as the CMP. |
18+
| [`examples/sourcepoint`](./examples/sourcepoint) | Integration using Sourcepoint as the CMP (bare React Native). |
19+
| [`examples/sourcepoint-expo`](./examples/sourcepoint-expo) | Integration using Sourcepoint as the CMP (Expo). |
13820

13921
## Contributing
14022

141-
See the [contributing guide](packages/react-native-contentpass/docs/CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
142-
23+
See the [contributing guide](./packages/react-native-contentpass/docs/CONTRIBUTING.md).
14324

14425
## License
14526

14627
MIT
147-
148-
---
149-
150-
Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# @contentpass/react-native-contentpass-cmp-onetrust
2+
3+
A [OneTrust](https://www.onetrust.com/) CMP adapter for `@contentpass/react-native-contentpass`. Bridges the OneTrust SDK (`react-native-onetrust-cmp`) to the Contentpass `CmpAdapter` interface, so the Contentpass consent layer can manage consent through OneTrust.
4+
5+
## Installation
6+
7+
```bash
8+
npm install @contentpass/react-native-contentpass-cmp-onetrust
9+
# or
10+
yarn add @contentpass/react-native-contentpass-cmp-onetrust
11+
```
12+
13+
### Peer dependencies
14+
15+
- `@contentpass/react-native-contentpass`
16+
- `react-native-onetrust-cmp` — the OneTrust React Native SDK must be installed and configured in your project
17+
18+
## Usage
19+
20+
First, initialize the OneTrust SDK, then create the adapter using `createOnetrustCmpAdapter`:
21+
22+
```tsx
23+
import OTPublishersNativeSDK from 'react-native-onetrust-cmp';
24+
import { createOnetrustCmpAdapter } from '@contentpass/react-native-contentpass-cmp-onetrust';
25+
import type { CmpAdapter } from '@contentpass/react-native-contentpass';
26+
27+
// 1. Start the OneTrust SDK
28+
await OTPublishersNativeSDK.startSDK(
29+
'cdn.cookielaw.org', // CDN location
30+
'YOUR_APP_ID', // OneTrust app ID
31+
'en', // language code
32+
{}, // params
33+
false // auto-show banner
34+
);
35+
36+
// 2. Create the CMP adapter
37+
const cmpAdapter: CmpAdapter = await createOnetrustCmpAdapter(OTPublishersNativeSDK);
38+
```
39+
40+
The returned `cmpAdapter` can then be passed to `ContentpassConsentGate` from `@contentpass/react-native-contentpass-ui`, or used directly via the `CmpAdapter` interface.
41+
42+
### Full example
43+
44+
```tsx
45+
import { useEffect, useState } from 'react';
46+
import { View, Text } from 'react-native';
47+
import OTPublishersNativeSDK from 'react-native-onetrust-cmp';
48+
import { ContentpassSdkProvider } from '@contentpass/react-native-contentpass';
49+
import { ContentpassConsentGate } from '@contentpass/react-native-contentpass-ui';
50+
import { createOnetrustCmpAdapter } from '@contentpass/react-native-contentpass-cmp-onetrust';
51+
import type { CmpAdapter } from '@contentpass/react-native-contentpass';
52+
53+
export default function App() {
54+
const [cmpAdapter, setCmpAdapter] = useState<CmpAdapter | null>(null);
55+
56+
useEffect(() => {
57+
OTPublishersNativeSDK.startSDK('cdn.cookielaw.org', 'YOUR_APP_ID', 'en', {}, false)
58+
.then(() => createOnetrustCmpAdapter(OTPublishersNativeSDK))
59+
.then((adapter) => setCmpAdapter(adapter))
60+
.catch((error) => console.error('Failed to initialize CMP', error));
61+
}, []);
62+
63+
if (!cmpAdapter) {
64+
return <Text>Loading...</Text>;
65+
}
66+
67+
return (
68+
<ContentpassSdkProvider contentpassConfig={contentpassConfig}>
69+
<ContentpassConsentGate
70+
cmpAdapter={cmpAdapter}
71+
contentpassConfig={contentpassConfig}
72+
>
73+
<View>
74+
<Text>Your app content</Text>
75+
</View>
76+
</ContentpassConsentGate>
77+
</ContentpassSdkProvider>
78+
);
79+
}
80+
```
81+
82+
For a complete working example, see the [`examples/onetrust`](../../examples/onetrust) directory.
83+
84+
## API
85+
86+
### `createOnetrustCmpAdapter(sdk)`
87+
88+
Factory function that creates a `CmpAdapter` from an initialized OneTrust SDK instance.
89+
90+
| Parameter | Type | Description |
91+
|-----------|------|-------------|
92+
| `sdk` | `OTPublishersNativeSDK` | An initialized OneTrust SDK instance (after `startSDK` has resolved). |
93+
94+
Returns `Promise<CmpAdapter>`.
95+
96+
The adapter fetches banner and preference center data from the OneTrust SDK during creation, and automatically extracts TCF purpose IDs and the vendor count.
97+
98+
### `CmpAdapter` methods provided
99+
100+
| Method | Description |
101+
|--------|-------------|
102+
| `acceptAll()` | Saves "accept all" consent via OneTrust. |
103+
| `denyAll()` | Saves "reject all" consent via OneTrust. |
104+
| `hasFullConsent()` | Checks whether all consent categories are granted. |
105+
| `onConsentStatusChange(callback)` | Registers a listener that fires whenever full-consent status changes. Returns an unsubscribe function. |
106+
| `showSecondLayer(view)` | Opens the OneTrust preference center (`'purpose'`) or vendor list (`'vendor'`) UI. The returned promise resolves when the user dismisses it. |
107+
| `getRequiredPurposes()` | Returns the list of TCF purpose identifiers extracted from OneTrust. |
108+
| `getNumberOfVendors()` | Returns the vendor count parsed from the OneTrust banner data. |
109+
| `waitForInit()` | Resolves immediately (OneTrust initialization is handled before adapter creation). |
110+
111+
## License
112+
113+
MIT

packages/react-native-contentpass-cmp-onetrust/src/OnetrustCmpAdapter.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@ export async function createOnetrustCmpAdapter(
99
): Promise<OnetrustCmpAdapter> {
1010
try {
1111
const bannerData = await sdk.getBannerData();
12-
console.log('Banner data', bannerData);
1312

1413
const preferenceCenterData: PreferenceCenterData =
1514
await sdk.getPreferenceCenterData();
16-
console.log('Preference center data', preferenceCenterData);
1715

1816
return new OnetrustCmpAdapter(sdk, bannerData, preferenceCenterData);
1917
} catch (error: any) {

packages/react-native-contentpass-ui/README.md

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# @contentpass/react-native-contentpass-ui
22

3-
React Native UI components for Contentpass layer rendering.
3+
Pre-built UI components for integrating the Contentpass consent layer into React Native apps. Renders the Contentpass first-layer consent dialog in a WebView and manages its visibility based on the user's authentication and consent state.
44

55
## Installation
66

@@ -10,18 +10,75 @@ npm install @contentpass/react-native-contentpass-ui
1010
yarn add @contentpass/react-native-contentpass-ui
1111
```
1212

13+
### Peer dependencies
14+
15+
Make sure the following peer dependencies are installed in your project:
16+
17+
- `@contentpass/react-native-contentpass`
18+
- `react`
19+
- `react-native`
20+
- `react-native-webview`
21+
22+
You also need a CMP adapter (e.g. `@contentpass/react-native-contentpass-cmp-onetrust`) that implements the `CmpAdapter` interface.
23+
24+
## Components
25+
26+
### `ContentpassConsentGate`
27+
28+
A gate component that wraps your app content. It automatically shows the Contentpass consent layer when the user has neither authenticated with Contentpass nor given full CMP consent. Once consent is granted or the user authenticates, the layer is dismissed and the children are displayed.
29+
30+
#### Props
31+
32+
| Prop | Type | Required | Default | Description |
33+
|------|------|----------|---------|-------------|
34+
| `children` | `ReactNode` | Yes || The app content to render when consent is given or the user is authenticated. |
35+
| `cmpAdapter` | `CmpAdapter` | Yes || A CMP adapter instance (e.g. from `@contentpass/react-native-contentpass-cmp-onetrust`). |
36+
| `contentpassConfig` | `ContentpassConfig` | Yes || The Contentpass SDK configuration object. |
37+
| `hideAppWhenVisible` | `boolean` | No | `true` | When `true`, the app content is completely replaced by the consent layer. When `false`, the consent layer is rendered as an overlay on top of the app content. |
38+
| `onVisibilityChange` | `(visible: boolean) => void` | No || Callback invoked when the consent layer visibility changes. |
39+
1340
## Usage
1441

42+
Wrap your app with `ContentpassSdkProvider` (from `@contentpass/react-native-contentpass`) and place `ContentpassConsentGate` around the content that should be gated:
43+
1544
```tsx
16-
import { YourComponent } from '@contentpass/react-native-contentpass-ui';
45+
import { ContentpassSdkProvider } from '@contentpass/react-native-contentpass';
46+
import { ContentpassConsentGate } from '@contentpass/react-native-contentpass-ui';
47+
import type { CmpAdapter } from '@contentpass/react-native-contentpass';
48+
49+
function App() {
50+
// Initialize your CMP and create an adapter first
51+
const cmpAdapter: CmpAdapter = /* ... */;
52+
const contentpassConfig = /* your ContentpassConfig */;
1753

18-
// Use the component
54+
return (
55+
<ContentpassSdkProvider contentpassConfig={contentpassConfig}>
56+
<ContentpassConsentGate
57+
cmpAdapter={cmpAdapter}
58+
contentpassConfig={contentpassConfig}
59+
hideAppWhenVisible={false}
60+
>
61+
{/* Your app content */}
62+
</ContentpassConsentGate>
63+
</ContentpassSdkProvider>
64+
);
65+
}
1966
```
2067

68+
For a full working example using OneTrust as the CMP, see the [`examples/onetrust`](../../examples/onetrust) directory.
69+
70+
## How it works
71+
72+
1. `ContentpassConsentGate` waits for both the CMP adapter and the Contentpass SDK to be ready.
73+
2. It evaluates whether the user needs to see the consent layer: the layer is shown when the user is **neither** authenticated with Contentpass **nor** has given full consent via the CMP.
74+
3. The consent layer itself is a hosted web page rendered in a WebView (`ContentpassLayer`). It communicates back to the native app via `postMessage` to trigger actions like "accept all", "show CMP details", or "login/signup with Contentpass".
75+
4. When the user takes an action (e.g. accepts all cookies or logs in), the gate re-evaluates and hides the layer when appropriate.
76+
2177
## Requirements
2278

2379
- React Native >= 0.76.0
24-
- @contentpass/react-native-contentpass (peer dependency)
80+
- `@contentpass/react-native-contentpass` (peer dependency)
81+
- `react-native-webview` (peer dependency)
2582

2683
## License
2784

0 commit comments

Comments
 (0)