diff --git a/config/default.js b/config/default.js index 8e9a01bae..57be6d2f3 100644 --- a/config/default.js +++ b/config/default.js @@ -50,6 +50,6 @@ module.exports = { "img-src": ["*", "data:"], "media-src": ["self"], "object-src": ["self"], - "script-src": ["self", "https://www.google-analytics.com/"], + "script-src": ["self", "https://www.googletagmanager.com/"], }, }; diff --git a/package.json b/package.json index c8ca6a7e9..04f3b24c9 100644 --- a/package.json +++ b/package.json @@ -182,7 +182,6 @@ "polished": "4.1.3", "process": "0.11.10", "react": "17.0.2", - "react-apollo": "4.0.0-beta.1", "react-dom": "17.0.2", "react-helmet": "6.1.0", "react-outside-click-handler": "1.3.0", diff --git a/src/server/generate-static-html.ts b/src/server/generate-static-html.ts deleted file mode 100644 index 96aa5a033..000000000 --- a/src/server/generate-static-html.ts +++ /dev/null @@ -1,17 +0,0 @@ -import axios from "axios"; -import config from "config"; -import fs from "fs"; -import { startServer } from "@/server/start-server"; - -const port = config.get("server.port"); - -async function generateStaticHtml(): Promise { - await startServer(); - const res = await axios.get(`http://localhost:${port}/`); - const html = res.data; - fs.writeFileSync(`${__dirname}/../../dist/index.html`, html); -} - -generateStaticHtml().catch((err) => { - window.console.error(`failed to generate static HTML: ${err}`); -}); diff --git a/src/shared/app.tsx b/src/shared/app.tsx index 858b897a7..fc943970b 100644 --- a/src/shared/app.tsx +++ b/src/shared/app.tsx @@ -1,25 +1,18 @@ import { Switch } from "onefx/lib/react-router"; import { Route } from "onefx/lib/react-router-dom"; import { styled } from "onefx/lib/styletron-react"; -import React, { useEffect } from "react"; -import { FOOTER_ABOVE, Footer } from "@/shared/common/footer"; +import React from "react"; +import { Footer, FOOTER_ABOVE } from "@/shared/common/footer"; import { Head } from "@/shared/common/head"; import { NotFound } from "@/shared/common/not-found"; import { ScrollToTop } from "@/shared/common/scroll-top"; import { fonts } from "@/shared/common/styles/style-font"; import { TopBar } from "@/shared/common/top-bar"; import { Home } from "@/shared/home/home"; +import { useGtag } from "@/shared/common/use-gtag"; -const initGoogleAnalytics = require("./common/google-analytics"); - -type Props = { - googleTid: string; -}; - -export function App(props: Props): JSX.Element { - useEffect(() => { - initGoogleAnalytics({ tid: props.googleTid }); - }, []); +export function App(): JSX.Element { + useGtag(); return ( diff --git a/src/shared/common/google-analytics.js b/src/shared/common/google-analytics.js deleted file mode 100644 index a5343f7e4..000000000 --- a/src/shared/common/google-analytics.js +++ /dev/null @@ -1,36 +0,0 @@ -/* eslint-disable */ -let loaded = false; -module.exports = function initGoogleAnalytics({ tid, userId, cb }) { - if (loaded) { - return; - } - loaded = true; - - (function(i, s, o, g, r, a, m) { - i["GoogleAnalyticsObject"] = r; - (i[r] = - i[r] || - function() { - (i[r].q = i[r].q || []).push(arguments); - }), - (i[r].l = 1 * new Date()); - (a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]); - a.async = 1; - a.src = g; - m.parentNode.insertBefore(a, m); - })( - window, - document, - "script", - "https://www.google-analytics.com/analytics.js", - "ga" - ); - - ga("create", tid, "auto"); - if (userId) { - ga("set", "userId", userId); - } - ga("send", "pageview"); - cb && cb(); -}; -/* eslint-enable */ diff --git a/src/shared/common/head.tsx b/src/shared/common/head.tsx index 247b9bf20..7c3154f86 100644 --- a/src/shared/common/head.tsx +++ b/src/shared/common/head.tsx @@ -5,15 +5,17 @@ import { mobileViewPortContent } from "onefx/lib/iso-react-render/root/mobile-vi import { Helmet } from "onefx/lib/react-helmet"; import { noFlashColorMode } from "onefx/lib/styletron-react"; import React from "react"; -import { connect } from "react-redux"; +import { useSelector } from "react-redux"; import { colors } from "./styles/style-color"; function HeadInner({ locale, nonce, + gaMeasurementId, }: { locale: string; nonce: string; + gaMeasurementId: string; }): JSX.Element { return ( {noFlashColorMode({ defaultMode: "light" })} + ); } -export const Head = connect( - (state: { base: { locale: string; nonce: string } }) => ({ - locale: state.base.locale, - nonce: state.base.nonce, - }) -)(HeadInner); +export const Head: React.FC = () => { + const props = useSelector( + (state: { + base: { + locale: string; + nonce: string; + analytics: { gaMeasurementId: string }; + }; + }) => ({ + locale: state.base.locale, + nonce: state.base.nonce, + gaMeasurementId: state.base.analytics.gaMeasurementId, + }) + ); + + return ; +}; diff --git a/src/shared/common/use-gtag.ts b/src/shared/common/use-gtag.ts new file mode 100644 index 000000000..61e26d97f --- /dev/null +++ b/src/shared/common/use-gtag.ts @@ -0,0 +1,39 @@ +import { useEffect } from "react"; +import { useHistory } from "react-router-dom"; +import { useSelector } from "react-redux"; + +declare global { + interface Window { + gtag?: ( + key: string, + trackingId: string, + // eslint-disable-next-line camelcase + config: { page_path: string } + ) => void; + } +} + +export const useGtag = () => { + const { listen } = useHistory(); + const gaMeasurementId = useSelector( + (state: { + base: { + analytics: { gaMeasurementId: string }; + }; + }) => state.base.analytics.gaMeasurementId + ); + + useEffect(() => { + return listen((location) => { + if (!window.gtag) { + return; + } + if (!gaMeasurementId) { + console.warn("please specify your gaMeasurementId"); + return; + } + + window.gtag("config", gaMeasurementId, { page_path: location.pathname }); + }); + }, [gaMeasurementId, listen]); +}; diff --git a/src/shared/onefx-auth-provider/email-password-identity-provider/view/identity-app.tsx b/src/shared/onefx-auth-provider/email-password-identity-provider/view/identity-app.tsx index 0f11d5856..bbcd1ef36 100644 --- a/src/shared/onefx-auth-provider/email-password-identity-provider/view/identity-app.tsx +++ b/src/shared/onefx-auth-provider/email-password-identity-provider/view/identity-app.tsx @@ -1,7 +1,7 @@ import { t } from "onefx/lib/iso-i18n"; import { Link, Route, Switch } from "onefx/lib/react-router-dom"; import { styled } from "onefx/lib/styletron-react"; -import React, { useEffect } from "react"; +import React from "react"; import { Flex } from "@/shared/common/flex"; import { FOOTER_ABOVE, Footer } from "@/shared/common/footer"; import { Head } from "@/shared/common/head"; @@ -10,23 +10,14 @@ import { colors } from "@/shared/common/styles/style-color"; import { fonts } from "@/shared/common/styles/style-font"; import { ContentPadding } from "@/shared/common/styles/style-padding"; import { TopBar } from "@/shared/common/top-bar"; +import { useGtag } from "@/shared/common/use-gtag"; import { ForgotPassword } from "./forgot-password"; import { ResetPasswordContainer } from "./reset-password"; import { SignIn } from "./sign-in"; import { SignUp } from "./sign-up"; -const initGoogleAnalytics = require("../../../common/google-analytics"); - -type Props = { - googleTid?: string; -}; - -export const IdentityApp = ({ googleTid }: Props): JSX.Element => { - useEffect(() => { - if (googleTid) { - initGoogleAnalytics({ tid: googleTid }); - } - }, [googleTid]); +export const IdentityApp = (): JSX.Element => { + useGtag(); return (