@grainql/analytics-web 2.0.0 → 2.1.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 (173) hide show
  1. package/dist/activity.d.ts +59 -0
  2. package/dist/activity.d.ts.map +1 -0
  3. package/dist/cjs/activity.d.ts +59 -0
  4. package/dist/cjs/activity.d.ts.map +1 -0
  5. package/dist/cjs/activity.js +131 -0
  6. package/dist/cjs/activity.js.map +1 -0
  7. package/dist/cjs/consent.d.ts +68 -0
  8. package/dist/cjs/consent.d.ts.map +1 -0
  9. package/dist/cjs/consent.js +191 -0
  10. package/dist/cjs/consent.js.map +1 -0
  11. package/dist/cjs/cookies.d.ts +28 -0
  12. package/dist/cjs/cookies.d.ts.map +1 -0
  13. package/dist/cjs/cookies.js +95 -0
  14. package/dist/cjs/cookies.js.map +1 -0
  15. package/dist/cjs/heartbeat.d.ts +42 -0
  16. package/dist/cjs/heartbeat.d.ts.map +1 -0
  17. package/dist/cjs/heartbeat.js +92 -0
  18. package/dist/cjs/heartbeat.js.map +1 -0
  19. package/dist/cjs/index.d.ts +100 -3
  20. package/dist/cjs/index.d.ts.map +1 -1
  21. package/dist/cjs/index.js.map +1 -1
  22. package/dist/cjs/page-tracking.d.ts +60 -0
  23. package/dist/cjs/page-tracking.d.ts.map +1 -0
  24. package/dist/cjs/page-tracking.js +180 -0
  25. package/dist/cjs/page-tracking.js.map +1 -0
  26. package/dist/cjs/react/components/ConsentBanner.d.ts +16 -0
  27. package/dist/cjs/react/components/ConsentBanner.d.ts.map +1 -0
  28. package/dist/cjs/react/components/ConsentBanner.js +112 -0
  29. package/dist/cjs/react/components/ConsentBanner.js.map +1 -0
  30. package/dist/cjs/react/components/CookieNotice.d.ts +12 -0
  31. package/dist/cjs/react/components/CookieNotice.d.ts.map +1 -0
  32. package/dist/cjs/react/components/CookieNotice.js +62 -0
  33. package/dist/cjs/react/components/CookieNotice.js.map +1 -0
  34. package/dist/cjs/react/components/PrivacyPreferenceCenter.d.ts +12 -0
  35. package/dist/cjs/react/components/PrivacyPreferenceCenter.d.ts.map +1 -0
  36. package/dist/cjs/react/components/PrivacyPreferenceCenter.js +120 -0
  37. package/dist/cjs/react/components/PrivacyPreferenceCenter.js.map +1 -0
  38. package/dist/cjs/react/hooks/useConsent.d.ts +13 -0
  39. package/dist/cjs/react/hooks/useConsent.d.ts.map +1 -0
  40. package/dist/cjs/react/hooks/useConsent.js +84 -0
  41. package/dist/cjs/react/hooks/useConsent.js.map +1 -0
  42. package/dist/cjs/react/hooks/useDataDeletion.d.ts +17 -0
  43. package/dist/cjs/react/hooks/useDataDeletion.d.ts.map +1 -0
  44. package/dist/cjs/react/hooks/useDataDeletion.js +117 -0
  45. package/dist/cjs/react/hooks/useDataDeletion.js.map +1 -0
  46. package/dist/cjs/react/hooks/usePrivacyPreferences.d.ts +15 -0
  47. package/dist/cjs/react/hooks/usePrivacyPreferences.d.ts.map +1 -0
  48. package/dist/cjs/react/hooks/usePrivacyPreferences.js +82 -0
  49. package/dist/cjs/react/hooks/usePrivacyPreferences.js.map +1 -0
  50. package/dist/cjs/react/index.d.ts +11 -0
  51. package/dist/cjs/react/index.d.ts.map +1 -1
  52. package/dist/cjs/react/index.js +15 -1
  53. package/dist/cjs/react/index.js.map +1 -1
  54. package/dist/consent.d.ts +68 -0
  55. package/dist/consent.d.ts.map +1 -0
  56. package/dist/cookies.d.ts +28 -0
  57. package/dist/cookies.d.ts.map +1 -0
  58. package/dist/esm/activity.d.ts +59 -0
  59. package/dist/esm/activity.d.ts.map +1 -0
  60. package/dist/esm/activity.js +127 -0
  61. package/dist/esm/activity.js.map +1 -0
  62. package/dist/esm/consent.d.ts +68 -0
  63. package/dist/esm/consent.d.ts.map +1 -0
  64. package/dist/esm/consent.js +187 -0
  65. package/dist/esm/consent.js.map +1 -0
  66. package/dist/esm/cookies.d.ts +28 -0
  67. package/dist/esm/cookies.d.ts.map +1 -0
  68. package/dist/esm/cookies.js +89 -0
  69. package/dist/esm/cookies.js.map +1 -0
  70. package/dist/esm/heartbeat.d.ts +42 -0
  71. package/dist/esm/heartbeat.d.ts.map +1 -0
  72. package/dist/esm/heartbeat.js +88 -0
  73. package/dist/esm/heartbeat.js.map +1 -0
  74. package/dist/esm/index.d.ts +100 -3
  75. package/dist/esm/index.d.ts.map +1 -1
  76. package/dist/esm/index.js.map +1 -1
  77. package/dist/esm/page-tracking.d.ts +60 -0
  78. package/dist/esm/page-tracking.d.ts.map +1 -0
  79. package/dist/esm/page-tracking.js +176 -0
  80. package/dist/esm/page-tracking.js.map +1 -0
  81. package/dist/esm/react/components/ConsentBanner.d.ts +16 -0
  82. package/dist/esm/react/components/ConsentBanner.d.ts.map +1 -0
  83. package/dist/esm/react/components/ConsentBanner.js +76 -0
  84. package/dist/esm/react/components/ConsentBanner.js.map +1 -0
  85. package/dist/esm/react/components/CookieNotice.d.ts +12 -0
  86. package/dist/esm/react/components/CookieNotice.d.ts.map +1 -0
  87. package/dist/esm/react/components/CookieNotice.js +26 -0
  88. package/dist/esm/react/components/CookieNotice.js.map +1 -0
  89. package/dist/esm/react/components/PrivacyPreferenceCenter.d.ts +12 -0
  90. package/dist/esm/react/components/PrivacyPreferenceCenter.d.ts.map +1 -0
  91. package/dist/esm/react/components/PrivacyPreferenceCenter.js +84 -0
  92. package/dist/esm/react/components/PrivacyPreferenceCenter.js.map +1 -0
  93. package/dist/esm/react/hooks/useConsent.d.ts +13 -0
  94. package/dist/esm/react/hooks/useConsent.d.ts.map +1 -0
  95. package/dist/esm/react/hooks/useConsent.js +48 -0
  96. package/dist/esm/react/hooks/useConsent.js.map +1 -0
  97. package/dist/esm/react/hooks/useDataDeletion.d.ts +17 -0
  98. package/dist/esm/react/hooks/useDataDeletion.d.ts.map +1 -0
  99. package/dist/esm/react/hooks/useDataDeletion.js +81 -0
  100. package/dist/esm/react/hooks/useDataDeletion.js.map +1 -0
  101. package/dist/esm/react/hooks/usePrivacyPreferences.d.ts +15 -0
  102. package/dist/esm/react/hooks/usePrivacyPreferences.d.ts.map +1 -0
  103. package/dist/esm/react/hooks/usePrivacyPreferences.js +46 -0
  104. package/dist/esm/react/hooks/usePrivacyPreferences.js.map +1 -0
  105. package/dist/esm/react/index.d.ts +11 -0
  106. package/dist/esm/react/index.d.ts.map +1 -1
  107. package/dist/esm/react/index.js +8 -0
  108. package/dist/esm/react/index.js.map +1 -1
  109. package/dist/heartbeat.d.ts +42 -0
  110. package/dist/heartbeat.d.ts.map +1 -0
  111. package/dist/index.d.ts +100 -3
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.global.dev.js +903 -12
  114. package/dist/index.global.dev.js.map +3 -3
  115. package/dist/index.global.js +2 -2
  116. package/dist/index.global.js.map +4 -4
  117. package/dist/index.js +321 -11
  118. package/dist/index.mjs +321 -11
  119. package/dist/page-tracking.d.ts +60 -0
  120. package/dist/page-tracking.d.ts.map +1 -0
  121. package/dist/react/activity.d.ts +59 -0
  122. package/dist/react/activity.d.ts.map +1 -0
  123. package/dist/react/activity.js +130 -0
  124. package/dist/react/activity.mjs +126 -0
  125. package/dist/react/consent.d.ts +68 -0
  126. package/dist/react/consent.d.ts.map +1 -0
  127. package/dist/react/consent.js +190 -0
  128. package/dist/react/consent.mjs +186 -0
  129. package/dist/react/cookies.d.ts +28 -0
  130. package/dist/react/cookies.d.ts.map +1 -0
  131. package/dist/react/cookies.js +94 -0
  132. package/dist/react/cookies.mjs +88 -0
  133. package/dist/react/heartbeat.d.ts +42 -0
  134. package/dist/react/heartbeat.d.ts.map +1 -0
  135. package/dist/react/heartbeat.js +91 -0
  136. package/dist/react/heartbeat.mjs +87 -0
  137. package/dist/react/index.d.ts +100 -3
  138. package/dist/react/index.d.ts.map +1 -1
  139. package/dist/react/index.js +321 -11
  140. package/dist/react/index.mjs +321 -11
  141. package/dist/react/page-tracking.d.ts +60 -0
  142. package/dist/react/page-tracking.d.ts.map +1 -0
  143. package/dist/react/page-tracking.js +179 -0
  144. package/dist/react/page-tracking.mjs +175 -0
  145. package/dist/react/react/components/ConsentBanner.d.ts +16 -0
  146. package/dist/react/react/components/ConsentBanner.d.ts.map +1 -0
  147. package/dist/react/react/components/ConsentBanner.js +78 -0
  148. package/dist/react/react/components/ConsentBanner.mjs +75 -0
  149. package/dist/react/react/components/CookieNotice.d.ts +12 -0
  150. package/dist/react/react/components/CookieNotice.d.ts.map +1 -0
  151. package/dist/react/react/components/CookieNotice.js +28 -0
  152. package/dist/react/react/components/CookieNotice.mjs +25 -0
  153. package/dist/react/react/components/PrivacyPreferenceCenter.d.ts +12 -0
  154. package/dist/react/react/components/PrivacyPreferenceCenter.d.ts.map +1 -0
  155. package/dist/react/react/components/PrivacyPreferenceCenter.js +86 -0
  156. package/dist/react/react/components/PrivacyPreferenceCenter.mjs +83 -0
  157. package/dist/react/react/hooks/useConsent.d.ts +13 -0
  158. package/dist/react/react/hooks/useConsent.d.ts.map +1 -0
  159. package/dist/react/react/hooks/useConsent.js +50 -0
  160. package/dist/react/react/hooks/useConsent.mjs +47 -0
  161. package/dist/react/react/hooks/useDataDeletion.d.ts +17 -0
  162. package/dist/react/react/hooks/useDataDeletion.d.ts.map +1 -0
  163. package/dist/react/react/hooks/useDataDeletion.js +83 -0
  164. package/dist/react/react/hooks/useDataDeletion.mjs +80 -0
  165. package/dist/react/react/hooks/usePrivacyPreferences.d.ts +15 -0
  166. package/dist/react/react/hooks/usePrivacyPreferences.d.ts.map +1 -0
  167. package/dist/react/react/hooks/usePrivacyPreferences.js +48 -0
  168. package/dist/react/react/hooks/usePrivacyPreferences.mjs +45 -0
  169. package/dist/react/react/index.d.ts +11 -0
  170. package/dist/react/react/index.d.ts.map +1 -1
  171. package/dist/react/react/index.js +15 -1
  172. package/dist/react/react/index.mjs +8 -0
  173. package/package.json +1 -1
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ /**
3
+ * PrivacyPreferenceCenter - Detailed preference management modal
4
+ * Follows Grain Design System specifications
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.PrivacyPreferenceCenter = PrivacyPreferenceCenter;
8
+ const React = require("react");
9
+ const useGrainAnalytics_1 = require("../hooks/useGrainAnalytics");
10
+ const CATEGORIES = [
11
+ {
12
+ id: 'necessary',
13
+ name: 'Necessary',
14
+ description: 'Essential for the website to function properly. Cannot be disabled.',
15
+ required: true,
16
+ },
17
+ {
18
+ id: 'analytics',
19
+ name: 'Analytics',
20
+ description: 'Help us understand how visitors interact with our website.',
21
+ required: false,
22
+ },
23
+ {
24
+ id: 'functional',
25
+ name: 'Functional',
26
+ description: 'Enable enhanced functionality and personalization.',
27
+ required: false,
28
+ },
29
+ ];
30
+ function PrivacyPreferenceCenter({ isOpen, onClose, onSave, }) {
31
+ const client = (0, useGrainAnalytics_1.useGrainAnalytics)();
32
+ const [selectedCategories, setSelectedCategories] = React.useState(['necessary']);
33
+ React.useEffect(() => {
34
+ if (!client)
35
+ return;
36
+ const consentState = client.getConsentState();
37
+ if (consentState) {
38
+ setSelectedCategories(consentState.categories);
39
+ }
40
+ }, [client, isOpen]);
41
+ const handleToggle = (categoryId, required) => {
42
+ if (required)
43
+ return; // Cannot toggle required categories
44
+ setSelectedCategories((prev) => prev.includes(categoryId)
45
+ ? prev.filter((id) => id !== categoryId)
46
+ : [...prev, categoryId]);
47
+ };
48
+ const handleSave = () => {
49
+ if (client) {
50
+ if (selectedCategories.length > 0) {
51
+ client.grantConsent(selectedCategories);
52
+ }
53
+ else {
54
+ client.revokeConsent();
55
+ }
56
+ }
57
+ onSave?.(selectedCategories);
58
+ onClose();
59
+ };
60
+ const handleEscape = (e) => {
61
+ if (e.key === 'Escape') {
62
+ onClose();
63
+ }
64
+ };
65
+ if (!isOpen)
66
+ return null;
67
+ return (React.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center", onKeyDown: handleEscape, role: "dialog", "aria-labelledby": "preferences-title", "aria-modal": "true" },
68
+ React.createElement("div", { className: "fixed inset-0 bg-zinc-950/80 backdrop-blur-sm", onClick: onClose }),
69
+ React.createElement("div", { className: "relative bg-zinc-950/95 border border-zinc-800/60 backdrop-blur-xl rounded-lg shadow-2xl max-w-2xl w-full mx-4 p-6" },
70
+ React.createElement("h2", { id: "preferences-title", className: "text-xl font-semibold text-zinc-100 mb-4" }, "Privacy Preferences"),
71
+ React.createElement("div", { className: "space-y-4 mb-6" }, CATEGORIES.map((category) => (React.createElement("div", { key: category.id, className: "p-4 bg-zinc-900/40 border border-zinc-800/40 rounded-lg" },
72
+ React.createElement("div", { className: "flex items-start justify-between" },
73
+ React.createElement("div", { className: "flex-1" },
74
+ React.createElement("h3", { className: "font-medium text-zinc-200 mb-1" },
75
+ category.name,
76
+ category.required && (React.createElement("span", { className: "ml-2 text-xs text-emerald-500" }, "(Required)"))),
77
+ React.createElement("p", { className: "text-sm text-zinc-400" }, category.description)),
78
+ React.createElement("label", { className: "relative inline-flex items-center cursor-pointer" },
79
+ React.createElement("input", { type: "checkbox", checked: selectedCategories.includes(category.id), onChange: () => handleToggle(category.id, category.required), disabled: category.required, className: "sr-only peer" }),
80
+ React.createElement("div", { className: "w-11 h-6 bg-zinc-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-emerald-600" }))))))),
81
+ React.createElement("div", { className: "flex justify-end gap-2" },
82
+ React.createElement("button", { onClick: onClose, className: "px-4 py-2 bg-zinc-900/60 hover:bg-zinc-800/60 text-zinc-300 border border-zinc-800/60 rounded-lg font-medium transition-all" },
83
+ "Cancel",
84
+ React.createElement("kbd", { className: "ml-2 px-2 py-0.5 bg-zinc-900/50 border border-zinc-800 rounded text-[10px] font-mono" }, "ESC")),
85
+ React.createElement("button", { onClick: handleSave, className: "px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-white rounded-lg font-medium transition-all" }, "Save Preferences")))));
86
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * PrivacyPreferenceCenter - Detailed preference management modal
3
+ * Follows Grain Design System specifications
4
+ */
5
+ import * as React from 'react';
6
+ import { useGrainAnalytics } from '../hooks/useGrainAnalytics';
7
+ const CATEGORIES = [
8
+ {
9
+ id: 'necessary',
10
+ name: 'Necessary',
11
+ description: 'Essential for the website to function properly. Cannot be disabled.',
12
+ required: true,
13
+ },
14
+ {
15
+ id: 'analytics',
16
+ name: 'Analytics',
17
+ description: 'Help us understand how visitors interact with our website.',
18
+ required: false,
19
+ },
20
+ {
21
+ id: 'functional',
22
+ name: 'Functional',
23
+ description: 'Enable enhanced functionality and personalization.',
24
+ required: false,
25
+ },
26
+ ];
27
+ export function PrivacyPreferenceCenter({ isOpen, onClose, onSave, }) {
28
+ const client = useGrainAnalytics();
29
+ const [selectedCategories, setSelectedCategories] = React.useState(['necessary']);
30
+ React.useEffect(() => {
31
+ if (!client)
32
+ return;
33
+ const consentState = client.getConsentState();
34
+ if (consentState) {
35
+ setSelectedCategories(consentState.categories);
36
+ }
37
+ }, [client, isOpen]);
38
+ const handleToggle = (categoryId, required) => {
39
+ if (required)
40
+ return; // Cannot toggle required categories
41
+ setSelectedCategories((prev) => prev.includes(categoryId)
42
+ ? prev.filter((id) => id !== categoryId)
43
+ : [...prev, categoryId]);
44
+ };
45
+ const handleSave = () => {
46
+ if (client) {
47
+ if (selectedCategories.length > 0) {
48
+ client.grantConsent(selectedCategories);
49
+ }
50
+ else {
51
+ client.revokeConsent();
52
+ }
53
+ }
54
+ onSave?.(selectedCategories);
55
+ onClose();
56
+ };
57
+ const handleEscape = (e) => {
58
+ if (e.key === 'Escape') {
59
+ onClose();
60
+ }
61
+ };
62
+ if (!isOpen)
63
+ return null;
64
+ return (React.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center", onKeyDown: handleEscape, role: "dialog", "aria-labelledby": "preferences-title", "aria-modal": "true" },
65
+ React.createElement("div", { className: "fixed inset-0 bg-zinc-950/80 backdrop-blur-sm", onClick: onClose }),
66
+ React.createElement("div", { className: "relative bg-zinc-950/95 border border-zinc-800/60 backdrop-blur-xl rounded-lg shadow-2xl max-w-2xl w-full mx-4 p-6" },
67
+ React.createElement("h2", { id: "preferences-title", className: "text-xl font-semibold text-zinc-100 mb-4" }, "Privacy Preferences"),
68
+ React.createElement("div", { className: "space-y-4 mb-6" }, CATEGORIES.map((category) => (React.createElement("div", { key: category.id, className: "p-4 bg-zinc-900/40 border border-zinc-800/40 rounded-lg" },
69
+ React.createElement("div", { className: "flex items-start justify-between" },
70
+ React.createElement("div", { className: "flex-1" },
71
+ React.createElement("h3", { className: "font-medium text-zinc-200 mb-1" },
72
+ category.name,
73
+ category.required && (React.createElement("span", { className: "ml-2 text-xs text-emerald-500" }, "(Required)"))),
74
+ React.createElement("p", { className: "text-sm text-zinc-400" }, category.description)),
75
+ React.createElement("label", { className: "relative inline-flex items-center cursor-pointer" },
76
+ React.createElement("input", { type: "checkbox", checked: selectedCategories.includes(category.id), onChange: () => handleToggle(category.id, category.required), disabled: category.required, className: "sr-only peer" }),
77
+ React.createElement("div", { className: "w-11 h-6 bg-zinc-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-emerald-600" }))))))),
78
+ React.createElement("div", { className: "flex justify-end gap-2" },
79
+ React.createElement("button", { onClick: onClose, className: "px-4 py-2 bg-zinc-900/60 hover:bg-zinc-800/60 text-zinc-300 border border-zinc-800/60 rounded-lg font-medium transition-all" },
80
+ "Cancel",
81
+ React.createElement("kbd", { className: "ml-2 px-2 py-0.5 bg-zinc-900/50 border border-zinc-800 rounded text-[10px] font-mono" }, "ESC")),
82
+ React.createElement("button", { onClick: handleSave, className: "px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-white rounded-lg font-medium transition-all" }, "Save Preferences")))));
83
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * useConsent - Hook for managing user consent
3
+ */
4
+ import type { ConsentState } from '../../consent';
5
+ export declare function useConsent(): {
6
+ consentState: ConsentState;
7
+ grantConsent: (categories?: string[]) => void;
8
+ revokeConsent: (categories?: string[]) => void;
9
+ hasConsent: (category?: string) => boolean;
10
+ isGranted: boolean;
11
+ categories: string[];
12
+ };
13
+ //# sourceMappingURL=useConsent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useConsent.d.ts","sourceRoot":"","sources":["../../../../src/react/hooks/useConsent.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,wBAAgB,UAAU;;gCAwBR,MAAM,EAAE;iCASR,MAAM,EAAE;4BASV,MAAM;;;EAerB"}
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ /**
3
+ * useConsent - Hook for managing user consent
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.useConsent = useConsent;
7
+ const React = require("react");
8
+ const useGrainAnalytics_1 = require("./useGrainAnalytics");
9
+ function useConsent() {
10
+ const client = (0, useGrainAnalytics_1.useGrainAnalytics)();
11
+ const [consentState, setConsentState] = React.useState(null);
12
+ React.useEffect(() => {
13
+ if (!client)
14
+ return;
15
+ // Get initial consent state
16
+ const initialState = client.getConsentState();
17
+ setConsentState(initialState);
18
+ // Listen for consent changes
19
+ const listener = (state) => {
20
+ setConsentState(state);
21
+ };
22
+ client.onConsentChange(listener);
23
+ return () => {
24
+ client.offConsentChange(listener);
25
+ };
26
+ }, [client]);
27
+ const grantConsent = React.useCallback((categories) => {
28
+ if (client) {
29
+ client.grantConsent(categories);
30
+ }
31
+ }, [client]);
32
+ const revokeConsent = React.useCallback((categories) => {
33
+ if (client) {
34
+ client.revokeConsent(categories);
35
+ }
36
+ }, [client]);
37
+ const hasConsent = React.useCallback((category) => {
38
+ if (!client)
39
+ return false;
40
+ return client.hasConsent(category);
41
+ }, [client]);
42
+ return {
43
+ consentState,
44
+ grantConsent,
45
+ revokeConsent,
46
+ hasConsent,
47
+ isGranted: consentState?.granted ?? false,
48
+ categories: consentState?.categories ?? [],
49
+ };
50
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * useConsent - Hook for managing user consent
3
+ */
4
+ import * as React from 'react';
5
+ import { useGrainAnalytics } from './useGrainAnalytics';
6
+ export function useConsent() {
7
+ const client = useGrainAnalytics();
8
+ const [consentState, setConsentState] = React.useState(null);
9
+ React.useEffect(() => {
10
+ if (!client)
11
+ return;
12
+ // Get initial consent state
13
+ const initialState = client.getConsentState();
14
+ setConsentState(initialState);
15
+ // Listen for consent changes
16
+ const listener = (state) => {
17
+ setConsentState(state);
18
+ };
19
+ client.onConsentChange(listener);
20
+ return () => {
21
+ client.offConsentChange(listener);
22
+ };
23
+ }, [client]);
24
+ const grantConsent = React.useCallback((categories) => {
25
+ if (client) {
26
+ client.grantConsent(categories);
27
+ }
28
+ }, [client]);
29
+ const revokeConsent = React.useCallback((categories) => {
30
+ if (client) {
31
+ client.revokeConsent(categories);
32
+ }
33
+ }, [client]);
34
+ const hasConsent = React.useCallback((category) => {
35
+ if (!client)
36
+ return false;
37
+ return client.hasConsent(category);
38
+ }, [client]);
39
+ return {
40
+ consentState,
41
+ grantConsent,
42
+ revokeConsent,
43
+ hasConsent,
44
+ isGranted: consentState?.granted ?? false,
45
+ categories: consentState?.categories ?? [],
46
+ };
47
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * useDataDeletion - Hook for triggering data deletion requests
3
+ * This is a client-side utility - actual deletion happens on the server
4
+ */
5
+ export interface DataDeletionOptions {
6
+ apiUrl: string;
7
+ tenantId: string;
8
+ onSuccess?: (message: string) => void;
9
+ onError?: (error: string) => void;
10
+ }
11
+ export declare function useDataDeletion(options: DataDeletionOptions): {
12
+ requestDeletion: (userId: string) => Promise<any>;
13
+ requestAnonymization: (userId: string) => Promise<any>;
14
+ loading: boolean;
15
+ error: string;
16
+ };
17
+ //# sourceMappingURL=useDataDeletion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDataDeletion.d.ts","sourceRoot":"","sources":["../../../../src/react/hooks/useDataDeletion.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,mBAAmB;8BAKzC,MAAM;mCAyCN,MAAM;;;EA6CxB"}
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ /**
3
+ * useDataDeletion - Hook for triggering data deletion requests
4
+ * This is a client-side utility - actual deletion happens on the server
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.useDataDeletion = useDataDeletion;
8
+ const React = require("react");
9
+ function useDataDeletion(options) {
10
+ const [loading, setLoading] = React.useState(false);
11
+ const [error, setError] = React.useState(null);
12
+ const requestDeletion = React.useCallback(async (userId) => {
13
+ setLoading(true);
14
+ setError(null);
15
+ try {
16
+ const response = await fetch(`${options.apiUrl}/v1/privacy/${options.tenantId}/data-deletion`, {
17
+ method: 'POST',
18
+ headers: {
19
+ 'Content-Type': 'application/json',
20
+ },
21
+ body: JSON.stringify({
22
+ userId,
23
+ deleteEvents: true,
24
+ deleteProperties: true,
25
+ deleteConsentAudit: false,
26
+ }),
27
+ });
28
+ if (!response.ok) {
29
+ throw new Error(`HTTP ${response.status}`);
30
+ }
31
+ const result = await response.json();
32
+ options.onSuccess?.(result.message);
33
+ return result;
34
+ }
35
+ catch (err) {
36
+ const errorMessage = err instanceof Error ? err.message : 'Unknown error';
37
+ setError(errorMessage);
38
+ options.onError?.(errorMessage);
39
+ throw err;
40
+ }
41
+ finally {
42
+ setLoading(false);
43
+ }
44
+ }, [options]);
45
+ const requestAnonymization = React.useCallback(async (userId) => {
46
+ setLoading(true);
47
+ setError(null);
48
+ try {
49
+ const response = await fetch(`${options.apiUrl}/v1/privacy/${options.tenantId}/anonymize-user`, {
50
+ method: 'POST',
51
+ headers: {
52
+ 'Content-Type': 'application/json',
53
+ },
54
+ body: JSON.stringify({
55
+ userId,
56
+ anonymizeEvents: true,
57
+ anonymizeProperties: true,
58
+ }),
59
+ });
60
+ if (!response.ok) {
61
+ throw new Error(`HTTP ${response.status}`);
62
+ }
63
+ const result = await response.json();
64
+ options.onSuccess?.(result.message);
65
+ return result;
66
+ }
67
+ catch (err) {
68
+ const errorMessage = err instanceof Error ? err.message : 'Unknown error';
69
+ setError(errorMessage);
70
+ options.onError?.(errorMessage);
71
+ throw err;
72
+ }
73
+ finally {
74
+ setLoading(false);
75
+ }
76
+ }, [options]);
77
+ return {
78
+ requestDeletion,
79
+ requestAnonymization,
80
+ loading,
81
+ error,
82
+ };
83
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * useDataDeletion - Hook for triggering data deletion requests
3
+ * This is a client-side utility - actual deletion happens on the server
4
+ */
5
+ import * as React from 'react';
6
+ export function useDataDeletion(options) {
7
+ const [loading, setLoading] = React.useState(false);
8
+ const [error, setError] = React.useState(null);
9
+ const requestDeletion = React.useCallback(async (userId) => {
10
+ setLoading(true);
11
+ setError(null);
12
+ try {
13
+ const response = await fetch(`${options.apiUrl}/v1/privacy/${options.tenantId}/data-deletion`, {
14
+ method: 'POST',
15
+ headers: {
16
+ 'Content-Type': 'application/json',
17
+ },
18
+ body: JSON.stringify({
19
+ userId,
20
+ deleteEvents: true,
21
+ deleteProperties: true,
22
+ deleteConsentAudit: false,
23
+ }),
24
+ });
25
+ if (!response.ok) {
26
+ throw new Error(`HTTP ${response.status}`);
27
+ }
28
+ const result = await response.json();
29
+ options.onSuccess?.(result.message);
30
+ return result;
31
+ }
32
+ catch (err) {
33
+ const errorMessage = err instanceof Error ? err.message : 'Unknown error';
34
+ setError(errorMessage);
35
+ options.onError?.(errorMessage);
36
+ throw err;
37
+ }
38
+ finally {
39
+ setLoading(false);
40
+ }
41
+ }, [options]);
42
+ const requestAnonymization = React.useCallback(async (userId) => {
43
+ setLoading(true);
44
+ setError(null);
45
+ try {
46
+ const response = await fetch(`${options.apiUrl}/v1/privacy/${options.tenantId}/anonymize-user`, {
47
+ method: 'POST',
48
+ headers: {
49
+ 'Content-Type': 'application/json',
50
+ },
51
+ body: JSON.stringify({
52
+ userId,
53
+ anonymizeEvents: true,
54
+ anonymizeProperties: true,
55
+ }),
56
+ });
57
+ if (!response.ok) {
58
+ throw new Error(`HTTP ${response.status}`);
59
+ }
60
+ const result = await response.json();
61
+ options.onSuccess?.(result.message);
62
+ return result;
63
+ }
64
+ catch (err) {
65
+ const errorMessage = err instanceof Error ? err.message : 'Unknown error';
66
+ setError(errorMessage);
67
+ options.onError?.(errorMessage);
68
+ throw err;
69
+ }
70
+ finally {
71
+ setLoading(false);
72
+ }
73
+ }, [options]);
74
+ return {
75
+ requestDeletion,
76
+ requestAnonymization,
77
+ loading,
78
+ error,
79
+ };
80
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * usePrivacyPreferences - Hook for managing privacy preferences
3
+ */
4
+ export interface PrivacyPreferences {
5
+ necessary: boolean;
6
+ analytics: boolean;
7
+ functional: boolean;
8
+ }
9
+ export declare function usePrivacyPreferences(): {
10
+ preferences: PrivacyPreferences;
11
+ updatePreferences: (newPreferences: Partial<PrivacyPreferences>) => void;
12
+ acceptAll: () => void;
13
+ rejectAll: () => void;
14
+ };
15
+ //# sourceMappingURL=usePrivacyPreferences.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePrivacyPreferences.d.ts","sourceRoot":"","sources":["../../../../src/react/hooks/usePrivacyPreferences.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,qBAAqB;;wCAahB,OAAO,CAAC,kBAAkB,CAAC;;;EAqC/C"}
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ /**
3
+ * usePrivacyPreferences - Hook for managing privacy preferences
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.usePrivacyPreferences = usePrivacyPreferences;
7
+ const React = require("react");
8
+ const useConsent_1 = require("./useConsent");
9
+ function usePrivacyPreferences() {
10
+ const { consentState, grantConsent, revokeConsent } = (0, useConsent_1.useConsent)();
11
+ const preferences = React.useMemo(() => {
12
+ const categories = consentState?.categories ?? [];
13
+ return {
14
+ necessary: categories.includes('necessary'),
15
+ analytics: categories.includes('analytics'),
16
+ functional: categories.includes('functional'),
17
+ };
18
+ }, [consentState]);
19
+ const updatePreferences = React.useCallback((newPreferences) => {
20
+ const categories = [];
21
+ // Necessary is always enabled
22
+ categories.push('necessary');
23
+ if (newPreferences.analytics ?? preferences.analytics) {
24
+ categories.push('analytics');
25
+ }
26
+ if (newPreferences.functional ?? preferences.functional) {
27
+ categories.push('functional');
28
+ }
29
+ if (categories.length > 0) {
30
+ grantConsent(categories);
31
+ }
32
+ else {
33
+ revokeConsent();
34
+ }
35
+ }, [preferences, grantConsent, revokeConsent]);
36
+ const acceptAll = React.useCallback(() => {
37
+ grantConsent(['necessary', 'analytics', 'functional']);
38
+ }, [grantConsent]);
39
+ const rejectAll = React.useCallback(() => {
40
+ grantConsent(['necessary']); // Keep only necessary
41
+ }, [grantConsent]);
42
+ return {
43
+ preferences,
44
+ updatePreferences,
45
+ acceptAll,
46
+ rejectAll,
47
+ };
48
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * usePrivacyPreferences - Hook for managing privacy preferences
3
+ */
4
+ import * as React from 'react';
5
+ import { useConsent } from './useConsent';
6
+ export function usePrivacyPreferences() {
7
+ const { consentState, grantConsent, revokeConsent } = useConsent();
8
+ const preferences = React.useMemo(() => {
9
+ const categories = consentState?.categories ?? [];
10
+ return {
11
+ necessary: categories.includes('necessary'),
12
+ analytics: categories.includes('analytics'),
13
+ functional: categories.includes('functional'),
14
+ };
15
+ }, [consentState]);
16
+ const updatePreferences = React.useCallback((newPreferences) => {
17
+ const categories = [];
18
+ // Necessary is always enabled
19
+ categories.push('necessary');
20
+ if (newPreferences.analytics ?? preferences.analytics) {
21
+ categories.push('analytics');
22
+ }
23
+ if (newPreferences.functional ?? preferences.functional) {
24
+ categories.push('functional');
25
+ }
26
+ if (categories.length > 0) {
27
+ grantConsent(categories);
28
+ }
29
+ else {
30
+ revokeConsent();
31
+ }
32
+ }, [preferences, grantConsent, revokeConsent]);
33
+ const acceptAll = React.useCallback(() => {
34
+ grantConsent(['necessary', 'analytics', 'functional']);
35
+ }, [grantConsent]);
36
+ const rejectAll = React.useCallback(() => {
37
+ grantConsent(['necessary']); // Keep only necessary
38
+ }, [grantConsent]);
39
+ return {
40
+ preferences,
41
+ updatePreferences,
42
+ acceptAll,
43
+ rejectAll,
44
+ };
45
+ }
@@ -32,5 +32,16 @@ export { useGrainAnalytics } from './hooks/useGrainAnalytics';
32
32
  export { useConfig } from './hooks/useConfig';
33
33
  export { useAllConfigs } from './hooks/useAllConfigs';
34
34
  export { useTrack } from './hooks/useTrack';
35
+ export { useConsent } from './hooks/useConsent';
36
+ export { usePrivacyPreferences } from './hooks/usePrivacyPreferences';
37
+ export { useDataDeletion } from './hooks/useDataDeletion';
38
+ export { ConsentBanner } from './components/ConsentBanner';
39
+ export { PrivacyPreferenceCenter } from './components/PrivacyPreferenceCenter';
40
+ export { CookieNotice } from './components/CookieNotice';
35
41
  export type { GrainProviderProps, UseConfigOptions, UseConfigResult, UseAllConfigsOptions, UseAllConfigsResult, TrackFunction, } from './types';
42
+ export type { ConsentBannerProps } from './components/ConsentBanner';
43
+ export type { PrivacyPreferenceCenterProps } from './components/PrivacyPreferenceCenter';
44
+ export type { CookieNoticeProps } from './components/CookieNotice';
45
+ export type { PrivacyPreferences } from './hooks/usePrivacyPreferences';
46
+ export type { DataDeletionOptions } from './hooks/useDataDeletion';
36
47
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,YAAY,EACV,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,aAAa,GACd,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAG1D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGzD,YAAY,EACV,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,aAAa,GACd,MAAM,SAAS,CAAC;AAGjB,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,YAAY,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AACzF,YAAY,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnE,YAAY,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACxE,YAAY,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -29,7 +29,7 @@
29
29
  * ```
30
30
  */
31
31
  Object.defineProperty(exports, "__esModule", { value: true });
32
- exports.useTrack = exports.useAllConfigs = exports.useConfig = exports.useGrainAnalytics = exports.GrainProvider = void 0;
32
+ exports.CookieNotice = exports.PrivacyPreferenceCenter = exports.ConsentBanner = exports.useDataDeletion = exports.usePrivacyPreferences = exports.useConsent = exports.useTrack = exports.useAllConfigs = exports.useConfig = exports.useGrainAnalytics = exports.GrainProvider = void 0;
33
33
  // Provider
34
34
  var GrainProvider_1 = require("./GrainProvider");
35
35
  Object.defineProperty(exports, "GrainProvider", { enumerable: true, get: function () { return GrainProvider_1.GrainProvider; } });
@@ -42,3 +42,17 @@ var useAllConfigs_1 = require("./hooks/useAllConfigs");
42
42
  Object.defineProperty(exports, "useAllConfigs", { enumerable: true, get: function () { return useAllConfigs_1.useAllConfigs; } });
43
43
  var useTrack_1 = require("./hooks/useTrack");
44
44
  Object.defineProperty(exports, "useTrack", { enumerable: true, get: function () { return useTrack_1.useTrack; } });
45
+ // Privacy hooks
46
+ var useConsent_1 = require("./hooks/useConsent");
47
+ Object.defineProperty(exports, "useConsent", { enumerable: true, get: function () { return useConsent_1.useConsent; } });
48
+ var usePrivacyPreferences_1 = require("./hooks/usePrivacyPreferences");
49
+ Object.defineProperty(exports, "usePrivacyPreferences", { enumerable: true, get: function () { return usePrivacyPreferences_1.usePrivacyPreferences; } });
50
+ var useDataDeletion_1 = require("./hooks/useDataDeletion");
51
+ Object.defineProperty(exports, "useDataDeletion", { enumerable: true, get: function () { return useDataDeletion_1.useDataDeletion; } });
52
+ // Privacy components
53
+ var ConsentBanner_1 = require("./components/ConsentBanner");
54
+ Object.defineProperty(exports, "ConsentBanner", { enumerable: true, get: function () { return ConsentBanner_1.ConsentBanner; } });
55
+ var PrivacyPreferenceCenter_1 = require("./components/PrivacyPreferenceCenter");
56
+ Object.defineProperty(exports, "PrivacyPreferenceCenter", { enumerable: true, get: function () { return PrivacyPreferenceCenter_1.PrivacyPreferenceCenter; } });
57
+ var CookieNotice_1 = require("./components/CookieNotice");
58
+ Object.defineProperty(exports, "CookieNotice", { enumerable: true, get: function () { return CookieNotice_1.CookieNotice; } });
@@ -34,3 +34,11 @@ export { useGrainAnalytics } from './hooks/useGrainAnalytics';
34
34
  export { useConfig } from './hooks/useConfig';
35
35
  export { useAllConfigs } from './hooks/useAllConfigs';
36
36
  export { useTrack } from './hooks/useTrack';
37
+ // Privacy hooks
38
+ export { useConsent } from './hooks/useConsent';
39
+ export { usePrivacyPreferences } from './hooks/usePrivacyPreferences';
40
+ export { useDataDeletion } from './hooks/useDataDeletion';
41
+ // Privacy components
42
+ export { ConsentBanner } from './components/ConsentBanner';
43
+ export { PrivacyPreferenceCenter } from './components/PrivacyPreferenceCenter';
44
+ export { CookieNotice } from './components/CookieNotice';