<commit_before>import { Box, Flex, Theme } from "@artsy/palette"
import { useNetworkOfflineMonitor } from "v2/Utils/Hooks/useNetworkOfflineMonitor"
import { findCurrentRoute } from "v2/System/Router/Utils/findCurrentRoute"
import { useMaybeReloadAfterInquirySignIn } from "v2/System/Router/Utils/useMaybeReloadAfterInquirySignIn"
import { NavBar } from "v2/Components/NavBar"
import { Match } from "found"
import { isFunction } from "lodash"
import { Footer } from "v2/Components/Footer"
import { useEffect, useState } from "react"
import * as React from "react"
import createLogger from "v2/Utils/logger"
import { useSystemContext } from "v2/System"
import { HorizontalPadding } from "v2/Apps/Components/HorizontalPadding"
import { AppContainer } from "./AppContainer"
import { useRouteComplete } from "v2/Utils/Hooks/useRouteComplete"
import { useAuthIntent } from "v2/Utils/Hooks/useAuthIntent"
import { AppToasts } from "./AppToasts"
import { useNavBarHeight } from "v2/Components/NavBar/useNavBarHeight"
import { useProductionEnvironmentWarning } from "v2/Utils/Hooks/useProductionEnvironmentWarning"
import { useAuthValidation } from "v2/Utils/Hooks/useAuthValidation"
import { Z } from "./constants"

const logger = createLogger("Apps/Components/AppShell")

interface AppShellProps {
  children: React.ReactNode
  match?: Match
}

export const AppShell: React.FC<AppShellProps> = props => {
  useAuthIntent()
  useAuthValidation()

  const { children, match } = props
  const routeConfig = match ? findCurrentRoute(match) : null
  const { isEigen } = useSystemContext()
  const showNav = !routeConfig?.hideNav
  const showFooter = !isEigen && !routeConfig?.hideFooter
  const appContainerMaxWidth = routeConfig?.displayFullPage ? "100%" : null

  // Check to see if a route has a onServerSideRender key; if so call it. Used
  // typically to preload bundle-split components (import()) while the route is
  // fetching data in the background.
  useEffect(() => {
    if (isFunction(routeConfig?.onClientSideRender) && match) {
      try {
        routeConfig?.onClientSideRender({ match })
      } catch (error) {
        logger.error(error)
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [routeConfig])

  // Let our end-to-end tests know that the app is hydrated and ready to go
  useEffect(() => {
    document.body.setAttribute("data-test", "AppReady")
  }, [])

  useEffect(() => {
    let script: HTMLScriptElement
    if (match?.location.pathname === "order/success") {
      script = document.createElement("script")

      script.id = "mntn_conversion"
      script.src = "../../System/Analytics/MNTN"
      script.async = true
      script.type = "javascript/text"

      document.body.appendChild(script)
    }
    return () => {
      if (document.getElementById("mntn_conversion")) {
        document.body.removeChild(script)
      }
    }
  }, [match])

  /**
   * Wait for route to finish rendering before (possibly) switching out the theme.
   *
   * When the route changes, the configured theme will change immediately; this
   * will cause the styles to update out of sync with the page change. Here we
   * wait for the route to finish rendering before setting the next theme.
   */
  const nextTheme = routeConfig?.theme ?? "v3"
  const [theme, setTheme] = useState<"v2" | "v3">(nextTheme)
  useRouteComplete({ onComplete: () => setTheme(nextTheme) })

  // TODO: When old backbone inquiry modal goes away, this can be removed
  useMaybeReloadAfterInquirySignIn()

  const { height: navBarHeight } = useNavBarHeight()

  useNetworkOfflineMonitor()
  useProductionEnvironmentWarning()

  return (
    <Flex
      width="100%"
      // Prevents horizontal scrollbars from `FullBleed` + persistent vertical scrollbars
      overflowX="hidden"
      // Implements "Sticky footer" pattern
      // https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/
      minHeight="100vh"
      flexDirection="column"
    >
      {showNav && (
        <Box height={navBarHeight}>
          <Box left={0} position="fixed" width="100%" zIndex={Z.globalNav}>
            <NavBar />
          </Box>
        </Box>
      )}

      <Theme theme={theme}>
        <AppToasts accomodateNav={showNav} />

        <Flex
          as="main"
          id="main"
          // Occupies available vertical space
          flex={1}
        >
          <AppContainer maxWidth={appContainerMaxWidth}>
            <HorizontalPadding>{children}</HorizontalPadding>
          </AppContainer>
        </Flex>

        {showFooter && (
          <Flex bg="white100">
            <AppContainer>
              <HorizontalPadding>
                <Footer />
              </HorizontalPadding>
            </AppContainer>
          </Flex>
        )}
      </Theme>
    </Flex>
  )
}<commit_msg>add function to screen for conversion route<commit_after>import { Box, Flex, Theme } from "@artsy/palette"
import { useNetworkOfflineMonitor } from "v2/Utils/Hooks/useNetworkOfflineMonitor"
import { findCurrentRoute } from "v2/System/Router/Utils/findCurrentRoute"
import { useMaybeReloadAfterInquirySignIn } from "v2/System/Router/Utils/useMaybeReloadAfterInquirySignIn"
import { NavBar } from "v2/Components/NavBar"
import { Match } from "found"
import { isFunction } from "lodash"
import { Footer } from "v2/Components/Footer"
import { useEffect, useState } from "react"
import * as React from "react"
import createLogger from "v2/Utils/logger"
import { useSystemContext } from "v2/System"
import { HorizontalPadding } from "v2/Apps/Components/HorizontalPadding"
import { AppContainer } from "./AppContainer"
import { useRouteComplete } from "v2/Utils/Hooks/useRouteComplete"
import { useAuthIntent } from "v2/Utils/Hooks/useAuthIntent"
import { AppToasts } from "./AppToasts"
import { useNavBarHeight } from "v2/Components/NavBar/useNavBarHeight"
import { useProductionEnvironmentWarning } from "v2/Utils/Hooks/useProductionEnvironmentWarning"
import { useAuthValidation } from "v2/Utils/Hooks/useAuthValidation"
import { Z } from "./constants"

const logger = createLogger("Apps/Components/AppShell")
interface AppShellProps {
  children: React.ReactNode
  match?: Match
}

export const AppShell: React.FC<AppShellProps> = props => {
  useAuthIntent()
  useAuthValidation()

  const { children, match } = props
  const routeConfig = match ? findCurrentRoute(match) : null
  const { isEigen } = useSystemContext()
  const showNav = !routeConfig?.hideNav
  const showFooter = !isEigen && !routeConfig?.hideFooter
  const appContainerMaxWidth = routeConfig?.displayFullPage ? "100%" : null

  // Check to see if a route has a onServerSideRender key; if so call it. Used
  // typically to preload bundle-split components (import()) while the route is
  // fetching data in the background.
  useEffect(() => {
    if (isFunction(routeConfig?.onClientSideRender) && match) {
      try {
        routeConfig?.onClientSideRender({ match })
      } catch (error) {
        logger.error(error)
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [routeConfig])

  // Let our end-to-end tests know that the app is hydrated and ready to go
  useEffect(() => {
    document.body.setAttribute("data-test", "AppReady")
  }, [])

  useEffect(() => {
    let script: HTMLScriptElement

    if (idConversionRoute(match?.location.pathname)) {
      script = document.createElement("script")

      script.id = "mntn_conversion"
      script.src = "../../System/Analytics/MNTN/conversionPixelScript.js"
      script.async = true
      script.type = "javascript/text"

      document.body.appendChild(script)
    }

    // does the removal of this element even matter if it is mounted in AppShell?
    return () => {
      if (document.getElementById("mntn_conversion")) {
        document.body.removeChild(script)
      }
    }
  }, [match])

  /**
   * Wait for route to finish rendering before (possibly) switching out the theme.
   *
   * When the route changes, the configured theme will change immediately; this
   * will cause the styles to update out of sync with the page change. Here we
   * wait for the route to finish rendering before setting the next theme.
   */
  const nextTheme = routeConfig?.theme ?? "v3"
  const [theme, setTheme] = useState<"v2" | "v3">(nextTheme)
  useRouteComplete({ onComplete: () => setTheme(nextTheme) })

  // TODO: When old backbone inquiry modal goes away, this can be removed
  useMaybeReloadAfterInquirySignIn()

  const { height: navBarHeight } = useNavBarHeight()

  useNetworkOfflineMonitor()
  useProductionEnvironmentWarning()

  return (
    <Flex
      width="100%"
      // Prevents horizontal scrollbars from `FullBleed` + persistent vertical scrollbars
      overflowX="hidden"
      // Implements "Sticky footer" pattern
      // https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/
      minHeight="100vh"
      flexDirection="column"
    >
      {showNav && (
        <Box height={navBarHeight}>
          <Box left={0} position="fixed" width="100%" zIndex={Z.globalNav}>
            <NavBar />
          </Box>
        </Box>
      )}

      <Theme theme={theme}>
        <AppToasts accomodateNav={showNav} />

        <Flex
          as="main"
          id="main"
          // Occupies available vertical space
          flex={1}
        >
          <AppContainer maxWidth={appContainerMaxWidth}>
            <HorizontalPadding>{children}</HorizontalPadding>
          </AppContainer>
        </Flex>

        {showFooter && (
          <Flex bg="white100">
            <AppContainer>
              <HorizontalPadding>
                <Footer />
              </HorizontalPadding>
            </AppContainer>
          </Flex>
        )}
      </Theme>
    </Flex>
  )
}

// account creation, auction registration, bid placed, inquiry made,
// gallery contacted, offer made, purchase
function idConversionRoute(pathname: string | undefined) {
  if (!pathname) {
    console.log("AppShell::idConversionRoute: pathname is undefined")
    return false
  }
  const paths = pathname.split(/(?=\/)/g)
  console.log("AppShell::idConversionRoute: paths", paths)
  const conversionRoutes = [
    ["/signup"],
    ["/personalize", "/artists"],
    ["/personalize", "/budget"],
    ["/auction", "/bid"],
    ["/auction-registration"],
    ["/orders", "/status"],
    // "/signup", // account creation
    // "/personalize/artists", // account creation
    // "/personalize/budget", // account creation
    // `/auction/${saleName}/bid/${artworkID}?bid=${bidID}`, // bid placed
    // `/auction-registration/${saleName}`, // auction registration
    // `/orders/7ef042fe-1897-4076-8f15-0d336db880c6/status`, // offer made, purchase
    //  no route for 'gallery contacted',
  ]

  let x = conversionRoutes.length - 1
  let matchFound = false
  do {
    matchFound = conversionRoutes[x--].every(route => {
      console.log("AppShell::idConversionRoute: comparing", route, "to", paths)
      return paths.indexOf(route) !== -1
    })
  } while (x >= 0 && !matchFound)

  console.log("AppShell::idConversionRoute: matchFound:", matchFound)
  return matchFound
}
{'fraction_non_alphanumeric': 0.12300662963626591, 'fraction_numerical': 0.008242250492743236, 'mean_word_length': 3.131384159881569, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 67, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5268646', 'n_tokens_mistral': 3345, 'n_tokens_neox': 3219, 'n_words': 813}