103 lines
3.2 KiB
TypeScript
103 lines
3.2 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { useParams } from "next/navigation";
|
|
import { useScrollDepth } from "@/hooks/useScrollDepth";
|
|
import { useExitIntent } from "@/hooks/useExitIntent";
|
|
import { useVisitorStore } from "@/hooks/useVisitorStore";
|
|
import EmailCapturePopup from "./EmailCapturePopup";
|
|
import { useAnalytics } from "@/lib/analytics";
|
|
|
|
const SCROLL_POPUP_DELAY_MS = 5000;
|
|
|
|
export default function ExitIntentDetector() {
|
|
const params = useParams();
|
|
const locale = (params.locale as string) || "en";
|
|
const { trackPopupView } = useAnalytics();
|
|
|
|
const scrollTriggered = useScrollDepth(10);
|
|
const exitTriggered = useExitIntent();
|
|
const { canShowPopup, markPopupShown, markSubscribed } = useVisitorStore();
|
|
|
|
const [showPopup, setShowPopup] = useState(false);
|
|
const [trigger, setTrigger] = useState<"scroll" | "exit">("scroll");
|
|
const [country, setCountry] = useState("Unknown");
|
|
const [countryCode, setCountryCode] = useState("XX");
|
|
const [city, setCity] = useState("");
|
|
const [region, setRegion] = useState("");
|
|
const [isReady, setIsReady] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const fetchCountry = async () => {
|
|
try {
|
|
const response = await fetch("/api/geoip");
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
setCountry(data.country);
|
|
setCountryCode(data.countryCode);
|
|
setCity(data.city || "");
|
|
setRegion(data.region || "");
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to get country:", error);
|
|
}
|
|
setIsReady(true);
|
|
};
|
|
fetchCountry();
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
console.log("[ExitIntent] Scroll triggered:", scrollTriggered);
|
|
console.log("[ExitIntent] Exit triggered:", exitTriggered);
|
|
console.log("[ExitIntent] isReady:", isReady);
|
|
console.log("[ExitIntent] canShowPopup:", canShowPopup());
|
|
|
|
if (!isReady || !canShowPopup()) return;
|
|
|
|
let timer: NodeJS.Timeout;
|
|
|
|
if (scrollTriggered || exitTriggered) {
|
|
const newTrigger = exitTriggered ? "exit" : "scroll";
|
|
console.log("[ExitIntent] Trigger activated:", newTrigger);
|
|
setTrigger(newTrigger);
|
|
|
|
// Exit intent shows immediately, scroll has a delay
|
|
const delay = exitTriggered ? 0 : SCROLL_POPUP_DELAY_MS;
|
|
|
|
timer = setTimeout(() => {
|
|
console.log("[ExitIntent] Timer fired, checking canShowPopup again");
|
|
if (canShowPopup()) {
|
|
console.log("[ExitIntent] Showing popup!");
|
|
setShowPopup(true);
|
|
markPopupShown(newTrigger);
|
|
trackPopupView({ trigger: newTrigger, locale, country: countryCode });
|
|
}
|
|
}, delay);
|
|
}
|
|
|
|
return () => clearTimeout(timer);
|
|
}, [scrollTriggered, exitTriggered, isReady, canShowPopup, markPopupShown, trackPopupView, locale, countryCode]);
|
|
|
|
const handleClose = () => {
|
|
setShowPopup(false);
|
|
};
|
|
|
|
const handleSubscribe = () => {
|
|
markSubscribed();
|
|
};
|
|
|
|
if (!isReady) return null;
|
|
|
|
return (
|
|
<EmailCapturePopup
|
|
isOpen={showPopup}
|
|
onClose={handleClose}
|
|
onSubscribe={handleSubscribe}
|
|
trigger={trigger}
|
|
locale={locale}
|
|
country={country}
|
|
countryCode={countryCode}
|
|
/>
|
|
);
|
|
}
|