Keep AdSense rendering limited to anonymous visitors.
Show guest-only ad units on public pages and skip the AdSense script entirely for signed-in users.
This commit is contained in:
@@ -9,6 +9,7 @@ import ArtworkTags from '../components/artwork/ArtworkTags'
|
||||
import ArtworkDescription from '../components/artwork/ArtworkDescription'
|
||||
import ArtworkEvolutionPanel from '../components/artwork/ArtworkEvolutionPanel'
|
||||
import ArtworkComments from '../components/artwork/ArtworkComments'
|
||||
import AdSenseUnit from '../components/ads/AdSenseUnit'
|
||||
import ArtworkActionBar from '../components/artwork/ArtworkActionBar'
|
||||
import ArtworkDetailsPanel from '../components/artwork/ArtworkDetailsPanel'
|
||||
import CreatorSpotlight from '../components/artwork/CreatorSpotlight'
|
||||
@@ -319,6 +320,10 @@ function publisherToGroupSummary(publisher) {
|
||||
{/* Tags & categories */}
|
||||
<ArtworkTags artwork={artwork} />
|
||||
|
||||
{!isAuthenticated ? (
|
||||
<AdSenseUnit key={artwork.id} slot="4398418697" />
|
||||
) : null}
|
||||
|
||||
{/* Comments */}
|
||||
<ArtworkComments
|
||||
artworkId={artwork.id}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
|
||||
export default function AdSenseUnit({
|
||||
slot,
|
||||
client = 'ca-pub-6457864535683080',
|
||||
format = 'auto',
|
||||
className = '',
|
||||
enabled = true,
|
||||
}) {
|
||||
const pushed = useRef(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (!enabled || !slot || pushed.current) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
pushed.current = true
|
||||
|
||||
try {
|
||||
window.adsbygoogle = window.adsbygoogle || []
|
||||
window.adsbygoogle.push({})
|
||||
} catch {
|
||||
// AdSense may be blocked or not yet loaded (consent not granted).
|
||||
}
|
||||
|
||||
return undefined
|
||||
}, [enabled, slot])
|
||||
|
||||
if (!enabled || !slot) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={['flex w-full justify-center', className].filter(Boolean).join(' ')}>
|
||||
<ins
|
||||
className="adsbygoogle w-full max-w-3xl"
|
||||
style={{ display: 'block', textAlign: 'center' }}
|
||||
data-ad-client={client}
|
||||
data-ad-slot={slot}
|
||||
data-ad-format={format}
|
||||
data-full-width-responsive="true"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import React from 'react'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { cleanup, render } from '@testing-library/react'
|
||||
import AdSenseUnit from './AdSenseUnit'
|
||||
|
||||
describe('AdSenseUnit', () => {
|
||||
afterEach(() => {
|
||||
cleanup()
|
||||
vi.restoreAllMocks()
|
||||
delete window.adsbygoogle
|
||||
})
|
||||
|
||||
it('renders the dashboard horizontal slot and pushes once', () => {
|
||||
window.adsbygoogle = []
|
||||
|
||||
const { container } = render(<AdSenseUnit slot="8766048277" />)
|
||||
const unit = container.querySelector('ins.adsbygoogle')
|
||||
|
||||
expect(unit).not.toBeNull()
|
||||
expect(container.firstChild.className).toContain('justify-center')
|
||||
expect(unit.className).toContain('max-w-3xl')
|
||||
expect(unit.getAttribute('data-ad-client')).toBe('ca-pub-6457864535683080')
|
||||
expect(unit.getAttribute('data-ad-slot')).toBe('8766048277')
|
||||
expect(unit.getAttribute('data-ad-format')).toBe('auto')
|
||||
expect(unit.getAttribute('data-full-width-responsive')).toBe('true')
|
||||
expect(window.adsbygoogle).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('renders nothing without a slot', () => {
|
||||
const { container } = render(<AdSenseUnit />)
|
||||
|
||||
expect(container.querySelector('ins.adsbygoogle')).toBeNull()
|
||||
})
|
||||
|
||||
it('renders nothing when disabled for authenticated users', () => {
|
||||
window.adsbygoogle = []
|
||||
|
||||
const { container } = render(<AdSenseUnit slot="8766048277" enabled={false} />)
|
||||
|
||||
expect(container.querySelector('ins.adsbygoogle')).toBeNull()
|
||||
expect(window.adsbygoogle).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
@@ -209,6 +209,7 @@ export default function ArtworkActionBar({ artwork, stats, canonicalUrl, onStats
|
||||
const [reported, setReported] = useState(false)
|
||||
const [reportOpen, setReportOpen] = useState(false)
|
||||
const isLoggedIn = Boolean(artwork?.viewer?.is_authenticated)
|
||||
const downloadUnavailable = ['missing', 'pending'].includes(String(artwork?.download_status || '').toLowerCase())
|
||||
useEffect(() => {
|
||||
setFavorited(Boolean(artwork?.viewer?.is_favorited))
|
||||
}, [artwork?.id, artwork?.viewer?.is_favorited])
|
||||
@@ -404,7 +405,7 @@ export default function ArtworkActionBar({ artwork, stats, canonicalUrl, onStats
|
||||
</button>
|
||||
|
||||
{/* Download button */}
|
||||
<button
|
||||
{!downloadUnavailable && <button
|
||||
type="button"
|
||||
aria-label="Download artwork"
|
||||
onClick={handleDownload}
|
||||
@@ -413,7 +414,7 @@ export default function ArtworkActionBar({ artwork, stats, canonicalUrl, onStats
|
||||
>
|
||||
<DownloadArrowIcon />
|
||||
{downloading ? 'Downloading…' : 'Download'}
|
||||
</button>
|
||||
</button>}
|
||||
</div>
|
||||
|
||||
{/* ── Mobile fixed bottom bar ─────────────────────────────────── */}
|
||||
@@ -491,7 +492,7 @@ export default function ArtworkActionBar({ artwork, stats, canonicalUrl, onStats
|
||||
<FlagIcon />
|
||||
</button>
|
||||
|
||||
<button
|
||||
{!downloadUnavailable && <button
|
||||
type="button"
|
||||
aria-label="Download artwork"
|
||||
onClick={handleDownload}
|
||||
@@ -500,7 +501,7 @@ export default function ArtworkActionBar({ artwork, stats, canonicalUrl, onStats
|
||||
>
|
||||
<DownloadArrowIcon />
|
||||
{downloading ? '…' : 'Download'}
|
||||
</button>
|
||||
</button>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user