react-lgpd-consent 0.2.0 → 0.2.2

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.
@@ -8,10 +8,208 @@ import FormControlLabel from "@mui/material/FormControlLabel";
8
8
  import FormGroup from "@mui/material/FormGroup";
9
9
  import Switch from "@mui/material/Switch";
10
10
  import Typography2 from "@mui/material/Typography";
11
- import { useEffect as useEffect2, useState as useState2 } from "react";
11
+ import { useEffect as useEffect4, useState as useState2 } from "react";
12
12
 
13
- // src/context/ConsentContext.tsx
13
+ // src/context/CategoriesContext.tsx
14
14
  import * as React2 from "react";
15
+
16
+ // src/utils/developerGuidance.ts
17
+ import * as React from "react";
18
+ var DEFAULT_PROJECT_CATEGORIES = {
19
+ enabledCategories: ["analytics"],
20
+ // Só analytics além de necessary
21
+ customCategories: []
22
+ };
23
+ function analyzeDeveloperConfiguration(config) {
24
+ const guidance = {
25
+ warnings: [],
26
+ suggestions: [],
27
+ activeCategoriesInfo: [],
28
+ usingDefaults: !config
29
+ };
30
+ const finalConfig = config || DEFAULT_PROJECT_CATEGORIES;
31
+ if (!config) {
32
+ guidance.warnings.push(
33
+ 'LGPD-CONSENT: Nenhuma configura\xE7\xE3o de categorias especificada. Usando padr\xE3o: necessary + analytics. Para produ\xE7\xE3o, recomenda-se especificar explicitamente as categorias via prop "categories".'
34
+ );
35
+ }
36
+ guidance.activeCategoriesInfo.push({
37
+ id: "necessary",
38
+ name: "Cookies Necess\xE1rios",
39
+ description: "Essenciais para funcionamento b\xE1sico do site",
40
+ essential: true,
41
+ uiRequired: false
42
+ // Não precisa de toggle (sempre ativo)
43
+ });
44
+ const enabledCategories = finalConfig.enabledCategories || [];
45
+ const categoryNames = {
46
+ analytics: {
47
+ name: "Cookies Anal\xEDticos",
48
+ description: "Medem uso e performance do site"
49
+ },
50
+ functional: {
51
+ name: "Cookies Funcionais",
52
+ description: "Melhoram experi\xEAncia e funcionalidades"
53
+ },
54
+ marketing: {
55
+ name: "Cookies de Marketing",
56
+ description: "Publicidade direcionada e campanhas"
57
+ },
58
+ social: {
59
+ name: "Cookies de Redes Sociais",
60
+ description: "Integra\xE7\xE3o com plataformas sociais"
61
+ },
62
+ personalization: {
63
+ name: "Cookies de Personaliza\xE7\xE3o",
64
+ description: "Adaptam conte\xFAdo \xE0s prefer\xEAncias do usu\xE1rio"
65
+ }
66
+ };
67
+ enabledCategories.forEach((categoryId) => {
68
+ const categoryInfo = categoryNames[categoryId];
69
+ if (categoryInfo) {
70
+ guidance.activeCategoriesInfo.push({
71
+ id: categoryId,
72
+ name: categoryInfo.name,
73
+ description: categoryInfo.description,
74
+ essential: false,
75
+ uiRequired: true
76
+ // Precisa de toggle na UI
77
+ });
78
+ }
79
+ });
80
+ const customCategories = finalConfig.customCategories || [];
81
+ customCategories.forEach((category) => {
82
+ guidance.activeCategoriesInfo.push({
83
+ id: category.id,
84
+ name: category.name,
85
+ description: category.description,
86
+ essential: category.essential === true,
87
+ uiRequired: category.essential !== true
88
+ // Apenas não-essenciais precisam toggle
89
+ });
90
+ });
91
+ const totalToggleable = guidance.activeCategoriesInfo.filter(
92
+ (c) => c.uiRequired
93
+ ).length;
94
+ if (totalToggleable === 0) {
95
+ guidance.suggestions.push(
96
+ 'Apenas cookies necess\xE1rios est\xE3o configurados. Para compliance completo LGPD, considere adicionar categorias como "analytics" ou "functional" conforme uso real.'
97
+ );
98
+ }
99
+ if (totalToggleable > 5) {
100
+ guidance.warnings.push(
101
+ `${totalToggleable} categorias opcionais detectadas. UI com muitas op\xE7\xF5es pode ' +
102
+ 'prejudicar experi\xEAncia do usu\xE1rio. Considere agrupar categorias similares.`
103
+ );
104
+ }
105
+ const poorDescriptions = customCategories.filter(
106
+ (c) => !c.description || c.description.length < 10
107
+ );
108
+ if (poorDescriptions.length > 0) {
109
+ guidance.warnings.push(
110
+ `Categorias customizadas com descri\xE7\xF5es inadequadas: ${poorDescriptions.map((c) => c.id).join(", ")}. Descri\xE7\xF5es claras s\xE3o obrigat\xF3rias para compliance LGPD.`
111
+ );
112
+ }
113
+ return guidance;
114
+ }
115
+ function logDeveloperGuidance(guidance) {
116
+ const isProduction = typeof globalThis !== "undefined" && globalThis.__LGPD_PRODUCTION__ || typeof window !== "undefined" && !window.__LGPD_DEV__;
117
+ if (isProduction) return;
118
+ if (guidance.warnings.length > 0) {
119
+ console.group("\u{1F7E8} LGPD-CONSENT: Avisos de Configura\xE7\xE3o");
120
+ guidance.warnings.forEach((warning) => console.warn(warning));
121
+ console.groupEnd();
122
+ }
123
+ if (guidance.suggestions.length > 0) {
124
+ console.group("\u{1F4A1} LGPD-CONSENT: Sugest\xF5es");
125
+ guidance.suggestions.forEach((suggestion) => console.info(suggestion));
126
+ console.groupEnd();
127
+ }
128
+ if (guidance.usingDefaults) {
129
+ console.info(
130
+ '\u{1F4CB} LGPD-CONSENT: Usando configura\xE7\xE3o padr\xE3o. Para personalizar, use a prop "categories" no ConsentProvider.'
131
+ );
132
+ }
133
+ console.group("\u{1F527} LGPD-CONSENT: Categorias Ativas (para UI customizada)");
134
+ console.table(
135
+ guidance.activeCategoriesInfo.map((cat) => ({
136
+ ID: cat.id,
137
+ Nome: cat.name,
138
+ "Toggle UI?": cat.uiRequired ? "\u2705 SIM" : "\u274C N\xC3O (sempre ativo)",
139
+ "Essencial?": cat.essential ? "\u{1F512} SIM" : "\u2699\uFE0F N\xC3O"
140
+ }))
141
+ );
142
+ console.groupEnd();
143
+ }
144
+
145
+ // src/context/CategoriesContext.tsx
146
+ import { jsx } from "react/jsx-runtime";
147
+ var CategoriesContext = React2.createContext(
148
+ null
149
+ );
150
+ var CategoriesCtx = React2.createContext([]);
151
+ function CategoriesProvider({
152
+ children,
153
+ categories,
154
+ // LEGACY: prop antiga (apenas customCategories)
155
+ config
156
+ // NOVO: configuração completa
157
+ }) {
158
+ const contextValue = React2.useMemo(() => {
159
+ let finalConfig;
160
+ if (categories && !config) {
161
+ finalConfig = {
162
+ enabledCategories: DEFAULT_PROJECT_CATEGORIES.enabledCategories,
163
+ customCategories: categories
164
+ };
165
+ } else {
166
+ finalConfig = config || DEFAULT_PROJECT_CATEGORIES;
167
+ }
168
+ const guidance = analyzeDeveloperConfiguration(
169
+ config || (categories ? { customCategories: categories } : void 0)
170
+ );
171
+ const toggleableCategories = guidance.activeCategoriesInfo.filter(
172
+ (cat) => cat.uiRequired
173
+ );
174
+ return {
175
+ config: finalConfig,
176
+ guidance,
177
+ toggleableCategories,
178
+ allCategories: guidance.activeCategoriesInfo,
179
+ legacyCategories: categories || []
180
+ };
181
+ }, [config, categories]);
182
+ React2.useEffect(() => {
183
+ logDeveloperGuidance(contextValue.guidance);
184
+ }, [contextValue.guidance]);
185
+ return /* @__PURE__ */ jsx(CategoriesContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(CategoriesCtx.Provider, { value: contextValue.legacyCategories, children }) });
186
+ }
187
+ function useCategories() {
188
+ const context = React2.useContext(CategoriesContext);
189
+ if (!context) {
190
+ throw new Error(
191
+ "useCategories deve ser usado dentro de CategoriesProvider. Certifique-se de que o ConsentProvider est\xE1 envolvendo seu componente."
192
+ );
193
+ }
194
+ return context;
195
+ }
196
+ function useCategoryStatus(categoryId) {
197
+ const { allCategories } = useCategories();
198
+ const category = allCategories.find((cat) => cat.id === categoryId);
199
+ return {
200
+ isActive: !!category,
201
+ isEssential: category?.essential || false,
202
+ needsToggle: category?.uiRequired || false,
203
+ name: category?.name,
204
+ description: category?.description
205
+ };
206
+ }
207
+ function useCustomCategories() {
208
+ return React2.useContext(CategoriesCtx);
209
+ }
210
+
211
+ // src/context/ConsentContext.tsx
212
+ import * as React3 from "react";
15
213
  import { ThemeProvider } from "@mui/material/styles";
16
214
 
17
215
  // src/utils/cookieUtils.ts
@@ -23,20 +221,61 @@ var DEFAULT_COOKIE_OPTS = {
23
221
  secure: typeof window !== "undefined" ? window.location.protocol === "https:" : false,
24
222
  path: "/"
25
223
  };
224
+ var COOKIE_SCHEMA_VERSION = "1.0";
26
225
  function readConsentCookie(name = DEFAULT_COOKIE_OPTS.name) {
27
226
  if (typeof document === "undefined") return null;
28
227
  const raw = Cookies.get(name);
29
228
  if (!raw) return null;
30
229
  try {
31
- return JSON.parse(raw);
230
+ const data = JSON.parse(raw);
231
+ if (!data.version) {
232
+ return migrateLegacyCookie(data);
233
+ }
234
+ if (data.version !== COOKIE_SCHEMA_VERSION) {
235
+ console.warn(
236
+ `[react-lgpd-consent] Cookie version mismatch: ${data.version} != ${COOKIE_SCHEMA_VERSION}`
237
+ );
238
+ return null;
239
+ }
240
+ return data;
241
+ } catch {
242
+ return null;
243
+ }
244
+ }
245
+ function migrateLegacyCookie(legacyData) {
246
+ try {
247
+ const now = (/* @__PURE__ */ new Date()).toISOString();
248
+ return {
249
+ version: COOKIE_SCHEMA_VERSION,
250
+ consented: legacyData.consented || false,
251
+ preferences: legacyData.preferences || { necessary: true },
252
+ consentDate: now,
253
+ // Não temos o original, usar data atual
254
+ lastUpdate: now,
255
+ source: "banner",
256
+ // Assumir origem banner
257
+ isModalOpen: false
258
+ // Nunca persistir estado de UI
259
+ };
32
260
  } catch {
33
261
  return null;
34
262
  }
35
263
  }
36
- function writeConsentCookie(state, opts) {
264
+ function writeConsentCookie(state, source = "banner", opts) {
37
265
  if (typeof document === "undefined") return;
266
+ const now = (/* @__PURE__ */ new Date()).toISOString();
38
267
  const o = { ...DEFAULT_COOKIE_OPTS, ...opts };
39
- Cookies.set(o.name, JSON.stringify(state), {
268
+ const cookieData = {
269
+ version: COOKIE_SCHEMA_VERSION,
270
+ consented: state.consented,
271
+ preferences: state.preferences,
272
+ consentDate: state.consentDate || now,
273
+ // Preservar data original ou usar atual
274
+ lastUpdate: now,
275
+ source
276
+ // isModalOpen NÃO é persistido (campo de UI apenas)
277
+ };
278
+ Cookies.set(o.name, JSON.stringify(cookieData), {
40
279
  expires: o.maxAgeDays,
41
280
  sameSite: o.sameSite,
42
281
  secure: o.secure,
@@ -117,86 +356,16 @@ var defaultConsentTheme = createTheme({
117
356
  }
118
357
  });
119
358
 
120
- // src/context/CategoriesContext.tsx
121
- import * as React from "react";
122
- import { jsx } from "react/jsx-runtime";
123
- var CategoriesCtx = React.createContext([]);
124
- function CategoriesProvider({
125
- categories,
126
- children
127
- }) {
128
- const value = React.useMemo(() => categories || [], [categories]);
129
- return /* @__PURE__ */ jsx(CategoriesCtx.Provider, { value, children });
130
- }
131
- function useCustomCategories() {
132
- return React.useContext(CategoriesCtx);
133
- }
134
- function useAllCategories() {
135
- const customCategories = useCustomCategories();
136
- return React.useMemo(() => {
137
- const defaultCategories = [
138
- {
139
- id: "necessary",
140
- name: "Cookies Necess\xE1rios",
141
- description: "Essenciais para o funcionamento b\xE1sico do site. Incluem cookies de sess\xE3o, autentica\xE7\xE3o e seguran\xE7a.",
142
- essential: true,
143
- cookies: ["PHPSESSID", "JSESSIONID", "cookieConsent", "csrf_token"]
144
- },
145
- {
146
- id: "analytics",
147
- name: "Analytics e Estat\xEDsticas",
148
- description: "Permitem medir audi\xEAncia e desempenho, gerando estat\xEDsticas an\xF4nimas de uso.",
149
- essential: false,
150
- cookies: ["_ga", "_ga_*", "_gid", "_gat", "gtag"]
151
- },
152
- {
153
- id: "functional",
154
- name: "Cookies Funcionais",
155
- description: "Melhoram a experi\xEAncia do usu\xE1rio, lembrando prefer\xEAncias e configura\xE7\xF5es.",
156
- essential: false,
157
- cookies: ["language", "theme", "timezone", "preferences"]
158
- },
159
- {
160
- id: "marketing",
161
- name: "Marketing e Publicidade",
162
- description: "Utilizados para publicidade direcionada e medi\xE7\xE3o de campanhas publicit\xE1rias.",
163
- essential: false,
164
- cookies: ["_fbp", "fr", "tr", "ads_*", "doubleclick"]
165
- },
166
- {
167
- id: "social",
168
- name: "Redes Sociais",
169
- description: "Permitem compartilhamento e integra\xE7\xE3o com redes sociais como Facebook, YouTube, etc.",
170
- essential: false,
171
- cookies: ["__Secure-*", "sb", "datr", "c_user", "social_*"]
172
- },
173
- {
174
- id: "personalization",
175
- name: "Personaliza\xE7\xE3o",
176
- description: "Adaptam o conte\xFAdo e interface \xE0s prefer\xEAncias individuais do usu\xE1rio.",
177
- essential: false,
178
- cookies: ["personalization_*", "content_*", "layout_*"]
179
- }
180
- ];
181
- return [...defaultCategories, ...customCategories];
182
- }, [customCategories]);
183
- }
184
-
185
359
  // src/context/ConsentContext.tsx
186
360
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
187
- var PreferencesModal = React2.lazy(
188
- () => import("./PreferencesModal-QQOOLRDY.js").then((m) => ({
361
+ var PreferencesModal = React3.lazy(
362
+ () => import("./PreferencesModal-UL552BFP.js").then((m) => ({
189
363
  default: m.PreferencesModal
190
364
  }))
191
365
  );
192
366
  var DEFAULT_PREFERENCES = {
193
- necessary: true,
367
+ necessary: true
194
368
  // Sempre ativo (essencial)
195
- analytics: false,
196
- functional: false,
197
- marketing: false,
198
- social: false,
199
- personalization: false
200
369
  };
201
370
  function createInitialPreferences(customCategories) {
202
371
  const prefs = { ...DEFAULT_PREFERENCES };
@@ -207,6 +376,18 @@ function createInitialPreferences(customCategories) {
207
376
  }
208
377
  return prefs;
209
378
  }
379
+ function createFullConsentState(consented, preferences, source, isModalOpen = false, existingState) {
380
+ const now = (/* @__PURE__ */ new Date()).toISOString();
381
+ return {
382
+ version: "1.0",
383
+ consented,
384
+ preferences,
385
+ consentDate: existingState?.consentDate || now,
386
+ lastUpdate: now,
387
+ source,
388
+ isModalOpen
389
+ };
390
+ }
210
391
  var DEFAULT_TEXTS = {
211
392
  // Textos básicos
212
393
  bannerMessage: "Utilizamos cookies para melhorar sua experi\xEAncia.",
@@ -243,11 +424,7 @@ function reducer(state, action) {
243
424
  Object.keys(prefs).forEach((key) => {
244
425
  prefs[key] = true;
245
426
  });
246
- return {
247
- consented: true,
248
- preferences: prefs,
249
- isModalOpen: false
250
- };
427
+ return createFullConsentState(true, prefs, "banner", false, state);
251
428
  }
252
429
  case "REJECT_ALL": {
253
430
  const prefs = createInitialPreferences(action.customCategories);
@@ -258,11 +435,7 @@ function reducer(state, action) {
258
435
  }
259
436
  });
260
437
  }
261
- return {
262
- consented: true,
263
- preferences: prefs,
264
- isModalOpen: false
265
- };
438
+ return createFullConsentState(true, prefs, "banner", false, state);
266
439
  }
267
440
  case "SET_CATEGORY":
268
441
  return {
@@ -270,42 +443,54 @@ function reducer(state, action) {
270
443
  preferences: {
271
444
  ...state.preferences,
272
445
  [action.category]: action.value
273
- }
446
+ },
447
+ lastUpdate: (/* @__PURE__ */ new Date()).toISOString()
274
448
  };
275
449
  case "SET_PREFERENCES":
276
- return {
277
- ...state,
278
- consented: true,
279
- preferences: action.preferences,
280
- isModalOpen: false
281
- };
450
+ return createFullConsentState(
451
+ true,
452
+ action.preferences,
453
+ "modal",
454
+ false,
455
+ state
456
+ );
282
457
  case "OPEN_MODAL":
283
458
  return { ...state, isModalOpen: true };
284
459
  case "CLOSE_MODAL":
285
- return { ...state, isModalOpen: false, consented: true };
286
- // houve interação
460
+ return createFullConsentState(
461
+ true,
462
+ state.preferences,
463
+ "modal",
464
+ false,
465
+ state
466
+ );
287
467
  case "RESET": {
288
- return {
289
- consented: false,
290
- preferences: createInitialPreferences(action.customCategories),
291
- isModalOpen: false
292
- };
468
+ return createFullConsentState(
469
+ false,
470
+ createInitialPreferences(action.customCategories),
471
+ "programmatic",
472
+ false
473
+ );
293
474
  }
294
475
  case "HYDRATE":
295
- return { ...action.state };
476
+ return { ...action.state, isModalOpen: false };
477
+ // Nunca hidratar com modal aberto
296
478
  default:
297
479
  return state;
298
480
  }
299
481
  }
300
- var StateCtx = React2.createContext(null);
301
- var ActionsCtx = React2.createContext(null);
302
- var TextsCtx = React2.createContext(DEFAULT_TEXTS);
303
- var HydrationCtx = React2.createContext(false);
482
+ var StateCtx = React3.createContext(null);
483
+ var ActionsCtx = React3.createContext(null);
484
+ var TextsCtx = React3.createContext(DEFAULT_TEXTS);
485
+ var HydrationCtx = React3.createContext(false);
304
486
  function ConsentProvider({
305
487
  initialState,
488
+ categories,
489
+ // NOVO: configuração completa de categorias
306
490
  texts: textsProp,
307
491
  theme,
308
492
  customCategories,
493
+ // LEGACY: compatibilidade
309
494
  scriptIntegrations,
310
495
  PreferencesModalComponent,
311
496
  preferencesModalProps = {},
@@ -316,29 +501,41 @@ function ConsentProvider({
316
501
  cookie: cookieOpts,
317
502
  children
318
503
  }) {
319
- const texts = React2.useMemo(
504
+ const texts = React3.useMemo(
320
505
  () => ({ ...DEFAULT_TEXTS, ...textsProp ?? {} }),
321
506
  [textsProp]
322
507
  );
323
- const cookie = React2.useMemo(
508
+ const cookie = React3.useMemo(
324
509
  () => ({ ...DEFAULT_COOKIE_OPTS, ...cookieOpts ?? {} }),
325
510
  [cookieOpts]
326
511
  );
327
- const appliedTheme = React2.useMemo(
512
+ const appliedTheme = React3.useMemo(
328
513
  () => theme || defaultConsentTheme,
329
514
  [theme]
330
515
  );
331
- const boot = React2.useMemo(() => {
516
+ const finalCategoriesConfig = React3.useMemo(() => {
517
+ if (categories) return categories;
518
+ if (customCategories) {
519
+ return {
520
+ enabledCategories: ["analytics"],
521
+ // padrão quando usando API antiga
522
+ customCategories
523
+ };
524
+ }
525
+ return void 0;
526
+ }, [categories, customCategories]);
527
+ const boot = React3.useMemo(() => {
332
528
  if (initialState) return { ...initialState, isModalOpen: false };
333
- return {
334
- consented: false,
335
- preferences: createInitialPreferences(customCategories),
336
- isModalOpen: false
337
- };
529
+ return createFullConsentState(
530
+ false,
531
+ createInitialPreferences(customCategories),
532
+ "banner",
533
+ false
534
+ );
338
535
  }, [initialState, customCategories]);
339
- const [state, dispatch] = React2.useReducer(reducer, boot);
340
- const [isHydrated, setIsHydrated] = React2.useState(false);
341
- React2.useEffect(() => {
536
+ const [state, dispatch] = React3.useReducer(reducer, boot);
537
+ const [isHydrated, setIsHydrated] = React3.useState(false);
538
+ React3.useEffect(() => {
342
539
  if (!initialState) {
343
540
  const saved = readConsentCookie(cookie.name);
344
541
  if (saved?.consented) {
@@ -348,24 +545,24 @@ function ConsentProvider({
348
545
  }
349
546
  setIsHydrated(true);
350
547
  }, [cookie.name, initialState]);
351
- React2.useEffect(() => {
352
- if (state.consented) writeConsentCookie(state, cookie);
548
+ React3.useEffect(() => {
549
+ if (state.consented) writeConsentCookie(state, state.source, cookie);
353
550
  }, [state, cookie]);
354
- const prevConsented = React2.useRef(state.consented);
355
- React2.useEffect(() => {
551
+ const prevConsented = React3.useRef(state.consented);
552
+ React3.useEffect(() => {
356
553
  if (!prevConsented.current && state.consented && onConsentGiven) {
357
554
  setTimeout(() => onConsentGiven(state), 150);
358
555
  }
359
556
  prevConsented.current = state.consented;
360
557
  }, [state, onConsentGiven]);
361
- const prevPrefs = React2.useRef(state.preferences);
362
- React2.useEffect(() => {
558
+ const prevPrefs = React3.useRef(state.preferences);
559
+ React3.useEffect(() => {
363
560
  if (state.consented && onPreferencesSaved && prevPrefs.current !== state.preferences) {
364
561
  setTimeout(() => onPreferencesSaved(state.preferences), 150);
365
562
  prevPrefs.current = state.preferences;
366
563
  }
367
564
  }, [state, onPreferencesSaved]);
368
- const api = React2.useMemo(() => {
565
+ const api = React3.useMemo(() => {
369
566
  const acceptAll = () => dispatch({ type: "ACCEPT_ALL", customCategories });
370
567
  const rejectAll = () => dispatch({ type: "REJECT_ALL", customCategories });
371
568
  const setPreference = (category, value) => dispatch({ type: "SET_CATEGORY", category, value });
@@ -389,29 +586,36 @@ function ConsentProvider({
389
586
  resetConsent
390
587
  };
391
588
  }, [state, cookie, customCategories]);
392
- return /* @__PURE__ */ jsx2(ThemeProvider, { theme: appliedTheme, children: /* @__PURE__ */ jsx2(StateCtx.Provider, { value: state, children: /* @__PURE__ */ jsx2(ActionsCtx.Provider, { value: api, children: /* @__PURE__ */ jsx2(TextsCtx.Provider, { value: texts, children: /* @__PURE__ */ jsx2(HydrationCtx.Provider, { value: isHydrated, children: /* @__PURE__ */ jsxs(CategoriesProvider, { categories: customCategories, children: [
393
- children,
394
- !disableAutomaticModal && /* @__PURE__ */ jsx2(React2.Suspense, { fallback: null, children: PreferencesModalComponent ? /* @__PURE__ */ jsx2(PreferencesModalComponent, { ...preferencesModalProps }) : /* @__PURE__ */ jsx2(PreferencesModal, { hideBranding }) })
395
- ] }) }) }) }) }) });
589
+ return /* @__PURE__ */ jsx2(ThemeProvider, { theme: appliedTheme, children: /* @__PURE__ */ jsx2(StateCtx.Provider, { value: state, children: /* @__PURE__ */ jsx2(ActionsCtx.Provider, { value: api, children: /* @__PURE__ */ jsx2(TextsCtx.Provider, { value: texts, children: /* @__PURE__ */ jsx2(HydrationCtx.Provider, { value: isHydrated, children: /* @__PURE__ */ jsxs(
590
+ CategoriesProvider,
591
+ {
592
+ config: finalCategoriesConfig,
593
+ categories: customCategories,
594
+ children: [
595
+ children,
596
+ !disableAutomaticModal && /* @__PURE__ */ jsx2(React3.Suspense, { fallback: null, children: PreferencesModalComponent ? /* @__PURE__ */ jsx2(PreferencesModalComponent, { ...preferencesModalProps }) : /* @__PURE__ */ jsx2(PreferencesModal, { hideBranding }) })
597
+ ]
598
+ }
599
+ ) }) }) }) }) });
396
600
  }
397
601
  function useConsentStateInternal() {
398
- const ctx = React2.useContext(StateCtx);
602
+ const ctx = React3.useContext(StateCtx);
399
603
  if (!ctx)
400
604
  throw new Error("useConsentState must be used within ConsentProvider");
401
605
  return ctx;
402
606
  }
403
607
  function useConsentActionsInternal() {
404
- const ctx = React2.useContext(ActionsCtx);
608
+ const ctx = React3.useContext(ActionsCtx);
405
609
  if (!ctx)
406
610
  throw new Error("useConsentActions must be used within ConsentProvider");
407
611
  return ctx;
408
612
  }
409
613
  function useConsentTextsInternal() {
410
- const ctx = React2.useContext(TextsCtx);
614
+ const ctx = React3.useContext(TextsCtx);
411
615
  return ctx;
412
616
  }
413
617
  function useConsentHydrationInternal() {
414
- return React2.useContext(HydrationCtx);
618
+ return React3.useContext(HydrationCtx);
415
619
  }
416
620
 
417
621
  // src/hooks/useConsent.ts
@@ -505,12 +709,25 @@ function PreferencesModal2({
505
709
  }) {
506
710
  const { preferences, setPreferences, closePreferences, isModalOpen } = useConsent();
507
711
  const texts = useConsentTexts();
508
- const [tempPreferences, setTempPreferences] = useState2(preferences);
509
- useEffect2(() => {
712
+ const { toggleableCategories } = useCategories();
713
+ const [tempPreferences, setTempPreferences] = useState2(
714
+ () => {
715
+ const initialPrefs = { necessary: true };
716
+ toggleableCategories.forEach((category) => {
717
+ initialPrefs[category.id] = preferences[category.id] ?? false;
718
+ });
719
+ return initialPrefs;
720
+ }
721
+ );
722
+ useEffect4(() => {
510
723
  if (isModalOpen) {
511
- setTempPreferences(preferences);
724
+ const syncedPrefs = { necessary: true };
725
+ toggleableCategories.forEach((category) => {
726
+ syncedPrefs[category.id] = preferences[category.id] ?? false;
727
+ });
728
+ setTempPreferences(syncedPrefs);
512
729
  }
513
- }, [isModalOpen, preferences]);
730
+ }, [isModalOpen, preferences, toggleableCategories]);
514
731
  const open = DialogProps2?.open ?? isModalOpen ?? false;
515
732
  const handleSave = () => {
516
733
  setPreferences(tempPreferences);
@@ -531,38 +748,23 @@ function PreferencesModal2({
531
748
  /* @__PURE__ */ jsxs3(DialogContent, { dividers: true, children: [
532
749
  /* @__PURE__ */ jsx4(Typography2, { variant: "body2", sx: { mb: 2 }, children: texts.modalIntro }),
533
750
  /* @__PURE__ */ jsxs3(FormGroup, { children: [
534
- /* @__PURE__ */ jsx4(
535
- FormControlLabel,
536
- {
537
- control: /* @__PURE__ */ jsx4(
538
- Switch,
539
- {
540
- checked: tempPreferences.analytics,
541
- onChange: (e) => setTempPreferences((prev) => ({
542
- ...prev,
543
- analytics: e.target.checked
544
- }))
545
- }
546
- ),
547
- label: "Cookies Anal\xEDticos (medem uso do site)"
548
- }
549
- ),
550
- /* @__PURE__ */ jsx4(
751
+ toggleableCategories.map((category) => /* @__PURE__ */ jsx4(
551
752
  FormControlLabel,
552
753
  {
553
754
  control: /* @__PURE__ */ jsx4(
554
755
  Switch,
555
756
  {
556
- checked: tempPreferences.marketing,
757
+ checked: tempPreferences[category.id] ?? false,
557
758
  onChange: (e) => setTempPreferences((prev) => ({
558
759
  ...prev,
559
- marketing: e.target.checked
760
+ [category.id]: e.target.checked
560
761
  }))
561
762
  }
562
763
  ),
563
- label: "Cookies de Marketing/Publicidade"
564
- }
565
- ),
764
+ label: `${category.name} - ${category.description}`
765
+ },
766
+ category.id
767
+ )),
566
768
  /* @__PURE__ */ jsx4(
567
769
  FormControlLabel,
568
770
  {
@@ -584,8 +786,11 @@ function PreferencesModal2({
584
786
 
585
787
  export {
586
788
  defaultConsentTheme,
789
+ DEFAULT_PROJECT_CATEGORIES,
790
+ analyzeDeveloperConfiguration,
791
+ useCategories,
792
+ useCategoryStatus,
587
793
  useCustomCategories,
588
- useAllCategories,
589
794
  Branding,
590
795
  PreferencesModal2 as PreferencesModal,
591
796
  ConsentProvider,