-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement range date filter as standalone component
- Loading branch information
1 parent
2f83a52
commit 572aad4
Showing
5 changed files
with
656 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
124 changes: 124 additions & 0 deletions
124
packages/gatsby-theme-docs/src/layouts/release-notes-search.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
import React, { useRef } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { LordIcon, Markdown } from '@commercetools-docs/ui-kit'; | ||
import SpacingsStack from '@commercetools-uikit/spacings-stack'; | ||
import { useInView } from 'react-intersection-observer'; | ||
import useLayoutState from '../hooks/use-layout-state'; | ||
import { useSiteData } from '../hooks/use-site-data'; | ||
import { | ||
PlanTag, | ||
BetaTag, | ||
ContentPagination, | ||
GlobalNotification, | ||
} from '../components'; | ||
import PlaceholderPageHeaderSide from '../overrides/page-header-side'; | ||
import PlaceholderPageHeaderSideBannerArea from '../overrides/page-header-banner-area'; | ||
import LayoutApplication from './internals/layout-application'; | ||
import LayoutHeader from './internals/layout-header'; | ||
import LayoutSidebar from './internals/layout-sidebar'; | ||
import LayoutMain from './internals/layout-main'; | ||
import LayoutFooter from './internals/layout-footer'; | ||
import LayoutPageWrapper from './internals/layout-page-wrapper'; | ||
import LayoutPage from './internals/layout-page'; | ||
import LayoutGlobalNotification from './internals/layout-global-notification'; | ||
import LayoutPageHeader from './internals/layout-page-header'; | ||
import LayoutPageHeaderSide from '../overrides/layout-page-header-side'; | ||
import LayoutPageNavigation from './internals/layout-page-navigation'; | ||
import LayoutPageContent from './internals/layout-page-content'; | ||
import PageContentInset from './internals/page-content-inset'; | ||
import PageReadTime from './internals/page-read-time-estimation'; | ||
import CourseCompleteModal from '../modules/self-learning/components/course-complete-modal'; | ||
import { useCourseInfoByPageSlugs } from '../modules/self-learning/hooks/use-course-pages'; | ||
import styled from '@emotion/styled'; | ||
import useAiAssistant from '../modules/ai-assistant/hooks/use-ai-assistant'; | ||
|
||
const PlansWrapper = styled.div` | ||
& > span { | ||
margin-right: 10px; | ||
} | ||
`; | ||
|
||
const LayoutReleaseNotesSearch = (props) => { | ||
const { ref, inView, entry } = useInView(); | ||
const isSearchBoxInView = !Boolean(entry) || inView; | ||
const layoutState = useLayoutState(); | ||
const siteData = useSiteData(); | ||
const excludeFromSearchIndex = false; | ||
useAiAssistant(); | ||
return ( | ||
<LayoutApplication | ||
globalNotification={siteData.siteMetadata.globalNotification} | ||
> | ||
<LayoutSidebar | ||
{...layoutState.sidebar} | ||
{...layoutState.searchDialog} | ||
{...layoutState.topMenu} | ||
siteTitle={siteData.siteMetadata.title} | ||
isGlobalBeta={siteData.siteMetadata.beta} | ||
hasReleaseNotes={false} | ||
/> | ||
<LayoutMain | ||
{...layoutState.topMenu} | ||
preventScroll={ | ||
layoutState.topMenu.isTopMenuOpen || | ||
layoutState.sidebar.isSidebarMenuOpen | ||
} | ||
> | ||
<LayoutHeader | ||
{...layoutState.searchDialog} | ||
{...layoutState.topMenu} | ||
ref={ref} | ||
siteTitle={siteData.siteMetadata.title} | ||
excludeFromSearchIndex={excludeFromSearchIndex} | ||
allowWideContentLayout={false} | ||
/> | ||
<LayoutPageWrapper> | ||
<LayoutPage allowWideContentLayout={false}> | ||
<LayoutGlobalNotification> | ||
{siteData.siteMetadata.globalNotification.active && ( | ||
<GlobalNotification | ||
type={ | ||
siteData.siteMetadata.globalNotification.notificationType | ||
} | ||
> | ||
{siteData.siteMetadata.globalNotification.content} | ||
</GlobalNotification> | ||
)} | ||
</LayoutGlobalNotification> | ||
<LayoutPageHeader> | ||
<Markdown.H1>Relase notes</Markdown.H1> | ||
</LayoutPageHeader> | ||
<LayoutPageHeaderSide> | ||
<SpacingsStack scale="m"> | ||
<PlaceholderPageHeaderSide /> | ||
<PlaceholderPageHeaderSideBannerArea /> | ||
</SpacingsStack> | ||
</LayoutPageHeaderSide> | ||
<LayoutPageContent> | ||
<PageContentInset id="body-content" showRightBorder> | ||
{props.children} | ||
</PageContentInset> | ||
</LayoutPageContent> | ||
{/* <LayoutPageNavigation | ||
{...layoutState.searchDialog} | ||
isSearchBoxInView={isSearchBoxInView} | ||
excludeFromSearchIndex={excludeFromSearchIndex} | ||
pageTitle={props.pageContext.shortTitle || props.pageData.title} | ||
tableOfContents={props.pageData.tableOfContents} | ||
navLevels={props.pageData.navLevels} | ||
beta={isBeta} | ||
planTags={planTags} | ||
/> */} | ||
</LayoutPage> | ||
</LayoutPageWrapper> | ||
<LayoutFooter /> | ||
</LayoutMain> | ||
</LayoutApplication> | ||
); | ||
}; | ||
LayoutReleaseNotesSearch.displayName = 'LayoutReleaseNotesSearch'; | ||
LayoutReleaseNotesSearch.propTypes = { | ||
children: PropTypes.node.isRequired, | ||
}; | ||
|
||
export default LayoutReleaseNotesSearch; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
96 changes: 96 additions & 0 deletions
96
websites/docs-smoke-test/src/pages/release-notes-search.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import { ThemeProvider } from '@commercetools-docs/gatsby-theme-docs'; | ||
import LayoutReleaseNotesSearch from '@commercetools-docs/gatsby-theme-docs/src/layouts/release-notes-search'; | ||
import algoliasearch from 'algoliasearch/lite'; | ||
import { | ||
Hits, | ||
InstantSearch, | ||
RefinementList, | ||
useRange, | ||
} from 'react-instantsearch'; | ||
import 'instantsearch.css/themes/satellite.css'; | ||
import { IntlProvider } from 'react-intl'; | ||
import DateRangeField from '@commercetools-uikit/date-range-field'; | ||
import { useEffect, useState } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
const convertDateToTimestamp = (dateString) => { | ||
const dateRegex = /^\d{4}-\d{2}-\d{2}$/; | ||
if (!dateString || !dateString.match(dateRegex)) { | ||
return null; | ||
} | ||
const date = new Date(dateString); | ||
const timestamp = Math.floor(date.getTime() / 1000); | ||
return timestamp; | ||
}; | ||
|
||
const DateRangeInput = (props) => { | ||
// Two important concept to keep in mind: | ||
// - `range` is the maximum and minimum selectable values, they don't make much sense in the context of a date picker | ||
// - `start` (stupid name) is the actual selected range, it's an array of two values. It must always be defined, meaning that | ||
// when date picker is cleared the values must be set to undefined which automatically sets the start to the value of `range` | ||
const { canRefine, refine } = useRange(props); | ||
const [value, setValue] = useState([]); | ||
|
||
const handleDateChange = (event) => { | ||
const changeValue = event.target.value; | ||
if (!changeValue || changeValue.length !== 2) { | ||
setValue([]); | ||
} | ||
setValue(changeValue); | ||
}; | ||
|
||
useEffect(() => { | ||
if (value.length !== 2) { | ||
refine(undefined); | ||
} | ||
refine([ | ||
convertDateToTimestamp(value[0]), | ||
convertDateToTimestamp(value[1]), | ||
]); | ||
}, [value, refine]); | ||
|
||
return ( | ||
<DateRangeField | ||
horizontalConstraint={7} | ||
title="Release Date" | ||
value={value} | ||
onChange={handleDateChange} | ||
isDisabled={!canRefine} | ||
/> | ||
); | ||
}; | ||
|
||
const searchClient = algoliasearch(); | ||
// REDACTED: App ID | ||
// REDACTED: API key | ||
|
||
const ReleaseNotesSearch = () => { | ||
return ( | ||
<IntlProvider locale="en"> | ||
<ThemeProvider> | ||
<LayoutReleaseNotesSearch> | ||
<InstantSearch searchClient={searchClient} indexName="docs-releases"> | ||
<RefinementList attribute="product" /> | ||
<DateRangeInput | ||
attribute="dateTimestamp" | ||
min={0} // min and max are required as they define the selected range and it must always be defined. | ||
max={2537011284} | ||
/> | ||
<Hits hitComponent={Hit}></Hits> | ||
</InstantSearch> | ||
</LayoutReleaseNotesSearch> | ||
</ThemeProvider> | ||
</IntlProvider> | ||
); | ||
}; | ||
const Hit = ({ hit }) => { | ||
return <p>{hit.date}</p>; | ||
}; | ||
|
||
Hit.propTypes = { | ||
hit: PropTypes.shape({ | ||
date: PropTypes.string.isRequired, | ||
}).isRequired, | ||
}; | ||
|
||
export default ReleaseNotesSearch; |
Oops, something went wrong.