@asafarim/react-privacy-consent
Version:
A comprehensive React TypeScript package for GDPR/CCPA privacy consent management with customizable UI components
2 lines • 18.2 kB
JavaScript
import {createContext,useRef,useEffect,useCallback,useState,useContext}from'react';import {jsx,jsxs,Fragment}from'react/jsx-runtime';var D={};function j(n){let e=typeof Storage<"u",t=useRef(n);useEffect(()=>{t.current=n;},[n]);let l=useCallback(s=>{if(!e){console.warn("Storage is not available, cannot save consent");return}try{if(!s||!s.decisions||!Array.isArray(s.decisions)||s.decisions.length===0){console.error("Cannot save invalid consent record",s);return}let a={...s,decisions:[...s.decisions]};D[t.current]=a;let u=JSON.stringify(a);console.log(`Saving consent to localStorage (key: ${t.current}):`,a),localStorage.setItem(t.current,u),sessionStorage.setItem(`${t.current}_backup`,u);}catch(a){console.error("Failed to save consent to localStorage:",a);}},[e]),g=useCallback(()=>{if(!e)return console.warn("Storage is not available, cannot load consent"),null;try{if(D[t.current])return console.log(`Using cached consent record for key: ${t.current}`),D[t.current];console.log(`Loading consent from localStorage (key: ${t.current})`);let s=localStorage.getItem(t.current);if(s||(console.log("No saved consent found in localStorage, checking sessionStorage backup"),s=sessionStorage.getItem(`${t.current}_backup`),s&&console.log("Found consent record in sessionStorage backup")),!s)return console.log("No saved consent found in any storage"),null;console.log("Found serialized consent record:",s.substring(0,100)+"...");let a=JSON.parse(s);if(console.log("Parsed consent record:",a),!a||!a.decisions||!Array.isArray(a.decisions)||!a.version||!a.sessionId||!a.lastUpdated)return console.warn("Consent record missing required fields, discarding",a),null;let u=["accepted","rejected","pending"],C=a.decisions.filter(d=>{let x=d&&d.categoryId&&typeof d.categoryId=="string"&&d.status&&u.indexOf(d.status)!==-1&&d.timestamp&&d.version;return x||console.warn("Invalid decision found:",d),x});if(C.length!==a.decisions.length&&console.warn("Some consent decisions were invalid and filtered out","Valid:",C.length,"Total:",a.decisions.length),C.length===0)return console.warn("No valid consent decisions found, discarding record"),null;let o={...a,lastUpdated:new Date(a.lastUpdated),decisions:C.map(d=>({...d,timestamp:new Date(d.timestamp)}))};return console.log("Successfully loaded consent record with",o.decisions.length,"valid decisions:",o.decisions.map(d=>`${d.categoryId}:${d.status}`).join(", ")),D[t.current]=o,o}catch(s){return console.warn("Failed to load consent from storage:",s),null}},[e]),i=useCallback(()=>{if(!e){console.warn("Storage is not available, cannot clear consent");return}try{console.log(`Clearing consent from storage (key: ${t.current})`),localStorage.removeItem(t.current),sessionStorage.removeItem(`${t.current}_backup`),delete D[t.current],console.log("Consent data cleared successfully");}catch(s){console.error("Failed to clear consent from storage:",s);}},[e]);return {saveConsent:l,loadConsent:g,clearConsent:i,isStorageAvailable:e}}function z(){return "session_"+Date.now()+"_"+Math.random().toString(36).substring(2,15)}function P(n,e,t,l){return {userId:l,sessionId:n,decisions:e,lastUpdated:new Date,version:t,userAgent:typeof navigator<"u"?navigator.userAgent:void 0}}function re(n,e){return !!(n&&n.version===e&&n.decisions&&Array.isArray(n.decisions)&&n.lastUpdated&&n.sessionId)}function ae(n,e){return n?n.decisions.find(l=>l.categoryId===e)?.status==="accepted":false}function ie(n,e){let t=[...n];return e.forEach(l=>{let g=t.findIndex(i=>i.categoryId===l.categoryId);g>=0?t[g]=l:t.push(l);}),t}function ce(n,e){if(!n.lastUpdated)return true;let t=new Date(n.lastUpdated);return t.setDate(t.getDate()+e),t<=new Date}function le(n){return {userId:n.userId,sessionId:n.sessionId,decisions:n.decisions.map(e=>({categoryId:e.categoryId,status:e.status,timestamp:new Date(e.timestamp),version:e.version})),lastUpdated:new Date(n.lastUpdated),version:n.version,ipAddress:n.ipAddress,userAgent:n.userAgent}}function $(n){let e=document.documentElement;e.style.setProperty("--consent-primary-color",n.primaryColor),e.style.setProperty("--consent-secondary-color",n.secondaryColor),e.style.setProperty("--consent-background-color",n.backgroundColor),e.style.setProperty("--consent-text-color",n.textColor),e.style.setProperty("--consent-border-color",n.borderColor),e.style.setProperty("--consent-border-radius",n.borderRadius),e.style.setProperty("--consent-font-family",n.fontFamily),e.style.setProperty("--consent-font-size",n.fontSize),e.style.setProperty("--consent-button-style",n.buttonStyle),e.style.setProperty("--consent-shadow",n.shadow?"0 4px 6px rgba(0, 0, 0, 0.1)":"none");}function de(){let n=document.documentElement;["--consent-primary-color","--consent-secondary-color","--consent-background-color","--consent-text-color","--consent-border-color","--consent-border-radius","--consent-font-family","--consent-font-size","--consent-button-style","--consent-shadow"].forEach(t=>{n.style.removeProperty(t);});}function ue(){return {primaryColor:"#007bff",secondaryColor:"#6c757d",backgroundColor:"#ffffff",textColor:"#212529",borderColor:"#dee2e6",borderRadius:"0.375rem",fontFamily:"system-ui, -apple-system, sans-serif",fontSize:"14px",buttonStyle:"solid",shadow:true}}function pe(){return {primaryColor:"#0d6efd",secondaryColor:"#adb5bd",backgroundColor:"#212529",textColor:"#ffffff",borderColor:"#495057",borderRadius:"0.375rem",fontFamily:"system-ui, -apple-system, sans-serif",fontSize:"14px",buttonStyle:"solid",shadow:true}}var W=createContext(void 0);function fe({children:n,config:e}){let[t,l]=useState(false),[g,i]=useState(false),[s,a]=useState(null),[u]=useState(()=>z()),C=useRef(false),{saveConsent:o,loadConsent:d,clearConsent:x}=j(e.settings.storageKey);useEffect(()=>{if(console.log("[ConsentProvider] Initializing with storage key:",e.settings.storageKey),(e.settings.version||e.settings.storageKey)&&(C.current=false),C.current){console.log("[ConsentProvider] Already initialized, skipping");return}console.log("[ConsentProvider] useEffect triggered - initializing consent"),console.log("[ConsentProvider] Config version:",e.settings.version),console.log("[ConsentProvider] Config categories:",e.settings.categories.map(v=>v.id));let r=d();if(console.log("Loaded consent from storage:",r?"found":"not found"),r&&r.version===e.settings.version){console.log("Consent version matches current version:",e.settings.version);let v=new Date(r.lastUpdated);if(v.setDate(v.getDate()+e.settings.expirationDays),v>new Date)if(console.log("Consent is not expired, valid until:",v),e.settings.categories.every(N=>r.decisions.some(k=>k.categoryId===N.id))){console.log("[ConsentProvider] All categories present in saved consent, using it",r.decisions),console.log("[ConsentProvider] Setting consent record to:",r),a(r),o(r),console.log("[ConsentProvider] Consent record set successfully"),C.current=true;return}else {console.log("[ConsentProvider] Some categories missing in saved consent, merging with defaults");let N=[...r.decisions];e.settings.categories.forEach(A=>{r.decisions.some(te=>te.categoryId===A.id)||N.push({categoryId:A.id,status:A.required||A.defaultValue?"accepted":"rejected",timestamp:new Date,version:e.settings.version});});let k=P(r.sessionId,N,e.settings.version);console.log("[ConsentProvider] Setting merged consent record:",k),a(k),o(k),C.current=true;return}else console.log("[ConsentProvider] Consent is expired, expired on:",v);}else console.log("[ConsentProvider] No valid consent found or version mismatch"),r&&(console.log("[ConsentProvider] Saved consent version:",r.version),console.log("[ConsentProvider] Expected version:",e.settings.version));console.log("[ConsentProvider] Creating default consent record");let c=e.settings.categories.map(v=>({categoryId:v.id,status:v.required||v.defaultValue?"accepted":"rejected",timestamp:new Date,version:e.settings.version})),p=P(u,c,e.settings.version);console.log("[ConsentProvider] Setting initial default consent record:",p),a(p),console.log("[ConsentProvider] Saving default record to localStorage"),o(p);let _=e.settings.autoShowDelay||0;setTimeout(()=>{(!r||r.version!==e.settings.version)&&(console.log("[ConsentProvider] Showing consent banner"),l(true),e.onBannerShow?.());},_),C.current=true;},[e.settings.version,e.settings.storageKey,e.settings.categories,e.settings.expirationDays,d,o,u,e.onBannerShow]),useEffect(()=>{e.theme&&$(e.theme);},[e.theme]),useEffect(()=>{if(e.settings.respectDoNotTrack&&navigator.doNotTrack==="1"){let r=P(u,e.settings.categories.map(c=>({categoryId:c.id,status:c.required?"accepted":"rejected",timestamp:new Date,version:e.settings.version})),e.settings.version);a(r),o(r),l(false);}},[e.settings,u,o]);let w=useCallback(()=>{l(true),e.onBannerShow?.();},[e]),h=useCallback(()=>{l(false),e.onBannerHide?.();},[e]),U=useCallback(()=>{i(true);},[]),V=useCallback(()=>{i(false);},[]),y=useCallback(r=>{let c=P(u,r,e.settings.version);return a(c),o(c),e.onConsentChange?.(c),c},[e,u,o]),M=useCallback((r,c)=>{if(!s)return;let p=s.decisions.map(_=>_.categoryId===r?{..._,status:c?"accepted":"rejected",timestamp:new Date}:_);y(p);},[s,y]),q=useCallback(()=>s,[s]),J=useCallback(r=>{if(!s)return false;let c=s.decisions.find(p=>p.categoryId===r);return c?c.status==="accepted":false},[s]),Q=useCallback(r=>J(r),[J]),X=useCallback(()=>{let r=e.settings.categories.map(p=>({categoryId:p.id,status:"accepted",timestamp:new Date,version:e.settings.version})),c=y(r);return h(),c},[e.settings.categories,e.settings.version,h,y]),Y=useCallback(()=>{let r=e.settings.categories.map(p=>({categoryId:p.id,status:p.required?"accepted":"rejected",timestamp:new Date,version:e.settings.version})),c=y(r);return h(),c},[e.settings.categories,e.settings.version,h,y]),Z=useCallback(()=>{console.log("Resetting consent to default state"),x();let r=e.settings.categories.map(p=>({categoryId:p.id,status:p.required||p.defaultValue?"accepted":"rejected",timestamp:new Date,version:e.settings.version})),c=P(u,r,e.settings.version);return a(c),o(c),l(true),e.onBannerShow?.(),c},[x,e,u,o]),ee=useCallback(r=>{if(!s)return "pending";let c=s.decisions.find(p=>p.categoryId===r);return c?c.status:"pending"},[s]),ne={isVisible:t,isPreferencesVisible:g,consentRecord:s,showBanner:w,hideBanner:h,showPreferences:U,hidePreferences:V,acceptAll:X,rejectAll:Y,getConsent:ee,resetConsent:Z,updateConsent:M,getAllConsent:q,hasConsent:Q,config:e};return jsx(W.Provider,{value:ne,children:n},u)}function L(){let n=useContext(W);if(n===void 0)throw new Error("useConsentContext must be used within a ConsentProvider");return n}function T(){return L()}function ve({className:n="",style:e={},onAcceptAll:t,onRejectAll:l,onManagePreferences:g,children:i}){let{isVisible:s,acceptAll:a,rejectAll:u,showPreferences:C,config:o}=T();if(!s)return null;let d=()=>{a(),t?.();},x=()=>{u(),l?.();},w=()=>{C(),g?.();},h=["consent-banner",`consent-banner--${o.banner.position}`,`consent-banner--${o.banner.layout}`,o.banner.animation?"consent-banner--animated":"",n].filter(Boolean).join(" ");return jsxs(Fragment,{children:[o.banner.backdrop&&jsx("div",{className:"consent-backdrop"}),jsx("div",{className:h,style:e,role:"dialog","aria-labelledby":"consent-title","aria-describedby":"consent-description",children:i||jsxs("div",{className:"consent-banner__content",children:[jsxs("div",{className:"consent-banner__text",children:[jsx("h3",{id:"consent-title",className:"consent-banner__title",children:o.texts.title}),jsx("p",{id:"consent-description",className:"consent-banner__description",children:o.texts.description}),(o.texts.learnMoreUrl||o.texts.privacyPolicyUrl)&&jsxs("div",{className:"consent-banner__links",children:[o.texts.learnMoreUrl&&jsx("a",{href:o.texts.learnMoreUrl,target:"_blank",rel:"noopener noreferrer",className:"consent-banner__link",children:o.texts.learnMoreText}),o.texts.privacyPolicyUrl&&jsx("a",{href:o.texts.privacyPolicyUrl,target:"_blank",rel:"noopener noreferrer",className:"consent-banner__link",children:"Privacy Policy"})]})]}),jsxs("div",{className:"consent-banner__actions",children:[o.settings.showAcceptAll&&jsx("button",{onClick:d,className:"consent-button consent-button--primary",type:"button",children:o.texts.acceptAllText}),o.settings.showDeclineAll&&jsx("button",{onClick:x,className:"consent-button consent-button--secondary",type:"button",children:o.texts.rejectAllText}),o.settings.showManagePreferences&&jsx("button",{onClick:w,className:"consent-button consent-button--ghost",type:"button",children:o.texts.managePreferencesText})]}),o.banner.showCloseButton&&jsx("button",{onClick:x,className:"consent-banner__close","aria-label":o.texts.closeText,type:"button",children:"\xD7"}),o.texts.poweredByText&&jsx("div",{className:"consent-banner__powered-by",children:o.texts.poweredByText})]})})]})}function K({checked:n,onChange:e,disabled:t=false,size:l="md",className:g="",label:i}){let s=["consent-toggle",`consent-toggle--${l}`,n?"consent-toggle--checked":"",t?"consent-toggle--disabled":"",g].filter(Boolean).join(" ");return jsxs("label",{className:s,children:[jsx("input",{type:"checkbox",checked:n,onChange:u=>{t||e(u.target.checked);},disabled:t,className:"consent-toggle__input","aria-label":i}),jsx("span",{className:"consent-toggle__slider"}),i&&jsx("span",{className:"consent-toggle__label",children:i})]})}function O({category:n,value:e,onChange:t,disabled:l=false,className:g=""}){let i=["consent-category",l?"consent-category--disabled":"",n.required?"consent-category--required":"",g].filter(Boolean).join(" ");return jsxs("div",{className:i,children:[jsxs("div",{className:"consent-category__header",children:[jsx("h4",{className:"consent-category__name",children:n.name}),jsx(K,{checked:e,onChange:t,disabled:l,size:"md"})]}),jsx("p",{className:"consent-category__description",children:n.description}),n.required&&jsx("span",{className:"consent-category__required-badge",children:"Required"})]})}function he({isOpen:n,onClose:e,className:t="",style:l={},showBackdrop:g=true}){let{config:i,consentRecord:s,updateConsent:a,acceptAll:u,rejectAll:C,hidePreferences:o,hideBanner:d,getConsent:x}=T();if(!n)return null;let w=()=>{o(),d(),e();},h=()=>{u(),e();},U=()=>{C(),e();},V=["consent-modal",t].filter(Boolean).join(" ");return jsxs(Fragment,{children:[g&&jsx("div",{className:"consent-modal__backdrop",onClick:e,role:"presentation"}),jsx("div",{className:V,style:l,role:"dialog","aria-labelledby":"consent-modal-title","aria-modal":"true",children:jsxs("div",{className:"consent-modal__content",children:[jsxs("div",{className:"consent-modal__header",children:[jsx("h2",{id:"consent-modal-title",className:"consent-modal__title",children:i.texts.managePreferencesText}),jsx("button",{onClick:e,className:"consent-modal__close","aria-label":i.texts.closeText,type:"button",children:"\xD7"})]}),jsxs("div",{className:"consent-modal__body",children:[jsx("p",{className:"consent-modal__description",children:i.texts.description}),jsx("div",{className:"consent-modal__categories",children:i.settings.categories.map(y=>{let M=x(y.id)==="accepted";return jsx(O,{category:y,value:M,onChange:q=>a(y.id,q),disabled:y.required},y.id)})}),(i.texts.privacyPolicyUrl||i.texts.cookiePolicyUrl)&&jsxs("div",{className:"consent-modal__links",children:[i.texts.privacyPolicyUrl&&jsx("a",{href:i.texts.privacyPolicyUrl,target:"_blank",rel:"noopener noreferrer",className:"consent-modal__link",children:"Privacy Policy"}),i.texts.cookiePolicyUrl&&jsx("a",{href:i.texts.cookiePolicyUrl,target:"_blank",rel:"noopener noreferrer",className:"consent-modal__link",children:"Cookie Policy"})]})]}),jsx("div",{className:"consent-modal__footer",children:jsxs("div",{className:"consent-modal__actions",children:[jsx("button",{onClick:w,className:"consent-button consent-button--primary",type:"button",children:i.texts.savePreferencesText}),i.settings.showAcceptAll&&jsx("button",{onClick:h,className:"consent-button consent-button--secondary",type:"button",children:i.texts.acceptAllText}),i.settings.showDeclineAll&&jsx("button",{onClick:U,className:"consent-button consent-button--ghost",type:"button",children:i.texts.rejectAllText})]})})]})})]})}var Se={categories:[{id:"necessary",name:"Necessary",description:"Essential cookies required for basic website functionality.",type:"necessary",required:true,defaultValue:true},{id:"analytics",name:"Analytics",description:"Cookies that help us understand how visitors interact with our website.",type:"analytics",required:false,defaultValue:false},{id:"marketing",name:"Marketing",description:"Cookies used to deliver personalized advertisements.",type:"marketing",required:false,defaultValue:false},{id:"preferences",name:"Preferences",description:"Cookies that remember your preferences and settings.",type:"preferences",required:false,defaultValue:false}],version:"1.0.0",expirationDays:365,storageKey:"asafarim-privacy-consent",showDeclineAll:true,showAcceptAll:true,showManagePreferences:true,autoShowDelay:1e3,respectDoNotTrack:true},we={position:"bottom",layout:"banner",showCloseButton:true,showCompanyLogo:false,blocking:false,animation:true,backdrop:false},_e={title:"We value your privacy",description:"We use cookies and similar technologies to provide the best experience on our website. Some are necessary for functionality, while others help us understand usage and improve our services.",acceptAllText:"Accept All",rejectAllText:"Reject All",managePreferencesText:"Manage Preferences",savePreferencesText:"Save Preferences",closeText:"Close",learnMoreText:"Learn More",poweredByText:"Powered by @asafarim/react-privacy-consent"},en={settings:Se,banner:we,texts:_e};export{ve as ConsentBanner,O as ConsentCategory,he as ConsentModal,fe as ConsentProvider,K as ConsentToggle,$ as applyConsentTheme,P as createConsentRecord,we as defaultBannerConfig,_e as defaultConsentTexts,en as defaultPrivacyConsentConfig,Se as defaultPrivacySettings,z as generateSessionId,ae as getConsentValue,pe as getDarkTheme,ue as getDefaultTheme,ce as hasExpiredConsent,re as isValidConsentRecord,ie as mergeConsentDecisions,de as removeConsentTheme,le as sanitizeConsentRecord,T as useConsent,L as useConsentContext,j as useConsentStorage};//# sourceMappingURL=index.mjs.map
//# sourceMappingURL=index.mjs.map