fix(ads): Fix logic for checking ad content presence in Ezoic components
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { runEzoic } from "@/lib/ezoic";
|
||||
|
||||
@@ -11,6 +11,8 @@ interface EzoicPlaceholderProps {
|
||||
export function EzoicPlaceholder({ id }: EzoicPlaceholderProps) {
|
||||
const t = useTranslations("common");
|
||||
const [isRendered, setIsRendered] = useState(false);
|
||||
const [hasAdContent, setHasAdContent] = useState(true);
|
||||
const placeholderRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// Render the placeholder div first, then tell Ezoic to fill it.
|
||||
@@ -25,14 +27,45 @@ export function EzoicPlaceholder({ id }: EzoicPlaceholderProps) {
|
||||
});
|
||||
});
|
||||
|
||||
// Observe the placeholder for ad content injection by Ezoic.
|
||||
// If nothing is injected after a timeout, hide the container
|
||||
// to avoid showing an empty white card.
|
||||
const el = document.getElementById(`ezoic-pub-ad-placeholder-${id}`);
|
||||
let observer: MutationObserver | undefined;
|
||||
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
||||
|
||||
if (el) {
|
||||
let filled = false;
|
||||
|
||||
observer = new MutationObserver(() => {
|
||||
if (el.childNodes.length > 0 || el.innerHTML.trim().length > 0) {
|
||||
filled = true;
|
||||
setHasAdContent(true);
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(el, { childList: true, subtree: true });
|
||||
|
||||
// If Ezoic doesn't fill the placeholder within 5s, hide it
|
||||
timeoutId = setTimeout(() => {
|
||||
if (!filled && el.childNodes.length === 0) {
|
||||
setHasAdContent(false);
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
return () => {
|
||||
cancelAnimationFrame(rafId);
|
||||
observer?.disconnect();
|
||||
if (timeoutId) clearTimeout(timeoutId);
|
||||
runEzoic(() => {
|
||||
window.ezstandalone?.destroyPlaceholders(id);
|
||||
});
|
||||
};
|
||||
}, [id]);
|
||||
|
||||
if (!hasAdContent) return null;
|
||||
|
||||
return (
|
||||
<div className="ezoic-ad-container group border rounded-[var(--radius)] overflow-hidden hover:border-foreground/20 transition-colors flex flex-col">
|
||||
<div className="px-3 py-1.5 border-b bg-muted/50">
|
||||
@@ -41,7 +74,7 @@ export function EzoicPlaceholder({ id }: EzoicPlaceholderProps) {
|
||||
</span>
|
||||
</div>
|
||||
<div className="ezoic-ad-content overflow-hidden flex items-center justify-center">
|
||||
{isRendered && <div id={`ezoic-pub-ad-placeholder-${id}`} />}
|
||||
{isRendered && <div id={`ezoic-pub-ad-placeholder-${id}`} ref={placeholderRef} />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useRef } from "react";
|
||||
import Script from "next/script";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { runEzoic } from "@/lib/ezoic";
|
||||
@@ -18,10 +18,17 @@ declare global {
|
||||
|
||||
export function EzoicAds() {
|
||||
const pathname = usePathname();
|
||||
const isFirstRender = useRef(true);
|
||||
|
||||
// Re-trigger ads on SPA route changes
|
||||
// Per Ezoic docs: destroyPlaceholders first, then showAds in next frame
|
||||
// Per Ezoic docs: destroyPlaceholders first, then showAds in next frame.
|
||||
// Skip the first render to avoid racing with individual EzoicPlaceholder
|
||||
// components that call showAds(id) on mount.
|
||||
useEffect(() => {
|
||||
if (isFirstRender.current) {
|
||||
isFirstRender.current = false;
|
||||
return;
|
||||
}
|
||||
runEzoic(() => {
|
||||
window.ezstandalone?.destroyPlaceholders();
|
||||
requestAnimationFrame(() => {
|
||||
|
||||
Reference in New Issue
Block a user