Skip to content

Commit

Permalink
Merge e88666d into 0bd77b4
Browse files Browse the repository at this point in the history
  • Loading branch information
oshi97 committed Oct 15, 2021
2 parents 0bd77b4 + e88666d commit 077947e
Show file tree
Hide file tree
Showing 15 changed files with 450 additions and 181 deletions.
6 changes: 3 additions & 3 deletions THIRD-PARTY-NOTICES
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

The following NPM package may be included in this product:

- @reduxjs/toolkit@1.6.1
- @reduxjs/toolkit@1.6.2

This package contains the following license and notice below:

Expand Down Expand Up @@ -96,7 +96,7 @@ The following NPM packages may be included in this product:

- @yext/answers-core@1.3.2
- @yext/answers-headless-react@0.3.0-beta.0
- @yext/answers-headless@0.0.4
- @yext/answers-headless@0.0.5

These packages each contain the following license and notice below:

Expand Down Expand Up @@ -220,7 +220,7 @@ SOFTWARE.

The following NPM package may be included in this product:

- immer@9.0.5
- immer@9.0.6

This package contains the following license and notice below:

Expand Down
195 changes: 25 additions & 170 deletions sample-app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,184 +1,39 @@
import './sass/App.scss';
import VerticalSearchPage from './pages/VerticalSearchPage';
import UniversalSearchPage from './pages/UniversalSearchPage';
import PageRouter from './PageRouter';
import StandardLayout from './pages/StandardLayout';
import { AnswersActionsProvider } from '@yext/answers-headless-react';
import AlternativeVerticals from './components/AlternativeVerticals';
import DecoratedAppliedFilters from './components/DecoratedAppliedFilters';
import { StandardCard } from './components/cards/StandardCard';
import ResultsCount from './components/ResultsCount';
import SearchBar from './components/SearchBar';
import StaticFilters from './components/StaticFilters';
import VerticalResults from './components/VerticalResults';
import SpellCheck from './components/SpellCheck';
import LocationBias from './components/LocationBias';
import UniversalResults from './components/UniversalResults';
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import Facets from './components/Facets';

function App() {
const staticFilterOptions = [
{
label: 'canada',
fieldId: 'c_employeeCountry',
value: 'Canada',
},
{
label: 'remote',
fieldId: 'c_employeeCountry',
value: 'Remote'
},
{
label: 'usa',
fieldId: 'c_employeeCountry',
value: 'United States',
},
{
label: 'tech',
fieldId: 'c_employeeDepartment',
value: 'Technology'
},
{
label: 'consult',
fieldId: 'c_employeeDepartment',
value: 'Consulting',
},
{
label: 'fin',
fieldId: 'c_employeeDepartment',
value: 'Finance',
}
]

const universalResultsConfig = {
people: {
label: "People",
viewMore: true,
cardConfig: {
CardComponent: StandardCard,
showOrdinal: true
}
},
events: {
label: "events",
cardConfig: {
CardComponent: StandardCard,
showOrdinal: true
}
},
links: {
label: "links",
viewMore: true,
cardConfig: {
CardComponent: StandardCard,
showOrdinal: true
}
},
financial_professionals: {
label: "Financial Professionals",
},
healthcare_professionals: {
label: "Healthcare Professionals",
import { universalResultsConfig } from './universalResultsConfig';

const routes = [
{
path: '/',
exact: true,
page: <UniversalSearchPage universalResultsConfig={universalResultsConfig} />
},
...Object.keys(universalResultsConfig).map(key => {
return {
path: `/${key}`,
page: <VerticalSearchPage verticalKey={key} />
}
}

const universalResultsFilterConfig = {
show: true
};

const facetConfigs = {
c_employeeDepartment: {
label: 'Employee Department!'
}
}
})
];

export default function App() {
return (
<AnswersActionsProvider
apiKey='2d8c550071a64ea23e263118a2b0680b'
experienceKey='slanswers'
locale='en'
verticalKey='people'
>
{/*
TODO: use Navigation component for routing when that's added to repo.
current setup is for testing purposes.
*/}
<Router>
<Switch>
{/* universal search */}
<Route exact path='/'>
<div className='start'>
test
</div>
<div className='end'>
<SearchBar
placeholder='Search...'
isVertical={false}
/>
<div>
<UniversalResults
appliedFiltersConfig={universalResultsFilterConfig}
verticalConfigs={universalResultsConfig}
/>
</div>
</div>
</Route>

{/* vertical page */}
<Route path={Object.keys(universalResultsConfig).map(key => `/${key}`)}>
<div>
A VERTICAL PAGE!
</div>
</Route>

{/* vertical search */}
<Route exact path='/vertical'>
<div className='start'>
test
<StaticFilters
title='~Country and Employee Departments~'
options={staticFilterOptions}
/>
<Facets
searchOnChange={true}
searchable={true}
collapsible={true}
defaultExpanded={true}
facetConfigs={facetConfigs}
/>
<SpellCheck
isVertical={true}
/>
</div>
<div className='end'>
<SearchBar
placeholder='Search...'
isVertical={true}
/>
<div>
<ResultsCount />
<DecoratedAppliedFilters
showFieldNames={true}
hiddenFields={['builtin.entityType']}
delimiter='|'
/>
<AlternativeVerticals
currentVerticalLabel='People'
verticalsConfig={[
{ label: 'Locations', verticalKey: 'KM' },
{ label: 'FAQs', verticalKey: 'faq' }
]}
/>
<VerticalResults
CardComponent={StandardCard}
cardConfig={{ showOrdinal: true }}
displayAllResults={true}
/>
<LocationBias isVertical={false} />
</div>
</div>
</Route>
</Switch>
</Router>
<div className='App'>
<PageRouter
Layout={StandardLayout}
routes={routes}
/>
</div>
</AnswersActionsProvider>
);
}

export default App;
41 changes: 41 additions & 0 deletions sample-app/src/PageRouter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { ComponentType } from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';

interface RouteData {
path: string
page: JSX.Element
exact?: boolean
}

export type LayoutComponent = ComponentType<{ page: JSX.Element }>

interface PageProps {
Layout?: LayoutComponent
routes: RouteData[]
}

/**
* PageRouter abstracts away logic surrounding react-router, and provides an easy way
* to specify a {@link LayoutComponent} for a page.
*/
export default function PageRouter({ Layout, routes }: PageProps) {
const pages = routes.map(routeData => {
const { path, page, exact } = routeData;
if (Layout) {
return (
<Route key={path} path={path} exact={exact}>
<Layout page={page}/>
</Route>
);
}
return <Route key={path} path={path} exact={exact}>{page}</Route>;
});

return (
<Router>
<Switch>
{pages}
</Switch>
</Router>
);
}
99 changes: 99 additions & 0 deletions sample-app/src/components/Navigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import classNames from 'classnames';
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
import { NavLink, useLocation } from 'react-router-dom';
import { ReactComponent as KebabIcon } from '../icons/kebab.svg';
import '../sass/Navigation.scss';

interface LinkData {
to: string
label: string
}

interface NavigationProps {
links: LinkData[]
}

export default function Navigation({ links }: NavigationProps) {
// Close the menu when clicking the document
const [menuOpen, setMenuOpen] = useState<boolean>(false);
const menuRef = useRef<HTMLButtonElement>(null);
const handleDocumentClick = (e: MouseEvent) => {
if (e.target !== menuRef.current) {
setMenuOpen(false);
}
};
useLayoutEffect(() => {
document.addEventListener('click', handleDocumentClick)
return () => document.removeEventListener('click', handleDocumentClick);
}, []);

// Responsive tabs
const [numOverflowLinks, setNumOverflowLinks] = useState<number>(0);
const navigationRef = useRef<HTMLDivElement>(null);
const handleResize = useCallback(() => {
const navEl = navigationRef.current;
if (!navEl) {
return;
}
const isOverflowing = navEl.scrollWidth > navEl.offsetWidth;
if (isOverflowing && numOverflowLinks < links.length) {
setNumOverflowLinks(numOverflowLinks + 1);
}
}, [links.length, numOverflowLinks])
useLayoutEffect(handleResize, [handleResize]);
useEffect(() => {
let timeoutId: NodeJS.Timeout;
function resizeListener() {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
setNumOverflowLinks(0);
handleResize()
}, 50)
};
window.addEventListener('resize', resizeListener);
return () => window.removeEventListener('resize', resizeListener);
}, [handleResize]);

const { search } = useLocation();
const visibleLinks = links.slice(0, links.length - numOverflowLinks);
const overflowLinks = links.slice(-numOverflowLinks);
const menuButtonClassNames = classNames('Navigation__menuButton', {
'Navigation__menuButton--open': menuOpen
});
return (
<nav className='Navigation' ref={navigationRef}>
<div className='Navigation__links'>
{visibleLinks.map(l => renderLink(l, search))}
</div>
{numOverflowLinks > 0 &&
<div className='Navigation__menuWrapper'>
<button
className={menuButtonClassNames}
ref={menuRef}
onClick={() => setMenuOpen(!menuOpen)}
>
<KebabIcon /> More
</button>
<div className='Navigation__menuLinks'>
{menuOpen && overflowLinks.map(l => renderLink(l, search))}
</div>
</div>
}
</nav>
)
}

function renderLink(linkData: LinkData, queryParams: string) {
const { to, label } = linkData;
return (
<NavLink
key={to}
className='Navigation__link'
activeClassName='Navigation__link--currentRoute'
to={`${to}${queryParams}`}
exact={true}
>
{label}
</NavLink>
)
}
2 changes: 1 addition & 1 deletion sample-app/src/components/UniversalResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { CardConfig } from '../models/cardComponent';
import classNames from "classnames";
import '../sass/UniversalResults.scss';

interface VerticalConfig {
export interface VerticalConfig {
SectionComponent?: SectionComponent,
cardConfig?: CardConfig,
label?: string,
Expand Down
Loading

0 comments on commit 077947e

Please sign in to comment.