OurBigBook
web/pages/_app.tsx
import Head from 'next/head';
import { useRouter } from 'next/router';
import React, { useEffect, useState } from 'react';
import useSWR from 'swr'
import useLoggedInUser from 'front/useLoggedInUser'

import { aboutUrl, appName, contactUrl, docsUrl, donateUrl, googleAnalyticsId, isProduction } from 'front/config';
import Navbar from 'front/Navbar'
import { AppContext, AppContextProvider, HelpIcon, logout } from 'front'
import { webApi } from 'front/api'
import routes from 'front/routes'

// Css
// migrating the local ourbigbook to webpack: https://github.com/ourbigbook/ourbigbook/issues/157
import 'ourbigbook/dist/ourbigbook.css'
import 'ourbigbook/editor.scss'
import 'ionicons/css/ionicons.min.css'
import 'style.scss'

//// https://nextjs.org/docs/advanced-features/measuring-performance
//export function reportWebVitals(metric) {
//  console.log(metric)
//}

function MyHead() {
  const { title } = React.useContext(AppContext)
  let realTitle = title ? title + ' - ' : ''
  return (
    <Head>
      <meta
        name="viewport"
        content="width=device-width, initial-scale=1, maximum-scale=1"
      />
      <title>{realTitle + appName}</title>
    </Head>
  )
}

function handleRouteChange(url) {
  window.gtag('config', googleAnalyticsId, {
    page_path: url,
  })
}

const MyApp = ({ Component, pageProps }) => {
  const router = useRouter()
  const [prevPageNoSignup, setPrevPageNoSignup] = useState({ prev: null, cur: null });
  function updatePrevPageNoSignup(newCur) {
    if (newCur !== routes.userNew()) {
      const newVal = {
        prev: prevPageNoSignup.cur,
        cur: newCur,
      }
      setPrevPageNoSignup(newVal)
    }
  }
  useEffect(() => {
      updatePrevPageNoSignup(router?.asPath)
    },
    [router?.asPath, setPrevPageNoSignup]
  )
  if (isProduction) {
    // Google Analytics page switches:
    // https://stackoverflow.com/questions/60411351/how-to-use-google-analytics-with-next-js-app/62552263#62552263
    const router = useRouter();
    useEffect(() => {
      router.events.on('routeChangeComplete', handleRouteChange);
      return () => {
        router.events.off('routeChangeComplete', handleRouteChange);
      };
    }, [router.events]);
  }

  // Fetch every post-load user-specific data required for a page at once here.
  // We can get things up from inner components with properties much like `Component.isEditor`.
  // And ideally one day we will do it all in a single GraphQL query!
  const loggedInUser = useLoggedInUser()
  const { data, error } = useSWR(loggedInUser ? '/api/min' : null, async () => {
    return webApi.min()
  })
  let scoreDelta
  if (!data || error) {
    scoreDelta = 0
  } else {
    scoreDelta = data.data.scoreDelta
  }
  useEffect(() => {
    if (error || (data && !data.data.loggedIn)) {
      logout()
    }
  }, [data, error])

  const isEditor = !!Component.isEditor
  return (
    <AppContextProvider vals={{ prevPageNoSignup: prevPageNoSignup.prev, updatePrevPageNoSignup }} >
      <MyHead />
      <div className={`toplevel${isEditor ? ' editor' : ''}`}>
        <Navbar {...{ isEditor, scoreDelta }} />
        <div className="main">
          <Component {...pageProps} />
        </div>
        {!isEditor &&
          <footer>
            <a href={aboutUrl}><HelpIcon /> About</a>
            <a href={donateUrl}>$ Donate</a>
            <a href={`${docsUrl}#ourbigbook-com-content-license`}><i className="ion-document-text" /> Content license: CC BY-SA 4.0 unless noted</a>
            <a href="https://github.com/ourbigbook/ourbigbook/tree/master/web"><i className="ion-social-github" /> Website source code</a>
            <a href={contactUrl}><i className="ion-ios-chatbubble" /> Contact, bugs, suggestions, abuse reports</a>
            <a href="https://twitter.com/OurBigBook"><i className="ion-social-twitter" /> @OurBigBook</a>
            <a href="https://www.youtube.com/@OurBigBook"><i className="ion-social-youtube" /> @OurBigBook</a>
          </footer>
        }
      </div>
    </AppContextProvider>
  )
}

export default MyApp;