feat(popup): add email capture popup with Mautic integration
Some checks failed
Build and Deploy / build (push) Has been cancelled
Some checks failed
Build and Deploy / build (push) Has been cancelled
- Email capture popup with scroll (10%) and exit intent triggers - First name field and full tracking (UTM, device, time on page) - Mautic API integration for contact creation - GeoIP detection for country/region - 4 locale support (sr, en, de, fr) - Mautic tracking script in layout
This commit is contained in:
102
src/components/home/ExitIntentDetector.tsx
Normal file
102
src/components/home/ExitIntentDetector.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
"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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user