@@ -44,17 +44,18 @@ const EU_COUNTRIES = [
4444
4545export default function CookieConsent ( ) {
4646 const [ showBanner , setShowBanner ] = useState ( false )
47- const [ showSettings , setShowSettings ] = useState ( false )
47+
4848 const consentSettings = ( ( ) => {
4949 if ( typeof document === 'undefined' ) {
50- return { analytics : false , ads : false }
50+ return { analytics : false }
5151 }
5252 try {
5353 const stored = localStorage . getItem ( 'cookie_consent' )
54- if ( ! stored ) return { analytics : false , ads : false }
55- return JSON . parse ( stored ) as { analytics : boolean ; ads : boolean }
54+ if ( ! stored ) return { analytics : false }
55+ const parsed = JSON . parse ( stored )
56+ return { analytics : Boolean ( parsed . analytics ) }
5657 } catch {
57- return { analytics : false , ads : false }
58+ return { analytics : false }
5859 }
5960 } ) ( )
6061
@@ -82,26 +83,26 @@ export default function CookieConsent() {
8283 }
8384 }
8485
85- const updateGTMConsent = ( settings : { analytics : boolean ; ads : boolean } ) => {
86+ const updateGTMConsent = ( settings : { analytics : boolean } ) => {
8687 window . dataLayer = window . dataLayer || [ ]
8788 window . dataLayer . push ( {
8889 event : 'cookie_consent' ,
8990 consent : {
9091 analytics_storage : settings . analytics ? 'granted' : 'denied' ,
91- ad_storage : settings . ads ? 'granted' : 'denied' ,
92- ad_personalization : settings . ads ? 'granted' : 'denied' ,
92+ ad_storage : 'denied' ,
93+ ad_personalization : 'denied' ,
9394 } ,
9495 } )
9596
9697 if ( typeof window . gtag === 'function' ) {
9798 window . gtag ( 'consent' , 'update' , {
9899 analytics_storage : settings . analytics ? 'granted' : 'denied' ,
99- ad_storage : settings . ads ? 'granted' : 'denied' ,
100- ad_personalization : settings . ads ? 'granted' : 'denied' ,
100+ ad_storage : 'denied' ,
101+ ad_personalization : 'denied' ,
101102 } )
102103 }
103104
104- if ( settings . analytics || settings . ads ) {
105+ if ( settings . analytics ) {
105106 restoreGoogleScripts ( )
106107 } else {
107108 blockGoogleScripts ( )
@@ -110,8 +111,7 @@ export default function CookieConsent() {
110111
111112 useEffect ( ( ) => {
112113 const checkLocationAndSetConsent = async ( ) => {
113- // Only check location if no consent has been set yet
114- if ( ! consentSettings . analytics && ! consentSettings . ads ) {
114+ if ( ! consentSettings . analytics ) {
115115 try {
116116 const response = await fetch (
117117 'https://www.cloudflare.com/cdn-cgi/trace' ,
@@ -121,14 +121,12 @@ export default function CookieConsent() {
121121 const isEU = country ? EU_COUNTRIES . includes ( country ) : false
122122
123123 if ( isEU ) {
124- // Set default denied consent for EU users
125- const euConsent = { analytics : false , ads : false }
124+ const euConsent = { analytics : false }
126125 localStorage . setItem ( 'cookie_consent' , JSON . stringify ( euConsent ) )
127126 updateGTMConsent ( euConsent )
128127 setShowBanner ( true )
129128 } else {
130- // For non-EU users, set default accepted consent and don't show banner
131- const nonEuConsent = { analytics : true , ads : true }
129+ const nonEuConsent = { analytics : true }
132130 localStorage . setItem ( 'cookie_consent' , JSON . stringify ( nonEuConsent ) )
133131 updateGTMConsent ( nonEuConsent )
134132 setShowBanner ( false )
@@ -146,123 +144,44 @@ export default function CookieConsent() {
146144 // eslint-disable-next-line react-hooks/exhaustive-deps
147145 } , [ ] )
148146
149- const acceptAllCookies = ( ) => {
150- const consent = { analytics : true , ads : true }
147+ const acceptCookies = ( ) => {
148+ const consent = { analytics : true }
151149 localStorage . setItem ( 'cookie_consent' , JSON . stringify ( consent ) )
152150 updateGTMConsent ( consent )
153151 setShowBanner ( false )
154152 }
155153
156- const rejectAllCookies = ( ) => {
157- const consent = { analytics : false , ads : false }
154+ const rejectCookies = ( ) => {
155+ const consent = { analytics : false }
158156 localStorage . setItem ( 'cookie_consent' , JSON . stringify ( consent ) )
159157 updateGTMConsent ( consent )
160158 setShowBanner ( false )
161159 }
162160
163- const openSettings = ( ) => setShowSettings ( true )
164- const closeSettings = ( ) => setShowSettings ( false )
161+ if ( ! showBanner ) return null
165162
166163 return (
167- < >
168- { showBanner && (
169- < div
170- className = "fixed bottom-0 left-0 right-0 bg-white dark:bg-gray-800 p-4 z-50
171- text-sm gap-2 flex flex-col lg:flex-row [box-shadow:0_0_10px_rgba(0,0,0,0.2)]
172- items-center justify-between
173- "
174- >
175- < span className = "text-xs" >
176- We use cookies for site functionality, analytics, and ads{ ' ' }
177- < strong >
178- (which is a large part of how TanStack OSS remains free forever)
179- </ strong >
180- . See our{ ' ' }
181- < Link to = "/privacy" className = "underline" >
182- Privacy Policy
183- </ Link > { ' ' }
184- for details.
185- </ span >
186- < div className = "flex gap-2 flex-wrap items-center" >
187- < Button color = "red" onClick = { rejectAllCookies } >
188- Reject All
189- </ Button >
190- < Button color = "gray" onClick = { openSettings } >
191- Customize
192- </ Button >
193- < Button color = "emerald" onClick = { acceptAllCookies } >
194- Accept All
195- </ Button >
196- </ div >
197- </ div >
198- ) }
199-
200- { showSettings && (
201- < div className = "fixed inset-0 bg-black/50 flex items-center justify-center" >
202- < div className = "bg-white dark:bg-gray-800 p-6 rounded-lg shadow-lg max-w-md w-full mx-4" >
203- < h3 className = "text-lg font-bold mb-4" > Cookie Settings</ h3 >
204- < div className = "space-y-4" >
205- < div className = "flex items-start gap-2" >
206- < input
207- type = "checkbox"
208- id = "analytics-checkbox"
209- defaultChecked = { consentSettings . analytics }
210- onChange = { ( e ) => {
211- const updated = {
212- ...consentSettings ,
213- analytics : e . target . checked ,
214- }
215- localStorage . setItem (
216- 'cookie_consent' ,
217- JSON . stringify ( updated ) ,
218- )
219- updateGTMConsent ( updated )
220- } }
221- className = "mt-1"
222- />
223- < label htmlFor = "analytics-checkbox" className = "cursor-pointer" >
224- < span className = "font-medium" > Analytics</ span >
225- < p className = "text-sm text-gray-600 dark:text-gray-400" >
226- Track site usage anonymously
227- </ p >
228- </ label >
229- </ div >
230- < div className = "flex items-start gap-2" >
231- < input
232- type = "checkbox"
233- id = "ads-checkbox"
234- defaultChecked = { consentSettings . ads }
235- onChange = { ( e ) => {
236- const updated = {
237- ...consentSettings ,
238- ads : e . target . checked ,
239- }
240- if ( typeof document !== 'undefined' ) {
241- localStorage . setItem (
242- 'cookie_consent' ,
243- JSON . stringify ( updated ) ,
244- )
245- }
246- updateGTMConsent ( updated )
247- } }
248- className = "mt-1"
249- />
250- < label htmlFor = "ads-checkbox" className = "cursor-pointer" >
251- < span className = "font-medium" > Advertising</ span >
252- < p className = "text-sm text-gray-600 dark:text-gray-400" >
253- Show personalized ads
254- </ p >
255- </ label >
256- </ div >
257- < div className = "mt-6" >
258- < Button color = "emerald" onClick = { closeSettings } >
259- Save
260- </ Button >
261- </ div >
262- </ div >
263- </ div >
264- </ div >
265- ) }
266- </ >
164+ < div
165+ className = "fixed bottom-0 left-0 right-0 bg-white dark:bg-gray-800 p-4 z-50
166+ text-sm gap-2 flex flex-col lg:flex-row [box-shadow:0_0_10px_rgba(0,0,0,0.2)]
167+ items-center justify-between
168+ "
169+ >
170+ < span className = "text-xs" >
171+ We use cookies for analytics to help improve TanStack. See our{ ' ' }
172+ < Link to = "/privacy" className = "underline" >
173+ Privacy Policy
174+ </ Link > { ' ' }
175+ for details.
176+ </ span >
177+ < div className = "flex gap-2 flex-wrap items-center" >
178+ < Button color = "red" onClick = { rejectCookies } >
179+ Reject
180+ </ Button >
181+ < Button color = "emerald" onClick = { acceptCookies } >
182+ Accept
183+ </ Button >
184+ </ div >
185+ </ div >
267186 )
268187}
0 commit comments