|
1 | 1 | import clsx from 'clsx'; |
2 | | -import React, { type ReactNode, useEffect, useMemo, useState } from 'react'; |
| 2 | +import { type ReactNode, useEffect, useMemo, useState } from 'react'; |
3 | 3 |
|
4 | 4 | import HandIcon from '../HandIcon'; |
5 | 5 | import styles from './styles.module.css'; |
6 | 6 |
|
| 7 | +declare global { |
| 8 | + interface Window { |
| 9 | + dataLayer?: unknown[]; |
| 10 | + } |
| 11 | +} |
| 12 | + |
7 | 13 | type Promo = { |
8 | 14 | key: string; |
9 | 15 | href: string; |
@@ -45,11 +51,44 @@ const PROMOS: readonly Promo[] = [ |
45 | 51 | }, |
46 | 52 | ]; |
47 | 53 |
|
48 | | -export default function TopPromoRotator() { |
| 54 | +// bump when adding promos so users who dismissed banner see the new one |
| 55 | +export const PROMO_VERSION = 1; |
| 56 | + |
| 57 | +type Props = { |
| 58 | + onClose?: () => void; |
| 59 | +}; |
| 60 | + |
| 61 | +export default function TopPromoRotator({ onClose }: Props) { |
49 | 62 | const promos = useMemo(() => PROMOS, []); |
50 | 63 |
|
51 | 64 | const [index, setIndex] = useState(0); |
52 | 65 |
|
| 66 | + useEffect(() => { |
| 67 | + if (typeof window === 'undefined' || typeof document === 'undefined') { |
| 68 | + return; |
| 69 | + } |
| 70 | + |
| 71 | + const existingScript = document.querySelector<HTMLScriptElement>( |
| 72 | + 'script[src*="www.googletagmanager.com/gtm.js?id=GTM-WV2G3SQL"]' |
| 73 | + ); |
| 74 | + |
| 75 | + if (existingScript) return; |
| 76 | + |
| 77 | + (function (w: Window, d: Document, s: string, l: string, i: string) { |
| 78 | + w.dataLayer = w.dataLayer || []; |
| 79 | + w.dataLayer.push({ |
| 80 | + 'gtm.start': new Date().getTime(), |
| 81 | + event: 'gtm.js', |
| 82 | + }); |
| 83 | + const f = d.getElementsByTagName(s)[0] as HTMLScriptElement; |
| 84 | + const j = d.createElement(s) as HTMLScriptElement; |
| 85 | + const dl = l !== 'dataLayer' ? `&l=${l}` : ''; |
| 86 | + j.async = true; |
| 87 | + j.src = `https://www.googletagmanager.com/gtm.js?id=${i}${dl}`; |
| 88 | + f.parentNode?.insertBefore(j, f); |
| 89 | + })(window, document, 'script', 'dataLayer', 'GTM-WV2G3SQL'); |
| 90 | + }, []); |
| 91 | + |
53 | 92 | useEffect(() => { |
54 | 93 | const id = window.setInterval(() => { |
55 | 94 | setIndex(i => (i + 1) % promos.length); |
@@ -89,6 +128,15 @@ export default function TopPromoRotator() { |
89 | 128 | </a> |
90 | 129 | ))} |
91 | 130 | </div> |
| 131 | + {onClose && ( |
| 132 | + <button |
| 133 | + type="button" |
| 134 | + className={styles.closeButton} |
| 135 | + aria-label="Close promotion banner" |
| 136 | + onClick={onClose}> |
| 137 | + × |
| 138 | + </button> |
| 139 | + )} |
92 | 140 | <span className="sr-only"> |
93 | 141 | {typeof active.label === 'string' ? active.label : ''} |
94 | 142 | </span> |
|
0 commit comments