@osano/osano-cmp-react-native 0.13.0 → 0.15.0

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 (145) hide show
  1. package/README.dev.md +237 -12
  2. package/android/build.gradle +1 -1
  3. package/android/src/main/java/com/OsanoCMPSDK/OsanoCMPSDKModule.kt +147 -64
  4. package/android/src/main/java/com/OsanoCMPSDK/OsanoCMPSDKPackage.kt +0 -1
  5. package/ios/OsanoCmpSDK.mm +33 -3
  6. package/ios/OsanoCmpSdk.h +0 -7
  7. package/lib/commonjs/ConsentManager.js +32 -4
  8. package/lib/commonjs/ConsentManager.js.map +1 -1
  9. package/lib/commonjs/components/Button.js +105 -95
  10. package/lib/commonjs/components/Button.js.map +1 -1
  11. package/lib/commonjs/components/Locale.js +5 -3
  12. package/lib/commonjs/components/Locale.js.map +1 -1
  13. package/lib/commonjs/index.js +1 -1
  14. package/lib/commonjs/index.js.map +1 -1
  15. package/lib/commonjs/native/OsanoCmp.js +35 -8
  16. package/lib/commonjs/native/OsanoCmp.js.map +1 -1
  17. package/lib/commonjs/native/OsanoCmpSdkSpec.js +9 -0
  18. package/lib/commonjs/native/OsanoCmpSdkSpec.js.map +1 -0
  19. package/lib/commonjs/services/consent.js +6 -2
  20. package/lib/commonjs/services/consent.js.map +1 -1
  21. package/lib/commonjs/utils/ExpoDetector.js +105 -0
  22. package/lib/commonjs/utils/ExpoDetector.js.map +1 -0
  23. package/lib/commonjs/utils/ExpoGoMemoryStorage.js +61 -0
  24. package/lib/commonjs/utils/ExpoGoMemoryStorage.js.map +1 -0
  25. package/lib/commonjs/views/Dialog/Buttons.js +26 -16
  26. package/lib/commonjs/views/Dialog/Buttons.js.map +1 -1
  27. package/lib/commonjs/views/Dialog/index.js +58 -95
  28. package/lib/commonjs/views/Dialog/index.js.map +1 -1
  29. package/lib/commonjs/views/Drawer/Drawer.ConsentCategories.js +12 -13
  30. package/lib/commonjs/views/Drawer/Drawer.ConsentCategories.js.map +1 -1
  31. package/lib/commonjs/views/Drawer/Drawer.Header.js +2 -2
  32. package/lib/commonjs/views/Drawer/Drawer.Header.js.map +1 -1
  33. package/lib/commonjs/views/Drawer/Drawer.Iab.Disclosures.js +10 -1
  34. package/lib/commonjs/views/Drawer/Drawer.Iab.Disclosures.js.map +1 -1
  35. package/lib/commonjs/views/Drawer/index.js +5 -4
  36. package/lib/commonjs/views/Drawer/index.js.map +1 -1
  37. package/lib/module/ConsentManager.js +32 -4
  38. package/lib/module/ConsentManager.js.map +1 -1
  39. package/lib/module/components/Button.js +99 -88
  40. package/lib/module/components/Button.js.map +1 -1
  41. package/lib/module/components/Locale.js +4 -3
  42. package/lib/module/components/Locale.js.map +1 -1
  43. package/lib/module/index.js +1 -1
  44. package/lib/module/index.js.map +1 -1
  45. package/lib/module/native/OsanoCmp.js +34 -8
  46. package/lib/module/native/OsanoCmp.js.map +1 -1
  47. package/lib/module/native/OsanoCmpSdkSpec.js +3 -0
  48. package/lib/module/native/OsanoCmpSdkSpec.js.map +1 -0
  49. package/lib/module/services/consent.js +7 -3
  50. package/lib/module/services/consent.js.map +1 -1
  51. package/lib/module/utils/ExpoDetector.js +98 -0
  52. package/lib/module/utils/ExpoDetector.js.map +1 -0
  53. package/lib/module/utils/ExpoGoMemoryStorage.js +54 -0
  54. package/lib/module/utils/ExpoGoMemoryStorage.js.map +1 -0
  55. package/lib/module/views/Dialog/Buttons.js +27 -17
  56. package/lib/module/views/Dialog/Buttons.js.map +1 -1
  57. package/lib/module/views/Dialog/index.js +59 -96
  58. package/lib/module/views/Dialog/index.js.map +1 -1
  59. package/lib/module/views/Drawer/Drawer.ConsentCategories.js +10 -12
  60. package/lib/module/views/Drawer/Drawer.ConsentCategories.js.map +1 -1
  61. package/lib/module/views/Drawer/Drawer.Header.js +2 -2
  62. package/lib/module/views/Drawer/Drawer.Header.js.map +1 -1
  63. package/lib/module/views/Drawer/Drawer.Iab.Disclosures.js +10 -1
  64. package/lib/module/views/Drawer/Drawer.Iab.Disclosures.js.map +1 -1
  65. package/lib/module/views/Drawer/index.js +6 -6
  66. package/lib/module/views/Drawer/index.js.map +1 -1
  67. package/lib/typescript/lib/commonjs/ConsentManager.d.ts.map +1 -1
  68. package/lib/typescript/lib/commonjs/components/Button.d.ts +4 -4
  69. package/lib/typescript/lib/commonjs/components/Button.d.ts.map +1 -1
  70. package/lib/typescript/lib/commonjs/components/Locale.d.ts.map +1 -1
  71. package/lib/typescript/lib/commonjs/hooks/useDeviceOrientation.d.ts +1 -1
  72. package/lib/typescript/lib/commonjs/native/OsanoCmp.d.ts.map +1 -1
  73. package/lib/typescript/lib/commonjs/native/OsanoCmpSdkSpec.d.ts +5 -0
  74. package/lib/typescript/lib/commonjs/native/OsanoCmpSdkSpec.d.ts.map +1 -0
  75. package/lib/typescript/lib/commonjs/services/consent.d.ts.map +1 -1
  76. package/lib/typescript/lib/commonjs/utils/ExpoDetector.d.ts +28 -0
  77. package/lib/typescript/lib/commonjs/utils/ExpoDetector.d.ts.map +1 -0
  78. package/lib/typescript/lib/commonjs/utils/ExpoGoMemoryStorage.d.ts +22 -0
  79. package/lib/typescript/lib/commonjs/utils/ExpoGoMemoryStorage.d.ts.map +1 -0
  80. package/lib/typescript/lib/commonjs/views/Dialog/Buttons.d.ts.map +1 -1
  81. package/lib/typescript/lib/commonjs/views/Dialog/index.d.ts.map +1 -1
  82. package/lib/typescript/lib/commonjs/views/Drawer/Drawer.ConsentCategories.d.ts.map +1 -1
  83. package/lib/typescript/lib/commonjs/views/Drawer/Drawer.Iab.Disclosures.d.ts.map +1 -1
  84. package/lib/typescript/lib/commonjs/views/Drawer/index.d.ts.map +1 -1
  85. package/lib/typescript/lib/module/ConsentManager.d.ts.map +1 -1
  86. package/lib/typescript/lib/module/components/Button.d.ts +7 -7
  87. package/lib/typescript/lib/module/components/Button.d.ts.map +1 -1
  88. package/lib/typescript/lib/module/components/Locale.d.ts +4 -1
  89. package/lib/typescript/lib/module/components/Locale.d.ts.map +1 -1
  90. package/lib/typescript/lib/module/hooks/useDeviceOrientation.d.ts +1 -1
  91. package/lib/typescript/lib/module/native/OsanoCmp.d.ts.map +1 -1
  92. package/lib/typescript/lib/module/native/OsanoCmpSdkSpec.d.ts +3 -0
  93. package/lib/typescript/lib/module/native/OsanoCmpSdkSpec.d.ts.map +1 -0
  94. package/lib/typescript/lib/module/services/consent.d.ts.map +1 -1
  95. package/lib/typescript/lib/module/utils/ExpoDetector.d.ts +27 -0
  96. package/lib/typescript/lib/module/utils/ExpoDetector.d.ts.map +1 -0
  97. package/lib/typescript/lib/module/utils/ExpoGoMemoryStorage.d.ts +21 -0
  98. package/lib/typescript/lib/module/utils/ExpoGoMemoryStorage.d.ts.map +1 -0
  99. package/lib/typescript/lib/module/views/Dialog/Buttons.d.ts.map +1 -1
  100. package/lib/typescript/lib/module/views/Dialog/index.d.ts.map +1 -1
  101. package/lib/typescript/lib/module/views/Drawer/Drawer.ConsentCategories.d.ts.map +1 -1
  102. package/lib/typescript/lib/module/views/Drawer/Drawer.Header.d.ts.map +1 -1
  103. package/lib/typescript/lib/module/views/Drawer/Drawer.Iab.Disclosures.d.ts.map +1 -1
  104. package/lib/typescript/lib/module/views/Drawer/index.d.ts.map +1 -1
  105. package/lib/typescript/src/ConsentManager.d.ts.map +1 -1
  106. package/lib/typescript/src/components/Button.d.ts +7 -7
  107. package/lib/typescript/src/components/Button.d.ts.map +1 -1
  108. package/lib/typescript/src/components/Locale.d.ts +2 -1
  109. package/lib/typescript/src/components/Locale.d.ts.map +1 -1
  110. package/lib/typescript/src/native/OsanoCmp.d.ts.map +1 -1
  111. package/lib/typescript/src/native/OsanoCmpSdkSpec.d.ts +17 -0
  112. package/lib/typescript/src/native/OsanoCmpSdkSpec.d.ts.map +1 -0
  113. package/lib/typescript/src/services/consent.d.ts.map +1 -1
  114. package/lib/typescript/src/utils/ExpoDetector.d.ts +29 -0
  115. package/lib/typescript/src/utils/ExpoDetector.d.ts.map +1 -0
  116. package/lib/typescript/src/utils/ExpoGoMemoryStorage.d.ts +21 -0
  117. package/lib/typescript/src/utils/ExpoGoMemoryStorage.d.ts.map +1 -0
  118. package/lib/typescript/src/views/Dialog/Buttons.d.ts +4 -2
  119. package/lib/typescript/src/views/Dialog/Buttons.d.ts.map +1 -1
  120. package/lib/typescript/src/views/Dialog/index.d.ts +1 -1
  121. package/lib/typescript/src/views/Dialog/index.d.ts.map +1 -1
  122. package/lib/typescript/src/views/Drawer/Drawer.ConsentCategories.d.ts.map +1 -1
  123. package/lib/typescript/src/views/Drawer/Drawer.Header.d.ts +1 -1
  124. package/lib/typescript/src/views/Drawer/Drawer.Header.d.ts.map +1 -1
  125. package/lib/typescript/src/views/Drawer/Drawer.Iab.Disclosures.d.ts.map +1 -1
  126. package/lib/typescript/src/views/Drawer/index.d.ts.map +1 -1
  127. package/osano-cmp-sdk.podspec +15 -15
  128. package/package.json +28 -3
  129. package/src/ConsentManager.ts +37 -4
  130. package/src/components/Button.tsx +122 -88
  131. package/src/components/Locale.tsx +28 -28
  132. package/src/constants.ts +2 -2
  133. package/src/index.tsx +1 -1
  134. package/src/native/OsanoCmp.ts +39 -23
  135. package/src/native/OsanoCmpSdkSpec.ts +25 -0
  136. package/src/services/consent.ts +9 -3
  137. package/src/utils/ExpoDetector.ts +114 -0
  138. package/src/utils/ExpoGoMemoryStorage.ts +61 -0
  139. package/src/views/Dialog/Buttons.tsx +33 -23
  140. package/src/views/Dialog/index.tsx +164 -208
  141. package/src/views/Drawer/Drawer.ConsentCategories.tsx +25 -25
  142. package/src/views/Drawer/Drawer.Header.tsx +7 -7
  143. package/src/views/Drawer/Drawer.Iab.Disclosures.tsx +6 -3
  144. package/src/views/Drawer/index.tsx +20 -19
  145. package/android/src/main/AndroidManifestNew.xml +0 -2
@@ -1,4 +1,7 @@
1
1
  import { NativeModules, Platform } from 'react-native';
2
+ import OsanoCmpSdkTurboModule from './OsanoCmpSdkSpec';
3
+ import { ExpoDetector } from '../utils/ExpoDetector';
4
+ import { ExpoGoMemoryStorage } from '../utils/ExpoGoMemoryStorage';
2
5
 
3
6
  const LINKING_ERROR =
4
7
  `The package 'osano-cmp-react-native' doesn't seem to be linked. Make sure: \n\n` +
@@ -6,56 +9,69 @@ const LINKING_ERROR =
6
9
  '- You rebuilt the app after installing the package\n' +
7
10
  '- You are not using Expo Go\n';
8
11
 
9
- const OsanoCmpNativeModule = NativeModules.OsanoCmpSdk;
10
- const OsanoCmp = OsanoCmpNativeModule
11
- ? OsanoCmpNativeModule
12
- : new Proxy(
13
- {},
14
- {
15
- get() {
16
- throw new Error(LINKING_ERROR);
17
- },
18
- },
19
- );
12
+ const OsanoCmp = OsanoCmpSdkTurboModule || NativeModules.OsanoCmpSdk || new Proxy(
13
+ {},
14
+ {
15
+ get(_, prop) {
16
+ throw new Error(`${LINKING_ERROR}\nAttempted to call: ${String(prop)}`);
17
+ },
18
+ },
19
+ );
20
20
 
21
21
  export function getDeviceId(): Promise<string | null | undefined> {
22
+ if (ExpoDetector.isExpoGo()) {
23
+ return ExpoGoMemoryStorage.getDeviceId();
24
+ }
22
25
  return OsanoCmp.getDeviceId();
23
26
  }
24
27
  export function setStorage(key: string, value: string): Promise<string> {
28
+ if (ExpoDetector.isExpoGo()) {
29
+ return ExpoGoMemoryStorage.setStorage(key, value);
30
+ }
25
31
  return OsanoCmp.setStorage(key, value);
26
32
  }
27
33
  export function getStorage(key: string): Promise<string | null | undefined> {
34
+ if (ExpoDetector.isExpoGo()) {
35
+ return ExpoGoMemoryStorage.getStorage(key);
36
+ }
28
37
  return OsanoCmp.getStorage(key);
29
38
  }
30
39
  export function clearStorage(key: string): Promise<void> {
40
+ if (ExpoDetector.isExpoGo()) {
41
+ return ExpoGoMemoryStorage.clearStorage(key);
42
+ }
31
43
  return OsanoCmp.clearStorage(key);
32
44
  }
33
45
  export function setStorageToDefault(
34
46
  key: string,
35
47
  value: string,
36
48
  ): Promise<string> {
37
- return OsanoCmp.setStorageToDefault
38
- ? OsanoCmp.setStorageToDefault(key, value)
39
- : Promise.resolve(value);
49
+ if (ExpoDetector.isExpoGo()) {
50
+ return ExpoGoMemoryStorage.setStorageToDefault(key, value);
51
+ }
52
+ return OsanoCmp.setStorageToDefault?.(key, value) ?? Promise.resolve(value);
40
53
  }
41
54
  export function setIntStorageToDefault(
42
55
  key: string,
43
56
  value: number,
44
57
  ): Promise<number> {
45
- return OsanoCmp.setIntStorageToDefault
46
- ? OsanoCmp.setIntStorageToDefault(key, value)
47
- : Promise.resolve(value);
58
+ if (ExpoDetector.isExpoGo()) {
59
+ return ExpoGoMemoryStorage.setIntStorageToDefault(key, value);
60
+ }
61
+ return OsanoCmp.setIntStorageToDefault?.(key, value) ?? Promise.resolve(value);
48
62
  }
49
63
  export function setBoolStorageToDefault(
50
64
  key: string,
51
65
  value: boolean,
52
66
  ): Promise<boolean> {
53
- return OsanoCmp.setBoolStorageToDefault
54
- ? OsanoCmp.setBoolStorageToDefault(key, value)
55
- : Promise.resolve(value);
67
+ if (ExpoDetector.isExpoGo()) {
68
+ return ExpoGoMemoryStorage.setBoolStorageToDefault(key, value);
69
+ }
70
+ return OsanoCmp.setBoolStorageToDefault?.(key, value) ?? Promise.resolve(value);
56
71
  }
57
72
  export function clearStorageFromDefault(key: string): Promise<void> {
58
- return OsanoCmp.clearStorageFromDefault
59
- ? OsanoCmp.clearStorageFromDefault(key)
60
- : Promise.resolve();
73
+ if (ExpoDetector.isExpoGo()) {
74
+ return ExpoGoMemoryStorage.clearStorageFromDefault(key);
75
+ }
76
+ return OsanoCmp.clearStorageFromDefault?.(key) ?? Promise.resolve();
61
77
  }
@@ -0,0 +1,25 @@
1
+ import type { TurboModule } from 'react-native';
2
+ import { TurboModuleRegistry } from 'react-native';
3
+
4
+ export interface Spec extends TurboModule {
5
+ // Core storage methods
6
+ setStorage(key: string, value: string): Promise<string>;
7
+ getStorage(key: string): Promise<string | null>;
8
+ clearStorage(key: string): Promise<void>;
9
+
10
+ // Default storage methods (iOS specific functionality)
11
+ setStorageToDefault(key: string, value: string): Promise<string>;
12
+ setIntStorageToDefault(key: string, value: number): Promise<number>;
13
+ setBoolStorageToDefault(key: string, value: boolean): Promise<boolean>;
14
+ clearStorageFromDefault(key: string): Promise<void>;
15
+
16
+ // Device identification
17
+ getDeviceId(): Promise<string>;
18
+
19
+ // Constants only (no synchronous methods for TurboModule compatibility)
20
+ getConstants(): {
21
+ IS_OFFICIAL_SAMPLE: boolean;
22
+ };
23
+ }
24
+
25
+ export default TurboModuleRegistry.get<Spec>('OsanoCmpSdk');
@@ -1,5 +1,5 @@
1
1
  import { sha512 } from 'js-sha512';
2
- import { Platform } from 'react-native';
2
+ import { Platform, NativeModules } from 'react-native';
3
3
  import { TextEncoder } from 'text-encoding';
4
4
  import type { ConsentManager } from '../ConsentManager';
5
5
  import {
@@ -17,6 +17,10 @@ const Buffer = require('buffer').Buffer;
17
17
 
18
18
  const { CONSENT_URI, LOOKUPS_URI, OSANO_ORIGIN } = env;
19
19
 
20
+ const IS_OFFICIAL_SAMPLE: boolean = (NativeModules as any)?.OsanoCmpSdk?.IS_OFFICIAL_SAMPLE;
21
+
22
+ const CONSENTING_PLATFORM_TAG = IS_OFFICIAL_SAMPLE ? `${Platform.OS}.sample-react-native` : `${Platform.OS}.react-native`;
23
+
20
24
  const overrideConfig: Partial<Config> = {
21
25
  // Override config here
22
26
  variant: 'two',
@@ -52,13 +56,14 @@ function createConsentPayload(
52
56
  cmp: ConsentManager,
53
57
  consent?: ConsentCategoryType[],
54
58
  ): ConsentPayload {
59
+ osanoLogger.debug(`Consenting Platform: ${CONSENTING_PLATFORM_TAG}`);
55
60
  return Object.fromEntries(
56
61
  Object.entries({
57
62
  customerId: cmp.customerId,
58
63
  configId: cmp.configId,
59
64
  consented: consent ?? cmp.consent,
60
65
  consentingDomain: cmp.consentingDomain,
61
- consentingPlatform: `${Platform.OS}.react-native`,
66
+ consentingPlatform: CONSENTING_PLATFORM_TAG,
62
67
  deviceId: cmp.deviceId,
63
68
  extUsrData: cmp.extUsrData,
64
69
  }).filter(([, value]) => value !== undefined),
@@ -81,7 +86,7 @@ function createConsentRecordPayload(
81
86
  osnoConfigId: cmp.configId,
82
87
  consented: consentedCategories.join(','),
83
88
  consentingDomain: cmp.consentingDomain,
84
- consentingPlatform: `${Platform.OS}.react-native`,
89
+ consentingPlatform: CONSENTING_PLATFORM_TAG,
85
90
  userConsentId: cmp.deviceId,
86
91
  extUsrData: hashedExtUsrData,
87
92
  }).filter(([, value]) => value !== undefined),
@@ -134,6 +139,7 @@ export const clearConsent = async (cmp: ConsentManager) => {
134
139
  clearStorage(`${STORAGE_KEY}_${cmp.configId}`).then(resConsent);
135
140
  break;
136
141
  default:
142
+ resConsent();
137
143
  break;
138
144
  }
139
145
  });
@@ -0,0 +1,114 @@
1
+ import { Platform } from 'react-native';
2
+ import { osanoLogger as OsanoLogger } from './OsanoLogger';
3
+
4
+ interface ExpoDetectionResult {
5
+ isExpo: boolean;
6
+ isExpoGo: boolean;
7
+ }
8
+
9
+ export class ExpoDetector {
10
+ private static _detectionResult: ExpoDetectionResult | null = null;
11
+
12
+ /**
13
+ * Detect Expo environment and cache result
14
+ */
15
+ public static detect(): ExpoDetectionResult {
16
+ // Return cached result if available
17
+ if (this._detectionResult) {
18
+ return this._detectionResult;
19
+ }
20
+
21
+ const result: ExpoDetectionResult = {
22
+ isExpo: false,
23
+ isExpoGo: false,
24
+ };
25
+
26
+ // Check for Expo runtime via globals
27
+ try {
28
+ const hasExpoGlobalProp = !!(global as any).expo;
29
+
30
+ if (hasExpoGlobalProp) {
31
+ result.isExpo = true;
32
+
33
+ // Analyze global.expo to distinguish Expo Go from dev builds
34
+ const globalExpoContent = (global as any).expo;
35
+
36
+ if (globalExpoContent && typeof globalExpoContent === 'object') {
37
+ const documentsDir = globalExpoContent.documentsDir || '';
38
+ const cacheDir = globalExpoContent.cacheDir || '';
39
+
40
+ // Check execution environment
41
+ const exponentConstants = globalExpoContent.modules?.ExponentConstants;
42
+ const executionEnvironment = exponentConstants?.executionEnvironment;
43
+
44
+ // Check for Expo Go app ID
45
+ const expoApplication = globalExpoContent.modules?.ExpoApplication;
46
+ const applicationId = expoApplication?.applicationId;
47
+
48
+ // Expo Go indicators: package name, execution env, app ID
49
+ const hasExpoGoPackageName = documentsDir.includes('host.exp.exponent') ||
50
+ cacheDir.includes('host.exp.exponent');
51
+ const isStoreClient = executionEnvironment === 'storeClient';
52
+ const hasExpoGoAppId = applicationId === 'host.exp.exponent';
53
+
54
+ if (hasExpoGoPackageName || isStoreClient || hasExpoGoAppId) {
55
+ result.isExpoGo = true;
56
+ } else {
57
+ result.isExpoGo = false;
58
+ }
59
+ } else {
60
+ // Assume dev build for safety
61
+ result.isExpoGo = false;
62
+ }
63
+ }
64
+ } catch (error) {
65
+ OsanoLogger.debug(`Expo detection failed: ${String(error)}`);
66
+ }
67
+
68
+ // Cache the result
69
+ this._detectionResult = result;
70
+
71
+ return result;
72
+ }
73
+
74
+ /**
75
+ * Check if running in Expo Go
76
+ */
77
+ public static isExpoGo(): boolean {
78
+ const result = this.detect();
79
+ return result.isExpoGo;
80
+ }
81
+
82
+ /**
83
+ * Check if any Expo environment
84
+ */
85
+ public static isExpo(): boolean {
86
+ const result = this.detect();
87
+ return result.isExpo;
88
+ }
89
+
90
+ /**
91
+ * Get environment description
92
+ */
93
+ public static getEnvironmentDescription(): string {
94
+ const result = this.detect();
95
+
96
+ if (!result.isExpo) {
97
+ return 'Bare React Native';
98
+ }
99
+
100
+ if (result.isExpoGo) {
101
+ return 'Expo Go';
102
+ }
103
+
104
+ return 'Expo Development Build';
105
+ }
106
+
107
+ /**
108
+ * Reset cached result for testing
109
+ */
110
+ public static resetCache(): void {
111
+ this._detectionResult = null;
112
+ }
113
+ }
114
+
@@ -0,0 +1,61 @@
1
+ /**
2
+ * In-memory storage fallback for Expo Go environment
3
+ * Provides storage functionality when native modules are not available
4
+ */
5
+ export class ExpoGoMemoryStorage {
6
+ private static storage = new Map<string, string>();
7
+ private static defaultStorage = new Map<string, string | number | boolean>();
8
+
9
+ static setStorage(key: string, value: string): Promise<string> {
10
+ this.storage.set(key, value);
11
+ return Promise.resolve(value);
12
+ }
13
+
14
+ static getStorage(key: string): Promise<string | null> {
15
+ const value = this.storage.get(key) || null;
16
+ return Promise.resolve(value);
17
+ }
18
+
19
+ static clearStorage(key: string): Promise<void> {
20
+ this.storage.delete(key);
21
+ return Promise.resolve();
22
+ }
23
+
24
+ static setStorageToDefault(key: string, value: string): Promise<string> {
25
+ this.defaultStorage.set(key, value);
26
+ return Promise.resolve(value);
27
+ }
28
+
29
+ static setIntStorageToDefault(key: string, value: number): Promise<number> {
30
+ this.defaultStorage.set(key, value);
31
+ return Promise.resolve(value);
32
+ }
33
+
34
+ static setBoolStorageToDefault(key: string, value: boolean): Promise<boolean> {
35
+ this.defaultStorage.set(key, value);
36
+ return Promise.resolve(value);
37
+ }
38
+
39
+ static clearStorageFromDefault(key: string): Promise<void> {
40
+ this.defaultStorage.delete(key);
41
+ return Promise.resolve();
42
+ }
43
+
44
+ static getDeviceId(): Promise<string> {
45
+ // Generate a consistent device ID for Expo Go session
46
+ let deviceId = this.storage.get('__expo_device_id');
47
+ if (!deviceId) {
48
+ deviceId = `expo_go_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
49
+ this.storage.set('__expo_device_id', deviceId);
50
+ }
51
+ return Promise.resolve(deviceId);
52
+ }
53
+
54
+ /**
55
+ * Clear all storage for testing purposes
56
+ */
57
+ static clearAll(): void {
58
+ this.storage.clear();
59
+ this.defaultStorage.clear();
60
+ }
61
+ }
@@ -1,3 +1,5 @@
1
+ import React, { useContext, useMemo } from 'react';
2
+ import { StyleSheet, View, type ViewProps, type ViewStyle } from 'react-native';
1
3
  import {
2
4
  AcceptAllButton,
3
5
  AcceptButton,
@@ -6,24 +8,27 @@ import {
6
8
  RejectAllButton,
7
9
  SaveButton,
8
10
  } from '../../components/Button';
9
- import React, { useContext } from 'react';
10
- import { StyleSheet, View, type ViewProps } from 'react-native';
11
-
12
11
  import { OsanoPrivateContext } from '../../context';
13
12
  import { isDialogOpen } from '../../selectors';
14
13
 
15
- export const Buttons: React.FC<ViewProps> = (props) => {
14
+ export const Buttons: React.FC<ViewProps & { buttonStyle?: ViewStyle }> = (
15
+ props,
16
+ ) => {
16
17
  const { style } = props;
17
18
  const { config, getState } = useContext(OsanoPrivateContext);
18
19
 
19
20
  const state = getState();
20
21
  const disabled = !isDialogOpen(state);
22
+ const buttonStyle = useMemo(
23
+ () => [styles.button, props.buttonStyle],
24
+ [props.buttonStyle],
25
+ );
21
26
 
22
27
  // Button Group 1
23
28
  if (config?.isConsentImplied) {
24
29
  return config.forceManagePreferencesButton ? (
25
- <View style={style}>
26
- <ManagePreferencesButton disabled={disabled} style={styles.fullWidth} />
30
+ <View style={[styles.container, style]}>
31
+ <ManagePreferencesButton disabled={disabled} style={buttonStyle} />
27
32
  </View>
28
33
  ) : null;
29
34
  }
@@ -31,41 +36,46 @@ export const Buttons: React.FC<ViewProps> = (props) => {
31
36
  // Button Group 2
32
37
  if (config?.tcfIsApplicable || config?.isButtonGroupTwo) {
33
38
  return (
34
- <View style={style}>
39
+ <View style={[styles.container, style]}>
35
40
  {config.showManagePreferencesButtonInDialog ? (
36
- <ManagePreferencesButton
37
- disabled={disabled}
38
- style={styles.fullWidth}
39
- />
41
+ <ManagePreferencesButton disabled={disabled} style={buttonStyle} />
40
42
  ) : (
41
- <SaveButton disabled={disabled} style={styles.fullWidth} />
43
+ <SaveButton disabled={disabled} style={buttonStyle} />
42
44
  )}
43
- <AcceptAllButton disabled={disabled} style={styles.fullWidth} />
45
+ <AcceptAllButton disabled={disabled} style={buttonStyle} />
44
46
  {config.rejectAllRequired ? (
45
- <RejectAllButton disabled={disabled} style={styles.fullWidth} />
47
+ <RejectAllButton disabled={disabled} style={buttonStyle} />
46
48
  ) : null}
47
49
  </View>
48
50
  );
49
51
  }
50
52
 
53
+ // Default button group
51
54
  return (
52
- <View style={style}>
53
- <AcceptButton disabled={disabled} style={styles.fullWidth} />
54
- <DenyButton disabled={disabled} style={styles.fullWidth} />
55
+ <View style={[styles.container, style]}>
56
+ <AcceptButton disabled={disabled} style={buttonStyle} />
57
+ <DenyButton disabled={disabled} style={buttonStyle} />
55
58
  {config?.rejectAllRequired ? (
56
- <RejectAllButton disabled={disabled} style={styles.fullWidth} />
59
+ <RejectAllButton disabled={disabled} style={buttonStyle} />
57
60
  ) : null}
58
61
  {config?.forceManagePreferencesButton ? (
59
- <ManagePreferencesButton disabled={disabled} style={styles.fullWidth} />
62
+ <ManagePreferencesButton disabled={disabled} style={buttonStyle} />
60
63
  ) : null}
61
64
  </View>
62
65
  );
63
66
  };
64
67
 
65
- export default Buttons;
66
-
67
68
  const styles = StyleSheet.create({
68
- fullWidth: {
69
- flexBasis: '100%',
69
+ container: {
70
+ justifyContent: 'center',
71
+ alignItems: 'center',
72
+ gap: 8,
73
+ },
74
+ button: {
75
+ flex: 1,
76
+ minWidth: 120,
77
+ maxWidth: 200,
70
78
  },
71
79
  });
80
+
81
+ export default Buttons;