diff --git a/.eslintignore b/.eslintignore index 88edb62..42c9181 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,4 @@ node_modules/ lib/ +ios/ +android/ diff --git a/.yarn/patches/@sourcepoint-react-native-cmp-npm-0.3.0-2434c31dc9.patch b/.yarn/patches/@sourcepoint-react-native-cmp-npm-0.3.0-2434c31dc9.patch new file mode 100644 index 0000000..b916e3c --- /dev/null +++ b/.yarn/patches/@sourcepoint-react-native-cmp-npm-0.3.0-2434c31dc9.patch @@ -0,0 +1,78 @@ +diff --git a/android/src/main/java/com/sourcepoint/reactnativecmp/RNSourcepointCmpModule.kt b/android/src/main/java/com/sourcepoint/reactnativecmp/RNSourcepointCmpModule.kt +index deb04fb18dbd8adffcb225801ad35b3154a3c7ad..4d372d921cbae6163179435feb9c821e3c37134b 100644 +--- a/android/src/main/java/com/sourcepoint/reactnativecmp/RNSourcepointCmpModule.kt ++++ b/android/src/main/java/com/sourcepoint/reactnativecmp/RNSourcepointCmpModule.kt +@@ -119,6 +119,7 @@ class RNSourcepointCmpModule internal constructor(context: ReactApplicationConte + override fun onAction(view: View, consentAction: ConsentAction): ConsentAction { + sendEvent(SDKEvent.onAction, createMap().apply { + putString("actionType", RNSourcepointActionType.from(consentAction.actionType).name) ++ putString("customActionId", consentAction.customActionId ?: "") + }) + return consentAction + } +diff --git a/ios/RNSourcepointCmp.swift b/ios/RNSourcepointCmp.swift +index 556b56618c847ad8aeaf9cdc680813cc26b732a9..ba7d707232d72fe5038ec05fb6fdb8e27216e4ee 100644 +--- a/ios/RNSourcepointCmp.swift ++++ b/ios/RNSourcepointCmp.swift +@@ -69,7 +69,10 @@ extension RNSourcepointCmp: SPDelegate { + func onAction(_ action: SPAction, from controller: UIViewController) { + RNSourcepointCmp.shared?.sendEvent( + withName: "onAction", +- body: ["actionType": RNSourcepointActionType(from: action.type).rawValue] ++ body: [ ++ "actionType": RNSourcepointActionType(from: action.type).rawValue, ++ "customActionId": action.customActionId ?? "", ++ ] + ) + } + +diff --git a/lib/typescript/src/index.d.ts b/lib/typescript/src/index.d.ts +index 1602516717becd5ec0a8e5036ad2d821110af96f..67bb9e5153b7489c5ead4dcd056b502b71bc2a7d 100644 +--- a/lib/typescript/src/index.d.ts ++++ b/lib/typescript/src/index.d.ts +@@ -12,6 +12,7 @@ export declare class SPConsentManager implements Spec { + loadUSNatPrivacyManager(pmId: string): void; + onAction(callback: (body: { + actionType: SPActionType; ++ customActionId: string; + }) => void): void; + onSPUIReady(callback: () => void): void; + onSPUIFinished(callback: () => void): void; +diff --git a/lib/typescript/src/types.d.ts b/lib/typescript/src/types.d.ts +index a15f7a06c3e0635168987a44a33009ff42bbd31c..a035a72af14f32adf0ff88f959eb8c517ffaea47 100644 +--- a/lib/typescript/src/types.d.ts ++++ b/lib/typescript/src/types.d.ts +@@ -86,6 +86,7 @@ export interface Spec extends TurboModule { + loadUSNatPrivacyManager(pmId: string): void; + onAction(callback: (body: { + actionType: SPActionType; ++ customActionId: string; + }) => void): void; + onSPUIReady(callback: () => void): void; + onSPUIFinished(callback: () => void): void; +diff --git a/src/index.ts b/src/index.ts +index b3e76b15572c56f1a4e54068b90243d6dd028e18..a03d87fea4a93edb6bf904c99d32b029b840bade 100644 +--- a/src/index.ts ++++ b/src/index.ts +@@ -67,7 +67,7 @@ export class SPConsentManager implements Spec { + RNSourcepointCmp.loadUSNatPrivacyManager(pmId); + } + +- onAction(callback: (body: { actionType: SPActionType }) => void): void { ++ onAction(callback: (body: { actionType: SPActionType, customActionId: string }) => void): void { + this.emitter.removeAllListeners('onAction'); + this.emitter.addListener('onAction', callback); + } +diff --git a/src/types.ts b/src/types.ts +index 26ac3d8162c0534af98e2a20d237856195fe5a10..4257aff5ed128988c7d3fba60545672966162b20 100644 +--- a/src/types.ts ++++ b/src/types.ts +@@ -113,7 +113,7 @@ export interface Spec extends TurboModule { + loadGDPRPrivacyManager(pmId: string): void; + loadUSNatPrivacyManager(pmId: string): void; + +- onAction(callback: (body: { actionType: SPActionType }) => void): void; ++ onAction(callback: (body: { actionType: SPActionType, customActionId: string }) => void): void; + onSPUIReady(callback: () => void): void; + onSPUIFinished(callback: () => void): void; + onFinished(callback: () => void): void; diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 5e24e3a..9fb1566 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -32,7 +32,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 # your application. You should enable this flag either if you want # to write custom TurboModules/Fabric components OR use libraries that # are providing them. -newArchEnabled=true +newArchEnabled=false # Use this property to enable or disable the Hermes JS engine. # If set to false, you will be using JSC instead. diff --git a/example/ios/ContentpassExample/PrivacyInfo.xcprivacy b/example/ios/ContentpassExample/PrivacyInfo.xcprivacy index 41b8317..bad3276 100644 --- a/example/ios/ContentpassExample/PrivacyInfo.xcprivacy +++ b/example/ios/ContentpassExample/PrivacyInfo.xcprivacy @@ -6,18 +6,18 @@ NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPICategoryUserDefaults NSPrivacyAccessedAPITypeReasons - C617.1 + CA92.1 NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPICategoryFileTimestamp NSPrivacyAccessedAPITypeReasons - CA92.1 + C617.1 diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 96de977..a96e1df 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -6,6 +6,8 @@ PODS: - AppAuth/ExternalUserAgent (1.7.5): - AppAuth/Core - boost (1.84.0) + - ConsentViewController (7.6.7): + - Down (~> 0.11.0) - DoubleConversion (1.1.6) - FBLazyVector (0.76.2) - fmt (9.1.0) @@ -1542,6 +1544,28 @@ PODS: - React-perflogger (= 0.76.2) - React-utils (= 0.76.2) - SocketRocket (0.7.1) + - sourcepoint-react-native-cmp (0.3.0): + - ConsentViewController (= 7.6.7) + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.01.01.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - Yoga (0.0.0) DEPENDENCIES: @@ -1612,11 +1636,13 @@ DEPENDENCIES: - React-utils (from `../node_modules/react-native/ReactCommon/react/utils`) - ReactCodegen (from `build/generated/ios`) - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - "sourcepoint-react-native-cmp (from `../node_modules/@sourcepoint/react-native-cmp`)" - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) SPEC REPOS: trunk: - AppAuth + - ConsentViewController - SocketRocket EXTERNAL SOURCES: @@ -1751,12 +1777,15 @@ EXTERNAL SOURCES: :path: build/generated/ios ReactCommon: :path: "../node_modules/react-native/ReactCommon" + sourcepoint-react-native-cmp: + :path: "../node_modules/@sourcepoint/react-native-cmp" Yoga: :path: "../node_modules/react-native/ReactCommon/yoga" SPEC CHECKSUMS: AppAuth: 501c04eda8a8d11f179dbe8637b7a91bb7e5d2fa boost: 1dca942403ed9342f98334bf4c3621f011aa7946 + ConsentViewController: 243f7bfcde4b6ec71a5033486465b7c17448493c DoubleConversion: f16ae600a246532c4020132d54af21d0ddb2a385 FBLazyVector: bc70dcb22ad30ce734a7cce7210791dc737e230f fmt: 10c6e61f4be25dc963c36bd73fc7b1705fe975be @@ -1822,6 +1851,7 @@ SPEC CHECKSUMS: ReactCodegen: 93b271af49774429f34d7fd561197020d86436e2 ReactCommon: 208cb02e3c0bb8a727b3e1a1782202bcfa5d9631 SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 + sourcepoint-react-native-cmp: 895d48d036184268872955c4df25bb3bd44c2266 Yoga: 96872ee462cfc43866ad013c8160d4ff6b85709b PODFILE CHECKSUM: c50a131c6dd5a8e1657bf6b76ff12413d914b88e diff --git a/example/package.json b/example/package.json index e3e135d..ee1095e 100644 --- a/example/package.json +++ b/example/package.json @@ -10,6 +10,7 @@ "build:ios": "react-native build-ios --scheme ContentpassExample --mode Debug --extra-params \"-sdk iphonesimulator CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ GCC_OPTIMIZATION_LEVEL=0 GCC_PRECOMPILE_PREFIX_HEADER=YES ASSETCATALOG_COMPILER_OPTIMIZATION=time DEBUG_INFORMATION_FORMAT=dwarf COMPILER_INDEX_STORE_ENABLE=NO\"" }, "dependencies": { + "@sourcepoint/react-native-cmp": "^0.3.0", "react": "18.3.1", "react-native": "0.76.2", "react-native-app-auth": "^8.0.0", diff --git a/example/src/ContentpassUsage.tsx b/example/src/ContentpassUsage.tsx index e4e971e..5faaaaf 100644 --- a/example/src/ContentpassUsage.tsx +++ b/example/src/ContentpassUsage.tsx @@ -1,23 +1,99 @@ import { useContentpassSdk } from './ContentpassContext'; -import { Button, Text } from 'react-native'; -import { useState } from 'react'; +import { Button, ScrollView, StyleSheet, Text, View } from 'react-native'; +import { useCallback, useEffect, useRef, useState } from 'react'; import type { AuthenticateResult } from 'react-native-contentpass'; +import { + SPConsentManager, + type SPUserData, +} from '@sourcepoint/react-native-cmp'; + +const styles = StyleSheet.create({ + sourcepointDataContainer: { + padding: 10, + height: 400, + flexGrow: 0, + }, + logsView: { + marginTop: 10, + }, +}); + +const sourcePointConfig = { + accountId: 375, + propertyId: 37858, + propertyName: 'mobile.cmpsourcepoint.demo', +}; + +const setupSourcepoint = (hasValidSubscription: boolean) => { + const { accountId, propertyName, propertyId } = sourcePointConfig; + const spConsentManager = new SPConsentManager(); + + spConsentManager.build(accountId, propertyId, propertyName, { + gdpr: { + targetingParams: { + acps: hasValidSubscription ? 'true' : 'false', + }, + }, + }); + + return spConsentManager; +}; export default function ContentpassUsage() { const [authResult, setAuthResult] = useState< AuthenticateResult | undefined >(); const contentpassSdk = useContentpassSdk(); + const spConsentManager = useRef(); + const [sourcepointUserData, setSourcepointUserData] = useState< + SPUserData | undefined + >(); - const authenticate = async () => { + const authenticate = useCallback(async () => { + spConsentManager.current?.dispose(); const result = await contentpassSdk.authenticate(); setAuthResult(result); + }, [contentpassSdk]); + + useEffect(() => { + spConsentManager.current = setupSourcepoint( + authResult?.hasValidSubscription ?? false + ); + + spConsentManager.current?.onFinished(() => { + spConsentManager.current?.getUserData().then(setSourcepointUserData); + }); + + spConsentManager.current?.onAction((action) => { + if (action.customActionId === "cp('login')") { + authenticate(); + } + }); + + spConsentManager.current?.loadMessage(); + + return () => { + spConsentManager.current?.dispose(); + }; + }, [authResult, authenticate]); + + const clearSourcepointData = () => { + spConsentManager.current?.clearLocalData(); + setSourcepointUserData(undefined); + spConsentManager.current?.loadMessage(); }; return ( <> -