@reach/router#useLocation JavaScript Examples

The following examples show how to use @reach/router#useLocation. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: cookieBar.js    From gatsby-starter-portfolio-minimal with MIT License 6 votes vote down vote up
CookieBar = () => {
  const location = useLocation()
  const controls = useAnimation()
  const { isIntroDone } = useContext(Context).state

  // Display cookie bar after the splashScreen sequence is done
  useEffect(() => {
    if (isIntroDone) {
      controls.start({
        opacity: 1,
        y: 0,
        transition: { delay: 1 },
      })
    }
  }, [isIntroDone])

  if (!isIntroDone) return null

  return (
    <StyledCookieBar initial={{ opacity: 0, y: 20 }} animate={controls}>
      <CookieConsent
        cookieName="gatsby-gdpr-google-analytics"
        buttonId="confirm"
        buttonText="Accept"
        declineButtonId="decline"
        declineButtonText="Decline"
        enableDeclineButton={true}
        disableStyles={true}
        onAccept={() => initializeAndTrack(location)}
      >
        <p className="cookieMessage">This website uses cookies ? </p>
      </CookieConsent>
    </StyledCookieBar>
  )
}
Example #2
Source File: header.js    From gatsby-framer-menu with BSD Zero Clause License 6 votes vote down vote up
Header = ({ menuState, setMenuState, setCursorHovered }) => {
  const location = useLocation()
  useEffect(() => {
    setMenuState(false)
  }, [location])
  return (
    <header>
      <div className="container fluid">
        <div className="header-inner">
          <Link activeClassName="active" to="/">
            Pocket.
          </Link>
          <div
            onClick={() => setMenuState(!menuState)}
            className="hamburger-menu"
            onMouseEnter={() => setCursorHovered(true)}
            onMouseLeave={() => setCursorHovered(false)}
          >
            <span></span>
            <span></span>
          </div>
        </div>
      </div>
    </header>
  )
}
Example #3
Source File: LanguageSwitcher.js    From warsinhk with MIT License 6 votes vote down vote up
function LanguageSwitcher(props, context) {
  const location = useLocation();
  const changeLanguage = lng => {
    let fullPath = location.pathname;
    if (lng === "en" && !fullPath.includes("/en")) {
      fullPath = removePathTrailingSlash(fullPath.replace("/", "/en/"))
      navigate(fullPath, { replace: true })
    } else if (lng === "zh" && fullPath.includes("/en")) {
      fullPath = removePathTrailingSlash(fullPath.replace("/en", "")) || "/"
      navigate(fullPath, { replace: true })
    }
  }

  const { t } = useTranslation()

  return (
    <>
      <LocaleButton onClick={() => changeLanguage("zh")}>
        {t("text.chinese")}
      </LocaleButton>
      <ListItemText> | </ListItemText>
      <LocaleButton onClick={() => changeLanguage("en")}>
        {t("text.english")}
      </LocaleButton>
    </>
  )
}
Example #4
Source File: BottomNav.js    From warsinhk with MIT License 6 votes vote down vote up
export default function SimpleBottomNavigation(props) {
  const { tabs } = props
  const { pathname: path } = useLocation()
  const pageIndex = tabs.findIndex(o => o.to === path)
  const { t, i18n } = useTranslation()

  return (
    <Hidden smUp implementation="css">
      <StyledBottomNavigation value={pageIndex} showLabels>
        {/* FIXME: the icon is not updated after navigating to other page */}
        {/*
            wingkwong: Cannot use <UnstyledLink> to wrap <BottomNavigationAction> because it has to be a direct child of BottomNavigation
        */}
        {tabs.map((tab, index) => (
          <BottomNavigationAction
            label={t(tab.title)}
            key={index}
            component={UnstyledLink}
            icon={mapIcon(tab.icon)}
            to={getLocalizedPath(i18n, tab.to)}
            replace
          />
        ))}
      </StyledBottomNavigation>
    </Hidden>
  )
}
Example #5
Source File: index.js    From gatsby-shopify-course with BSD Zero Clause License 6 votes vote down vote up
export function Search() {
  const [searchTerm, setSearchTerm] = React.useState('');
  const { search } = useLocation();
  const c = queryString.parse(search)?.c || '';

  const handleSubmit = e => {
    e.preventDefault();

    if (c) {
      navigate(
        `/all-products?s=${encodeURIComponent(
          searchTerm
        )}&c=${encodeURIComponent(c)}`
      );
    } else {
      navigate(`/all-products?s=${encodeURIComponent(searchTerm)}`);
    }
  };

  return (
    <SearchForm onSubmit={handleSubmit}>
      <Input
        value={searchTerm}
        onChange={e => setSearchTerm(e.currentTarget.value)}
        placeholder="Search"
      />
      <Button>
        <FaSearch />
      </Button>
    </SearchForm>
  );
}
Example #6
Source File: layout.jsx    From gsoc-organizations with GNU General Public License v3.0 6 votes vote down vote up
Layout = ({ children }) => {
  const location = useLocation()
  const breakpoints = useBreakpoint()

  const showFiltersAndSearch = location.pathname === "/"

  if (!breakpoints.md) {
    return (
      <DesktopLayout showFiltersAndSearch={showFiltersAndSearch}>
        {children}
      </DesktopLayout>
    )
  } else {
    return (
      <MobileLayout showFiltersAndSearch={showFiltersAndSearch}>
        {children}
      </MobileLayout>
    )
  }
}
Example #7
Source File: LanguageDropdown.js    From tbtc-website with MIT License 6 votes vote down vote up
LanguageDropdownTemplate = ({ languages = [], selectedLanguage }) => {
  /* eslint-disable no-redeclare */
  try {
    var location = useLocation()
  } catch (error) {
    var location = window.location
  }

  // strip prefix build name from url if present
  const pathname =
    location.pathname.replace(`/${process.env.GATSBY_BRANCH}/`, "/")

  return (
    <Dropdown className="language-dropdown" label={selectedLanguage}>
      <ul className="language-list">
        {languages.map((lang, i) => (
          <li key={`language-${i}`}>
            <Link
              to={pathname}
              locale={lang}
              className={classNames({"selected": lang === selectedLanguage})}
            >
              {lang}
            </Link>
          </li>
        ))}
      </ul>
    </Dropdown>
  )
}
Example #8
Source File: NavLink.js    From codeursenseine.com with MIT License 6 votes vote down vote up
NavLink = ({
  children = null,
  isMain = false,
  to = "",
  ...rest
}) => {
  const { pathname } = useLocation();
  const isActive = pathname === to;

  return (
    <Box role="group" d="block" textAlign={{ md: "right" }} to={to} {...rest}>
      <Box
        as="span"
        d="inline-flex"
        transition="0.2s"
        borderRadius="md"
        py="1"
        px="4"
        position="relative"
        fontFamily="heading"
        fontSize={isMain ? "xl" : "sm"}
        _hover={{ bg: "rgba(0, 0, 0, 0.1)" }}
        _after={
          isActive && {
            content: `""`,
            position: "absolute",
            left: 4,
            right: 4,
            bottom: "0.3rem",
            height: "0.15rem",
            bg: "brand.400",
          }
        }
      >
        {children}
      </Box>
    </Box>
  );
}
Example #9
Source File: seo.jsx    From markdown-dungeon with MIT License 6 votes vote down vote up
export default function Seo({ title, description, image, article }) {
  const { pathname } = useLocation();
  const { site } = useStaticQuery(query);
  const {
    defaultTitle,
    defaultDescription,
    siteUrl,
    defaultImage,
  } = site.siteMetadata;
  const seo = {
    title: title || defaultTitle,
    description: description || defaultDescription,
    image: `${siteUrl}${image || defaultImage}`,
    url: `${siteUrl}${pathname}`,
  };
  return (
    <Helmet title={seo.title}>
      <meta name='title' content={seo.title} />
      <meta name='description' content={seo.description} />
      <meta name='image' content={seo.image} />
      {seo.url && <meta property='og:url' content={seo.url} />}
      {(article ? true : null) && <meta property='og:type' content='article' />}
      {seo.title && <meta property='og:title' content={seo.title} />}
      {seo.description && (
        <meta property='og:description' content={seo.description} />
      )}
      {seo.image && <meta property='og:image' content={seo.image} />}
      <meta name='twitter:card' content='summary_large_image' />
      {seo.title && <meta name='twitter:title' content={seo.title} />}
      {seo.description && (
        <meta name='twitter:description' content={seo.description} />
      )}
      {seo.image && <meta name='twitter:image' content={seo.image} />}
    </Helmet>
  );
}
Example #10
Source File: index.js    From gatsby-shopify-course with BSD Zero Clause License 5 votes vote down vote up
export function CategoryFilterItem({ title, id }) {
  const { search } = useLocation();
  const qs = queryString.parse(search);
  const collectionIds = qs.c?.split(',').filter(c => !!c) || [];
  const checked = collectionIds?.find(cId => cId === id);
  const searchTerm = qs.s;

  const onClick = () => {
    let navigateTo = '/all-products';

    let newIds = [];

    if (checked) {
      newIds = collectionIds
        .filter(cId => cId !== id)
        .map(cId => encodeURIComponent(cId));
    } else {
      collectionIds.push(id);
      newIds = collectionIds.map(cId => encodeURIComponent(cId));
    }

    if (newIds.length && !searchTerm) {
      navigate(`${navigateTo}?c=${newIds.join(',')}`);
    } else if (newIds.length && !!searchTerm) {
      navigate(
        `${navigateTo}?c=${newIds.join(',')}&s=${encodeURIComponent(
          searchTerm
        )}`
      );
    } else if (!newIds.length && !!searchTerm) {
      navigate(`${navigateTo}?s=${encodeURIComponent(searchTerm)}`);
    } else {
      navigate(`${navigateTo}`);
    }
  };
  return (
    <CategoryFilterItemWrapper onClick={onClick}>
      <Checkbox checked={checked} />
      <div>{title}</div>
    </CategoryFilterItemWrapper>
  );
}
Example #11
Source File: TabHeader.js    From website with MIT License 5 votes vote down vote up
TabHeader = props => {
  const {
    items,
    activeId,
    centerAlign,
    typeLayout,
    setActiveStateId,
    isTabParam,
  } = props
  const { header: headerREF } = React.useContext(Context)
  const { headerRef } = headerREF || {}
  const { heroContainer: heroContainerREF } = React.useContext(Context)
  const { heroContainerRef } = heroContainerREF || {}

  const { pagination: paginationContextValue } = React.useContext(Context)
  const { paginationPage } = paginationContextValue || {}
  const ref = React.useRef(null)
  const location = useLocation()
  const params = qs.parse(location.search)

  React.useEffect(() => {
    if (ref && ref.current && (params.category || params.page)) {
      const y =
        headerRef.current.clientHeight +
        heroContainerRef.current.clientHeight -
        60
      if (
        headerRef.current.clientHeight + heroContainerRef.current.clientHeight >
        320
      ) {
        setTimeout(() => {
          window.scrollTo({ top: 180, behavior: 'smooth' })
        }, 100)
      } else {
        setTimeout(() => {
          window.scrollTo({ top: y, behavior: 'smooth' })
        }, 100)
      }
    }
  }, [params.category, params.page, paginationPage])

  return (
    <Header ref={ref} centerAlign={centerAlign} typeLayout={typeLayout}>
      <HeaderInner typeLayout={typeLayout}>
        {items.map(item => (
          <TabHeaderItem
            {...item}
            activeId={activeId}
            setActiveStateId={setActiveStateId}
            typeLayout={typeLayout}
            isTabParam={isTabParam}
          />
        ))}
      </HeaderInner>
    </Header>
  )
}
Example #12
Source File: seo.js    From thevaccinetracker with MIT License 5 votes vote down vote up
SEO = ({ title, description, article }) => {
  const { pathname } = useLocation()
  const { site } = useStaticQuery(query)

  const {
    lang,
    defaultTitle,
    defaultDescription,
    keywords,
    siteUrl,
    twitterUsername
  } = site.siteMetadata

  const seo = {
    lang: lang,
    title: title || defaultTitle,
    description: description || defaultDescription,
    url: `${siteUrl}${pathname}`,
    image: socialImage,
    keywords
  }

  return (
    <Helmet
      htmlAttributes={{
        lang: 'en'
      }}
      title={seo.title}
    >
      <meta name="description" content={seo.description} />
      {seo.image && <meta name="image" content={seo.image} />}
      <meta name="keywords" content={seo.keywords.join(',')} />
      {seo.url && <meta property="og:url" content={seo.url} />}
      {(article ? true : null) && <meta property="og:type" content="article" />}
      {seo.title && <meta property="og:title" content={seo.title} />}
      {seo.description && (
        <meta property="og:description" content={seo.description} />
      )}
      {seo.image && <meta property="og:image" content={seo.image} />}
      <meta name="twitter:card" content="summary_large_image" />
      {twitterUsername && (
        <meta name="twitter:creator" content={twitterUsername} />
      )}
      {seo.title && <meta name="twitter:title" content={seo.title} />}
      {seo.description && (
        <meta name="twitter:description" content={seo.description} />
      )}
      {seo.image && <meta name="twitter:image" content={seo.image} />}
    </Helmet>
  )
}
Example #13
Source File: Seo.js    From website with MIT License 5 votes vote down vote up
SEO = props => {
  const {
    title,
    description,
    image,
    metaTags,
    linkTags,
    pageType,
    pagePath,
  } = props

  const location = useLocation()
  const pathname = location.pathname

  return (
    <StaticQuery
      query={siteSeoQuery}
      render={data => {
        const {
          site: {
            siteMetadata: { defaultTitle, defaultDescription, siteUrl },
          },
        } = data

        const seo = {
          title: title || defaultTitle,
          desc: description || defaultDescription,
          canonicalUrl: `${siteUrl}${pagePath}`,
        }
        const getMetaTags = (name, value) =>
          name && value
            ? [
                { name, content: value },
                { property: `og:${name}`, content: value },
                { name: `twitter:${name}`, content: value },
              ]
            : []
        const urlImageMeta = image && image?.file?.url
        const urlImageMetaClean =
          urlImageMeta &&
          typeof urlImageMeta === 'string' &&
          urlImageMeta.startsWith('//')
            ? `https:${urlImageMeta}`
            : urlImageMeta
        const meta = [
          { property: 'og:type', content: pageType },
          ...getMetaTags('title', seo.title),
          ...getMetaTags('description', seo.desc),
          ...getMetaTags('image', urlImageMetaClean),
          pathname !== pagePath
            ? {
                'http-equiv': 'refresh',
                content: `0;URL='${siteUrl}${pagePath}'`,
              }
            : {},
          ...(metaTags || []),
        ]

        const link = [
          { rel: 'canonical', href: seo.canonicalUrl },
          ...(linkTags || []),
        ]

        return <Helmet meta={meta} link={link} title={seo.title} />
      }}
    />
  )
}
Example #14
Source File: Seo.js    From docs with BSD Zero Clause License 5 votes vote down vote up
SEO = ({ title, description, image, article }) => {
  const { pathname } = useLocation()
  const { site } = useStaticQuery(query)

  const {
    defaultTitle,
    titleTemplate,
    defaultDescription,
    siteUrl,
    defaultImage,
    twitterUsername,
  } = site.siteMetadata

  const seo = {
    title: title,
    defaultTitle: defaultTitle,
    description: description || defaultDescription,
    image: `${siteUrl}${image || defaultImage}`,
    url: `${siteUrl}${pathname}`,
  }

  return (
    <Helmet title={seo.title} defaultTitle={seo.defaultTitle} titleTemplate={titleTemplate}>
      <meta name="description" content={seo.description} />
      <meta name="image" content={seo.image} />
      <link rel="canonical" href={seo.url} />

      {seo.url && <meta property="og:url" content={seo.url} />}

      {(article ? true : null) && <meta property="og:type" content="article" />}

      {seo.title && <meta property="og:title" content={seo.title} />}

      {seo.description && (
        <meta property="og:description" content={seo.description} />
      )}

      {seo.image && <meta property="og:image" content={seo.image} />}

      <meta name="twitter:card" content="summary_large_image" />

      {twitterUsername && (
        <meta name="twitter:creator" content={twitterUsername} />
      )}

      {seo.title && <meta name="twitter:title" content={seo.title} />}

      {seo.description && (
        <meta name="twitter:description" content={seo.description} />
      )}

      {seo.image && <meta name="twitter:image" content={seo.image} />}
    </Helmet>
  )
}
Example #15
Source File: SocialButtonList.js    From website with MIT License 5 votes vote down vote up
SocialButtonList = () => {
  const list = [
    { name: 'copy', text: 'Copy link' },
    {
      name: 'twitter',
      url: 'https://twitter.com/intent/tweet?url=',
    },
    {
      name: 'facebook',
      url: 'https://www.facebook.com/sharer/sharer.php?u=',
    },
    {
      name: 'linkedin',
      url: 'https://www.linkedin.com/sharing/share-offsite/?url=',
    },
  ]
  const location = useLocation()
  const { href } = location

  const [hrefState, setHrefState] = React.useState('')
  React.useEffect(() => {
    if (typeof window !== 'undefined') {
      setHrefState(window.location?.href)
    } else {
      setHrefState(href)
    }
  }, [href])

  return (
    <ListIcon>
      {list.map(item => (
        <SocialButtonItem
          name={item.name}
          text={item.text}
          url={item.url + hrefState}
          customColor={'#bbc0c5'}
        />
      ))}
    </ListIcon>
  )
}
Example #16
Source File: seo.js    From gatsby-airtable-design-project with BSD Zero Clause License 5 votes vote down vote up
SEO = ({ title, description, image, article }) => {
  const { pathname } = useLocation()
  const { site } = useStaticQuery(query)

  const {
    defaultTitle,
    titleTemplate,
    defaultDescription,
    siteUrl,
    defaultImage,
    twitterUsername,
  } = site.siteMetadata

  const seo = {
    title: title || defaultTitle,
    description: description || defaultDescription,
    image: `${siteUrl}${image || defaultImage}`,
    url: `${siteUrl}${pathname}`,
  }

  return (
    <Helmet title={seo.title} titleTemplate={titleTemplate}>
      <meta name="description" content={seo.description} />
      <meta name="image" content={seo.image} />

      {seo.url && <meta property="og:url" content={seo.url} />}

      {(article ? true : null) && <meta property="og:type" content="article" />}

      {seo.title && <meta property="og:title" content={seo.title} />}

      {seo.description && (
        <meta property="og:description" content={seo.description} />
      )}

      {seo.image && <meta property="og:image" content={seo.image} />}

      <meta name="twitter:card" content="summary_large_image" />

      {twitterUsername && (
        <meta name="twitter:creator" content={twitterUsername} />
      )}

      {seo.title && <meta name="twitter:title" content={defaultTitle} />}

      {seo.description && (
        <meta name="twitter:description" content={seo.description} />
      )}

      {seo.image && <meta name="twitter:image" content={seo.image} />}
    </Helmet>
  )
}
Example #17
Source File: Nav.js    From codeursenseine.com with MIT License 4 votes vote down vote up
Nav = ({
  breakpoint,
  isOpen,
  onNavClose = () => {},
  ...props
}) => {
  const theme = useTheme();
  const { pathname } = useLocation();

  const data = useStaticQuery(graphql`
    query NavPagesQuery {
      site {
        siteMetadata {
          currentYear
        }
      }
    }
  `);

  const currentYear = data.site.siteMetadata.currentYear;

  return (
    <Flex
      direction="column"
      alignItems={{ [breakpoint]: "flex-end" }}
      background={theme.gradients.brand}
      color="white"
      position="fixed"
      top="0"
      left="0"
      bottom="0"
      transform={{
        base: `translate(${isOpen ? 0 : "100%"})`,
        [breakpoint]: "none",
      }}
      transition={{ base: "transform 0.4s", [breakpoint]: "none" }}
      overflowY="auto"
      overflowX="none"
      zIndex="3"
      as="nav"
      {...props}
    >
      <Flex direction="column" flexGrow={1}>
        <IconButton
          variant="unstyled"
          aria-label="Menu"
          d={{ base: "inline-flex", [breakpoint]: "none" }}
          icon={<FiX />}
          size="lg"
          position="absolute"
          top="0"
          right="0"
          onClick={() => onNavClose()}
        />
        <Stack px="2">
          <Flex
            px="2"
            pt="4vh"
            pb="2vh"
            align="center"
            justify={{ base: "center", [breakpoint]: "flex-end" }}
          >
            <Link to={`/${currentYear}`}>
              <Logo w={{ base: "8rem", [breakpoint]: "12rem" }} />
            </Link>
          </Flex>
          <Stack>
            <NavLink isMain as={Link} to={`/${currentYear}`}>
              Édition {currentYear}
            </NavLink>
            {pathname.startsWith(withPrefix(`/${currentYear}`)) && (
              <>
                {/* <NavLink as={Link} to={`/${currentYear}/programme`}>
                  Programme
                </NavLink>
                <NavLink as={Link} to={`/${currentYear}/speakers`}>
                  Intervenants
                </NavLink> */}
                <NavLink as={Link} to={`/${currentYear}/sponsors`}>
                  Sponsors
                </NavLink>
                <NavLink as={Link} to={`/${currentYear}/organisateurs`}>
                  Organisateurs
                </NavLink>
                {/* <NavLink as={Link} to={`/${currentYear}/kit-de-presse`}>
                  Kit de presse
                </NavLink> */}
                <NavLink as={Link} to={`/${currentYear}/code-of-conduct`}>
                  Code de conduite
                </NavLink>
                <NavLink as={Link} to={`/${currentYear}/review-2020-2021`}>
                  Review 2020-2021
                </NavLink>
              </>
            )}
          </Stack>
          <Stack spacing="0">
            <NavLink isMain as={Link} to="/meetups">
              Meetups
            </NavLink>
            {pathname.startsWith(withPrefix("/meetups")) && (
              <>
                <NavLink as={Link} to="/meetups/sponsors">
                  Sponsors
                </NavLink>
              </>
            )}
          </Stack>
          <Stack>
            <NavLink isMain as={Link} to="/live" title="Live Twitch">
              <span role="img" aria-label="Red circle">
                ?
              </span>{" "}
              Live Stream
            </NavLink>
          </Stack>
          <Stack>
            <NavLink isMain as={Link} to="/devoxx4kids" title="Devoxx4Kids">
              Devoxx4Kids
            </NavLink>
          </Stack>
        </Stack>
        <Stack mt="auto" p="4" mb="2">
          <NavSocial />
          <NavPreviousYears />
        </Stack>
      </Flex>
    </Flex>
  );
}
Example #18
Source File: header.js    From gatsby-starter-graphcms-blog with BSD Zero Clause License 4 votes vote down vote up
function Header() {
  const [mobileNavOpen, setMobileNavOpen] = useState(false)
  const location = useLocation()
  const { pages } = useStaticQuery(graphql`
    {
      pages: allGraphCmsPage {
        nodes {
          id
          slug
          title
        }
      }
    }
  `)

  useEffect(
    () =>
      globalHistory.listen(({ action }) => {
        if (action === 'PUSH') setMobileNavOpen(false)
      }),
    [setMobileNavOpen]
  )

  const toggleMobileNavOpen = () => setMobileNavOpen((open) => !open)

  return (
    <header className="py-10 relative">
      <nav className="relative flex items-center justify-between sm:h-10 lg:justify-start">
        <div className="flex items-center flex-grow flex-shrink-0 lg:flex-grow-0">
          <div className="flex items-center justify-between w-full md:w-auto">
            <Link to="/" aria-label="GraphCMS Gatsby Blog Starter">
              <GraphCMSLogo className="hidden sm:block h-10" />
              <GraphCMSMark className="h-10 sm:hidden" />
            </Link>
            <div className="-mr-2 flex items-center md:hidden">
              <button
                onClick={() => toggleMobileNavOpen()}
                type="button"
                className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out"
                id="main-menu"
                aria-label="Main menu"
                aria-haspopup="true"
              >
                <svg
                  className="h-6 w-6"
                  stroke="currentColor"
                  fill="none"
                  viewBox="0 0 24 24"
                >
                  <path
                    strokeLinecap="round"
                    strokeLinejoin="round"
                    strokeWidth="2"
                    d="M4 6h16M4 12h16M4 18h16"
                  />
                </svg>
              </button>
            </div>
          </div>
        </div>
        <div className="hidden md:flex md:ml-10 md:pr-4 space-x-8">
          {pages.nodes.map((page) => {
            const isActive = location.pathname.startsWith(`/${page.slug}`)

            return (
              <Link
                key={page.id}
                to={`/${page.slug}`}
                className={cx(
                  'inline-flex items-center px-1 pt-1 border-b-2 text-lg font-medium leading-5 focus:outline-none transition duration-150 ease-in-out',
                  {
                    'border-purple-500 text-gray-900 focus:border-purple-600': isActive,
                    'border-transparent text-gray-500 hover:text-gray-600 hover:border-gray-300 focus:text-gray-600 focus:border-grey-600': !isActive,
                  }
                )}
              >
                {page.title}
              </Link>
            )
          })}
        </div>
      </nav>
      <Transition
        show={mobileNavOpen}
        enter="duration-150 ease-out"
        enterFrom="opacity-0 scale-95"
        enterTo="opacity-100 scale-100"
        leave="duration-100 ease-in"
        leaveFrom="opacity-100 scale-100"
        leaveTo="opacity-0 scale-95"
      >
        <div className="absolute top-0 inset-x-0 py-2 -mx-2 transition transform origin-top-right md:hidden">
          <div className="rounded-lg shadow-md">
            <div
              className="rounded-lg bg-white shadow-xs overflow-hidden"
              role="menu"
              aria-orientation="vertical"
              aria-labelledby="main-menu"
            >
              <div className="px-2 pt-8 flex items-center justify-between">
                <div>
                  <GraphCMSMark className="h-10" />
                </div>
                <div className="-mr-2">
                  <button
                    onClick={() => toggleMobileNavOpen()}
                    type="button"
                    className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out"
                    aria-label="Close menu"
                  >
                    <svg
                      className="h-6 w-6"
                      stroke="currentColor"
                      fill="none"
                      viewBox="0 0 24 24"
                    >
                      <path
                        strokeLinecap="round"
                        strokeLinejoin="round"
                        strokeWidth="2"
                        d="M6 18L18 6M6 6l12 12"
                      />
                    </svg>
                  </button>
                </div>
              </div>
              <div className="mt-1 px-2 pt-2 pb-3 space-y-1">
                {pages.nodes.map((page) => {
                  const isActive = location.pathname.startsWith(`/${page.slug}`)

                  return (
                    <Link
                      key={page.id}
                      to={`/${page.slug}`}
                      className={cx(
                        'block pl-3 pr-4 py-2 border-l-4 font-medium focus:outline-none transition duration-150 ease-in-out',
                        {
                          'border-purple-500 text-purple-500 bg-purple-50 focus:text-purple-600 focus:bg-purple-100 focus:border-purple-600': isActive,
                          'border-transparent text-gray-500 hover:text-gray-600 hover:bg-gray-50 hover:border-gray-300 focus:text-gray-600 focus:bg-gray-50 focus:border-gray-300': !isActive,
                        }
                      )}
                      role="menuitem"
                    >
                      {page.title}
                    </Link>
                  )
                })}
              </div>
            </div>
          </div>
        </div>
      </Transition>
    </header>
  )
}
Example #19
Source File: HeroContainer.js    From website with MIT License 4 votes vote down vote up
HeroContainerComponent = props => {
  const {
    backgroundImage,
    headline,
    hideHeadline,
    description,
    sideImage,
    sideImageDarkMode,
    sideImageUrl,
    sideImageDarkModeUrl,
    showLearnMore,
    eyebrow,
    eyebrowLogo,
    eyebrowMobileLogo,
    eyebrowLogoDarkMode,
    eyebrowMobileLogoDarkMode,
    showFavIcon,
    hubSpotForm,
    ctas,
    contentAlignment,
    backgroundColor,
    headlineBorderBottom,
    sideImageFlex,
    backgroundColorMobile,
    isFaq,
    sectionPadding,
    customClass,
  } = props
  const { darkMode: darkModeContextValue } = React.useContext(ContextClientSide)
  const { isDarkMode } = darkModeContextValue || {}
  const location = useLocation()
  const pathname = location.pathname.replace(/\/?$/, '/')
  const isHome = pathname === '/'
  const isAbout = pathname === '/about/'
  const isFlask = pathname === '/flask/'
  const isInstitutions = pathname === '/institutions/'
  const isInstitutionalChild =
    pathname === '/institutions/portfolio/' ||
    pathname === '/institutions/compliance/' ||
    pathname === '/institutions/nft/'
  const isCustody = pathname === '/institutions/custody/'
  const isThankYou =
    pathname === '/institutions/thank-you/' ||
    pathname === '/institutions/defi-web3-report-thank-you/'
  let hubspotWrapper
  if (hubSpotForm) {
    hubspotWrapper = (
      <HubSpotDefault>
        {contentfulModuleToComponent({
          ...hubSpotForm,
        })}
      </HubSpotDefault>
    )
  }
  const isStyleHubspot = hubSpotForm
  const isStyleCenterSimple = contentAlignment === 'center' && !sideImageUrl
  let heroTitleFontsize = ''
  if (isStyleHubspot) {
    heroTitleFontsize = '16px'
  } else if (
    (contentAlignment === 'center' || headlineBorderBottom) &&
    !isThankYou
  ) {
    heroTitleFontsize = '30px'
  }
  const { heroContainer: heroContainerREF } = React.useContext(Context)
  const { heroContainerRef } = heroContainerREF || {}

  const scrollRef = React.useRef(null)
  const [scrolled, setScrolled] = React.useState(false)

  const onScroll = () => {
    const windowY =
      window.pageYOffset ||
      document.documentElement.scrollTop ||
      document.body.scrollTop ||
      0
    if (
      scrollRef.current.getBoundingClientRect().top <=
      Number(heroContainerRef.current.offsetTop - 40)
    ) {
      setScrolled(true)
    }

    if (windowY <= 40) {
      setScrolled(false)
    }
  }

  React.useEffect(() => {
    window.addEventListener('scroll', onScroll)

    return () => {
      window.addEventListener('scroll', onScroll)
    }
  }, [])

  return (
    <>
      {showFavIcon ? (
        <FavIconContainer>
          <ContentWrapper>
            <FavIconWrapper>
              <FavIcon src={'/images/metamask-logo.png'} alt="logo" />
            </FavIconWrapper>
          </ContentWrapper>
        </FavIconContainer>
      ) : null}
      <HeroContainer
        isThankYou={isThankYou}
        sectionPadding={sectionPadding || ''}
        headlineBorderBottom={headlineBorderBottom}
        isStyleCenterSimple={isStyleCenterSimple}
        showFavIcon={showFavIcon}
        image={!isThankYou && backgroundImage}
        ref={heroContainerRef}
        className={classnames({
          [`bg-${backgroundColor}`]: backgroundColor,
          [`bg-mobile-${backgroundColorMobile}`]: backgroundColorMobile,
          [`custom-${customClass}`]: customClass,
          [`scrolled`]: scrolled,
        })}
      >
        {isThankYou && backgroundImage ? (
          <BackgroundImageContain>
            <img alt={headline} src={backgroundImage} />
          </BackgroundImageContain>
        ) : null}
        <ContentWrapper customClass={customClass}>
          <HeroContentContainer
            isStyleCenterSimple={isStyleCenterSimple}
            contentAlignment={contentAlignment}
            bgSrc={
              !isStyleHubspot && !sideImageFlex && !isFlask
                ? isDarkMode && sideImageDarkModeUrl
                  ? sideImageDarkModeUrl
                  : sideImageUrl
                : ''
            }
            isAbout={isAbout}
            reverse={contentAlignment === 'right'}
            center={sideImageFlex}
            isCustody={isCustody}
            isInstitutions={isInstitutions}
            isFlask={isFlask}
            isInstitutionalChild={isInstitutionalChild}
            isThankYou={isThankYou}
          >
            <HeroImageTextContainer
              isStyleHubspot={isStyleHubspot}
              isHome={isHome}
              headlineBorderBottom={headlineBorderBottom}
              className={classnames({
                heroMobileOverlayContent: !backgroundImage,
              })}
              center={!sideImageFlex && !isHome}
              sideImageFlex={sideImageFlex}
            >
              {eyebrowLogo ? (
                <EyebrowWrapper
                  className={classnames({ 'hidden-mobile': eyebrowMobileLogo })}
                  hideHeadline={hideHeadline}
                  isFaq={isFaq}
                >
                  {contentfulModuleToComponent(
                    eyebrowLogoDarkMode && isDarkMode
                      ? {
                          ...eyebrowLogoDarkMode,
                          cleanStyle: true,
                        }
                      : {
                          ...eyebrowLogo,
                          cleanStyle: true,
                        }
                  )}
                </EyebrowWrapper>
              ) : null}
              {eyebrowMobileLogo ? (
                <EyebrowWrapper
                  className={'hidden-desktop'}
                  hideHeadline={hideHeadline}
                  isMobileLogo={true}
                  isFaq={isFaq}
                >
                  {contentfulModuleToComponent(
                    eyebrowMobileLogoDarkMode && isDarkMode
                      ? {
                          ...eyebrowMobileLogoDarkMode,
                          cleanStyle: true,
                        }
                      : {
                          ...eyebrowMobileLogo,
                          cleanStyle: true,
                        }
                  )}
                </EyebrowWrapper>
              ) : null}
              {eyebrow ? <EyebrowText>{eyebrow}</EyebrowText> : null}
              {headline && (
                <HeroTitle
                  headlineBorderBottom={headlineBorderBottom}
                  hideHeadline={hideHeadline}
                  fontSize={heroTitleFontsize}
                  isFaq={isFaq}
                  isFlask={isFlask}
                  ref={scrollRef}
                >
                  {' '}
                  {headline}{' '}
                </HeroTitle>
              )}
              {description && (
                <HeroDescription isFaq={isFaq}>
                  <div dangerouslySetInnerHTML={{ __html: description }} />
                </HeroDescription>
              )}
              {!isEmpty(ctas) && !isFlask ? (
                <HeroCTA>
                  {ctas.map(cta =>
                    contentfulModuleToComponent({
                      ...cta,
                      buttonSize: 'hero',
                    })
                  )}
                </HeroCTA>
              ) : null}
              {hubspotWrapper ? hubspotWrapper : null}
            </HeroImageTextContainer>
            {sideImage ? (
              <HeroSideImage
                sideImageFlex={sideImageFlex}
                isStyleHubspot={isStyleHubspot}
                isFlask={isFlask}
              >
                {isStyleHubspot || sideImageFlex || isFlask ? (
                  <Image
                    image={
                      isDarkMode && !isEmpty(sideImageDarkMode)
                        ? sideImageDarkMode
                        : sideImage
                    }
                  />
                ) : null}
              </HeroSideImage>
            ) : null}
            {!isEmpty(ctas) && isFlask ? (
              <HeroCTA isFlask={isFlask}>
                {ctas.map(cta =>
                  contentfulModuleToComponent({
                    ...cta,
                    buttonSize: 'hero',
                  })
                )}
              </HeroCTA>
            ) : null}
          </HeroContentContainer>
        </ContentWrapper>
      </HeroContainer>
      {showLearnMore ? (
        <div>
          <ContentWrapper>
            <LearnMoreWrapper>
              <LearnMoreInner className="text-block">
                Learn More
                <Icon className="w-icon w-icon-dropdown-toggle"></Icon>
              </LearnMoreInner>
            </LearnMoreWrapper>
          </ContentWrapper>
        </div>
      ) : null}
    </>
  )
}
Example #20
Source File: all-products.js    From gatsby-shopify-course with BSD Zero Clause License 4 votes vote down vote up
export default function AllProducts() {
  const { products, collections } = React.useContext(ProductContext);
  const collectionProductMap = {};
  const { search } = useLocation();
  const qs = queryString.parse(search);
  const selectedCollectionIds = qs.c?.split(',').filter(c => !!c) || [];
  const selectedCollectionIdsMap = {};
  const searchTerm = qs.s;

  selectedCollectionIds.forEach(collectionId => {
    selectedCollectionIdsMap[collectionId] = true;
  });

  if (collections) {
    collections.forEach(collection => {
      collectionProductMap[collection.shopifyId] = {};

      collection.products.forEach(product => {
        collectionProductMap[collection.shopifyId][product.shopifyId] = true;
      });
    });
  }

  const filterByCategory = product => {
    if (Object.keys(selectedCollectionIdsMap).length) {
      for (let key in selectedCollectionIdsMap) {
        if (collectionProductMap[key]?.[product.shopifyId]) {
          return true;
        }
      }
      return false;
    }

    return true;
  };

  const filterBySearchTerm = product => {
    if (searchTerm) {
      return product.title.toLowerCase().indexOf(searchTerm.toLowerCase()) >= 0;
    }

    return true;
  };

  const filteredProducts = products
    .filter(filterByCategory)
    .filter(filterBySearchTerm);
  return (
    <Layout>
      <SEO
        description="The MadHatter store all products"
        title="All products"
      />
      {!!searchTerm && !!filteredProducts.length && (
        <h3>
          Search term: <strong>'{searchTerm}'</strong>
        </h3>
      )}
      {!!filteredProducts.length && <h4>{filteredProducts.length} products</h4>}
      <Content>
        <Filters />
        {!filteredProducts.length && (
          <div>
            <h3>
              <span>Oh no! Nothing matches</span>
              &nbsp;
              <strong>'{searchTerm}'</strong>
            </h3>
            <div>
              To help with your search why not try:
              <br />
              <br />
              <ul>
                <li>Checking your spelling</li>
                <li>Using less words</li>
                <li>Try using a different search term</li>
              </ul>
            </div>
          </div>
        )}
        {!!filteredProducts.length && (
          <div>
            <ProductsGrid products={filteredProducts} />
          </div>
        )}
      </Content>
    </Layout>
  );
}
Example #21
Source File: index.js    From gatsby-shopify-course with BSD Zero Clause License 4 votes vote down vote up
export default function ProductTemplate(props) {
  const { getProductById } = React.useContext(CartContext);
  const [product, setProduct] = React.useState(null);
  const [selectedVariant, setSelectedVariant] = React.useState(null);
  const { search, origin, pathname } = useLocation();
  const variantId = queryString.parse(search).variant;

  React.useEffect(() => {
    getProductById(props.data.shopifyProduct.shopifyId).then(result => {
      setProduct(result);
      setSelectedVariant(
        result.variants.find(({ id }) => id === variantId) || result.variants[0]
      );
    });
  }, [
    getProductById,
    setProduct,
    props.data.shopifyProduct.shopifyId,
    variantId,
  ]);

  const handleVariantChange = e => {
    const newVariant = product?.variants.find(v => v.id === e.target.value);
    setSelectedVariant(newVariant);
    navigate(
      `${origin}${pathname}?variant=${encodeURIComponent(newVariant.id)}`,
      {
        replace: true,
      }
    );
  };

  return (
    <Layout>
      <SEO
        description={props.data.shopifyProduct.description}
        title={props.data.shopifyProduct.title}
      />
      <Button onClick={() => navigate(-1)}>Back to products</Button>
      <Grid>
        <div>
          <h1>{props.data.shopifyProduct.title}</h1>
          <p>{props.data.shopifyProduct.description}</p>
          {product?.availableForSale && !!selectedVariant && (
            <>
              {product?.variants.length > 1 && (
                <SelectWrapper>
                  <strong>Variant</strong>
                  <select
                    value={selectedVariant.id}
                    onChange={handleVariantChange}
                  >
                    {product?.variants.map(v => (
                      <option key={v.id} value={v.id}>
                        {v.title}
                      </option>
                    ))}
                  </select>
                </SelectWrapper>
              )}
              {!!selectedVariant && (
                <>
                  <Price>£{selectedVariant.price}</Price>
                  <ProductQuantityAdder
                    available={selectedVariant.available}
                    variantId={selectedVariant.id}
                  />
                </>
              )}
            </>
          )}
        </div>
        <div>
          <ImageGallery
            selectedVariantImageId={selectedVariant?.image.id}
            images={props.data.shopifyProduct.images}
          />
        </div>
      </Grid>
    </Layout>
  );
}
Example #22
Source File: summit-2020.js    From ebpf.io-website with Creative Commons Attribution 4.0 International 4 votes vote down vote up
SpeakerCard = ({ avatarSrc, name, description, aboutTitle, aboutDescription, id, idx, isSelected, setSelectedCardIdx, showVideo, slidesLink }) => {
  const hasPopupContent = aboutTitle && aboutDescription.length > 0

  const toggleSelectedCardIdx = useCallback(
    () => setSelectedCardIdx(isSelected || !hasPopupContent ? null : idx),
    [hasPopupContent, isSelected, idx]
  )

  const resetSelectedCardIdx = useCallback(
    () => setSelectedCardIdx(null),
    [isSelected, idx]
  )

  const cardRef = useRef(null)
  const location = useLocation()

  useEffect(
    () => {
      const cardElement = cardRef.current

      if(!cardElement || !location) {
        return
      }

      const {speaker} = queryString.parse(location.search);

      if(speaker === id) {
        if(hasPopupContent) {
          setSelectedCardIdx(idx)
        }

        cardElement.scrollIntoView()
      }
    },

    [hasPopupContent, id, idx, location],
  )

  const showVideoAndClosePopup = useCallback(
    () => {
      if(!!showVideo) {
        resetSelectedCardIdx()
        showVideo()
      }
    },

    [showVideo, resetSelectedCardIdx],
  )

  return <div className="summit-speaker-card">
    <div className={cn('section', {'is-selectable': hasPopupContent, 'is-selected': isSelected})} onClick={toggleSelectedCardIdx} ref={cardRef}>
      <div className="avatar">
        <img alt={name} className="image" src={avatarSrc} />
      </div>

      <div className="section">
        <h3 className="title">{name}</h3>
        <p className="description">{description}</p>
      </div>

      {!isSelected && hasPopupContent && <img alt="" aria-hidden className="corner" src={require("../assets/summit-2020/icon-corner.svg")} />}
    </div>

    {isSelected && <div className="popup">
      <h4 className={cn('title', {'link': !!showVideo})} onClick={showVideoAndClosePopup}>{aboutTitle}</h4>
      {aboutDescription.map((description, idx) => <p className="description" key={idx}>{description}</p>)}

      <div className="video-slides-container">
        {!!showVideo && <button className="download-link video-button" onClick={showVideoAndClosePopup}>
          <img alt="Show video icon" src={require('../assets/youtube-icon.svg')} width={18} />
          Watch full replay
        </button>}

        {!!slidesLink && <a className="download-link" href={slidesLink}>
          <img
            alt="PDF download icon"
            src={require('../assets/pdf-file.svg')}
            width={18}
          />

          View slides
        </a>}
      </div>

      <button aria-label="Close" className="button" onClick={resetSelectedCardIdx} type="button">
        <img alt="Close" aria-hidden className="icon" src={require("../assets/summit-2020/icon-close.svg")} />
      </button>
    </div>}
  </div>
}
Example #23
Source File: index.js    From hitw-landing-page with MIT License 4 votes vote down vote up
function SEO({
  title = null,
  image = null,
  description = '',
  lang = 'en',
  keywords = [],
  additionalMeta = [],
}) {
  const data = useStaticQuery(graphql`
    query {
      site {
        ...SiteInfo
      }
    }
  `).site.siteMetadata;

  const { pathname } = useLocation();

  const meta = {
    title: title || data.title,
    template: title ? `%s | ${data.title}` : `%s`,
    description: description || data.description,
    keywords: [...data.keywords, ...keywords].join(','),
    lang: lang || data.lang,
    twitter: data.twitter || '',
    image: {
      src: `${data.url}${(image && image.src) || data.image.src}`,
      width: (image && image.width) || data.image.width,
      height: (image && image.height) || data.image.height,
    },
    url: `${data.url}${pathname}`,
  };

  const hasImage = (image && image.src) || (data.image && data.image.src);

  // HTML Class Name
  // page--index
  // page--success
  const htmlClassName = `page--${slugify(`${pathname.substr(1) || 'index'}`)}`;

  return (
    <Helmet
      htmlAttributes={{
        lang: meta.lang,
        class: htmlClassName,
      }}
      title={meta.title}
      titleTemplate={meta.template}
      meta={[
        {
          name: `description`,
          content: meta.description,
        },
        {
          name: 'keywords',
          content: meta.keywords,
        },
        {
          property: `og:title`,
          content: meta.title,
        },
        {
          property: `og:description`,
          content: meta.description,
        },
        {
          property: `og:type`,
          content: 'website',
        },
        {
          name: `twitter:creator`,
          content: meta.twitter,
        },
        {
          name: `twitter:title`,
          content: meta.title,
        },
        {
          name: `twitter:description`,
          content: meta.description,
        },
      ]
        .concat(
          hasImage
            ? [
                {
                  property: 'og:image',
                  content: meta.image.src,
                },
                {
                  property: 'og:image:width',
                  content: meta.image.width,
                },
                {
                  property: 'og:image:height',
                  content: meta.image.height,
                },
                {
                  name: 'twitter:card',
                  content: 'summary_large_image',
                },
              ]
            : [
                {
                  name: 'twitter:card',
                  content: 'summary',
                },
              ]
        )
        .concat(meta)}
    />
  );
}
Example #24
Source File: ShareButton.js    From warsinhk with MIT License 4 votes vote down vote up
function ShareButton(props) {
  const [anchorEl, setAnchorEl] = React.useState(null)
  const { site } = useStaticQuery(
    graphql`
      query {
        site {
          siteMetadata {
            siteUrl
          }
        }
      }
    `
  )

  function getPageUrl() {
    let url = `${site.siteMetadata.siteUrl}${fullPath}`

    if (props.caseId) {
      url = `${site.siteMetadata.siteUrl}${fullPath}/${props.caseId}`
    }

    if (!isSSR()) {
      url = url + decodeURIComponent(window.location.hash)
    }

    return url
  }

  function handleShareButtonClick(event) {
    if (!isSSR() && isWebShareAPISupported()) {
      const data = getWebShareData(getPageUrl())
      if (navigator.canShare(data)) {
        navigator.share(data).then(() => {
          trackCustomEvent({
            category: "general",
            action: "click",
            label: "share",
          })
        })

        return
      }
    }

    setAnchorEl(event.currentTarget)
  }

  function handleShareButtonClose(media) {
    setAnchorEl(null)
    if (typeof media === "string") {
      trackCustomEvent({
        category: "general",
        action: "click",
        label: `share_${media}`,
      })
    }
  }
  const { pathname: fullPath } = useLocation()

  const url = getPageUrl()

  return (
    <>
      <StyledIconButton
        color="inherit"
        aria-label="Share"
        aria-controls="share-menu"
        aria-haspopup="true"
        onClick={handleShareButtonClick}
      >
        <ShareIcon />
      </StyledIconButton>
      <Menu
        id="share-menu"
        anchorEl={anchorEl}
        keepMounted
        open={Boolean(anchorEl)}
        onClose={handleShareButtonClose}
      >
        <MenuItem onClick={() => handleShareButtonClose("facebook")}>
          <FacebookShareButton
            url={getShareUrl(url, "facebook")}
            children={<FacebookIcon size={32} round={true} />}
          />
        </MenuItem>
        <MenuItem onClick={() => handleShareButtonClose("telegram")}>
          <TelegramShareButton
            url={getShareUrl(url, "telegram")}
            children={<TelegramIcon size={32} round={true} />}
          />
        </MenuItem>
        <MenuItem onClick={() => handleShareButtonClose("whatsapp")}>
          <WhatsappShareButton
            url={getShareUrl(url, "whatsapp")}
            children={<WhatsappIcon size={32} round={true} />}
          />
        </MenuItem>
        <MenuItem onClick={() => handleShareButtonClose("twitter")}>
          <TwitterShareButton
            url={getShareUrl(url, "twitter")}
            children={<TwitterIcon size={32} round={true} />}
          />
        </MenuItem>
        <MenuItem onClick={() => handleShareButtonClose("link")}>
          <StyledCopyIcon
            onClick={() => {
              navigator.clipboard.writeText(url)
            }}
          />
        </MenuItem>
      </Menu>
    </>
  )
}
Example #25
Source File: SEO.js    From warsinhk with MIT License 4 votes vote down vote up
SEO = ({ meta, uri, titleOveride }) => {
  const { t, i18n } = useTranslation()
  const { pathname: fullPath } = useLocation()
  const path = removePathTrailingSlash(
    fullPath.replace(/^\/en(?!\w)/, "").replace(/cases\/.*$/, "cases") || "/"
  )
  const { site, configJson } = useStaticQuery(
    graphql`
      query {
        site {
          siteMetadata {
            siteUrl
          }
        }
        configJson {
          languages
          pages {
            title
            to
            icon
          }
        }
      }
    `
  )
  const currentPage = configJson.pages.find(p => p.to === path) || {}
  let title = ""
  if (titleOveride) {
    title = titleOveride
  } else {
    title = _isEmpty(currentPage) ? t("index.title") : t(currentPage.title)
    if (_isEmpty(currentPage) && !uri) {
      console.error(
        `cannot look up page title. check the settings for path: ${path}`
      )
    }
  }

  const image = `${site.siteMetadata.siteUrl}/images/og_share${
    i18n.language === "zh" ? "" : `_${i18n.language}`
  }.png`

  const localePath = i18n.language === "zh" ? "" : `${i18n.language} /`

  const siteURL = uri
    ? `${site.siteMetadata.siteUrl}/${localePath}${uri}`
    : `${site.siteMetadata.siteUrl}${fullPath}`
  return (
    <Helmet
      htmlAttributes={{
        lang: i18n.language,
      }}
      title={title}
      titleTemplate={`%s | ${t("site.title")}`}
      meta={(meta || []).concat([
        {
          name: `description`,
          content: t("site.description"),
        },
        {
          name: `keywords`,
          content: t("site.keywords"),
        },
        {
          name: "image",
          content: image,
        },
        {
          property: `og:title`,
          content: `${title} | ${t("site.title")}`,
        },
        {
          property: `og:description`,
          content: t("site.description"),
        },
        {
          property: `og:type`,
          content: `website`,
        },
        {
          property: `og:url`,
          content: siteURL,
        },
        {
          property: `og:image`,
          content: image,
        },
        {
          property: "og:image:type",
          content: "image/png",
        },
        {
          property: "og:image:width",
          content: "1200",
        },
        {
          property: "og:image:width",
          content: "630",
        },
        {
          name: `twitter:card`,
          content: `summary`,
        },
        {
          name: `twitter:title`,
          content: `${t(title)} | ${t("site.title")}`,
        },
        {
          name: `twitter:description`,
          content: t("site.description"),
        },
        {
          name: "apple-mobile-web-app-capable",
          content: "yes",
        },
        {
          name: "mobile-web-app-capable",
          content: "yes",
        },
      ])}
    >
      <script
        src="https://widget.rss.app/v1/list.js"
        type="text/javascript"
      ></script>
    </Helmet>
  )
}
Example #26
Source File: cases.js    From warsinhk with MIT License 4 votes vote down vote up
CasesPageMain = ({ dispatch, view }) => {
  const data = useAllCasesData()
  const { i18n, t } = useTranslation()
  const patientTrackKeyedByCaseNo = useMemo(
    () => _keyBy(data.patient_track.group, "fieldValue"),
    [data]
  )
  // Do the sorting here since case_no is string instead of int
  const [cases, groupArrayColumnOptions] = useMemo(() => {
    const groupArray = data.allWarsCaseRelation.edges.flatMap(
      ({ node }, index) =>
        node.case_no.split`,`.map(nodeCase => ({
          ...node,
          id: index + 1,
          related_cases: node.case_no,
          case_no: +nodeCase,
        }))
    )
    const groupArrayByCaseNo = _groupBy(groupArray, "case_no")
    const groupArrayColumnOptions = data.allWarsCaseRelation.edges.map(
      ({ node }, index) => ({
        value: index + 1,
        label: node[`name_${i18n.language}`],
      })
    )
    const cases = data.allWarsCase.edges
      .map(i => ({
        node: {
          ...i.node,
          case_no_num: +i.node.case_no,
          age_num: +i.node.age,
          groups: groupArrayByCaseNo[i.node.case_no] || [],
          group_ids: (groupArrayByCaseNo[i.node.case_no] || []).map(i => i.id),
        },
      }))
      .sort((edge1, edge2) => {
        const res = edge2.node.confirmation_date.localeCompare(
          edge1.node.confirmation_date
        )
        if (res === 0) {
          return parseInt(edge2.node.case_no) - parseInt(edge1.node.case_no)
        }
        return res
      })
    return [cases, groupArrayColumnOptions]
  }, [data, i18n.language])
  const [internalCount, setInternalCounter] = useState(0)
  const [filteredCases, setFilteredCases] = useState([])
  const [selectedCase, setSelectedCase] = useState(null)
  // 1: by date   : from latest to oldest
  // 2: by date   : from oldest to latest
  // 3: by area   : from greatest to least
  // 4: by area   : from least to greatest
  // 5: by group  : from more to less
  // 6: by group  : from less to more
  // 7: by status

  const [selectedGroupButton, setGroupButton] = useState(1)
  const { pathname } = useLocation()
  const caseCodeMatch = pathname.match(/cases\/([^/]+)/)
  const toFilterEntry = ([key, value]) => [`node.${key}`, value]
  const parseToFilter = str => {
    if (/^[-A-Z0-9]+\.\.+[-A-Z0-9]+$/i.test(str))
      return { between: str.split(/\.\.+/) }
    if (/^[><]=[-A-Z0-9]+$/i.test(str))
      return { [str[0] === ">" ? "gte" : "lte"]: str.slice(2, str.length) }
    if (/^[><][-A-Z0-9]+$/i.test(str))
      return { [str[0] === ">" ? "gt" : "lt"]: str.slice(1, str.length) }
    if (/^[-A-Z0-9]+$/i.test(str)) return str
    return
  }
  const dateRangeOptionPresets = [
    {
      label: t("cases.filters_last_n_days", { n: 7 }),
      value: `${moment()
        .subtract(6, "day")
        .format("YYYY-MM-DD")}..${moment().format(`YYYY-MM-DD`)}`,
    },
    {
      label: t("cases.filters_previous_n_days", { n: 7 }),
      value: `${moment()
        .subtract(13, "day")
        .format("YYYY-MM-DD")}..${moment()
        .subtract(7, "day")
        .format(`YYYY-MM-DD`)}`,
    },
    {
      label: t("cases.filters_last_n_days", { n: 14 }),
      value: `${moment()
        .subtract(13, "day")
        .format("YYYY-MM-DD")}..${moment().format(`YYYY-MM-DD`)}`,
    },
    {
      label: t("cases.filters_previous_n_days", { n: 14 }),
      value: `${moment()
        .subtract(27, "day")
        .format("YYYY-MM-DD")}..${moment()
        .subtract(14, "day")
        .format(`YYYY-MM-DD`)}`,
    },
    {
      label: t("cases.filters_this_month"),
      value: `${moment().format(`[>]YYYY-MM`)}`,
    },
    {
      label: t("cases.filters_previous_month"),
      value: `${moment()
        .subtract(1, "month")
        .format("YYYY-MM")}..${moment().format(`YYYY-MM`)}`,
    },
  ]
  const options = useMemo(() => {
    const stringOrFilterEntry = ([key, value]) => {
      const filterPhrases = value
        .split(/,|\s+/g)
        .filter(phase => phase && /\w$/.test(phase))
        .map(parseToFilter)
        .reduce(
          (acc, curr) => {
            if (curr) {
              curr.constructor === String
                ? acc.inq.push(curr)
                : acc.or.push(curr)
            }
            return acc
          },
          { or: [], inq: [] }
        )

      return [
        filterPhrases.inq.length
          ? { [`node.${key}`]: { inq: filterPhrases.inq } }
          : undefined,
        ...filterPhrases.or.map(phrase => ({ [`node.${key}`]: phrase })),
      ].filter(Boolean)
    }
    return [
      {
        label: t("search.group"),
        options: groupArrayColumnOptions,
        orderOptionsByFilterCount: true,
        realFieldName: "group_ids",
        toFilterEntry,
      },
      {
        label: t("search.classification"),
        options: createDedupOptions(i18n, cases, "classification"),
        orderOptionsByFilterCount: true,
        realFieldName: "classification_" + i18n.language,
        toFilterEntry,
      },
      {
        label: t("search.district"),
        options: createDedupOptions(i18n, cases, "citizenship_district"),
        orderOptionsByFilterCount: true,
        realFieldName: "citizenship_district_" + i18n.language,
        toFilterEntry,
      },
      {
        label: t("search.citizenship"),
        options: createDedupOptions(i18n, cases, "citizenship"),
        orderOptionsByFilterCount: true,
        realFieldName: "citizenship_" + i18n.language,
        toFilterEntry,
      },
      {
        label: t("search.case_status"),
        options: createDedupOptions(i18n, cases, "status"),
        orderOptionsByFilterCount: true,
        realFieldName: "status_" + i18n.language,
        toFilterEntry,
      },
      {
        label: t("search.hospital"),
        options: createDedupOptions(i18n, cases, "hospital"),
        orderOptionsByFilterCount: true,
        realFieldName: "hospital_" + i18n.language,
        toFilterEntry,
      },
      {
        label: t("search.case_no"),
        realFieldName: "case_no_num",
        filterType: "string",
        options: [],
        toFilterEntry: stringOrFilterEntry,
        isOrFilter: true,
        filterPlaceholder: "e.g. 1,3,10..20",
      },
      {
        label: t("dashboard.patient_confirm_date"),
        realFieldName: "confirmation_date",
        filterType: "string",
        options: dateRangeOptionPresets,
        toFilterEntry: stringOrFilterEntry,
        isOrFilter: true,
        filterPlaceholder: "e.g. 2020-06..2020-07-21",
      },
      {
        label: t("dashboard.patient_onset_date"),
        realFieldName: "onset_date",
        options: [
          { label: t("cases.status_asymptomatic"), value: "asymptomatic,none" },
          ...dateRangeOptionPresets,
        ],
        filterType: "string",
        toFilterEntry: stringOrFilterEntry,
        isOrFilter: true,
        filterPlaceholder: "e.g. 2020-06..2020-07-21",
      },
      {
        label: t("cases_visual.age"),
        realFieldName: "age_num",
        filterType: "string",
        options: [],
        toFilterEntry: stringOrFilterEntry,
        isOrFilter: true,
        filterPlaceholder: "e.g. 10..20,>60,>=50",
      },
      {
        label: t("cases_visual.gender"),
        realFieldName: "gender",
        options: [
          {
            value: "M",
            label: t("dashboard.gender_M"),
          },
          {
            value: "F",
            label: t("dashboard.gender_F"),
          },
        ],
        toFilterEntry,
      },
    ]
  }, [cases, dateRangeOptionPresets, groupArrayColumnOptions, i18n, t])
  const onListFiltered = useCallback(data => {
    if (data !== filteredCases) {
      setFilteredCases(data)
      setInternalCounter(i => i + 1)
    }
  }, [filteredCases])
  // Calculate how much cards we should preload in order to scorll to that position
  let preloadedCases = cases.length - parseInt(selectedCase) + 1
  if (isNaN(preloadedCases)) {
    preloadedCases = 15
  }
  const renderCaseCard = useMemo(() => {
    const RenderSingleCaseCard = (node, i) => (
      <WarsCaseCard
        node={node}
        i18n={i18n}
        t={t}
        key={`${i}-${node.id}`}
        // isSelected={selectedCase === item.node.case_no}
        // ref={selectedCase === item.node.case_no ? selectedCard : null}
        patientTrack={
          patientTrackKeyedByCaseNo[node.case_no]
            ? [patientTrackKeyedByCaseNo[node.case_no]]
            : null
        }
        handleClose={
          view === CASES_BOX_VIEW ? e => setSelectedCase(null) : undefined
        }
      />
    )
    return RenderSingleCaseCard
  }, [i18n, patientTrackKeyedByCaseNo, t, view])

  const Legend = () => {
    const items = [
      {
        icon: <MaleIcon />,
        text: t("dashboard.gender_M"),
      },
      {
        icon: <FemaleIcon />,
        text: t("dashboard.gender_F"),
      },
      {
        icon: (
          <Circle
            width={48}
            height={48}
            bgColor={mapColorForStatus("discharged").main}
          />
        ),
        text: t("cases.status_discharged"),
      },
      {
        icon: (
          <Circle
            width={48}
            height={48}
            bgColor={mapColorForStatus("pending_admission").main}
          />
        ),
        text: t("cases.status_pending_admission"),
      },
      {
        icon: (
          <Circle
            width={48}
            height={48}
            bgColor={mapColorForStatus("stable").main}
          />
        ),
        text: t("cases.status_stable"),
      },
      {
        icon: (
          <Circle
            width={48}
            height={48}
            bgColor={mapColorForStatus("hospitalised_again").main}
          />
        ),
        text: t("cases.status_hospitalised_again"),
      },
      {
        icon: (
          <Circle
            width={48}
            height={48}
            bgColor={mapColorForStatus("serious").main}
          />
        ),
        text: t("cases.status_serious"),
      },
      {
        icon: (
          <Circle
            width={48}
            height={48}
            bgColor={mapColorForStatus("critical").main}
          />
        ),
        text: t("cases.status_critical"),
      },
      {
        icon: (
          <Circle
            width={48}
            height={48}
            bgColor={mapColorForStatus("deceased").main}
          />
        ),
        text: t("cases.status_deceased"),
      },
      {
        icon: (
          <Circle
            width={48}
            height={48}
            bgColor={mapColorForStatus("no_admission").main}
          />
        ),
        text: t("cases.status_no_admission"),
      },
      {
        icon: <ImportIcon />,
        text: t("cases.imported"),
      },
      {
        icon: <UnknownIcon />,
        text: t("cases.unknown"),
      },
    ]

    return (
      <Accordion
        style={{ marginBottom: 16 }}
        title={
          <LegendTitle>
            <QuestionIcon />
            <span>{t("cases.legend")}</span>
          </LegendTitle>
        }
        content={
          <LegendContent>
            {items.map((item, i) => (
              <div key={i} className="item">
                {item.icon}
                <span>{item.text}</span>
              </div>
            ))}
          </LegendContent>
        }
      />
    )
  }

  const toggleGroupingButtons = [
    "cases.toggle_date",
    "cases.toggle_date_reverse",
    "cases.toggle_area",
    "cases.toggle_area_reverse",
    "cases.toggle_group",
    "cases.toggle_group_reverse",
    "cases.toggle_status",
  ]

  const handleBoxClick = item => {
    setSelectedCase(item)

    trackCustomEvent({
      category: "cases",
      action: "click_avatar",
      label: item.case_no,
    })
  }
  const isCaseNumberMatch =
    caseCodeMatch && filteredCases.length === 1 && filteredCases[0]
  return (
    <Layout
      onClick={e =>
        typeof e.target.className === "string" &&
        !e.target.className.includes("wars_box") &&
        setSelectedCase(null)
      }
    >
      {isCaseNumberMatch ? (
        <SEO
          titleOveride={t("case.title")}
          // TODO: duplicated entries, filter out in SEO later?
          meta={[
            {
              property: `og:title`,
              content: `${t("index.title")} | ${t("case.case_no", {
                case_no: filteredCases[0].node.case_no,
              })}`,
            },
            {
              property: `og:description`,
              content: withLanguage(i18n, filteredCases[0].node, "detail"),
            },
          ]}
        />
      ) : (
        <SEO title="ConfirmedCasePage" />
      )}
      <TitleContainer>
        <Typography variant="h2">{t("cases.title")}</Typography>
        <span>
          <BoxViewIcon
            className={view === CASES_BOX_VIEW && "active"}
            onClick={() => {
              dispatch({
                type: CASES_BOX_VIEW,
              })
              trackCustomEvent({
                category: "cases",
                action: "toggle_view",
                label: "BOX_VIEW",
              })
            }}
          />
          <CardViewIcon
            className={view === CASES_CARD_VIEW && "active"}
            onClick={() => {
              dispatch({
                type: CASES_CARD_VIEW,
              })
              trackCustomEvent({
                category: "cases",
                action: "toggle_view",
                label: "CARD_VIEW",
              })
            }}
          />
        </span>
      </TitleContainer>
      <PageContent>
        <ConfirmedCasesSummary />
        {view === CASES_BOX_VIEW && <Legend />}
        <Typography variant="h5" style={{ marginTop: 16 }}>
          {t("cases.filters")}
        </Typography>
        <TagStyleFilter
          key={pathname}
          list={cases}
          placeholder={t("search.case_placeholder")}
          options={options}
          searchKey="case"
          onListFiltered={onListFiltered}
          filterWithOr={false}
          initialFilters={
            caseCodeMatch
              ? [
                  {
                    label: caseCodeMatch[1],
                    filterName: t("search.case_no"),
                    realFieldName: "case_no_num",
                    field: "case_no_num",
                    value: caseCodeMatch[1],
                  },
                ]
              : []
          }
        />
        {view === CASES_BOX_VIEW && (
          <DefaultSelect
            value={selectedGroupButton}
            onChange={event => {
              setGroupButton(event.target.value)
              trackCustomEvent({
                category: "cases",
                action: "set_grouping",
                label: toggleGroupingButtons[event.target.value - 1],
              })
            }}
            displayEmpty
            IconComponent={SortIcon}
          >
            {toggleGroupingButtons.map((groupBy, index) => (
              <MenuItem key={index} value={index + 1}>
                {t(groupBy)}
              </MenuItem>
            ))}
          </DefaultSelect>
        )}

        <Typography variant="h6" style={{ marginTop: 16 }}>
          {filteredCases.length > 1
            ? t("cases.filter_results_plural", { count: filteredCases.length })
            : t("cases.filter_results", { count: filteredCases.length })}
        </Typography>
      </PageContent>
      {view === CASES_BOX_VIEW ? (
        <>
          <WarsCaseBoxContainer
            filteredCases={filteredCases}
            handleBoxClick={handleBoxClick}
            selectedGroupButton={selectedGroupButton}
          />
          {selectedCase && (
            <SelectedCardContainer>
              {renderCaseCard(selectedCase)}
            </SelectedCardContainer>
          )}
        </>
      ) : (
        <InfiniteScroll
          key={internalCount} // The state of this InfiniteScroll Component need to be discarded when filteredCases changes.
          list={filteredCases.map(c => c.node)}
          step={{ mobile: 5, preload: preloadedCases }}
          onItem={renderCaseCard}
          Wrapper={ResponsiveWrapper}
        />
      )}
    </Layout>
  )
}
Example #27
Source File: ContentfulLayout.js    From website with MIT License 4 votes vote down vote up
ContentfulLayout = props => {
  const {
    data: {
      header,
      footer,
      seo,
      heroes: H,
      features: F,
      richTexts: RT,
      layoutModuleContainers: LMC,
      moduleContainers: MC,
      cards: C,
      ctas: CTA,
      faqs: FAQ,
      embeds: HTML,
      logos: L,
      hubspotForms: HF,
      fullWidthCtas: FWC,
    },
    pageContext: { modules, pathBuild, themeColor, isFaqLayout, h2FontSize },
    path,
    ...rest
  } = props

  const location = useLocation()
  const pathname = location.pathname
  let partnerId = '451393'
  let conversionId = ''
  if (pathname.includes('/institutions')) {
    partnerId = '4249353'
    conversionId = '7714137'
  }
  const linkedInPartnerId = '_linkedin_partner_id = "' + partnerId + '";'
  const linkedInEventPixel =
    '<img height="1" width="1" style="display:none;" alt="" src="https://px.ads.linkedin.com/collect/?pid=' +
    partnerId +
    (conversionId ? '&conversionId=' + conversionId : '') +
    '&fmt=gif"/>'

  const [idFaqActive, setIdFaqActive] = React.useState('')
  const [paginationPage, setPaginationPage] = React.useState(1)
  const valueContext = {
    faq: {
      idFaqActive,
      setIdFaqActive,
    },
    pagination: {
      paginationPage,
      setPaginationPage,
    },
  }

  // takes all modules single content type for a page and returns all instances
  const getNodes = mods => {
    if (!mods) return
    else if (isArray(mods.edges)) return getNodes(mods.edges)
    return isArray(mods) ? mods.map(n => n.node) : mods
  }

  // extract all top-level page modules from GraphQL and return in a flat array for rendering
  const pageModules = flatMapDeep(
    [H, F, RT, LMC, MC, C, CTA, FAQ, HTML, L, HF, FWC],
    getNodes
  )

  // Take unordered list of data from pageModules and reorder
  // based on contentful_id sequence in pageContext.modules
  // returned by CMS to maintain page structure
  const orderedPageModules = pageModules.reduce((acc, node) => {
    if (!node || !node.contentful_id) return acc
    const positionInPage = modules.indexOf(node.contentful_id)
    acc.splice(positionInPage, 1, node) // remove empty element and replace with module data
    return acc
  }, Array(modules.length - 1)) // prepopulate array so we can insert last elements if they appear first

  const allModules = [header, ...orderedPageModules, footer]

  return (
    <Context.Provider value={valueContext}>
      <Layout {...rest} themeColor={themeColor} h2FontSize={h2FontSize}>
        {seo && contentfulModuleToComponent({ ...seo, pagePath: pathBuild })}
        {allModules.map(module =>
          contentfulModuleToComponent({ ...module, isFaq: isFaqLayout })
        )}
        <script
          type="text/javascript"
          dangerouslySetInnerHTML={{
            __html: linkedInPartnerId + linkedInTrackingScript,
          }}
        />
        <noscript dangerouslySetInnerHTML={{ __html: linkedInEventPixel }} />
      </Layout>
    </Context.Provider>
  )
}