Last active 1751413089

dorsk revised this gist 1751413088. Go to revision

No changes

dorsk revised this gist 1751413077. Go to revision

1 file changed, 120 insertions

banner.tsx(file created)

@@ -0,0 +1,120 @@
1 + import { useCallback, useEffect, useState } from "react";
2 +
3 + // Check that the Enzuzo script has loaded
4 + // Polling is the only option for global variables that are not part of React
5 + function useEnzuzoLoaded() {
6 + const [isLoaded, setIsLoaded] = useState(false);
7 +
8 + useEffect(() => {
9 + if (isLoaded) return;
10 + const interval = setInterval(() => {
11 + if (typeof window !== "undefined" && window.__ENZUZO_STARTED__) {
12 + setIsLoaded(true);
13 + clearInterval(interval);
14 + }
15 + }, 1_000);
16 + return () => clearInterval(interval);
17 + }, [isLoaded]);
18 +
19 + return isLoaded;
20 + }
21 +
22 + // Hook to capture a single element
23 + function useCapturedElement<T extends HTMLElement>(selector: string) {
24 + const [element, setElement] = useState<T | null>(null);
25 + const [content, setContent] = useState<string>("");
26 + const isEnzuzoLoaded = useEnzuzoLoaded();
27 +
28 + useEffect(() => {
29 + if (!isEnzuzoLoaded) return;
30 + const el = document.querySelector(selector) as T | null;
31 + if (!el) return;
32 + setElement(el);
33 + setContent(el.textContent?.trim() || "");
34 + }, [selector, isEnzuzoLoaded]);
35 +
36 + const trigger = useCallback(() => {
37 + if (!element || !("click" in element)) return;
38 + const event = new MouseEvent("click", {
39 + bubbles: true,
40 + cancelable: true,
41 + view: window
42 + });
43 + element.dispatchEvent(event);
44 + }, [element]);
45 +
46 + return { element, content, trigger };
47 + }
48 +
49 + function AcceptButton() {
50 + const selector = "#ez-cookie-notification__accept";
51 + const { content, trigger } = useCapturedElement<HTMLButtonElement>(selector);
52 + return <button onClick={trigger}>{content}</button>;
53 + }
54 +
55 + function DeclineButton() {
56 + const selector = "#ez-cookie-notification__decline";
57 + const { content, trigger } = useCapturedElement<HTMLButtonElement>(selector);
58 + return <button onClick={trigger}>{content}</button>;
59 + }
60 +
61 + function SettingsButton() {
62 + const selector = "#notificationManagerLink";
63 + const { content, trigger } = useCapturedElement<HTMLButtonElement>(selector);
64 + return <button onClick={trigger}>{content}</button>;
65 + }
66 +
67 + function CloseButton() {
68 + const selector = "#close-notification";
69 + const { content, trigger } = useCapturedElement<HTMLButtonElement>(selector);
70 + return <button onClick={trigger}>{content}</button>;
71 + }
72 +
73 + function PrivacyPolicyLink() {
74 + const selector = "#notificationPolicyLink";
75 + const { element, content } = useCapturedElement<HTMLAnchorElement>(selector);
76 + return <a href={element?.href}>{content}</a>;
77 + }
78 +
79 + function CookieBannerText() {
80 + const selector = ".enzuzo-notification-desc p";
81 + const { content } = useCapturedElement<HTMLElement>(selector);
82 + return <p>{content}</p>;
83 + }
84 +
85 + export function CookieBanner() {
86 + const [isOpen, setIsOpen] = useState(true);
87 + const { element } = useCapturedElement<HTMLDivElement>("#ez-cookie-notification");
88 +
89 + useEffect(() => {
90 + if (!element) return;
91 + if (element.style.display !== "none") setIsOpen(true);
92 + element.style.display = "none";
93 + }, [element]);
94 +
95 + if (!isOpen) return null;
96 +
97 + const bannerStyles = {
98 + position: "fixed" as const,
99 + top: "16px",
100 + right: "16px",
101 + width: "500px",
102 + backgroundColor: "white",
103 + borderRadius: "8px",
104 + boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
105 + border: "2px solid red",
106 + padding: "24px",
107 + zIndex: 2147483647
108 + };
109 +
110 + return (
111 + <div style={bannerStyles}>
112 + <CloseButton />
113 + <CookieBannerText />
114 + <PrivacyPolicyLink />
115 + <SettingsButton />
116 + <AcceptButton />
117 + <DeclineButton />
118 + </div>
119 + );
120 + }
Newer Older