Skip to content

Commit

Permalink
Merge 967744d into bd984ed
Browse files Browse the repository at this point in the history
  • Loading branch information
cea2aj committed Dec 3, 2021
2 parents bd984ed + 967744d commit fae449e
Show file tree
Hide file tree
Showing 18 changed files with 235 additions and 105 deletions.
27 changes: 9 additions & 18 deletions sample-app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions sample-app/src/components/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ interface LinkData {
interface NavigationProps {
links: LinkData[],
customCssClasses?: NavigationCssClasses,
compositionMethod?: CompositionMethod
cssCompositionMethod?: CompositionMethod
}

export default function Navigation({ links, customCssClasses, compositionMethod }: NavigationProps) {
const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses, compositionMethod);
export default function Navigation({ links, customCssClasses, cssCompositionMethod }: NavigationProps) {
const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses, cssCompositionMethod);
// Close the menu when clicking the document
const [menuOpen, setMenuOpen] = useState<boolean>(false);
const menuRef = useRef<HTMLButtonElement>(null);
Expand Down
36 changes: 29 additions & 7 deletions sample-app/src/components/UniversalResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,24 @@ import { DecoratedAppliedFiltersConfig } from '../components/DecoratedAppliedFil
import SectionHeader from "../sections/SectionHeader";
import { SectionComponent } from "../models/sectionComponent";
import { CardConfig } from '../models/cardComponent';
import { useComposedCssClasses, CompositionMethod } from "../hooks/useComposedCssClasses";
import classNames from "classnames";
import '../sass/UniversalResults.scss';

interface UniversalResultsCssClasses {
container?: string,
results___loading?: string
}

const builtInCssClasses: UniversalResultsCssClasses = {
container: 'space-y-8 mt-6',
results___loading: 'opacity-50'
}

export interface VerticalConfig {
SectionComponent?: SectionComponent,
cardConfig?: CardConfig,
label?: string,
viewMore?: boolean
viewAllButton?: boolean
}

interface AppliedFiltersConfig extends Omit<DecoratedAppliedFiltersConfig, 'appliedQueryFilters'> {
Expand All @@ -20,24 +30,31 @@ interface AppliedFiltersConfig extends Omit<DecoratedAppliedFiltersConfig, 'appl

interface UniversalResultsProps {
appliedFiltersConfig?: AppliedFiltersConfig,
verticalConfigs: Record<string, VerticalConfig>
verticalConfigs: Record<string, VerticalConfig>,
customCssClasses?: UniversalResultsCssClasses,
cssCompositionMethod?: CompositionMethod
}

/**
* A component that displays all the vertical results of a universal search.
*/
export default function UniversalResults({
verticalConfigs,
appliedFiltersConfig
appliedFiltersConfig,
customCssClasses,
cssCompositionMethod
}: UniversalResultsProps): JSX.Element | null {
const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses, cssCompositionMethod)
const resultsFromAllVerticals = useAnswersState(state => state?.universal?.verticals) || [];
const isLoading = useAnswersState(state => state.searchStatus.isLoading);

if (resultsFromAllVerticals.length === 0) {
return null;
}

const resultsClassNames = classNames('UniversalResults', { 'UniversalResults--loading': isLoading });
const resultsClassNames = cssClasses.results___loading
? classNames(cssClasses.container, { [cssClasses.results___loading]: isLoading })
: cssClasses.container;

return (
<div className={resultsClassNames}>
Expand Down Expand Up @@ -81,9 +98,14 @@ function renderVerticalSections(props: VerticalSectionsProps): JSX.Element {
return <SectionComponent
results={results}
verticalKey={verticalKey}
header={<SectionHeader {...{ label, resultsCountConfig, appliedFiltersConfig }}/>}
header={<SectionHeader {...{
label,
resultsCountConfig,
appliedFiltersConfig,
verticalKey,
viewAllButton: verticalConfig.viewAllButton
}}/>}
cardConfig={verticalConfig.cardConfig}
viewMore={verticalConfig.viewMore}
key={verticalKey}
/>
})
Expand Down
25 changes: 20 additions & 5 deletions sample-app/src/components/VerticalResults.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import { CardComponent, CardConfigTypes } from '../models/cardComponent';
import { useAnswersState, Result } from '@yext/answers-headless-react';
import classNames from 'classnames';
import '../sass/VerticalResults.scss';
import { CompositionMethod, useComposedCssClasses } from '../hooks/useComposedCssClasses';

interface VerticalResultsCssClasses {
results___loading?: string
}

const builtInCssClasses: VerticalResultsCssClasses = {
results___loading: 'opacity-50'
}

interface VerticalResultsDisplayProps {
CardComponent: CardComponent,
cardConfig?: CardConfigTypes,
isLoading?: boolean,
results: Result[]
results: Result[],
customCssClasses?: VerticalResultsCssClasses,
cssCompositionMethod?: CompositionMethod
}

/**
Expand All @@ -17,13 +27,16 @@ interface VerticalResultsDisplayProps {
* to be used.
*/
export function VerticalResultsDisplay(props: VerticalResultsDisplayProps): JSX.Element | null {
const { CardComponent, results, cardConfig = {}, isLoading = false } = props;
const { CardComponent, results, cardConfig = {}, isLoading = false, customCssClasses, cssCompositionMethod } = props;
const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses, cssCompositionMethod);

if (results.length === 0) {
return null;
}

const resultsClassNames = classNames('VerticalResults', { 'VerticalResults--loading': isLoading });
const resultsClassNames = cssClasses.results___loading
? classNames({ [cssClasses.results___loading]: isLoading })
: '';

return (
<div className={resultsClassNames}>
Expand All @@ -46,7 +59,9 @@ function renderResult(CardComponent: CardComponent, cardConfig: CardConfigTypes,
interface VerticalResultsProps {
CardComponent: CardComponent,
cardConfig?: CardConfigTypes,
displayAllResults?: boolean
displayAllResults?: boolean,
customCssClasses?: VerticalResultsCssClasses,
cssCompositionMethod?: CompositionMethod
}

export default function VerticalResults(props: VerticalResultsProps): JSX.Element | null {
Expand Down
104 changes: 85 additions & 19 deletions sample-app/src/components/cards/StandardCard.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,54 @@
import { CompositionMethod, useComposedCssClasses } from '../../hooks/useComposedCssClasses';
import { CardProps } from '../../models/cardComponent';

export interface StandardCardConfig {
showOrdinal?: boolean
}

export interface StandardCardProps extends CardProps {
configuration: StandardCardConfig
configuration: StandardCardConfig,
customCssClasses?: StandardCardCssClasses,
cssCompositionMethod?: CompositionMethod
}

export interface StandardCardCssClasses {
container?: string,
header?: string,
body?: string,
descriptionContainer?: string,
ctaContainer?: string,
cta1?: string,
cta2?: string,
ordinal?: string,
title?: string
}

const builtInCssClasses: StandardCardCssClasses = {
container: 'StandardCard flex flex-col justify-between border rounded-lg mt-4 p-4',
header: 'flex text-gray-800',
body: 'flex justify-end pt-2.5',
descriptionContainer: 'w-full text-base',
ctaContainer: 'flex flex-col justify-end ml-4',
cta1: 'min-w-max bg-blue-600 text-white font-medium rounded-lg py-2 px-5',
cta2: 'min-w-max bg-white text-blue-600 font-medium rounded-lg py-2 px-5 mt-2 border',
ordinal: 'mr-1.5 text-lg font-medium',
title: 'text-lg font-medium'
}

interface CtaData {
label: string,
link: string,
linkType: string
}

function isCtaData(data: unknown): data is CtaData {
if (typeof data !== 'object' || data === null) {
return false;
}
const expectedKeys = ['label', 'link', 'linkType'];
return expectedKeys.every(key => {
return key in data;
});
}

/**
Expand All @@ -14,28 +57,51 @@ export interface StandardCardProps extends CardProps {
* @param props - An object containing the result itself.
*/
export function StandardCard(props: StandardCardProps): JSX.Element {
const { configuration, result } = props;
const { configuration, result, customCssClasses, cssCompositionMethod } = props;
const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses, cssCompositionMethod);

return (
<div className='StandardCard'>
{configuration.showOrdinal && result.index && renderOrdinal(result.index)}
<div className='StandardCard__contentWrapper'>
{result.name && renderTitle(result.name)}
</div>
</div>
);
}
const cta1 = isCtaData(result.rawData.c_primaryCTA) ? result.rawData.c_primaryCTA : undefined;
const cta2 = isCtaData(result.rawData.c_secondaryCTA) ? result.rawData.c_secondaryCTA : undefined;

// TODO (cea2aj) We need to handle the various linkType so these CTAs are clickable
function renderCTAs(cta1?: CtaData, cta2?: CtaData) {
return (<>
{(cta1 ?? cta2) &&
<div className={cssClasses.ctaContainer}>
{cta1 && <button className={cssClasses.cta1}>{cta1.label}</button>}
{cta2 && <button className={cssClasses.cta2}>{cta2.label}</button>}
</div>
}
</>);
}

// TODO (cea2aj) Update this to render the ordinal once we get mocks from UX
function renderOrdinal(index: number) {
// return (
// <div className={cssClasses.ordinal}>{index}</div>
// );
return null;
}

function renderTitle(title: string) {
return <div className={cssClasses.title}>{title}</div>
}

function renderOrdinal(ordinal: number) {
return (
<div className='StandardCard__ordinalWrapper'>
<div className='StandardCard__ordinal'>
{ordinal}
<div className={cssClasses.container}>
<div className={cssClasses.header}>
{configuration.showOrdinal && result.index && renderOrdinal(result.index)}
{result.name && renderTitle(result.name)}
</div>
{(result.description ?? cta1 ?? cta2) &&
<div className={cssClasses.body}>
{result.description &&
<div className={cssClasses.descriptionContainer}>
<span>{result.description}</span>
</div>}
{renderCTAs(cta1, cta2)}
</div>
}
</div>
);
}

function renderTitle(title: string) {
return <div className='StandardCard__title'>{title}</div>
}
Loading

0 comments on commit fae449e

Please sign in to comment.