<|start_filename|>src/components/layout.js<|end_filename|>
/**
 * Layout component that queries for data
 * with Gatsby's useStaticQuery component
 *
 * See: https://www.gatsbyjs.org/docs/use-static-query/
 */

import React from "react"
import PropTypes from "prop-types"
import { useStaticQuery, graphql } from "gatsby"

import Markdown from 'markdown-to-jsx';

import axios from 'axios';

import { createGlobalStyle } from 'styled-components'

import Header from "./Header/"
import Hero from "./Hero"
import Ending from "./Ending"
import Footer from "./Footer"
import { Snackbar } from "./Snackbar"
import { ButtonV2 } from "./ButtonV2"
import { colours } from '../colours'
import "./layout.css"
import "./inter.css"

import { SkeletonTheme } from 'react-loading-skeleton';
import { CookiesProvider } from 'react-cookie';

import { ThemeManagerContext } from 'gatsby-styled-components-dark-mode';

import { BackgroundInject } from './style'
import { useGlobalState } from '../../lib/context'

import { Banner } from "./Banner"
import { isBrowser } from "../../lib/helpers/login"

import cookie from '../assets/images/cookie.svg'

const GS = createGlobalStyle`${BackgroundInject}`;

const Layout = ({ children, noEnding, noHero, isHome, darkNav, blank }) => {
  const data = useStaticQuery(graphql`
    query SiteTitleQuery {
      site {
        siteMetadata {
          title
        }
      }
    }
  `)
				  
  const themeContext = React.useContext(ThemeManagerContext)

  const [motd, setMotd] = React.useState("");
  const [cookieBannerVisible, setCBVisible] = React.useState(isBrowser() && !localStorage.getItem("cookie-consented"))

  const [hidden, setHidden] = React.useState(false);
  const [onTop, setOnTop] = React.useState(false);

  const [builds, setBuilds] = useGlobalState('builds');

  const [alfUser, setAlfUser] = useGlobalState('afUser');
  const [alfBuilds, setAlfBuilds] = useGlobalState('afBuilds');

  React.useEffect(() => {
    let oldY = 0;

    axios.get("https://raw.githubusercontent.com/dothq/motd/main/motd.md")
      .then(res => setMotd(res.data))

    isBrowser() && window.addEventListener("scroll", (e) => {
      if(window.scrollY >= 500 && oldY < window.scrollY) setHidden(true);
      else setHidden(false);
      
      oldY = window.scrollY;
  
      if(window.scrollY >= 100) setOnTop(true)
      else setOnTop(false)
    })

    if(process.env.NODE_ENV !== "development") {
      console.log("%cBeware!", "font: 2em sans-serif; color: yellow; background-color: red;");
      console.log("%cThis is a browser feature intended for developers. If someone told you to copy-paste something here to enable a feature or “hack” someone’s account, it is a scam and will give them access to your account.", "font: 1.5em sans-serif; color: grey;");
    }

    if(typeof(alfUser) == "boolean") return;
    if(typeof(alfBuilds) == "boolean") return;

    setAlfUser(true)

    setAlfBuilds(true)

  }, [builds, setBuilds, themeContext, alfBuilds, alfUser, setAlfBuilds, setAlfUser, motd]);

  return (
    <CookiesProvider>
      <SkeletonTheme color={themeContext.isDark ? "#0f0f0f" : "#eee"} highlightColor={themeContext.isDark ? "#232323" : "#d8d8d8"}>
        <GS />
        {!noHero && <Hero>
          {!blank && <Header 
            className={"nav"} 
            siteTitle={data.site.siteMetadata.title} 
            isFixed={false} 
            hideMenu={hidden}
            isDark={typeof(darkNav) == "undefined" ? false : darkNav}
            hidden={hidden}
            onTop={onTop}
          >
            <Banner>
              <Markdown options={{ forceInline: true }}>{motd}</Markdown>
            </Banner>
          </Header>}
          {children}
        </Hero>}
        {noHero && <>{children}</>}
        {!noEnding && <Ending />}
        {!blank && <Footer />}
        <Snackbar visible={cookieBannerVisible} icon={cookie}>
          We use cookies to keep you logged into your account. We do not use cookies if you are browsing as a guest.
          <ButtonV2 onClick={() => setCBVisible(false)} style={{ marginLeft: "16px" }} background={colours.azure} color={colours.white}>OK</ButtonV2>
        </Snackbar>
      </SkeletonTheme>
    </CookiesProvider>
  )
}

Layout.propTypes = {
  children: PropTypes.node.isRequired,
  noEnding: PropTypes.bool,
  noHero: PropTypes.bool,
  isHome: PropTypes.bool,
  darkNav: PropTypes.bool,
  blank: PropTypes.bool
}

export default Layout


<|start_filename|>gatsby-browser.js<|end_filename|>
/**
 * Implement Gatsby's Browser APIs in this file.
 *
 * See: https://www.gatsbyjs.org/docs/browser-apis/
 */

// You can delete this file if you're not using it

import React from 'react';

import { getUser } from './src/services/authenticate';
import { isBrowser } from './lib/helpers/login'

import config from './dot.config';
import { navigate } from 'gatsby';

import { parse } from 'search-params' 

import { defaultGlobalState, globalStateContext, dispatchStateContext, useGlobalState } from "./src/store"

let route = window.location.pathname ?? ""

const GlobalStateProvider = ({ children }) => {
    const [state, dispatch] = React.useReducer(
        (state, newValue) => ({ ...state, ...newValue }),
        defaultGlobalState
    );

    return (
        <globalStateContext.Provider value={state}>
            <dispatchStateContext.Provider value={dispatch}>
                {children}
            </dispatchStateContext.Provider>
        </globalStateContext.Provider>
    );
};

const checkSession = (dispatch) => {
    if(isBrowser()) window.isLoggedIn = false;

    getUser()
        .then((res) => { 
            console.log(res)

            if(!res) return;
            if(isBrowser()) window.isLoggedIn = !!res;

            dispatch({ loaded: true, user: res, authenticated: true });
        })
        .catch(err => {
            dispatch({ loaded: true, authenticated: false })
        });
}

const SessionCheck = ({ children }) => {
    const [state, dispatch] = useGlobalState();

    const location = isBrowser() && window.location;
    const query = parse(location.search);

    React.useState(() => {
        if(document.cookie.indexOf("_dotid_loggedin") === -1) {
            if(location.pathname.startsWith("/sign-in")) return;

            if(config.auth.protectedPages.includes(location.pathname.replace(/\/$/, ""))) {
                return window.___navigate(`/sign-in?next=${encodeURIComponent(location.pathname + location.search)}`)
            }
        } else {
            if(location.pathname.startsWith("/sign-in")) window.___navigate(query.next ? decodeURIComponent(query.next) : "/");

            getUser()
                .then((res) => { 
                    if(!res) return;
                    if(isBrowser()) window.isLoggedIn = !!res;

                    dispatch({ loaded: !!res, user: res });
                })
                .catch(err => dispatch({ loaded: true }));
        }

        dispatch({ loaded: true })
    }, [document.cookie])

    return <div style={{ display: state.loaded ? "" : "none" }}>{children}</div>
}

export const onPreRouteUpdate = () => {
    const location = isBrowser() && window.location;
    const query = parse(location.search);

    if(document.cookie.indexOf("_dotid_loggedin") === -1) {
        if(location.pathname.startsWith("/sign-in")) return;

        if(config.auth.protectedPages.includes(location.pathname.replace(/\/$/, ""))) {
            return window.___navigate(`/sign-in?next=${encodeURIComponent(location.pathname + location.search)}`)
        }
    } else {
        if(location.pathname.startsWith("/sign-in")) window.___navigate(query.next ? decodeURIComponent(query.next) : "/");
    }
}
  
export const wrapRootElement = ({ element, location }) => (
    <GlobalStateProvider>
        <SessionCheck location={location}>
            {element}
        </SessionCheck>
    </GlobalStateProvider>
);

<|start_filename|>gatsby-node.js<|end_filename|>
const axios = require("axios")
const path = require(`path`)
const { paginate } = require(`gatsby-awesome-pagination`)
const { resolve } = require("path")
const fs = require("fs")

exports.onCreateNode = ({ node }) => {
  console.log(`Node created of type "${node.internal.type}"`)
}

/**
 * Here is the place where Gatsby creates the URLs for all the
 * posts, tags, pages and authors that we fetched from the Ghost site.
 */
exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions

  // const result = await graphql(`
  //   {
  //     allGhostPost(sort: { order: ASC, fields: published_at }) {
  //       edges {
  //         node {
  //           slug
  //         }
  //       }
  //     }
  //     allGhostTag(sort: { order: ASC, fields: name }) {
  //       edges {
  //         node {
  //           slug
  //           url
  //           postCount
  //         }
  //       }
  //     }
  //     allGhostAuthor(sort: { order: ASC, fields: name }) {
  //       edges {
  //         node {
  //           slug
  //           url
  //           postCount
  //         }
  //       }
  //     }
  //     allGhostPage(sort: { order: ASC, fields: published_at }) {
  //       edges {
  //         node {
  //           slug
  //           url
  //         }
  //       }
  //     }
  //   }
  // `)

  // // Check for any errors
  // if (result.errors) {
  //   throw new Error(result.errors)
  // }

  // // Extract query results
  // const pages = result.data.allGhostPage.edges
  // const posts = result.data.allGhostPost.edges

  // // Load templates
  // const pageTemplate = path.resolve(`./src/templates/blog.tsx`)
  // const postTemplate = path.resolve(`./src/templates/post.tsx`)

  // // Create pages
  // pages.forEach(({ node }) => {
  //   console.log(node)

  //   // This part here defines, that our pages will use
  //   // a `/:slug/` permalink.
  //   node.url = `/blog/${node.slug}/`

  //   createPage({
  //     path: node.url,
  //     component: pageTemplate,
  //     context: {
  //       // Data passed to context is available
  //       // in page queries as GraphQL variables.
  //       slug: node.slug,
  //     },
  //   })
  // })

  // // Create post pages
  // posts.forEach(({ node }) => {
  //   // This part here defines, that our posts will use
  //   // a `/:slug/` permalink.
  //   node.url = `/blog/${node.slug}/`

  //   createPage({
  //     path: node.url,
  //     component: postTemplate,
  //     context: {
  //       // Data passed to context is available
  //       // in page queries as GraphQL variables.
  //       slug: node.slug,
  //     },
  //   })
  // })

  // // Create pagination
  // paginate({
  //   createPage,
  //   items: posts,
  //   itemsPerPage: posts.length,
  //   component: pageTemplate,
  //   pathPrefix: ({ pageNumber }) => {
  //     if (pageNumber === 0) {
  //       return `/blog`
  //     } else {
  //       return `/blog`
  //     }
  //   },
  // })

  const getMarkdown = url => {
    return new Promise(resolve => {
      axios.get(url).then(res => {
        console.log(res.headers)
        resolve(res.data)
      })
    })
  }

  const getMarkdownMeta = file => {
    return new Promise(resolve => {
      axios
        .get(
          `https://api.github.com/repos/dothq/legal/commits?path=${file}&page=1&per_page=1`
        )
        .then(res => {
          const months = {
            0: "January",
            1: "February",
            2: "March",
            3: "April",
            4: "May",
            5: "June",
            6: "July",
            7: "August",
            8: "September",
            9: "October",
            10: "November",
            11: "December",
          }

          const d = new Date(res.data[0].commit.committer.date)
          const date = `${d.getDate()} ${
            months[d.getMonth()]
          } ${d.getFullYear()}`

          resolve({
            lastUpdated: date,
            author: {
              avatar: res.data[0].author.avatar_url,
              name: res.data[0].author.login,
            },
          })
        })
    })
  }

  const generateLegalContext = async policyName => {
    const base = "https://raw.githubusercontent.com/dothq/legal/master"

    let policy = await getMarkdown(`${base}/${policyName}.md`)
    const policyMeta = await getMarkdownMeta(`${policyName}.md`)

    policy = policy.replace(/<\/br>/g, "  ")

    const names = {
      PRIVACY_POLICY: "Privacy Policy",
      TERMS_OF_SERVICE: "Terms of Service"
    }

    return {
      title: names[policyName],
      content: policy,
      historyLink: `https://github.com/dothq/legal/commits/master/${policyName}.md`,
      ...policyMeta,
    }
  }

  createPage({
    path: `/legal/privacy`,
    component: require.resolve("./src/templates/legal.tsx"),
    context: { legal: await generateLegalContext("PRIVACY_POLICY") },
  })

  createPage({
    path: `/legal/terms`,
    component: require.resolve("./src/templates/legal.tsx"),
    context: { legal: await generateLegalContext("TERMS_OF_SERVICE") },
  })

  let icons = []

  fs.readdirSync(resolve(process.cwd(), "src", "assets", "images", "doticons")).forEach(icon => {
    const ic = fs.readFileSync(resolve(process.cwd(), "src", "assets", "images", "doticons", icon), "utf-8");

    icons.push({ name: icon.split(".svg")[0], data: ic, path: resolve(process.cwd(), "src", "assets", "images", "doticons", icon) })
  })

  createPage({
    path: `/design/icons`,
    component: require.resolve("./src/templates/icons.tsx"),
    context: { icons },
  })
}
