nextjs-cookie-consent 1.0.2 → 1.0.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"CookieBanner.d.ts","sourceRoot":"","sources":["../../src/CookieBanner.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAC;AACnD,OAAO,EAAgC,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAuD1E,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAmI7C,CAAC;AAEF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"CookieBanner.d.ts","sourceRoot":"","sources":["../../src/CookieBanner.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAC;AACnD,OAAO,EAAgB,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAkE1D,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAwI7C,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -41,7 +41,8 @@ const styles = {
41
41
  padding: '0.5rem 1rem',
42
42
  cursor: 'pointer',
43
43
  fontSize: '0.9rem',
44
- borderRadius: '4px'
44
+ borderRadius: '4px',
45
+ transition: 'background-color 0.2s ease'
45
46
  },
46
47
  cookieBannerText: {
47
48
  fontSize: '0.95rem',
@@ -53,23 +54,35 @@ const styles = {
53
54
  textDecoration: 'underline'
54
55
  }
55
56
  };
56
- const CookieBanner = ({ categories, content, storageStrategy }) => {
57
- const categoryKeys = categories.map((c) => c.key);
58
- const { consent, isSet, saveConsent } = useConsent(categoryKeys, storageStrategy);
57
+ const objectsEqual = (a, b) => {
58
+ const aKeys = Object.keys(a);
59
+ const bKeys = Object.keys(b);
60
+ if (aKeys.length !== bKeys.length)
61
+ return false;
62
+ for (const key of aKeys) {
63
+ if (a[key] !== b[key])
64
+ return false;
65
+ }
66
+ return true;
67
+ };
68
+ const CookieBanner = ({ categories, content, storageStrategy = 'localStorage' }) => {
69
+ const categoryKeys = categories.map(c => c.key);
70
+ const { consent, isSet, saveConsent, isInitialized } = useConsent(categoryKeys, storageStrategy);
59
71
  const [showSettings, setShowSettings] = useState(false);
60
72
  const [tempConsent, setTempConsent] = useState({});
61
- // Update tempConsent whenever consent changes
62
73
  useEffect(() => {
63
- setTempConsent(consent);
64
- }, [consent]);
65
- if (isSet)
74
+ if (isInitialized && !objectsEqual(tempConsent, consent)) {
75
+ setTempConsent(consent);
76
+ }
77
+ }, [consent, isInitialized]);
78
+ if (!isInitialized || isSet)
66
79
  return null;
67
80
  const updateTemp = (key, value) => {
68
- setTempConsent((prev) => (Object.assign(Object.assign({}, prev), { [key]: value })));
81
+ setTempConsent(prev => (Object.assign(Object.assign({}, prev), { [key]: value })));
69
82
  };
70
83
  const acceptAll = () => {
71
84
  const allTrue = { necessary: true };
72
- categoryKeys.forEach((key) => {
85
+ categoryKeys.forEach(key => {
73
86
  allTrue[key] = true;
74
87
  });
75
88
  saveConsent(allTrue);
@@ -79,7 +92,7 @@ const CookieBanner = ({ categories, content, storageStrategy }) => {
79
92
  };
80
93
  const acceptNecessaryOnly = () => {
81
94
  const necessaryOnly = { necessary: true };
82
- categoryKeys.forEach((key) => {
95
+ categoryKeys.forEach(key => {
83
96
  necessaryOnly[key] = false;
84
97
  });
85
98
  saveConsent(necessaryOnly);
@@ -90,6 +103,6 @@ const CookieBanner = ({ categories, content, storageStrategy }) => {
90
103
  const handleButtonLeave = (e) => {
91
104
  e.currentTarget.style.backgroundColor = '#111';
92
105
  };
93
- return (_jsx("div", { style: styles.cookieBanner, className: "njs-cookie-banner-container", children: !showSettings ? (_jsxs("div", { style: styles.cookieBannerBasic, className: "njs-cookie-banner-default", children: [_jsx("div", { style: styles.cookieBannerText, children: content || (_jsxs("p", { children: ["We use cookies to improve your experience.", ' ', _jsx("a", { href: "/privacy-policy", target: "_blank", rel: "noopener noreferrer", style: styles.cookieBannerTextLink, children: "Learn more" }), "."] })) }), _jsxs("div", { style: styles.cookieBannerButtons, className: "njs-cookie-banner-buttons", children: [_jsx("button", { className: "njs-cookie-banner-button-necessary", style: styles.cookieBannerButton, onMouseEnter: handleButtonHover, onMouseLeave: handleButtonLeave, onClick: acceptNecessaryOnly, children: "Only necessary" }), _jsx("button", { className: "njs-cookie-banner-button-settings", style: styles.cookieBannerButton, onMouseEnter: handleButtonHover, onMouseLeave: handleButtonLeave, onClick: () => setShowSettings(true), children: "Settings" }), _jsx("button", { className: "njs-cookie-banner-button-all", style: styles.cookieBannerButton, onMouseEnter: handleButtonHover, onMouseLeave: handleButtonLeave, onClick: acceptAll, children: "Accept all" })] })] })) : (_jsxs("div", { style: styles.cookieBannerSettings, className: "njs-cookie-banner-settings", children: [_jsx("h4", { className: "njs-cookie-banner-settings-heading", children: "Cookie Settings" }), _jsxs("label", { style: styles.cookieBannerSettingsLabel, className: "njs-cookie-banner-category", children: [_jsx("input", { type: "checkbox", checked: true, disabled: true }), "Necessary (always active)"] }), categories.map((cat) => (_jsxs("label", { style: styles.cookieBannerSettingsLabel, className: "njs-cookie-banner-category", children: [_jsx("input", { type: "checkbox", checked: tempConsent[cat.key] || false, onChange: (e) => updateTemp(cat.key, e.target.checked) }), cat.label] }, cat.key))), _jsxs("div", { style: styles.cookieBannerButtons, className: "njs-cookie-banner-buttons", children: [_jsx("button", { className: "njs-cookie-banner-button-save", style: styles.cookieBannerButton, onMouseEnter: handleButtonHover, onMouseLeave: handleButtonLeave, onClick: saveSelected, children: "Save" }), _jsx("button", { className: "njs-cookie-banner-button-back", style: styles.cookieBannerButton, onMouseEnter: handleButtonHover, onMouseLeave: handleButtonLeave, onClick: () => setShowSettings(false), children: "Back" })] })] })) }));
106
+ return (_jsx("div", { style: styles.cookieBanner, className: "njs-cookie-banner-container", children: !showSettings ? (_jsxs("div", { style: styles.cookieBannerBasic, children: [_jsx("div", { style: styles.cookieBannerText, children: content || (_jsxs("p", { children: ["We use cookies to improve your experience.", ' ', _jsx("a", { href: "/privacy-policy", target: "_blank", rel: "noopener noreferrer", style: styles.cookieBannerTextLink, children: "Learn more" }), "."] })) }), _jsxs("div", { style: styles.cookieBannerButtons, children: [_jsx("button", { style: styles.cookieBannerButton, onMouseEnter: handleButtonHover, onMouseLeave: handleButtonLeave, onClick: acceptNecessaryOnly, children: "Only necessary" }), _jsx("button", { style: styles.cookieBannerButton, onMouseEnter: handleButtonHover, onMouseLeave: handleButtonLeave, onClick: () => setShowSettings(true), children: "Settings" }), _jsx("button", { style: styles.cookieBannerButton, onMouseEnter: handleButtonHover, onMouseLeave: handleButtonLeave, onClick: acceptAll, children: "Accept all" })] })] })) : (_jsxs("div", { style: styles.cookieBannerSettings, children: [_jsx("h4", { children: "Cookie Settings" }), _jsxs("label", { style: styles.cookieBannerSettingsLabel, children: [_jsx("input", { type: "checkbox", checked: true, disabled: true }), "Necessary (always active)"] }), categories.map(cat => (_jsxs("label", { style: styles.cookieBannerSettingsLabel, children: [_jsx("input", { type: "checkbox", checked: tempConsent[cat.key] || false, onChange: e => updateTemp(cat.key, e.target.checked) }), cat.label] }, cat.key))), _jsxs("div", { style: styles.cookieBannerButtons, children: [_jsx("button", { style: styles.cookieBannerButton, onMouseEnter: handleButtonHover, onMouseLeave: handleButtonLeave, onClick: saveSelected, children: "Save" }), _jsx("button", { style: styles.cookieBannerButton, onMouseEnter: handleButtonHover, onMouseLeave: handleButtonLeave, onClick: () => setShowSettings(false), children: "Back" })] })] })) }));
94
107
  };
95
108
  export default CookieBanner;
@@ -1,7 +1,8 @@
1
- import { ConsentState, StorageStrategy } from './types';
2
- export declare function useConsent(categoryKeys: string[], storageStrategy?: StorageStrategy): {
1
+ import { ConsentState } from './types';
2
+ export declare const useConsent: (categoryKeys: string[], storageStrategy?: "localStorage" | "cookie") => {
3
3
  consent: ConsentState;
4
4
  isSet: boolean;
5
5
  saveConsent: (newConsent: ConsentState) => void;
6
+ isInitialized: boolean;
6
7
  };
7
8
  //# sourceMappingURL=useConsent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useConsent.d.ts","sourceRoot":"","sources":["../../src/useConsent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAExD,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,eAAe,GAAE,eAAgC;;;8BAqD/D,YAAY;EAQhD"}
1
+ {"version":3,"file":"useConsent.d.ts","sourceRoot":"","sources":["../../src/useConsent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AA0BvC,eAAO,MAAM,UAAU,GACnB,cAAc,MAAM,EAAE,EACtB,kBAAiB,cAAc,GAAG,QAAyB;;;8BAe1B,YAAY,KAAG,IAAI;;CAYvD,CAAC"}
@@ -1,56 +1,48 @@
1
1
  import { useState, useEffect } from 'react';
2
- export function useConsent(categoryKeys, storageStrategy = 'localStorage') {
3
- const storageKey = 'cookie-consent';
4
- const defaultConsent = Object.assign({ necessary: true }, categoryKeys.reduce((acc, key) => {
5
- acc[key] = false;
6
- return acc;
7
- }, {}));
8
- const getStoredConsent = () => {
9
- try {
10
- if (typeof window === 'undefined')
11
- return null; // SSR check
12
- if (storageStrategy === 'localStorage') {
13
- const stored = localStorage.getItem(storageKey);
14
- return stored ? JSON.parse(stored) : null;
15
- }
16
- else {
17
- const match = document.cookie.match(new RegExp('(^| )' + storageKey + '=([^;]+)'));
18
- return match ? JSON.parse(decodeURIComponent(match[2])) : null;
19
- }
20
- }
21
- catch (_a) {
22
- return null;
23
- }
24
- };
25
- const storeConsent = (consent) => {
26
- if (typeof window === 'undefined')
27
- return; // SSR check
28
- const encoded = JSON.stringify(consent);
29
- if (storageStrategy === 'localStorage') {
30
- localStorage.setItem(storageKey, encoded);
31
- }
32
- else {
33
- const expires = new Date();
34
- expires.setFullYear(expires.getFullYear() + 1);
35
- document.cookie = `${storageKey}=${encodeURIComponent(encoded)}; path=/; SameSite=Lax; expires=${expires.toUTCString()}`;
36
- }
37
- };
38
- const [consent, setConsent] = useState(defaultConsent);
2
+ const CONSENT_KEY = 'user_consent';
3
+ function getStoredConsent(strategy) {
4
+ var _a;
5
+ try {
6
+ const data = strategy === 'localStorage'
7
+ ? localStorage.getItem(CONSENT_KEY)
8
+ : decodeURIComponent(((_a = document.cookie.split('; ')
9
+ .find(row => row.startsWith(CONSENT_KEY + '='))) === null || _a === void 0 ? void 0 : _a.split('=')[1]) || '');
10
+ return data ? JSON.parse(data) : null;
11
+ }
12
+ catch (_b) {
13
+ return null;
14
+ }
15
+ }
16
+ function storeConsent(consent, strategy) {
17
+ const value = JSON.stringify(consent);
18
+ if (strategy === 'localStorage') {
19
+ localStorage.setItem(CONSENT_KEY, value);
20
+ }
21
+ else {
22
+ document.cookie = `${CONSENT_KEY}=${encodeURIComponent(value)}; path=/; max-age=31536000`;
23
+ }
24
+ }
25
+ export const useConsent = (categoryKeys, storageStrategy = 'localStorage') => {
26
+ const [consent, setConsent] = useState({});
39
27
  const [isSet, setIsSet] = useState(false);
28
+ const [isInitialized, setInitialized] = useState(false);
40
29
  useEffect(() => {
41
- const stored = getStoredConsent();
30
+ const stored = getStoredConsent(storageStrategy);
42
31
  if (stored) {
43
- // Merge stored consent with default consent to ensure all categories are present
44
- const mergedConsent = Object.assign(Object.assign({}, defaultConsent), stored);
45
- setConsent(mergedConsent);
32
+ setConsent(stored);
46
33
  setIsSet(true);
47
34
  }
48
- }, [categoryKeys.join(',')]); // Dependency auf categoryKeys um Re-render bei Änderungen zu triggern
35
+ setInitialized(true);
36
+ }, []);
49
37
  const saveConsent = (newConsent) => {
50
- const finalConsent = Object.assign(Object.assign({}, consent), newConsent);
51
- storeConsent(finalConsent);
52
- setConsent(finalConsent);
38
+ setConsent(newConsent);
53
39
  setIsSet(true);
40
+ storeConsent(newConsent, storageStrategy);
54
41
  };
55
- return { consent, isSet, saveConsent };
56
- }
42
+ return {
43
+ consent,
44
+ isSet,
45
+ saveConsent,
46
+ isInitialized
47
+ };
48
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nextjs-cookie-consent",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "GDPR-compliant cookie consent banner with fully customizable categories for Next.js",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",