OurBigBook logoOurBigBook Docs OurBigBook logoOurBigBook.comSite Source code
web/pages/_app.tsx
import { useRouter } from 'next/router';
import React, { useEffect, useState } from 'react';
import { useReportWebVitals } from 'next/web-vitals'

import {
  aboutUrl,
  contactUrl,
  docsUrl,
  donateUrl,
  googleAnalyticsId,
  log,
  isProduction
} from 'front/config';
import Navbar from 'front/Navbar'
import ThemeToggle from 'front/ThemeToggle'
import {
  AppContextProvider,
  FontAwesomeIcon,
  HelpIcon,
  DiscussionIcon,
} from 'front'
import routes from 'front/routes'

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

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

const routesThatDontUpdatePrevPageNoSignup = new Set([
 routes.userNew(),
 routes.resetPasswordUpdate(),
])

const MyApp = ({ Component, pageProps }) => {
  const router = useRouter()
  // https://nextjs.org/docs/pages/building-your-application/optimizing/analytics
  useReportWebVitals((metric) => {
    if (log.perf) {
      console.log(metric)
    }
  })

  const [prevPageNoSignup, setPrevPageNoSignup] = useState({ prev: null, cur: null });
  const [loggedInUserEffectiveImage, setLoggedInUserEffectiveImage] = useState(
    pageProps.loggedInUser?.effectiveImage
  )
  useEffect(() => {
    setLoggedInUserEffectiveImage(pageProps.loggedInUser?.effectiveImage)
  }, [pageProps.loggedInUser?.username, pageProps.loggedInUser?.effectiveImage])
  function updatePrevPageNoSignup(newCur) {
    // This is so that for logged off user the sequence:
    // - Create new article button
    if (!routesThatDontUpdatePrevPageNoSignup.has(newCur?.split(/[?#]/)[0])) {
      const newVal = {
        prev: prevPageNoSignup.cur,
        cur: newCur,
      }
      setPrevPageNoSignup(newVal)
    }
  }
  useEffect(() => {
      updatePrevPageNoSignup(router?.asPath)
    },
    [router?.asPath]
  )
  // Google Analytics page switches:
  // https://stackoverflow.com/questions/60411351/how-to-use-google-analytics-with-next-js-app/62552263#62552263
  useEffect(() => {
    if (isProduction) {
      router.events.on('routeChangeComplete', handleRouteChange)
      return () => {
        router.events.off('routeChangeComplete', handleRouteChange)
      }
    }
  }, [router.events])

  const isEditor = !!Component.isEditor
  const loggedInUser = pageProps.loggedInUser
    ? { ...pageProps.loggedInUser, effectiveImage: loggedInUserEffectiveImage }
    : pageProps.loggedInUser
  return (
    <AppContextProvider vals={{
      prevPageNoSignup: prevPageNoSignup.prev,
      setLoggedInUserEffectiveImage,
      updatePrevPageNoSignup,
    }} >
      <div className={`toplevel${isEditor ? ' editor' : ''}`}>
        <Navbar {...{
          isEditor,
          clearScoreDelta: pageProps.clearScoreDelta,
          loggedInUser,
          scoreDelta: pageProps.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`}>{FontAwesomeIcon(0xf15c)} Content license: CC BY-SA 4.0 unless noted</a>
            <a href="https://github.com/ourbigbook/ourbigbook/tree/master/web">{FontAwesomeIcon(0xf09b, { cls: 'fa-brands-400' })} Website source code</a>
            <a href={contactUrl}><DiscussionIcon /> Contact, bugs, suggestions, abuse reports</a>
            <a href="https://mastodon.social/@ourbigbook">{FontAwesomeIcon(0xf4f6, { cls: 'fa-brands-400' })} @ourbigbook</a>
            <a href="https://twitter.com/OurBigBook">{FontAwesomeIcon(0xf099, { cls: 'fa-brands-400' })} @OurBigBook</a>
            <a href="https://www.youtube.com/@OurBigBook">{FontAwesomeIcon(0xf167, { cls: 'fa-brands-400' })} @OurBigBook</a>
            <ThemeToggle />
          </footer>
        }
      </div>
    </AppContextProvider>
  )
}

export default MyApp;