c15t 0.0.1-rc.3
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/.turbo/turbo-build.log +54 -0
- package/.turbo/turbo-fmt.log +6 -0
- package/.turbo/turbo-lint.log +288 -0
- package/.turbo/turbo-test.log +33 -0
- package/CHANGELOG.md +20 -0
- package/LICENSE.md +595 -0
- package/README.md +28 -0
- package/dist/index.cjs +118 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/libs/__tests__/tracking-blocker.test.cjs +269 -0
- package/dist/libs/__tests__/tracking-blocker.test.d.ts +2 -0
- package/dist/libs/__tests__/tracking-blocker.test.d.ts.map +1 -0
- package/dist/libs/__tests__/tracking-blocker.test.js +267 -0
- package/dist/libs/consent-utils.cjs +68 -0
- package/dist/libs/consent-utils.d.ts +49 -0
- package/dist/libs/consent-utils.d.ts.map +1 -0
- package/dist/libs/consent-utils.js +23 -0
- package/dist/libs/tracking-blocker.cjs +167 -0
- package/dist/libs/tracking-blocker.d.ts +33 -0
- package/dist/libs/tracking-blocker.d.ts.map +1 -0
- package/dist/libs/tracking-blocker.js +108 -0
- package/dist/libs/tracking-domains.cjs +188 -0
- package/dist/libs/tracking-domains.d.ts +7 -0
- package/dist/libs/tracking-domains.d.ts.map +1 -0
- package/dist/libs/tracking-domains.js +146 -0
- package/dist/store.cjs +248 -0
- package/dist/store.d.ts +58 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.initial-state.cjs +105 -0
- package/dist/store.initial-state.d.ts +43 -0
- package/dist/store.initial-state.d.ts.map +1 -0
- package/dist/store.initial-state.js +66 -0
- package/dist/store.js +219 -0
- package/dist/store.type.cjs +22 -0
- package/dist/store.type.d.ts +159 -0
- package/dist/store.type.d.ts.map +1 -0
- package/dist/store.type.js +0 -0
- package/dist/translations/en.cjs +96 -0
- package/dist/translations/en.d.ts +3 -0
- package/dist/translations/en.d.ts.map +1 -0
- package/dist/translations/en.js +54 -0
- package/dist/translations/index.cjs +51 -0
- package/dist/translations/index.d.ts +3 -0
- package/dist/translations/index.d.ts.map +1 -0
- package/dist/translations/index.js +9 -0
- package/dist/types/callbacks.cjs +22 -0
- package/dist/types/callbacks.d.ts +146 -0
- package/dist/types/callbacks.d.ts.map +1 -0
- package/dist/types/callbacks.js +0 -0
- package/dist/types/compliance.cjs +22 -0
- package/dist/types/compliance.d.ts +196 -0
- package/dist/types/compliance.d.ts.map +1 -0
- package/dist/types/compliance.js +0 -0
- package/dist/types/gdpr.cjs +86 -0
- package/dist/types/gdpr.d.ts +168 -0
- package/dist/types/gdpr.d.ts.map +1 -0
- package/dist/types/gdpr.js +44 -0
- package/dist/types/index.cjs +44 -0
- package/dist/types/index.d.ts +141 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +4 -0
- package/dist/types/translations.cjs +22 -0
- package/dist/types/translations.d.ts +52 -0
- package/dist/types/translations.d.ts.map +1 -0
- package/dist/types/translations.js +0 -0
- package/package.json +33 -0
- package/rslib.config.ts +28 -0
- package/src/index.ts +31 -0
- package/src/libs/__tests__/tracking-blocker.test.ts +271 -0
- package/src/libs/consent-utils.ts +70 -0
- package/src/libs/tracking-blocker.ts +202 -0
- package/src/libs/tracking-domains.ts +158 -0
- package/src/store.initial-state.ts +123 -0
- package/src/store.ts +450 -0
- package/src/store.type.ts +187 -0
- package/src/translations/en.ts +55 -0
- package/src/translations/index.ts +10 -0
- package/src/types/callbacks.ts +152 -0
- package/src/types/compliance.ts +205 -0
- package/src/types/gdpr.ts +217 -0
- package/src/types/index.ts +148 -0
- package/src/types/translations.ts +60 -0
- package/tsconfig.json +12 -0
- package/vitest.config.ts +15 -0
package/src/store.ts
ADDED
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* Implements the core consent management store using Zustand.
|
|
4
|
+
* This module provides the main store creation and management functionality.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createStore } from 'zustand/vanilla';
|
|
8
|
+
import {
|
|
9
|
+
getEffectiveConsents,
|
|
10
|
+
hasConsentFor,
|
|
11
|
+
hasConsented,
|
|
12
|
+
} from './libs/consent-utils';
|
|
13
|
+
import { createTrackingBlocker } from './libs/tracking-blocker';
|
|
14
|
+
import type { TrackingBlockerConfig } from './libs/tracking-blocker';
|
|
15
|
+
import { initialState } from './store.initial-state';
|
|
16
|
+
import type { PrivacyConsentState } from './store.type';
|
|
17
|
+
import {
|
|
18
|
+
type ConsentState,
|
|
19
|
+
type TranslationConfig,
|
|
20
|
+
consentTypes,
|
|
21
|
+
} from './types';
|
|
22
|
+
|
|
23
|
+
/** Storage key for persisting consent data in localStorage */
|
|
24
|
+
const STORAGE_KEY = 'privacy-consent-storage';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Structure of consent data stored in localStorage.
|
|
28
|
+
*
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
interface StoredConsent {
|
|
32
|
+
/** Current consent states */
|
|
33
|
+
consents: ConsentState;
|
|
34
|
+
|
|
35
|
+
/** Metadata about when and how consent was given */
|
|
36
|
+
consentInfo: {
|
|
37
|
+
time: number;
|
|
38
|
+
type: string;
|
|
39
|
+
} | null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Retrieves stored consent data from localStorage.
|
|
44
|
+
*
|
|
45
|
+
* @remarks
|
|
46
|
+
* This function handles:
|
|
47
|
+
* - Checking for browser environment
|
|
48
|
+
* - Parsing stored JSON data
|
|
49
|
+
* - Error handling for invalid data
|
|
50
|
+
*
|
|
51
|
+
* @returns The stored consent data or null if not available
|
|
52
|
+
* @internal
|
|
53
|
+
*/
|
|
54
|
+
const getStoredConsent = (): StoredConsent | null => {
|
|
55
|
+
if (typeof window === 'undefined') return null;
|
|
56
|
+
|
|
57
|
+
const stored = localStorage.getItem(STORAGE_KEY);
|
|
58
|
+
if (!stored) return null;
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
return JSON.parse(stored);
|
|
62
|
+
} catch (e) {
|
|
63
|
+
console.error('Failed to parse stored consent:', e);
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
interface StoreConfig {
|
|
69
|
+
trackingBlockerConfig?: TrackingBlockerConfig;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Creates a new consent manager store instance.
|
|
74
|
+
*
|
|
75
|
+
* @remarks
|
|
76
|
+
* This function initializes a new consent management store with:
|
|
77
|
+
* - Persistence through localStorage
|
|
78
|
+
* - Initial state handling
|
|
79
|
+
* - Consent management methods
|
|
80
|
+
* - Privacy settings
|
|
81
|
+
* - Compliance configuration
|
|
82
|
+
*
|
|
83
|
+
* The store is typically used through React hooks but can also be
|
|
84
|
+
* accessed directly for non-React applications.
|
|
85
|
+
*
|
|
86
|
+
* @param namespace - Optional namespace for the store instance
|
|
87
|
+
* @returns A Zustand store instance with consent management functionality
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* Basic usage:
|
|
91
|
+
* ```typescript
|
|
92
|
+
* const store = createConsentManagerStore();
|
|
93
|
+
*
|
|
94
|
+
* // Subscribe to state changes
|
|
95
|
+
* const unsubscribe = store.subscribe(
|
|
96
|
+
* state => console.log('Consent updated:', state.consents)
|
|
97
|
+
* );
|
|
98
|
+
*
|
|
99
|
+
* // Update consent
|
|
100
|
+
* store.getState().setConsent('analytics', true);
|
|
101
|
+
* ```
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* Custom namespace:
|
|
105
|
+
* ```typescript
|
|
106
|
+
* const store = createConsentManagerStore('MyApp');
|
|
107
|
+
*
|
|
108
|
+
* // Access from window
|
|
109
|
+
* const state = window.MyApp.getState();
|
|
110
|
+
* ```
|
|
111
|
+
*
|
|
112
|
+
* @public
|
|
113
|
+
*/
|
|
114
|
+
export const createConsentManagerStore = (
|
|
115
|
+
namespace: string | undefined = 'c15tStore',
|
|
116
|
+
config?: StoreConfig
|
|
117
|
+
) => {
|
|
118
|
+
// Load initial state from localStorage if available
|
|
119
|
+
const storedConsent = getStoredConsent();
|
|
120
|
+
|
|
121
|
+
// Initialize tracking blocker
|
|
122
|
+
const trackingBlocker =
|
|
123
|
+
typeof window !== 'undefined'
|
|
124
|
+
? createTrackingBlocker(
|
|
125
|
+
config?.trackingBlockerConfig || {},
|
|
126
|
+
storedConsent?.consents || initialState.consents
|
|
127
|
+
)
|
|
128
|
+
: null;
|
|
129
|
+
|
|
130
|
+
const store = createStore<PrivacyConsentState>((set, get) => ({
|
|
131
|
+
...initialState,
|
|
132
|
+
...(storedConsent
|
|
133
|
+
? {
|
|
134
|
+
consents: storedConsent.consents,
|
|
135
|
+
consentInfo: storedConsent.consentInfo as {
|
|
136
|
+
time: number;
|
|
137
|
+
type: 'necessary' | 'all' | 'custom';
|
|
138
|
+
} | null,
|
|
139
|
+
showPopup: false, // Don't show popup if we have stored consent
|
|
140
|
+
}
|
|
141
|
+
: {
|
|
142
|
+
showPopup: true, // Show popup if no stored consent
|
|
143
|
+
}),
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Updates the consent state for a specific consent type and persists the change.
|
|
147
|
+
*
|
|
148
|
+
* @param name - The consent type to update
|
|
149
|
+
* @param value - The new consent value
|
|
150
|
+
*
|
|
151
|
+
* @remarks
|
|
152
|
+
* This function:
|
|
153
|
+
* 1. Updates the consent state
|
|
154
|
+
* 2. Persists changes to localStorage
|
|
155
|
+
* 3. Triggers consent mode update
|
|
156
|
+
*/
|
|
157
|
+
setConsent: (name, value) => {
|
|
158
|
+
set((state) => {
|
|
159
|
+
const consentType = state.consentTypes.find(
|
|
160
|
+
(type) => type.name === name
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// Don't allow changes to disabled consent types
|
|
164
|
+
if (consentType?.disabled) {
|
|
165
|
+
return state;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const newConsents = { ...state.consents, [name]: value };
|
|
169
|
+
|
|
170
|
+
// Update tracking blocker with new consents
|
|
171
|
+
trackingBlocker?.updateConsents(newConsents);
|
|
172
|
+
|
|
173
|
+
return { consents: newConsents };
|
|
174
|
+
});
|
|
175
|
+
get().updateConsentMode();
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Controls the visibility of the consent popup.
|
|
180
|
+
*
|
|
181
|
+
* @param show - Whether to show the popup
|
|
182
|
+
* @param force - Whether to force showing the popup regardless of consent state
|
|
183
|
+
*
|
|
184
|
+
* @remarks
|
|
185
|
+
* The popup will only be shown if:
|
|
186
|
+
* - Forcing is enabled, or
|
|
187
|
+
* - No stored consent exists and no current consent is given
|
|
188
|
+
*/
|
|
189
|
+
setShowPopup: (show, force = false) => {
|
|
190
|
+
const state = get();
|
|
191
|
+
const storedConsent = getStoredConsent();
|
|
192
|
+
if (force || (!storedConsent && !state.consentInfo && show)) {
|
|
193
|
+
set({ showPopup: show });
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Controls the visibility of the privacy dialog.
|
|
199
|
+
*
|
|
200
|
+
* @param isOpen - Whether the dialog should be open
|
|
201
|
+
*/
|
|
202
|
+
setIsPrivacyDialogOpen: (isOpen) => {
|
|
203
|
+
set({ isPrivacyDialogOpen: isOpen });
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Saves user consent preferences and triggers related callbacks.
|
|
208
|
+
*
|
|
209
|
+
* @param type - The type of consent being saved
|
|
210
|
+
*
|
|
211
|
+
* @remarks
|
|
212
|
+
* This function:
|
|
213
|
+
* 1. Updates consent states based on type
|
|
214
|
+
* 2. Records consent timestamp
|
|
215
|
+
* 3. Persists to localStorage
|
|
216
|
+
* 4. Updates UI state
|
|
217
|
+
* 5. Triggers callbacks
|
|
218
|
+
*/
|
|
219
|
+
saveConsents: (type) => {
|
|
220
|
+
const {
|
|
221
|
+
callbacks,
|
|
222
|
+
updateConsentMode,
|
|
223
|
+
consents,
|
|
224
|
+
consentTypes,
|
|
225
|
+
includeNonDisplayedConsents,
|
|
226
|
+
} = get();
|
|
227
|
+
const newConsents = { ...consents };
|
|
228
|
+
if (type === 'all') {
|
|
229
|
+
for (const consent of consentTypes) {
|
|
230
|
+
newConsents[consent.name] = true;
|
|
231
|
+
}
|
|
232
|
+
} else if (type === 'necessary') {
|
|
233
|
+
for (const consent of consentTypes) {
|
|
234
|
+
newConsents[consent.name] = consent.name === 'necessary';
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const consentInfo = {
|
|
239
|
+
time: Date.now(),
|
|
240
|
+
type: type as 'necessary' | 'all' | 'custom',
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
localStorage.setItem(
|
|
244
|
+
STORAGE_KEY,
|
|
245
|
+
JSON.stringify({
|
|
246
|
+
consents: newConsents,
|
|
247
|
+
consentInfo,
|
|
248
|
+
})
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
// Update tracking blocker with new consents
|
|
252
|
+
trackingBlocker?.updateConsents(newConsents);
|
|
253
|
+
|
|
254
|
+
set({
|
|
255
|
+
consents: newConsents,
|
|
256
|
+
showPopup: false,
|
|
257
|
+
consentInfo,
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
updateConsentMode();
|
|
261
|
+
callbacks.onConsentGiven?.();
|
|
262
|
+
callbacks.onPreferenceExpressed?.();
|
|
263
|
+
},
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Resets all consent preferences to their default values.
|
|
267
|
+
*
|
|
268
|
+
* @remarks
|
|
269
|
+
* This function:
|
|
270
|
+
* 1. Resets all consents to their type-specific defaults
|
|
271
|
+
* 2. Clears consent information
|
|
272
|
+
* 3. Removes stored consent from localStorage
|
|
273
|
+
*/
|
|
274
|
+
resetConsents: () => {
|
|
275
|
+
set((state) => {
|
|
276
|
+
const resetState = {
|
|
277
|
+
consents: consentTypes.reduce((acc, consent) => {
|
|
278
|
+
acc[consent.name] = consent.defaultValue;
|
|
279
|
+
return acc;
|
|
280
|
+
}, {} as ConsentState),
|
|
281
|
+
consentInfo: null,
|
|
282
|
+
};
|
|
283
|
+
localStorage.removeItem(STORAGE_KEY);
|
|
284
|
+
return resetState;
|
|
285
|
+
});
|
|
286
|
+
},
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Updates the active GDPR consent types.
|
|
290
|
+
*
|
|
291
|
+
* @param types - Array of consent types to activate
|
|
292
|
+
*/
|
|
293
|
+
setGdprTypes: (types) => set({ gdprTypes: types }),
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Updates compliance settings for a specific region.
|
|
297
|
+
*
|
|
298
|
+
* @param region - The region to update
|
|
299
|
+
* @param settings - New compliance settings
|
|
300
|
+
*
|
|
301
|
+
* @remarks
|
|
302
|
+
* Merges new settings with existing ones for the specified region
|
|
303
|
+
*/
|
|
304
|
+
setComplianceSetting: (region, settings) =>
|
|
305
|
+
set((state) => ({
|
|
306
|
+
complianceSettings: {
|
|
307
|
+
...state.complianceSettings,
|
|
308
|
+
[region]: { ...state.complianceSettings[region], ...settings },
|
|
309
|
+
},
|
|
310
|
+
})),
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Resets compliance settings to their default values.
|
|
314
|
+
*/
|
|
315
|
+
resetComplianceSettings: () =>
|
|
316
|
+
set({
|
|
317
|
+
complianceSettings: initialState.complianceSettings,
|
|
318
|
+
}),
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Sets a callback for a specific consent event.
|
|
322
|
+
*
|
|
323
|
+
* @param name - The callback event name
|
|
324
|
+
* @param callback - The callback function
|
|
325
|
+
*/
|
|
326
|
+
setCallback: (name, callback) =>
|
|
327
|
+
set((state) => ({
|
|
328
|
+
callbacks: { ...state.callbacks, [name]: callback },
|
|
329
|
+
})),
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Updates the user's detected country.
|
|
333
|
+
*
|
|
334
|
+
* @param country - The country code
|
|
335
|
+
*/
|
|
336
|
+
setDetectedCountry: (country) => set({ detectedCountry: country }),
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Retrieves the list of consent types that should be displayed.
|
|
340
|
+
*
|
|
341
|
+
* @returns Array of consent types that match the active GDPR types
|
|
342
|
+
*/
|
|
343
|
+
getDisplayedConsents: () => {
|
|
344
|
+
const { gdprTypes, consentTypes } = get();
|
|
345
|
+
return consentTypes.filter((consent) => gdprTypes.includes(consent.name));
|
|
346
|
+
},
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Checks if the user has provided any form of consent.
|
|
350
|
+
*
|
|
351
|
+
* @returns True if any consent has been given
|
|
352
|
+
*/
|
|
353
|
+
hasConsented: () => {
|
|
354
|
+
const { consentInfo } = get();
|
|
355
|
+
return hasConsented(consentInfo);
|
|
356
|
+
},
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Clears all consent data and resets to initial state.
|
|
360
|
+
*
|
|
361
|
+
* @remarks
|
|
362
|
+
* This function:
|
|
363
|
+
* 1. Resets state to initial values
|
|
364
|
+
* 2. Removes stored consent from localStorage
|
|
365
|
+
*/
|
|
366
|
+
clearAllData: () => {
|
|
367
|
+
set(initialState);
|
|
368
|
+
localStorage.removeItem(STORAGE_KEY);
|
|
369
|
+
},
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Updates the consent mode in external systems.
|
|
373
|
+
*
|
|
374
|
+
* @remarks
|
|
375
|
+
* Currently commented out, but designed to update Google Tag Manager
|
|
376
|
+
* consent states based on user preferences.
|
|
377
|
+
*/
|
|
378
|
+
updateConsentMode: () => {
|
|
379
|
+
const effectiveConsents = get().getEffectiveConsents();
|
|
380
|
+
// if (typeof window !== 'undefined' && window.gtag) {
|
|
381
|
+
// window.gtag('consent', 'update', {
|
|
382
|
+
// 'ad_storage': effectiveConsents.marketing ? 'granted' : 'denied',
|
|
383
|
+
// 'analytics_storage': effectiveConsents.measurement ? 'granted' : 'denied',
|
|
384
|
+
// 'ad_user_data': effectiveConsents.ad_user_data ? 'granted' : 'denied',
|
|
385
|
+
// 'ad_personalization': effectiveConsents.ad_personalization ? 'granted' : 'denied',
|
|
386
|
+
// });
|
|
387
|
+
// }
|
|
388
|
+
},
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Updates privacy-related settings.
|
|
392
|
+
*
|
|
393
|
+
* @param settings - New privacy settings
|
|
394
|
+
*/
|
|
395
|
+
setPrivacySettings: (settings) =>
|
|
396
|
+
set((state) => ({
|
|
397
|
+
privacySettings: { ...state.privacySettings, ...settings },
|
|
398
|
+
})),
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Gets the effective consent states after applying privacy settings.
|
|
402
|
+
*
|
|
403
|
+
* @returns The effective consent states considering Do Not Track
|
|
404
|
+
*/
|
|
405
|
+
getEffectiveConsents: () => {
|
|
406
|
+
const { consents, privacySettings } = get();
|
|
407
|
+
return getEffectiveConsents(consents, privacySettings.honorDoNotTrack);
|
|
408
|
+
},
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Checks if consent has been given for a specific type.
|
|
412
|
+
*
|
|
413
|
+
* @param consentType - The consent type to check
|
|
414
|
+
* @returns True if consent is granted for the specified type
|
|
415
|
+
*/
|
|
416
|
+
hasConsentFor: (consentType) => {
|
|
417
|
+
const { consents, privacySettings } = get();
|
|
418
|
+
return hasConsentFor(
|
|
419
|
+
consentType,
|
|
420
|
+
consents,
|
|
421
|
+
privacySettings.honorDoNotTrack
|
|
422
|
+
);
|
|
423
|
+
},
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Controls whether non-displayed consents should be included.
|
|
427
|
+
*
|
|
428
|
+
* @param include - Whether to include non-displayed consents
|
|
429
|
+
*/
|
|
430
|
+
setIncludeNonDisplayedConsents: (include) =>
|
|
431
|
+
set({ includeNonDisplayedConsents: include }),
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Updates the translation configuration.
|
|
435
|
+
* @param config - The new translation configuration
|
|
436
|
+
*/
|
|
437
|
+
setTranslationConfig: (config: TranslationConfig) => {
|
|
438
|
+
set({ translationConfig: config });
|
|
439
|
+
},
|
|
440
|
+
}));
|
|
441
|
+
|
|
442
|
+
if (typeof window !== 'undefined') {
|
|
443
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
444
|
+
(window as any)[namespace] = store;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
return store;
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
export default createConsentManagerStore;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* Defines the core types and interfaces for the consent management store.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
AllConsentNames,
|
|
8
|
+
CallbackFunction,
|
|
9
|
+
Callbacks,
|
|
10
|
+
ComplianceRegion,
|
|
11
|
+
ComplianceSettings,
|
|
12
|
+
ConsentState,
|
|
13
|
+
ConsentType,
|
|
14
|
+
PrivacySettings,
|
|
15
|
+
TranslationConfig,
|
|
16
|
+
consentTypes,
|
|
17
|
+
} from './types';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Core state and methods interface for the privacy consent management store.
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* This interface defines the complete API surface of the consent manager, including:
|
|
24
|
+
* - State properties for tracking consent status
|
|
25
|
+
* - Methods for managing consent preferences
|
|
26
|
+
* - Compliance and privacy settings
|
|
27
|
+
* - Callback management
|
|
28
|
+
* - UI state control
|
|
29
|
+
*
|
|
30
|
+
* The store is typically created using {@link createConsentManagerStore} and
|
|
31
|
+
* accessed through React hooks or direct store subscription.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* Basic store usage:
|
|
35
|
+
* ```typescript
|
|
36
|
+
* const store = createConsentManagerStore();
|
|
37
|
+
*
|
|
38
|
+
* // Check consent status
|
|
39
|
+
* if (store.getState().hasConsentFor('analytics')) {
|
|
40
|
+
* initializeAnalytics();
|
|
41
|
+
* }
|
|
42
|
+
*
|
|
43
|
+
* // Update consent preferences
|
|
44
|
+
* store.getState().saveConsents('all');
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @public
|
|
48
|
+
*/
|
|
49
|
+
export interface PrivacyConsentState {
|
|
50
|
+
/** Current consent states for all consent types */
|
|
51
|
+
consents: ConsentState;
|
|
52
|
+
|
|
53
|
+
/** Information about when and how consent was given */
|
|
54
|
+
consentInfo: { time: number; type: 'all' | 'custom' | 'necessary' } | null;
|
|
55
|
+
|
|
56
|
+
/** Whether to show the consent popup */
|
|
57
|
+
showPopup: boolean;
|
|
58
|
+
|
|
59
|
+
/** Active GDPR consent types */
|
|
60
|
+
gdprTypes: AllConsentNames[];
|
|
61
|
+
|
|
62
|
+
/** Whether the privacy dialog is currently open */
|
|
63
|
+
isPrivacyDialogOpen: boolean;
|
|
64
|
+
|
|
65
|
+
/** Region-specific compliance settings */
|
|
66
|
+
complianceSettings: Record<ComplianceRegion, ComplianceSettings>;
|
|
67
|
+
|
|
68
|
+
/** Event callbacks for consent actions */
|
|
69
|
+
callbacks: Callbacks;
|
|
70
|
+
|
|
71
|
+
/** User's detected country code */
|
|
72
|
+
detectedCountry: string;
|
|
73
|
+
|
|
74
|
+
/** Privacy-related settings */
|
|
75
|
+
privacySettings: PrivacySettings;
|
|
76
|
+
|
|
77
|
+
/** Translation configuration */
|
|
78
|
+
translationConfig: TranslationConfig;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Updates the translation configuration.
|
|
82
|
+
* @param config - The new translation configuration
|
|
83
|
+
*/
|
|
84
|
+
setTranslationConfig: (config: TranslationConfig) => void;
|
|
85
|
+
|
|
86
|
+
/** Whether to include non-displayed consents in operations */
|
|
87
|
+
includeNonDisplayedConsents: boolean;
|
|
88
|
+
|
|
89
|
+
/** Available consent type configurations */
|
|
90
|
+
consentTypes: ConsentType[];
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Updates the consent state for a specific consent type.
|
|
94
|
+
* @param name - The consent type to update
|
|
95
|
+
* @param value - The new consent value
|
|
96
|
+
*/
|
|
97
|
+
setConsent: (name: AllConsentNames, value: boolean) => void;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Controls the visibility of the consent popup.
|
|
101
|
+
* @param show - Whether to show the popup
|
|
102
|
+
*/
|
|
103
|
+
setShowPopup: (show: boolean) => void;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Controls the visibility of the privacy dialog.
|
|
107
|
+
* @param isOpen - Whether the dialog should be open
|
|
108
|
+
*/
|
|
109
|
+
setIsPrivacyDialogOpen: (isOpen: boolean) => void;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Saves the user's consent preferences.
|
|
113
|
+
* @param type - The type of consent being saved
|
|
114
|
+
*/
|
|
115
|
+
saveConsents: (type: 'all' | 'custom' | 'necessary') => void;
|
|
116
|
+
|
|
117
|
+
/** Resets all consent preferences to their default values */
|
|
118
|
+
resetConsents: () => void;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Updates the active GDPR consent types.
|
|
122
|
+
* @param types - Array of consent types to activate
|
|
123
|
+
*/
|
|
124
|
+
setGdprTypes: (types: AllConsentNames[]) => void;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Updates compliance settings for a specific region.
|
|
128
|
+
* @param region - The region to update
|
|
129
|
+
* @param settings - New compliance settings
|
|
130
|
+
*/
|
|
131
|
+
setComplianceSetting: (
|
|
132
|
+
region: ComplianceRegion,
|
|
133
|
+
settings: Partial<ComplianceSettings>
|
|
134
|
+
) => void;
|
|
135
|
+
|
|
136
|
+
/** Resets compliance settings to their default values */
|
|
137
|
+
resetComplianceSettings: () => void;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Sets a callback for a specific consent event.
|
|
141
|
+
* @param name - The callback event name
|
|
142
|
+
* @param callback - The callback function
|
|
143
|
+
*/
|
|
144
|
+
setCallback: (
|
|
145
|
+
name: keyof Callbacks,
|
|
146
|
+
callback: CallbackFunction | undefined
|
|
147
|
+
) => void;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Updates the user's detected country.
|
|
151
|
+
* @param country - The country code
|
|
152
|
+
*/
|
|
153
|
+
setDetectedCountry: (country: string) => void;
|
|
154
|
+
|
|
155
|
+
/** Retrieves the list of consent types that should be displayed */
|
|
156
|
+
getDisplayedConsents: () => typeof consentTypes;
|
|
157
|
+
|
|
158
|
+
/** Checks if the user has provided any form of consent */
|
|
159
|
+
hasConsented: () => boolean;
|
|
160
|
+
|
|
161
|
+
/** Clears all consent data and resets to initial state */
|
|
162
|
+
clearAllData: () => void;
|
|
163
|
+
|
|
164
|
+
/** Updates the consent mode in external systems (e.g., analytics) */
|
|
165
|
+
updateConsentMode: () => void;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Updates privacy-related settings.
|
|
169
|
+
* @param settings - New privacy settings
|
|
170
|
+
*/
|
|
171
|
+
setPrivacySettings: (settings: Partial<PrivacySettings>) => void;
|
|
172
|
+
|
|
173
|
+
/** Gets the effective consent states after applying privacy settings */
|
|
174
|
+
getEffectiveConsents: () => ConsentState;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Checks if consent has been given for a specific type.
|
|
178
|
+
* @param consentType - The consent type to check
|
|
179
|
+
*/
|
|
180
|
+
hasConsentFor: (consentType: AllConsentNames) => boolean;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Controls whether non-displayed consents should be included.
|
|
184
|
+
* @param include - Whether to include non-displayed consents
|
|
185
|
+
*/
|
|
186
|
+
setIncludeNonDisplayedConsents: (include: boolean) => void;
|
|
187
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { CompleteTranslations } from '../types/translations';
|
|
2
|
+
|
|
3
|
+
export const enTranslations: CompleteTranslations = {
|
|
4
|
+
cookieBanner: {
|
|
5
|
+
title: 'We value your privacy',
|
|
6
|
+
description:
|
|
7
|
+
'This site uses cookies to improve your browsing experience, analyze site traffic, and show personalized content.',
|
|
8
|
+
acceptAll: 'Accept All',
|
|
9
|
+
rejectAll: 'Reject All',
|
|
10
|
+
customize: 'Customize',
|
|
11
|
+
},
|
|
12
|
+
consentManagerDialog: {
|
|
13
|
+
title: 'Privacy Settings',
|
|
14
|
+
description:
|
|
15
|
+
'Customize your privacy settings here. You can choose which types of cookies and tracking technologies you allow.',
|
|
16
|
+
save: 'Save Settings',
|
|
17
|
+
acceptAll: 'Accept All',
|
|
18
|
+
rejectAll: 'Reject All',
|
|
19
|
+
close: 'Close',
|
|
20
|
+
},
|
|
21
|
+
consentManagerWidget: {
|
|
22
|
+
title: 'Privacy Preferences',
|
|
23
|
+
description: 'Manage your privacy settings',
|
|
24
|
+
save: 'Save Settings',
|
|
25
|
+
acceptAll: 'Accept All',
|
|
26
|
+
rejectAll: 'Reject All',
|
|
27
|
+
},
|
|
28
|
+
consentTypes: {
|
|
29
|
+
necessary: {
|
|
30
|
+
title: 'Strictly Necessary',
|
|
31
|
+
description:
|
|
32
|
+
'These cookies are essential for the website to function properly and cannot be disabled.',
|
|
33
|
+
},
|
|
34
|
+
functionality: {
|
|
35
|
+
title: 'Functionality',
|
|
36
|
+
description:
|
|
37
|
+
'These cookies enable enhanced functionality and personalization of the website.',
|
|
38
|
+
},
|
|
39
|
+
marketing: {
|
|
40
|
+
title: 'Marketing',
|
|
41
|
+
description:
|
|
42
|
+
'These cookies are used to deliver relevant advertisements and track their effectiveness.',
|
|
43
|
+
},
|
|
44
|
+
measurement: {
|
|
45
|
+
title: 'Analytics',
|
|
46
|
+
description:
|
|
47
|
+
'These cookies help us understand how visitors interact with the website and improve its performance.',
|
|
48
|
+
},
|
|
49
|
+
experience: {
|
|
50
|
+
title: 'Experience',
|
|
51
|
+
description:
|
|
52
|
+
'These cookies help us provide a better user experience and test new features.',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TranslationConfig } from '../types/translations';
|
|
2
|
+
import { enTranslations } from './en';
|
|
3
|
+
|
|
4
|
+
export const defaultTranslationConfig: TranslationConfig = {
|
|
5
|
+
translations: {
|
|
6
|
+
en: enTranslations,
|
|
7
|
+
},
|
|
8
|
+
defaultLanguage: 'en',
|
|
9
|
+
disableAutoLanguageSwitch: false,
|
|
10
|
+
};
|