@redacto.io/consent-sdk-react 1.0.0 → 1.2.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.
package/README.md CHANGED
@@ -1,49 +1,734 @@
1
1
  # @redacto.io/consent-sdk-react
2
2
 
3
- A React component library for managing consent notices and user preferences in your applications.
3
+ A comprehensive consent management SDK that provides seamless integration with Redacto's Consent Management Platform (CMP) for React and Next.js applications.
4
4
 
5
- ## Installation
5
+ ## Overview
6
+
7
+ The Redacto Consent SDK enables developers to easily integrate consent management functionality into their React applications. It provides a consistent user experience for collecting and managing user consent while maintaining compliance with privacy regulations.
8
+
9
+ ## Architecture
10
+
11
+ The SDK follows a client-server architecture pattern:
12
+
13
+ ```
14
+ ┌─────────────┐ ┌──────────────┐ ┌─────────────────┐
15
+ │ Client │────────▶│ Your Backend │────────▶│ Redacto API │
16
+ │ (React) │◀────────│ Server │◀────────│ (CMP API) │
17
+ └─────────────┘ └──────────────┘ └─────────────────┘
18
+ │ │
19
+ │ │
20
+ ▼ ▼
21
+ ┌─────────────────────────────────────────────┐
22
+ │ @redacto.io/consent-sdk-react │
23
+ │ (RedactoNoticeConsent / │
24
+ │ RedactoNoticeConsentInline) │
25
+ └─────────────────────────────────────────────┘
26
+ ```
27
+
28
+ ### How It Works
29
+
30
+ 1. **Your Backend Server**: Your server acts as a proxy between your React application and Redacto's API. It handles:
31
+
32
+ - Generating access tokens
33
+ - Token refresh operations
34
+
35
+ 2. **React Application**: Your React app uses the SDK components to:
36
+
37
+ - Display consent notices
38
+ - Collect user consent choices
39
+ - Submit consent records to Redacto API
40
+
41
+ 3. **SDK Components**: The SDK components handle:
42
+ - Fetching consent content from Redacto API
43
+ - Rendering consent UI
44
+ - Submitting consent records
45
+ - Managing user interactions
46
+
47
+ ## Supported Platforms
48
+
49
+ | Platform | Description | SDK | Demo App |
50
+ | ------------ | ------------------------------------------------ | --- | -------- |
51
+ | React | React/Next.js applications | ✅ | ✅ |
52
+ | JavaScript | Iframe & PHP applications (No jQuery dependency) | 🚧 | 🚧 |
53
+ | Android | Native Android (Kotlin) | 🚧 | 🚧 |
54
+ | iOS | Native iOS (Swift) | 🚧 | 🚧 |
55
+ | Flutter | Flutter applications | 🚧 | 🚧 |
56
+ | React Native | React Native applications | 🚧 | 🚧 |
57
+
58
+ ## Features
59
+
60
+ - **Consent Notice Display**
61
+
62
+ - Customizable consent notices
63
+ - Multiple display formats (modal popup, inline form)
64
+ - Responsive design
65
+
66
+ - **Consent Collection**
67
+
68
+ - User consent choices (accept, reject, manage preferences)
69
+ - Granular consent management
70
+ - Persistent consent storage
71
+
72
+ - **API Integration**
73
+
74
+ - Seamless communication with Redacto CMP API
75
+ - Automatic error handling and retries
76
+ - Token-based authentication
77
+
78
+ - **Configuration**
79
+
80
+ - Customizable UI settings
81
+ - Language preferences
82
+ - API endpoint configuration
83
+
84
+ - **Localization**
85
+ - Multi-language support
86
+ - RTL language support
87
+ - Customizable translations
88
+
89
+ ## Getting Started
90
+
91
+ ### Installation
6
92
 
7
93
  ```bash
94
+ # For React applications
8
95
  npm install @redacto.io/consent-sdk-react
9
- # or
10
- yarn add @redacto.io/consent-sdk-react
11
- # or
12
- pnpm add @redacto.io/consent-sdk-react
13
96
  ```
14
97
 
15
- ## Usage
98
+ ### Backend Server Setup
99
+
100
+ Before using the SDK components, you need to set up backend server endpoints that generate access tokens by calling Redacto's API. Your server should implement the following endpoints:
101
+
102
+ **Important:** You need to obtain your **CMS-API-Key** from the Redacto Dashboard. This key is required to authenticate your requests to Redacto's API. Store this key securely in your environment variables and never expose it to the frontend.
103
+
104
+ #### Example Backend Implementation
105
+
106
+ ```typescript
107
+ // Express.js example
108
+ import express, { Application, Request, Response } from "express";
109
+ import axios from "axios";
110
+
111
+ const app: Application = express();
112
+ app.use(express.json());
113
+
114
+ // Get CMS-API-Key from environment variables (obtained from Redacto Dashboard)
115
+ const CMS_API_KEY = process.env.CMS_API_KEY;
116
+
117
+ // Endpoint to generate access token
118
+ app.post(
119
+ "/api/consent/token",
120
+ async (req: Request, res: Response): Promise<void> => {
121
+ try {
122
+ const { email } = req.body;
123
+ const { organisation_uuid, workspace_uuid, base_url } = req.query;
124
+
125
+ if (!CMS_API_KEY) {
126
+ return res.status(500).json({ error: "CMS API Key not configured" });
127
+ }
128
+
129
+ // Call Redacto API to generate access token
130
+ const response = await axios.post(
131
+ `${base_url}/public/organisations/${organisation_uuid}/workspaces/${workspace_uuid}/tokens/generate-access-token`,
132
+ {
133
+ email,
134
+ // expires_in_days: 1, // Optional: set token expiration
135
+ },
136
+ {
137
+ headers: {
138
+ "X-CMS-API-Key": CMS_API_KEY,
139
+ },
140
+ }
141
+ );
142
+
143
+ // Return token data to frontend
144
+ res.json({
145
+ token: response.data.detail.token,
146
+ refresh_token: response.data.detail.refresh_token,
147
+ expires_at: response.data.detail.expires_at,
148
+ });
149
+ } catch (error) {
150
+ console.error("Error generating token:", error);
151
+ res.status(500).json({ error: "Failed to generate token" });
152
+ }
153
+ }
154
+ );
155
+
156
+ // Endpoint to refresh access token
157
+ app.post(
158
+ "/api/consent/refresh-token",
159
+ async (req: Request, res: Response): Promise<void> => {
160
+ try {
161
+ const { refresh_token, organisation_uuid, workspace_uuid, base_url } =
162
+ req.body;
163
+
164
+ if (!CMS_API_KEY) {
165
+ return res.status(500).json({ error: "CMS API Key not configured" });
166
+ }
167
+
168
+ // Call Redacto API to refresh access token
169
+ const response = await axios.post(
170
+ `${base_url}/consent/public/organisations/${organisation_uuid}/workspaces/${workspace_uuid}/tokens/refresh-token`,
171
+ { refresh_token: refresh_token },
172
+ {
173
+ headers: {
174
+ "X-CMS-API-Key": CMS_API_KEY,
175
+ },
176
+ }
177
+ );
178
+
179
+ res.json({
180
+ token: response.data.detail.token,
181
+ refresh_token: response.data.detail.refresh_token,
182
+ expires_at: response.data.detail.expires_at,
183
+ });
184
+ } catch (error) {
185
+ console.error("Error refreshing token:", error);
186
+ res.status(500).json({ error: "Failed to refresh token" });
187
+ }
188
+ }
189
+ );
190
+ ```
191
+
192
+ #### Redacto API Endpoints Used
193
+
194
+ Your backend needs to call the following Redacto API endpoints:
195
+
196
+ 1. **Generate Access Token**
197
+
198
+ - **Endpoint**: `POST /public/organisations/{organisation_uuid}/workspaces/{workspace_uuid}/tokens/generate-access-token`
199
+ - **Headers**: `X-CMS-API-Key: {your-cms-api-key}`
200
+ - **Body**: `{ email, expires_in_days? }`
201
+ - **Response**: `{ detail: { token, refresh_token, expires_at } }`
202
+
203
+ 2. **Refresh Access Token**
204
+ - **Endpoint**: `POST /consent/public/organisations/{organisation_uuid}/workspaces/{workspace_uuid}/tokens/refresh-token`
205
+ - **Headers**: `X-CMS-API-Key: {your-cms-api-key}`
206
+ - **Body**: `{ refresh_token }`
207
+ - **Response**: `{ detail: { token, refresh_token, expires_at } }`
208
+
209
+ **Note:** Replace `{your-cms-api-key}` with the CMS-API-Key you obtained from the Redacto Dashboard. Store this key securely in your environment variables.
210
+
211
+ ## Components
212
+
213
+ ### `RedactoNoticeConsent`
214
+
215
+ A modal popup component for consent collection. Displays a full-screen modal with consent options. This component is ideal for initial consent collection flows where you want to show consent before users can proceed.
216
+
217
+ **Key Characteristics:**
218
+
219
+ - Requires tokens upfront (must be provided before rendering)
220
+ - Displays as a modal overlay that blocks UI interaction
221
+ - Best for: Initial consent collection, standalone consent flows
222
+
223
+ **Props:**
224
+
225
+ | Prop | Type | Required | Default | Description |
226
+ | ----------------- | ------------------------ | -------- | ------- | ----------------------------------- |
227
+ | `noticeId` | `string` | Yes | - | UUID of the consent notice |
228
+ | `accessToken` | `string` | Yes | - | Authentication token for API calls |
229
+ | `refreshToken` | `string` | Yes | - | Refresh token for token renewal |
230
+ | `baseUrl` | `string` | No | - | Base URL for the consent API |
231
+ | `blockUI` | `boolean` | No | `true` | Whether to block UI interaction |
232
+ | `language` | `string` | No | `"en"` | Language code |
233
+ | `settings` | `object` | No | - | Custom styling options |
234
+ | `applicationId` | `string` | No | - | Application-specific UUID |
235
+ | `validateAgainst` | `"all" \| "required"` | No | `"all"` | Consent validation mode (see below) |
236
+ | `onAccept` | `() => void` | Yes | - | Callback when consent is accepted |
237
+ | `onDecline` | `() => void` | Yes | - | Callback when consent is declined |
238
+ | `onError` | `(error: Error) => void` | No | - | Error handler callback |
239
+
240
+ **`validateAgainst` Parameter:**
241
+
242
+ The `validateAgainst` prop controls how the backend validates consent status when fetching consent content. It accepts two values:
243
+
244
+ - **`"all"`** (default): Validates all purposes and data elements, regardless of whether they are required or optional. This is the standard mode for initial consent collection and provides comprehensive validation. Responses are cached for better performance.
245
+
246
+ - **`"required"`**: Only validates required purposes and data elements. This mode is useful for reconsent flows or scenarios where you only need to verify that mandatory consent elements are checked. Responses are not cached to ensure fresh validation data.
247
+
248
+ **Why use it:**
249
+
250
+ - Use `"all"` for standard consent flows where you need to validate all consent elements
251
+ - Use `"required"` for reconsent scenarios or when you only need to verify mandatory consent requirements
252
+ - The mode affects API caching behavior: `"all"` responses are cached for performance, while `"required"` responses bypass cache to ensure up-to-date validation
253
+
254
+ ### `RedactoNoticeConsentInline`
255
+
256
+ An inline component for embedding consent directly in forms. The component can load consent content without tokens and automatically submits consent when tokens are provided and all required conditions are met.
257
+
258
+ **Key Characteristics:**
259
+
260
+ - Can load content without tokens (tokens optional initially)
261
+ - Renders inline within your form
262
+ - Auto-submits consent when `accessToken` is provided and all required elements are checked
263
+ - Best for: Registration forms, checkout flows, embedded consent in multi-step processes
264
+
265
+ **Requirements to Display the Component:**
266
+
267
+ To see and display the `RedactoNoticeConsentInline` component, you must provide the following **required props**:
268
+
269
+ - `org_uuid` (string, required): Your organization UUID
270
+ - `workspace_uuid` (string, required): Your workspace UUID
271
+ - `notice_uuid` (string, required): The consent notice UUID
272
+
273
+ **Note:** The component can fetch and display consent content using only these three UUIDs. No `accessToken` is needed to display the component - users can see and interact with the consent form immediately.
274
+
275
+ **Requirements to Submit Consent:**
276
+
277
+ To actually submit/give consent, the component requires **all** of the following conditions to be met:
278
+
279
+ 1. **`accessToken` must be provided**: The authentication token obtained from your backend server (see Backend Server Setup section)
280
+ 2. **Consent content must be loaded**: The component must have successfully fetched the consent notice content
281
+ 3. **All required data elements must be checked**: The user must check all
282
+
283
+ When all these conditions are met, the component **automatically submits** the consent without requiring any additional user action.
284
+
285
+ **Auto-Submit Behavior:**
286
+
287
+ The component automatically submits consent when all of the following conditions are met:
288
+
289
+ - `accessToken` is provided
290
+ - Consent content has been loaded
291
+ - All required data elements are checked
292
+ - The component is not already submitting
293
+
294
+ **Important:** The `hasSubmittedRef` only prevents duplicate submissions with the **same token**. To allow users to re-submit consent, simply update the `accessToken` prop with a new token from your backend, and the component will automatically attempt submission again when all conditions are met.
295
+
296
+ **Props:**
297
+
298
+ | Prop | Type | Required | Default | Description |
299
+ | -------------------- | ---------------------------- | -------- | ------- | -------------------------------------- |
300
+ | `org_uuid` | `string` | Yes | - | Organization UUID |
301
+ | `workspace_uuid` | `string` | Yes | - | Workspace UUID |
302
+ | `notice_uuid` | `string` | Yes | - | Notice UUID |
303
+ | `accessToken` | `string` | No | - | Authentication token |
304
+ | `refreshToken` | `string` | No | - | Refresh token |
305
+ | `baseUrl` | `string` | No | - | Base URL for the consent API |
306
+ | `language` | `string` | No | `"en"` | Language code |
307
+ | `settings` | `object` | No | - | Custom styling options |
308
+ | `applicationId` | `string` | No | - | Application-specific UUID |
309
+ | `onAccept` | `() => void` | No | - | Callback when consent is accepted |
310
+ | `onDecline` | `() => void` | No | - | Callback when consent is declined |
311
+ | `onError` | `(error: Error) => void` | No | - | Error handler callback |
312
+ | `onValidationChange` | `(isValid: boolean) => void` | No | - | Callback when validation state changes |
313
+
314
+ ## Usage Examples
315
+
316
+ ### Example 1: Using `RedactoNoticeConsent` (Modal Popup)
317
+
318
+ This example shows how to use the modal component for initial consent collection. The user fills out a form, and after submission, tokens are fetched from your backend, then the consent modal is displayed.
16
319
 
17
320
  ```tsx
18
321
  import { RedactoNoticeConsent } from "@redacto.io/consent-sdk-react";
322
+ import { useState } from "react";
323
+
324
+ function SignUpPage() {
325
+ const [showConsent, setShowConsent] = useState(false);
326
+ const [tokens, setTokens] = useState({
327
+ accessToken: "",
328
+ refreshToken: "",
329
+ });
330
+ const [formData, setFormData] = useState({ email: "" });
331
+
332
+ const handleFormSubmit = async (e: React.FormEvent) => {
333
+ e.preventDefault();
334
+
335
+ try {
336
+ // Step 1: Get tokens from your backend
337
+ const response = await fetch(
338
+ `${BACKEND_URL}/api/consent/token?workspace_uuid=${WORKSPACE_UUID}&organisation_uuid=${ORG_UUID}&base_url=${BASE_URL}`,
339
+ {
340
+ method: "POST",
341
+ headers: { "Content-Type": "application/json" },
342
+ body: JSON.stringify({
343
+ email: formData.email,
344
+ organisation_uuid: ORG_UUID,
345
+ workspace_uuid: WORKSPACE_UUID,
346
+ base_url: BASE_URL,
347
+ }),
348
+ }
349
+ );
350
+
351
+ const data = await response.json();
352
+ setTokens({
353
+ accessToken: data.token,
354
+ refreshToken: data.refresh_token,
355
+ });
356
+
357
+ // Step 2: Show consent modal
358
+ setShowConsent(true);
359
+ } catch (error) {
360
+ console.error("Failed to get tokens:", error);
361
+ }
362
+ };
363
+
364
+ const handleConsentAccept = () => {
365
+ setShowConsent(false);
366
+ // Proceed with your application flow
367
+ console.log("Consent accepted, proceeding...");
368
+ };
369
+
370
+ const handleConsentDecline = () => {
371
+ setShowConsent(false);
372
+ // Handle decline case
373
+ console.log("Consent declined");
374
+ };
19
375
 
20
- function App() {
21
376
  return (
22
377
  <div>
23
- <RedactoNoticeConsent />
378
+ <form onSubmit={handleFormSubmit}>
379
+ <input
380
+ type="email"
381
+ value={formData.email}
382
+ onChange={(e) => setFormData({ email: e.target.value })}
383
+ placeholder="Enter your email"
384
+ />
385
+ <button type="submit">Sign Up</button>
386
+ </form>
387
+
388
+ {/* Consent Modal */}
389
+ {showConsent && tokens.accessToken && (
390
+ <RedactoNoticeConsent
391
+ noticeId={NOTICE_UUID}
392
+ accessToken={tokens.accessToken}
393
+ refreshToken={tokens.refreshToken}
394
+ baseUrl={BASE_URL}
395
+ blockUI={true}
396
+ validateAgainst="all"
397
+ onAccept={handleConsentAccept}
398
+ onDecline={handleConsentDecline}
399
+ onError={(error) => console.error("Consent error:", error)}
400
+ />
401
+ )}
24
402
  </div>
25
403
  );
26
404
  }
27
405
  ```
28
406
 
29
- ## Features
407
+ ### Example 2: Using `RedactoNoticeConsentInline` (Inline Form)
30
408
 
31
- - React components for consent management
32
- - TypeScript support
33
- - ESM and CommonJS module formats
409
+ This example shows how to use the inline component within a registration form. The component loads consent content immediately, validates user selections, and automatically submits consent when tokens are provided.
34
410
 
35
- ## Requirements
411
+ **Key Points:**
36
412
 
37
- - React 19.1.0 or higher
38
- - React DOM 19.1.0 or higher
413
+ - Component displays immediately with just `org_uuid`, `workspace_uuid`, and `notice_uuid`
414
+ - Users can interact with the consent form without tokens
415
+ - Consent is automatically submitted when `accessToken` is provided and all required elements are checked
416
+
417
+ ```tsx
418
+ import { RedactoNoticeConsentInline } from "@redacto.io/consent-sdk-react";
419
+ import { useState, useCallback } from "react";
420
+
421
+ function RegistrationForm() {
422
+ const [formData, setFormData] = useState({
423
+ email: "",
424
+ mobile: "",
425
+ });
426
+ const [tokens, setTokens] = useState({
427
+ accessToken: undefined as string | undefined,
428
+ refreshToken: undefined as string | undefined,
429
+ });
430
+ const [consentValid, setConsentValid] = useState(false);
431
+ const [isSubmitting, setIsSubmitting] = useState(false);
432
+
433
+ // Track when all required consent elements are checked
434
+ const handleValidationChange = useCallback((isValid: boolean) => {
435
+ setConsentValid(isValid);
436
+ }, []);
437
+
438
+ const handleFormSubmit = async (e: React.FormEvent) => {
439
+ e.preventDefault();
440
+
441
+ // Validate form data
442
+ if (!formData.email && !formData.mobile) {
443
+ alert("Please provide email or mobile number");
444
+ return;
445
+ }
446
+
447
+ if (!consentValid) {
448
+ alert("Please check all required consent elements");
449
+ return;
450
+ }
451
+
452
+ setIsSubmitting(true);
453
+
454
+ try {
455
+ // Step 1: Get tokens from your backend
456
+ const response = await fetch(
457
+ `${BACKEND_URL}/api/consent/token?workspace_uuid=${WORKSPACE_UUID}&organisation_uuid=${ORG_UUID}&base_url=${BASE_URL}`,
458
+ {
459
+ method: "POST",
460
+ headers: { "Content-Type": "application/json" },
461
+ body: JSON.stringify({
462
+ email: formData.email || undefined,
463
+ mobile: formData.mobile || undefined,
464
+ }),
465
+ }
466
+ );
467
+
468
+ const data = await response.json();
469
+
470
+ // Step 2: Set tokens - component will auto-submit consent
471
+ setTokens({
472
+ accessToken: data.token,
473
+ refreshToken: data.refresh_token,
474
+ });
475
+
476
+ // Store user info for consent submission
477
+ if (formData.email) {
478
+ localStorage.setItem("userEmail", formData.email);
479
+ }
480
+ if (formData.mobile) {
481
+ localStorage.setItem("userMobile", formData.mobile);
482
+ }
483
+
484
+ // Component will automatically submit consent when:
485
+ // - accessToken is set
486
+ // - all required elements are checked
487
+ // - content is loaded
488
+ } catch (error) {
489
+ console.error("Failed to complete registration:", error);
490
+ setIsSubmitting(false);
491
+ }
492
+ };
493
+
494
+ const handleConsentAccept = useCallback(() => {
495
+ console.log("Consent accepted and submitted");
496
+ setIsSubmitting(false);
497
+ // Proceed with your registration flow
498
+ }, []);
499
+
500
+ const handleConsentError = useCallback((error: Error) => {
501
+ console.error("Consent error:", error);
502
+
503
+ // Handle 409 CONFLICT (user already consented)
504
+ const errorWithStatus = error as Error & { status?: number; code?: number };
505
+ if (errorWithStatus.status === 409 || errorWithStatus.code === 409) {
506
+ // Treat as success
507
+ handleConsentAccept();
508
+ return;
509
+ }
510
+
511
+ setIsSubmitting(false);
512
+ }, []);
513
+
514
+ return (
515
+ <form onSubmit={handleFormSubmit}>
516
+ <input
517
+ type="email"
518
+ value={formData.email}
519
+ onChange={(e) => setFormData({ ...formData, email: e.target.value })}
520
+ placeholder="Email (optional)"
521
+ />
522
+
523
+ <input
524
+ type="tel"
525
+ value={formData.mobile}
526
+ onChange={(e) => setFormData({ ...formData, mobile: e.target.value })}
527
+ placeholder="Mobile (optional)"
528
+ />
529
+
530
+ {/*
531
+ Inline consent component
532
+
533
+ TO DISPLAY: Only requires org_uuid, workspace_uuid, notice_uuid
534
+ - Component will fetch and display consent content immediately
535
+ - Users can see and interact with consent form without tokens
536
+
537
+ TO SUBMIT CONSENT: Requires all of the following:
538
+ 1. accessToken must be provided (set after form submission)
539
+ 2. Consent content must be loaded (automatic)
540
+ 3. All required data elements must be checked (tracked via onValidationChange)
541
+ 4. Component will auto-submit when all conditions are met
542
+ */}
543
+ <RedactoNoticeConsentInline
544
+ org_uuid={ORG_UUID}
545
+ workspace_uuid={WORKSPACE_UUID}
546
+ notice_uuid={NOTICE_UUID}
547
+ accessToken={tokens.accessToken} // Initially undefined, set after form submit
548
+ refreshToken={tokens.refreshToken}
549
+ baseUrl={BASE_URL}
550
+ onValidationChange={handleValidationChange}
551
+ onAccept={handleConsentAccept}
552
+ onError={handleConsentError}
553
+ />
554
+
555
+ <button type="submit" disabled={isSubmitting || !consentValid}>
556
+ {isSubmitting ? "Processing..." : "Submit Registration"}
557
+ </button>
558
+ </form>
559
+ );
560
+ }
561
+ ```
562
+
563
+ ### Custom Styling
564
+
565
+ Both components support extensive styling customization:
566
+
567
+ ```tsx
568
+ const customSettings = {
569
+ button: {
570
+ accept: {
571
+ backgroundColor: "#9810fa",
572
+ textColor: "white",
573
+ },
574
+ decline: {
575
+ backgroundColor: "#0a0a14",
576
+ textColor: "white",
577
+ },
578
+ language: {
579
+ backgroundColor: "#0a0a14",
580
+ textColor: "white",
581
+ selectedBackgroundColor: "#9810fa",
582
+ selectedTextColor: "white",
583
+ },
584
+ },
585
+ borderRadius: "8px",
586
+ backgroundColor: "#1a1a2e",
587
+ headingColor: "#ffffff",
588
+ textColor: "#e6e6e6",
589
+ borderColor: "white",
590
+ link: "#9810fa",
591
+ font: "Arial, sans-serif", // Optional: custom font family
592
+ };
593
+
594
+ // Use in component
595
+ <RedactoNoticeConsent
596
+ // ... other props
597
+ settings={customSettings}
598
+ />;
599
+ ```
600
+
601
+ ### Available Style Properties
602
+
603
+ - `backgroundColor`: Background color of the modal/form
604
+ - `headingColor`: Color for headings
605
+ - `textColor`: Color for body text
606
+ - `borderColor`: Color for borders
607
+ - `borderRadius`: Border radius for rounded corners
608
+ - `link`: Color for links
609
+ - `font`: Font family (optional)
610
+ - `button.accept`: Styles for accept button
611
+ - `button.decline`: Styles for decline button
612
+ - `button.language`: Styles for language selector
613
+
614
+ ## Component Comparison
615
+
616
+ | Feature | `RedactoNoticeConsent` | `RedactoNoticeConsentInline` |
617
+ | ----------------------- | ----------------------------------------- | ------------------------------------------- |
618
+ | **Display Type** | Modal popup overlay | Inline form component |
619
+ | **Token Requirement** | Required upfront | Optional (can load without) |
620
+ | **Use Case** | Initial consent, standalone flows | Embedded in forms, multi-step processes |
621
+ | **Auto-Submit** | No (user clicks accept/decline) | Yes (when token provided + validated) |
622
+ | **Validation Callback** | No | Yes (`onValidationChange`) |
623
+ | **UI Blocking** | Yes (by default) | No (inline) |
624
+ | **Props Required** | `noticeId`, `accessToken`, `refreshToken` | `org_uuid`, `workspace_uuid`, `notice_uuid` |
625
+
626
+ ## Best Practices
627
+
628
+ 1. **Backend Token Generation**: Always generate tokens on your backend server, never expose API keys or authentication tokens to the frontend
629
+
630
+ 2. **Token Management**: Store tokens securely (consider using httpOnly cookies or secure storage) and handle token expiration/refresh
631
+
632
+ 3. **Error Handling**: Always provide `onError` callbacks to handle API errors gracefully. For inline component, handle 409 CONFLICT errors (already consented) as success cases
633
+
634
+ 4. **Validation Flow**: For inline component, use `onValidationChange` to track when all required elements are checked before allowing form submission
635
+
636
+ 5. **Auto-Submit Pattern**: For inline component, provide `accessToken` after obtaining it from your backend - the component will automatically submit consent when all conditions are met
637
+
638
+ 6. **User Feedback**: Show loading states and error messages to users during token generation and consent submission
639
+
640
+ 7. **Accessibility**: The components include ARIA labels and keyboard navigation - ensure your forms maintain accessibility standards
641
+
642
+ 8. **Re-submission**: Users can view and modify consent they've already given. To allow re-submission, update the `accessToken` prop with a new token from your backend. The component will automatically submit when all conditions are met. The internal ref only prevents duplicate submissions with the same token, not re-submission with a new token.
643
+
644
+ ## Troubleshooting
645
+
646
+ ### Component not rendering
647
+
648
+ - Check that all required props are provided
649
+ - For `RedactoNoticeConsent`: Verify that tokens are valid and not expired
650
+ - For `RedactoNoticeConsentInline`: Verify that `org_uuid`, `workspace_uuid`, and `notice_uuid` are correct
651
+ - Check browser console for error messages
652
+
653
+ ### Consent not submitting
654
+
655
+ - Ensure `accessToken` is provided and valid (not expired)
656
+ - Verify that all required elements are checked (check `onValidationChange` callback for inline component)
657
+ - Ensure consent content has loaded (check for loading state)
658
+ - Verify network requests in browser DevTools
659
+ - For inline component: Check that tokens are set after form validation passes
660
+
661
+ ### Backend token generation failing
662
+
663
+ - Verify authentication setup is correct for your environment
664
+ - Check that API key generation is working
665
+ - Ensure organisation and workspace UUIDs are correct
666
+ - Verify base URL matches your environment (staging vs production)
667
+
668
+ ### Validation not working
669
+
670
+ - Ensure `onValidationChange` callback is provided for inline component
671
+ - Check that required data elements are properly configured in your consent notice
672
+ - Verify that user has checked all required elements
673
+
674
+ ## API Documentation
675
+
676
+ ### Redacto CMP API Endpoints
677
+
678
+ The SDK communicates with Redacto's CMP API. Key endpoints used:
679
+
680
+ - **Get Consent Notice**: `GET /public/organisations/{org_uuid}/workspaces/{workspace_uuid}/notices/{notice_uuid}`
681
+ - **Submit Consent**: `POST /public/organisations/{org_uuid}/workspaces/{workspace_uuid}/submit-consent`
682
+ - **Generate Access Token**: `POST /public/organisations/{org_uuid}/workspaces/{workspace_uuid}/tokens/generate-access-token`
683
+
684
+ For complete API documentation, visit: [Redacto API Documentation](https://staging.api.redacto.io/consent/docs)
39
685
 
40
686
  ## Development
41
687
 
42
- This package is built using:
688
+ ### Prerequisites
689
+
690
+ - Node.js 16+
691
+ - npm or yarn
692
+ - Platform-specific development tools for native SDKs
693
+
694
+ ### Building
695
+
696
+ ```bash
697
+ # Install dependencies
698
+ npm install
699
+
700
+ # Build all packages
701
+ npm run build
702
+
703
+ # Build specific package
704
+ npm run build --workspace=@redacto.io/consent-sdk-react
705
+ ```
706
+
707
+ ### Testing
708
+
709
+ ```bash
710
+ # Run all tests
711
+ npm test
712
+
713
+ # Run tests for specific package
714
+ npm test --workspace=@redacto.io/consent-sdk-react
715
+ ```
716
+
717
+ ## Additional Information
718
+
719
+ ### Requirements
720
+
721
+ - React 19.1.0 or higher
722
+ - React DOM 19.1.0 or higher
723
+
724
+ ### Additional Features
43
725
 
44
- - TypeScript
45
- - tsup for bundling
46
- - React 19.1.0
726
+ - TypeScript support with full type definitions
727
+ - ESM and CommonJS module formats
728
+ - Accessibility features (ARIA labels, keyboard navigation)
729
+ - ✅ Text-to-speech support (English only)
730
+ - ✅ Age verification and guardian consent for minors
731
+ - ✅ Reconsent flow support
47
732
 
48
733
  ## License
49
734