From 8440ecc2b7ae2e6eb4112281878dba727a108525 Mon Sep 17 00:00:00 2001 From: Adrian Czerwiec Date: Wed, 18 Feb 2026 14:26:41 +0100 Subject: [PATCH 1/8] add promo widget --- .../web/src/components/PromoWidget.tsx | 160 ++++++++++++++++++ deep-sea-stories/packages/web/src/main.tsx | 68 ++++---- .../packages/web/src/views/GameView.tsx | 108 ++++++------ 3 files changed, 251 insertions(+), 85 deletions(-) create mode 100644 deep-sea-stories/packages/web/src/components/PromoWidget.tsx diff --git a/deep-sea-stories/packages/web/src/components/PromoWidget.tsx b/deep-sea-stories/packages/web/src/components/PromoWidget.tsx new file mode 100644 index 0000000..8874773 --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/PromoWidget.tsx @@ -0,0 +1,160 @@ +import { useEffect, useRef, useState } from "react"; +import { Button } from "./ui/button"; + +const PROMO_CODE = "DEEPSEA26"; +const PROMO_URL = "https://fishjam.swmansion.com/?utm_source=deep-sea-stories"; +const DISMISS_STORAGE_KEY = "promo-widget-dismissed"; +const PROMO_HIDE_AFTER = new Date("2026-03-19T00:00:00Z"); + +const readDismissedFromStorage = () => { + if (typeof window === "undefined") return false; + return window.localStorage.getItem(DISMISS_STORAGE_KEY) === "true"; +}; + +const PromoWidget = () => { + const [promoVisible, setPromoVisible] = useState(false); + const [dismissed, setDismissed] = useState(readDismissedFromStorage); + const [copied, setCopied] = useState(false); + const [isExpired] = useState(() => Date.now() >= PROMO_HIDE_AFTER.getTime()); + const copyResetRef = useRef(null); + + useEffect(() => { + return () => { + if (copyResetRef.current) { + window.clearTimeout(copyResetRef.current); + } + }; + }, []); + + useEffect(() => { + if (typeof window === "undefined") return; + if (dismissed) { + window.localStorage.setItem(DISMISS_STORAGE_KEY, "true"); + } + }, [dismissed]); + + const triggerCopiedFeedback = () => { + setCopied(true); + if (copyResetRef.current) { + window.clearTimeout(copyResetRef.current); + } + copyResetRef.current = window.setTimeout(() => setCopied(false), 2000); + }; + + const fallbackCopy = () => { + if (typeof document === "undefined") return; + const textarea = document.createElement("textarea"); + textarea.value = PROMO_CODE; + textarea.style.position = "fixed"; + textarea.style.opacity = "0"; + document.body.appendChild(textarea); + textarea.focus(); + textarea.select(); + document.execCommand("copy"); + document.body.removeChild(textarea); + triggerCopiedFeedback(); + }; + + const handleCopy = async () => { + try { + if (navigator.clipboard?.writeText) { + await navigator.clipboard.writeText(PROMO_CODE); + triggerCopiedFeedback(); + return; + } + } catch (error) { + console.warn("Failed to copy using clipboard API, falling back.", error); + } + + fallbackCopy(); + }; + + const handleDismiss = () => { + setDismissed(true); + }; + + if (dismissed || isExpired) { + return null; + } + + return ( +
+
+ + +
+
+

+ Powered by +

+ + Fishjam + +

+ The realtime infrastructure behind Deep Sea Stories. +
+ Build AI-first audio and video experiences without touching WebRTC + internals. +

+
+ +
+

+ Save 25% on your first three months of Regular Jar plan. +

+
+ + {promoVisible ? ( +
+
+ Promo code +
+
+ + {PROMO_CODE} + + +
+
+ ) : ( + + )} + + Redeem at fishjam.swmansion.com + +
+
+
+ ); +}; + +export default PromoWidget; diff --git a/deep-sea-stories/packages/web/src/main.tsx b/deep-sea-stories/packages/web/src/main.tsx index 1cebfbd..7dead47 100644 --- a/deep-sea-stories/packages/web/src/main.tsx +++ b/deep-sea-stories/packages/web/src/main.tsx @@ -1,38 +1,42 @@ -import { FishjamProvider } from '@fishjam-cloud/react-client'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { StrictMode } from 'react'; -import { createRoot } from 'react-dom/client'; -import { TRPCClientProvider } from './contexts/trpc.tsx'; -import './index.css'; -import { BrowserRouter, Route, Routes } from 'react-router'; -import Layout from './Layout.tsx'; -import HomeView from './views/HomeView.tsx'; -import RoomView from './views/RoomView.tsx'; +import { FishjamProvider } from "@fishjam-cloud/react-client"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import { TRPCClientProvider } from "./contexts/trpc.tsx"; +import "./index.css"; +import { BrowserRouter, Route, Routes } from "react-router"; +import Layout from "./Layout.tsx"; +import HomeView from "./views/HomeView.tsx"; +import RoomView from "./views/RoomView.tsx"; +import PromoWidget from "./components/PromoWidget.tsx"; const queryClient = new QueryClient({ - defaultOptions: { - queries: { - retryDelay: 2000, - }, - }, + defaultOptions: { + queries: { + retryDelay: 2000, + }, + }, }); // biome-ignore lint/style/noNonNullAssertion: root always exists -createRoot(document.getElementById('root')!).render( - - - - - - - - } /> - } /> - - - - - - - , +createRoot(document.getElementById("root")!).render( + + + + + + + + } /> + } /> + + +
+ +
+
+
+
+
+
, ); diff --git a/deep-sea-stories/packages/web/src/views/GameView.tsx b/deep-sea-stories/packages/web/src/views/GameView.tsx index 9a1cf61..808f2fc 100644 --- a/deep-sea-stories/packages/web/src/views/GameView.tsx +++ b/deep-sea-stories/packages/web/src/views/GameView.tsx @@ -1,68 +1,70 @@ -import { usePeers } from '@fishjam-cloud/react-client'; -import type { FC } from 'react'; -import { useEffect, useMemo, useRef, useState } from 'react'; -import GameControlPanel from '@/components/GameControlPanel'; -import PeerGrid from '@/components/PeerGrid'; -import { PlayerCountIndicator } from '@/components/PlayerCountIndicator'; +import { usePeers } from "@fishjam-cloud/react-client"; +import type { FC } from "react"; +import { useEffect, useMemo, useRef, useState } from "react"; +import GameControlPanel from "@/components/GameControlPanel"; +import PeerGrid from "@/components/PeerGrid"; +import { PlayerCountIndicator } from "@/components/PlayerCountIndicator"; +import PromoWidget from "@/components/PromoWidget"; export type GameViewProps = { - roomId: string; + roomId: string; }; const GameView: FC = ({ roomId }) => { - const { remotePeers, localPeer } = usePeers<{ name: string }>(); - const agentAudioRef = useRef(null); - const [volume, setVolume] = useState(1); + const { remotePeers, localPeer } = usePeers<{ name: string }>(); + const agentAudioRef = useRef(null); + const [volume, setVolume] = useState(1); - const displayedPeers = useMemo( - () => remotePeers.filter((peer) => peer.metadata), - [remotePeers], - ); + const displayedPeers = useMemo( + () => remotePeers.filter((peer) => peer.metadata), + [remotePeers], + ); - const agentPeer = useMemo( - () => remotePeers.find((peer) => !peer.metadata), - [remotePeers], - ); + const agentPeer = useMemo( + () => remotePeers.find((peer) => !peer.metadata), + [remotePeers], + ); - useEffect(() => { - if (!agentAudioRef.current) return; - const audioStream = agentPeer?.tracks[0]?.stream; - agentAudioRef.current.srcObject = audioStream ?? null; - }, [agentPeer?.tracks[0]?.stream]); + useEffect(() => { + if (!agentAudioRef.current) return; + const audioStream = agentPeer?.tracks[0]?.stream; + agentAudioRef.current.srcObject = audioStream ?? null; + }, [agentPeer?.tracks[0]?.stream]); - useEffect(() => { - if (agentAudioRef.current) { - agentAudioRef.current.volume = volume; - } - }, [volume]); + useEffect(() => { + if (agentAudioRef.current) { + agentAudioRef.current.volume = volume; + } + }, [volume]); - const userName = localPeer?.metadata?.peer?.name ?? 'Unknown'; - const playerCount = (localPeer ? 1 : 0) + displayedPeers.length; + const userName = localPeer?.metadata?.peer?.name ?? "Unknown"; + const playerCount = (localPeer ? 1 : 0) + displayedPeers.length; - return ( -
- + return ( +
+ -
-
- -
- -
+
+
+ +
- {/* biome-ignore lint/a11y/useMediaCaption: Peer audio feed from WebRTC doesn't have captions */} -
- ); + +
+ + {/* biome-ignore lint/a11y/useMediaCaption: Peer audio feed from WebRTC doesn't have captions */} +
+ ); }; export default GameView; From 3d792168942a771bdd3bb404db9c2d6e3c1e0cc9 Mon Sep 17 00:00:00 2001 From: Adrian Czerwiec Date: Wed, 18 Feb 2026 14:27:52 +0100 Subject: [PATCH 2/8] edit promo code --- deep-sea-stories/packages/web/src/components/PromoWidget.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deep-sea-stories/packages/web/src/components/PromoWidget.tsx b/deep-sea-stories/packages/web/src/components/PromoWidget.tsx index 8874773..5a95c73 100644 --- a/deep-sea-stories/packages/web/src/components/PromoWidget.tsx +++ b/deep-sea-stories/packages/web/src/components/PromoWidget.tsx @@ -1,7 +1,7 @@ import { useEffect, useRef, useState } from "react"; import { Button } from "./ui/button"; -const PROMO_CODE = "DEEPSEA26"; +const PROMO_CODE = "DeepSea25"; const PROMO_URL = "https://fishjam.swmansion.com/?utm_source=deep-sea-stories"; const DISMISS_STORAGE_KEY = "promo-widget-dismissed"; const PROMO_HIDE_AFTER = new Date("2026-03-19T00:00:00Z"); From cfa359301f3ea160102f338f0b18954d8e7a3750 Mon Sep 17 00:00:00 2001 From: Adrian Czerwiec Date: Wed, 18 Feb 2026 15:25:12 +0100 Subject: [PATCH 3/8] add promo analytics --- deep-sea-stories/packages/web/package.json | 1 + .../packages/web/src/components/PromoWidget.tsx | 13 ++++++++++++- deep-sea-stories/packages/web/src/types/window.d.ts | 9 +++++++++ deep-sea-stories/packages/web/src/window.d.ts | 7 +++++++ deep-sea-stories/yarn.lock | 8 ++++++++ 5 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 deep-sea-stories/packages/web/src/types/window.d.ts create mode 100644 deep-sea-stories/packages/web/src/window.d.ts diff --git a/deep-sea-stories/packages/web/package.json b/deep-sea-stories/packages/web/package.json index 6141245..4e6f98a 100644 --- a/deep-sea-stories/packages/web/package.json +++ b/deep-sea-stories/packages/web/package.json @@ -23,6 +23,7 @@ "@trpc/client": "^11.6.0", "@trpc/server": "^11.6.0", "@trpc/tanstack-react-query": "^11.6.0", + "@types/gtag.js": "^0.0.20", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.544.0", diff --git a/deep-sea-stories/packages/web/src/components/PromoWidget.tsx b/deep-sea-stories/packages/web/src/components/PromoWidget.tsx index 5a95c73..e14b7cc 100644 --- a/deep-sea-stories/packages/web/src/components/PromoWidget.tsx +++ b/deep-sea-stories/packages/web/src/components/PromoWidget.tsx @@ -6,6 +6,10 @@ const PROMO_URL = "https://fishjam.swmansion.com/?utm_source=deep-sea-stories"; const DISMISS_STORAGE_KEY = "promo-widget-dismissed"; const PROMO_HIDE_AFTER = new Date("2026-03-19T00:00:00Z"); +const PROMO_DISMISSED_EVENT = "promo_dismissed"; +const PROMO_CODE_DISPLAYED_EVENT = "promo_code_displayed"; +const PROMO_CODE_COPIED_EVENT = "promo_code_copied"; + const readDismissedFromStorage = () => { if (typeof window === "undefined") return false; return window.localStorage.getItem(DISMISS_STORAGE_KEY) === "true"; @@ -55,9 +59,15 @@ const PromoWidget = () => { triggerCopiedFeedback(); }; + const handleGetPromo = () => { + window.gtag("event", PROMO_CODE_DISPLAYED_EVENT, {}); + setPromoVisible(true); + }; + const handleCopy = async () => { try { if (navigator.clipboard?.writeText) { + window.gtag("event", PROMO_CODE_COPIED_EVENT, {}); await navigator.clipboard.writeText(PROMO_CODE); triggerCopiedFeedback(); return; @@ -70,6 +80,7 @@ const PromoWidget = () => { }; const handleDismiss = () => { + window.gtag("event", PROMO_DISMISSED_EVENT); setDismissed(true); }; @@ -137,7 +148,7 @@ const PromoWidget = () => { ) : ( - -
-
-

- Powered by -

-
- Fishjam - -

- The realtime infrastructure behind Deep Sea Stories. -
- Build AI-first audio and video experiences without touching WebRTC - internals. -

-
- -
-

- Save 25% on your first three months of Regular Jar plan. -

-
- - {promoVisible ? ( -
-
- Promo code -
-
- - {PROMO_CODE} - - -
-
- ) : ( - - )} - - Redeem at fishjam.swmansion.com - -
- - - ); + const [promoVisible, setPromoVisible] = useState(false); + const [dismissed, setDismissed] = useState(readDismissedFromStorage); + const [copied, setCopied] = useState(false); + + const copyResetRef = useRef(null); + + useEffect(() => { + return () => { + if (copyResetRef.current) { + window.clearTimeout(copyResetRef.current); + } + }; + }, []); + + useEffect(() => { + if (typeof window === 'undefined') return; + if (dismissed) { + window.localStorage.setItem(DISMISS_STORAGE_KEY, 'true'); + } + }, [dismissed]); + + const triggerCopiedFeedback = () => { + setCopied(true); + if (copyResetRef.current) { + window.clearTimeout(copyResetRef.current); + } + copyResetRef.current = window.setTimeout(() => setCopied(false), 2000); + }; + + const fallbackCopy = () => { + if (typeof document === 'undefined') return; + const textarea = document.createElement('textarea'); + textarea.value = PROMO_CODE; + textarea.style.position = 'fixed'; + textarea.style.opacity = '0'; + document.body.appendChild(textarea); + textarea.focus(); + textarea.select(); + document.execCommand('copy'); + document.body.removeChild(textarea); + triggerCopiedFeedback(); + }; + + const handleGetPromo = () => { + sendGAEvent(PROMO_CODE_DISPLAYED_EVENT); + setPromoVisible(true); + }; + + const handleCopy = async () => { + try { + if (navigator.clipboard?.writeText) { + sendGAEvent(PROMO_CODE_COPIED_EVENT); + await navigator.clipboard.writeText(PROMO_CODE); + triggerCopiedFeedback(); + return; + } + } catch (error) { + console.warn('Failed to copy using clipboard API, falling back.', error); + } + + fallbackCopy(); + }; + + const handleDismiss = () => { + sendGAEvent(PROMO_DISMISSED_EVENT); + setDismissed(true); + }; + + if (dismissed || isExpired) { + return null; + } + + return ( +
+
+ + +
+
+

+ Powered by +

+ + Fishjam + +

+ The realtime infrastructure behind Deep Sea Stories. +
+ Build AI-first audio and video experiences without touching WebRTC + internals. +

+
+ +
+

+ Save 25% on your first three months of Regular Jar plan. +

+
+ + {promoVisible ? ( +
+
+ Promo code +
+
+ + {PROMO_CODE} + + +
+
+ ) : ( + + )} + + Redeem at fishjam.swmansion.com + +
+
+
+ ); }; export default PromoWidget; diff --git a/deep-sea-stories/packages/web/src/main.tsx b/deep-sea-stories/packages/web/src/main.tsx index 2c9ca0e..7e3b775 100644 --- a/deep-sea-stories/packages/web/src/main.tsx +++ b/deep-sea-stories/packages/web/src/main.tsx @@ -1,42 +1,42 @@ -import { FishjamProvider } from "@fishjam-cloud/react-client"; -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import { StrictMode } from "react"; -import { createRoot } from "react-dom/client"; -import { TRPCClientProvider } from "./contexts/trpc.tsx"; -import "./index.css"; -import { BrowserRouter, Route, Routes } from "react-router"; -import Layout from "./Layout.tsx"; -import HomeView from "./views/HomeView.tsx"; -import RoomView from "./views/RoomView.tsx"; -import PromoWidget from "./components/PromoWidget.tsx"; +import { FishjamProvider } from '@fishjam-cloud/react-client'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; +import { TRPCClientProvider } from './contexts/trpc.tsx'; +import './index.css'; +import { BrowserRouter, Route, Routes } from 'react-router'; +import Layout from './Layout.tsx'; +import HomeView from './views/HomeView.tsx'; +import RoomView from './views/RoomView.tsx'; +import PromoWidget from './components/PromoWidget.tsx'; const queryClient = new QueryClient({ - defaultOptions: { - queries: { - retryDelay: 2000, - }, - }, + defaultOptions: { + queries: { + retryDelay: 2000, + }, + }, }); // biome-ignore lint/style/noNonNullAssertion: root always exists -createRoot(document.getElementById("root")!).render( - - - - - - - - } /> - } /> - - -
- -
-
-
-
-
-
, +createRoot(document.getElementById('root')!).render( + + + + + + + + } /> + } /> + + +
+ +
+
+
+
+
+
, ); diff --git a/deep-sea-stories/packages/web/src/types/window.d.ts b/deep-sea-stories/packages/web/src/types/window.d.ts index 0aef9ec..786b646 100644 --- a/deep-sea-stories/packages/web/src/types/window.d.ts +++ b/deep-sea-stories/packages/web/src/types/window.d.ts @@ -1,9 +1,9 @@ -import type { Gtag } from "gtag.js"; +import type { Gtag } from 'gtag.js'; declare global { - interface Window { - gtag: Gtag.Gtag; - } + interface Window { + gtag: Gtag.Gtag; + } } export {}; diff --git a/deep-sea-stories/packages/web/src/views/GameView.tsx b/deep-sea-stories/packages/web/src/views/GameView.tsx index 464e526..da3855e 100644 --- a/deep-sea-stories/packages/web/src/views/GameView.tsx +++ b/deep-sea-stories/packages/web/src/views/GameView.tsx @@ -1,69 +1,69 @@ -import { usePeers } from "@fishjam-cloud/react-client"; -import type { FC } from "react"; -import { useEffect, useMemo, useRef, useState } from "react"; -import GameControlPanel from "@/components/GameControlPanel"; -import PeerGrid from "@/components/PeerGrid"; -import { PlayerCountIndicator } from "@/components/PlayerCountIndicator"; +import { usePeers } from '@fishjam-cloud/react-client'; +import type { FC } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; +import GameControlPanel from '@/components/GameControlPanel'; +import PeerGrid from '@/components/PeerGrid'; +import { PlayerCountIndicator } from '@/components/PlayerCountIndicator'; export type GameViewProps = { - roomId: string; + roomId: string; }; const GameView: FC = ({ roomId }) => { - const { remotePeers, localPeer } = usePeers<{ name: string }>(); - const agentAudioRef = useRef(null); - const [volume, setVolume] = useState(1); + const { remotePeers, localPeer } = usePeers<{ name: string }>(); + const agentAudioRef = useRef(null); + const [volume, setVolume] = useState(1); - const displayedPeers = useMemo( - () => remotePeers.filter((peer) => peer.metadata), - [remotePeers], - ); + const displayedPeers = useMemo( + () => remotePeers.filter((peer) => peer.metadata), + [remotePeers], + ); - const agentPeer = useMemo( - () => remotePeers.find((peer) => !peer.metadata), - [remotePeers], - ); + const agentPeer = useMemo( + () => remotePeers.find((peer) => !peer.metadata), + [remotePeers], + ); - useEffect(() => { - if (!agentAudioRef.current) return; - const audioStream = agentPeer?.tracks[0]?.stream; - agentAudioRef.current.srcObject = audioStream ?? null; - }, [agentPeer?.tracks[0]?.stream]); + useEffect(() => { + if (!agentAudioRef.current) return; + const audioStream = agentPeer?.tracks[0]?.stream; + agentAudioRef.current.srcObject = audioStream ?? null; + }, [agentPeer?.tracks[0]?.stream]); - useEffect(() => { - if (agentAudioRef.current) { - agentAudioRef.current.volume = volume; - } - }, [volume]); + useEffect(() => { + if (agentAudioRef.current) { + agentAudioRef.current.volume = volume; + } + }, [volume]); - const userName = localPeer?.metadata?.peer?.name ?? "Unknown"; - const playerCount = (localPeer ? 1 : 0) + displayedPeers.length; + const userName = localPeer?.metadata?.peer?.name ?? 'Unknown'; + const playerCount = (localPeer ? 1 : 0) + displayedPeers.length; - return ( -
- + return ( +
+ -
-
- -
+
+
+ +
- -
+ +
- {/* biome-ignore lint/a11y/useMediaCaption: Peer audio feed from WebRTC doesn't have captions */} -
- ); + {/* biome-ignore lint/a11y/useMediaCaption: Peer audio feed from WebRTC doesn't have captions */} +
+ ); }; export default GameView; diff --git a/deep-sea-stories/packages/web/src/window.d.ts b/deep-sea-stories/packages/web/src/window.d.ts index 7ce5ba4..d86945d 100644 --- a/deep-sea-stories/packages/web/src/window.d.ts +++ b/deep-sea-stories/packages/web/src/window.d.ts @@ -1,7 +1,7 @@ -import type { Gtag } from "gtag.js"; +import type { Gtag } from 'gtag.js'; declare global { - interface Window { - gtag: Gtag.Gtag; - } + interface Window { + gtag: Gtag.Gtag; + } } From 4e34470983f20f86ee813ebe55ee0d0852077106 Mon Sep 17 00:00:00 2001 From: Adrian Czerwiec Date: Thu, 19 Feb 2026 10:44:24 +0100 Subject: [PATCH 8/8] fix positioning --- .../packages/web/src/components/PromoWidget.tsx | 7 ++----- deep-sea-stories/packages/web/src/main.tsx | 2 +- deep-sea-stories/packages/web/src/window.d.ts | 7 ------- 3 files changed, 3 insertions(+), 13 deletions(-) delete mode 100644 deep-sea-stories/packages/web/src/window.d.ts diff --git a/deep-sea-stories/packages/web/src/components/PromoWidget.tsx b/deep-sea-stories/packages/web/src/components/PromoWidget.tsx index e02749e..0289e0e 100644 --- a/deep-sea-stories/packages/web/src/components/PromoWidget.tsx +++ b/deep-sea-stories/packages/web/src/components/PromoWidget.tsx @@ -11,14 +11,12 @@ const PROMO_CODE_DISPLAYED_EVENT = 'promo_code_displayed'; const PROMO_CODE_COPIED_EVENT = 'promo_code_copied'; const readDismissedFromStorage = () => { - if (typeof window === 'undefined') return false; return window.localStorage.getItem(DISMISS_STORAGE_KEY) === 'true'; }; const isExpired = Date.now() >= PROMO_HIDE_AFTER.getTime(); const sendGAEvent = (event: string) => { - if (typeof window === 'undefined') return; if (typeof window.gtag !== 'function') { console.warn('gtag not defined'); return; @@ -47,7 +45,6 @@ const PromoWidget = () => { }, []); useEffect(() => { - if (typeof window === 'undefined') return; if (dismissed) { window.localStorage.setItem(DISMISS_STORAGE_KEY, 'true'); } @@ -62,7 +59,6 @@ const PromoWidget = () => { }; const fallbackCopy = () => { - if (typeof document === 'undefined') return; const textarea = document.createElement('textarea'); textarea.value = PROMO_CODE; textarea.style.position = 'fixed'; @@ -73,6 +69,7 @@ const PromoWidget = () => { document.execCommand('copy'); document.body.removeChild(textarea); triggerCopiedFeedback(); + sendGAEvent(PROMO_CODE_COPIED_EVENT); }; const handleGetPromo = () => { @@ -83,8 +80,8 @@ const PromoWidget = () => { const handleCopy = async () => { try { if (navigator.clipboard?.writeText) { - sendGAEvent(PROMO_CODE_COPIED_EVENT); await navigator.clipboard.writeText(PROMO_CODE); + sendGAEvent(PROMO_CODE_COPIED_EVENT); triggerCopiedFeedback(); return; } diff --git a/deep-sea-stories/packages/web/src/main.tsx b/deep-sea-stories/packages/web/src/main.tsx index 7e3b775..16f67d3 100644 --- a/deep-sea-stories/packages/web/src/main.tsx +++ b/deep-sea-stories/packages/web/src/main.tsx @@ -31,7 +31,7 @@ createRoot(document.getElementById('root')!).render( } /> -
+
diff --git a/deep-sea-stories/packages/web/src/window.d.ts b/deep-sea-stories/packages/web/src/window.d.ts deleted file mode 100644 index d86945d..0000000 --- a/deep-sea-stories/packages/web/src/window.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { Gtag } from 'gtag.js'; - -declare global { - interface Window { - gtag: Gtag.Gtag; - } -}