Files
wsa-website/components/ui/NavigationAdController.tsx
MR CYBER 515abc7bfa feat: fix homepage video, add AdSense banner/in-article ads, navigation ad refactor
- Fix VideoAdPlayer CSS conflict and YouTube API race condition
- Replace padding-bottom with aspect-video on homepage
- Add real AdSense slot IDs to all ad placements (4266907782 banner, 2044808434 in-article, 5341055619 PIP)
- AdFrame uses adSenseSlot from config instead of logical slot name
- AdFrame shows network name badge and 3 dot indicators for rotation
- Add InArticleAd component injecting ads every 4 paragraphs in blog posts
- Navigation ad: remove skip button, 5s countdown before Continue clickable
- Navigation ad: show on every page navigation (no counter)
- Navigation ad: square 400x400 ad area using PIP slot 5341055619
2026-07-23 20:50:23 -07:00

74 lines
2.0 KiB
TypeScript

"use client";
import { useState, useEffect, useCallback, useRef } from "react";
import { usePathname } from "next/navigation";
import NavigationAdOverlay from "./NavigationAdOverlay";
import { useNavigationAdConfig } from "@/hooks/useRuntimeConfig";
export default function NavigationAdController() {
const pathname = usePathname();
const navAd = useNavigationAdConfig();
const [showAd, setShowAd] = useState(false);
const [pendingPath, setPendingPath] = useState<string | null>(null);
const lastPathRef = useRef(pathname);
const isFirstMount = useRef(true);
useEffect(() => {
if (isFirstMount.current) {
isFirstMount.current = false;
lastPathRef.current = pathname;
return;
}
}, [pathname]);
useEffect(() => {
if (!navAd.enabled) return;
const handler = (url: string) => {
if (url === lastPathRef.current) return;
if (url.startsWith("#") || url.startsWith("javascript:")) return;
setPendingPath(url);
setShowAd(true);
return false;
};
const originalPush = window.history.pushState;
const originalReplace = window.history.replaceState;
window.history.pushState = function (...args) {
const result = originalPush.apply(this, args);
if (args[2] && typeof args[2] === "string") {
handler(args[2]);
}
return result;
};
window.history.replaceState = function (...args) {
return originalReplace.apply(this, args);
};
return () => {
window.history.pushState = originalPush;
window.history.replaceState = originalReplace;
};
}, [navAd.enabled]);
const handleAccept = useCallback(() => {
setShowAd(false);
if (pendingPath) {
lastPathRef.current = pendingPath;
window.history.pushState({}, "", pendingPath);
window.dispatchEvent(new PopStateEvent("popstate"));
setPendingPath(null);
}
}, [pendingPath]);
return (
<NavigationAdOverlay
visible={showAd}
onAccept={handleAccept}
/>
);
}