@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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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>
<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 |
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 |
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 |
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 |
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 |
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 |
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 |
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>
)
}