Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions src/components/Autocomplete/SectionItem/SectionItem.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { ReactNode, useContext } from 'react';
import { CioAutocompleteContext } from '../CioAutocompleteProvider';
import { Item } from '../../../types';
import { isProduct, isInGroupSuggestion } from '../../../typeGuards';
import { isProduct, isInGroupSuggestion, isSearchSuggestion } from '../../../typeGuards';

export interface SectionItemProps {
item: Item;
Expand All @@ -11,20 +11,41 @@ export interface SectionItemProps {

export default function SectionItem(props: SectionItemProps) {
const { item, children } = props;
const { getItemProps } = useContext(CioAutocompleteContext);
const { getItemProps, advancedParameters } = useContext(CioAutocompleteContext);
const { displaySearchSuggestionImages, displaySearchSuggestionResultCounts } =
advancedParameters || {};
let defaultChildren: ReactNode;

let defaultChildren;
if (isProduct(item)) {
defaultChildren = (
<>
<img data-testid='cio-img' src={item.data?.image_url} alt={item.value} />
<p data-testid='cio-text'>{item.value}</p>
<img
data-testid='cio-img'
src={item.data?.image_url}
alt={item.value}
className='cio-product-image'
/>
<p data-testid='cio-text' className='cio-product-text'>
{item.value}
</p>
</>
);
} else if (isInGroupSuggestion(item)) {
defaultChildren = <p className='cio-term-in-group'>in {item.groupName}</p>;
} else if (isSearchSuggestion(item)) {
defaultChildren = (
<>
{displaySearchSuggestionImages && item.data?.image_url && (
<img src={item.data?.image_url} alt={item.value} className='cio-suggestion-image' />
)}
<p className='cio-suggestion-text'>{item.value}</p>
{displaySearchSuggestionResultCounts && item.data?.total_num_results && (
<p className='cio-suggestion-count'>({item.data?.total_num_results})</p>
)}
</>
);
} else {
defaultChildren = <p>{item.value}</p>;
defaultChildren = <p className='cio-custom-text'>{item.value}</p>;
}

return <li {...getItemProps(item)}>{children || defaultChildren}</li>;
Expand Down
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,3 +220,5 @@ To see this in action:
4. Next, type "short" in the example autocomplete input field.
- Notice how the user is presented with only short sleeved items as results.
- This is because we are filtering to the "Shirts" group`;

export const termsWithImagesAndCountsDescription = `Pass boolean flags for \`displaySearchSuggestionImages\` and \`displaySearchSuggestionResultCounts\` fields to display images and counts for search suggestions. These fields need to be made displayable before they can be used. Please contact your Constructor Integration Engineer for details.`;
1 change: 1 addition & 0 deletions src/hooks/useCioAutocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ const useCioAutocomplete = (options: UseCioAutocompleteOptions) => {
cioClient,
autocompleteClassName,
selectedItem: items[highlightedIndex],
advancedParameters,
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
filteredSuggestionsDescription,
apiKey,
onSubmitDefault as onSubmit,
termsWithImagesAndCountsDescription,
} from '../../../constants';

export default {
Expand Down Expand Up @@ -66,3 +67,18 @@ addComponentStoryDescription(
`const args = ${stringifyWithDefaults(FilteredSuggestions.args)}`,
filteredSuggestionsDescription
);

export const TermsWithImagesAndCounts = ComponentTemplate.bind({});
TermsWithImagesAndCounts.args = {
apiKey,
onSubmit,
advancedParameters: {
displaySearchSuggestionImages: true,
displaySearchSuggestionResultCounts: true,
},
};
addComponentStoryDescription(
TermsWithImagesAndCounts,
`const args = ${stringifyWithDefaults(TermsWithImagesAndCounts.args)}`,
termsWithImagesAndCountsDescription
);
16 changes: 16 additions & 0 deletions src/stories/Autocomplete/Hook/AdvancedParameters.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
filteredSuggestionsDescription,
apiKey,
onSubmitDefault as onSubmit,
termsWithImagesAndCountsDescription,
} from '../../../constants';

export default {
Expand Down Expand Up @@ -66,3 +67,18 @@ addHookStoryCode(
`const args = ${stringifyWithDefaults(FilteredSuggestions.args)}`,
filteredSuggestionsDescription
);

export const TermsWithImagesAndCounts = HooksTemplate.bind({});
TermsWithImagesAndCounts.args = {
apiKey,
onSubmit,
advancedParameters: {
displaySearchSuggestionImages: true,
displaySearchSuggestionResultCounts: true,
},
};
addHookStoryCode(
TermsWithImagesAndCounts,
`const args = ${stringifyWithDefaults(TermsWithImagesAndCounts.args)}`,
termsWithImagesAndCountsDescription
);
143 changes: 96 additions & 47 deletions src/stories/Autocomplete/Hook/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable no-param-reassign */
import React from 'react';
import useCioAutocomplete from '../../../hooks/useCioAutocomplete';
import { Item } from '../../../types';
import { getStoryParams } from '../../../utils';

export function HooksTemplate(args) {
Expand All @@ -14,10 +15,51 @@ export function HooksTemplate(args) {
getItemProps,
setQuery,
autocompleteClassName,
advancedParameters,
} = useCioAutocomplete(args);
const { displaySearchSuggestionImages, displaySearchSuggestionResultCounts } =
advancedParameters || {};

const inputProps = getInputProps();

const renderItem = (item: Item) => {
const imageClassName =
item.section === 'Products' ? 'cio-product-image' : 'cio-suggestion-image';
const textClassName = item.section === 'Products' ? 'cio-product-text' : 'cio-suggestion-text';
let displayImage = false;

if (item.section === 'Products' && item.data?.image_url) {
displayImage = true;
}

if (item.section === 'Search Suggestions') {
if (displaySearchSuggestionImages && item.data?.image_url) {
displayImage = true;
}
}

return (
<div {...getItemProps(item)} key={item?.id}>
{displayImage && (
<img
src={item.data?.image_url}
alt={item.value}
className={imageClassName}
data-testid='cio-img'
/>
)}
{item.groupName ? (
<p className='cio-term-in-group'>in {item.groupName}</p>
) : (
<p className={textClassName}>{item.value}</p>
)}
{displaySearchSuggestionResultCounts && item.data?.total_num_results && (
<p className='cio-suggestion-count'>({item.data?.total_num_results})</p>
)}
</div>
);
};

return (
<div className={autocompleteClassName}>
<form {...getFormProps()}>
Expand Down Expand Up @@ -77,23 +119,7 @@ export function HooksTemplate(args) {
<div className='cio-section'>
<h5 className='cio-sectionName'>{section?.displayName || section.identifier}</h5>
<div className='cio-section-items'>
{section?.data?.map((item) => (
<div {...getItemProps(item)} key={item?.id}>
{item.data?.image_url && (
<img
width='100%'
src={item.data?.image_url}
alt=''
data-testid='cio-img'
/>
)}
{item.groupName ? (
<p className='cio-term-in-group'>in {item.groupName}</p>
) : (
<p>{item.value}</p>
)}
</div>
))}
{section?.data?.map((item) => renderItem(item))}
</div>
</div>
</div>
Expand All @@ -115,18 +141,58 @@ function YourComponent() {
getMenuProps,
getItemProps,
setQuery,
autocompleteClassName
autocompleteClassName,
advancedParameters,
} = useCioAutocomplete(args);
const { displaySearchSuggestionImages, displaySearchSuggestionResultCounts } =
advancedParameters || {};

const inputProps = getInputProps();

const renderItem = (item: Item) => {
const imageClassName =
item.section === 'Products' ? 'cio-product-image' : 'cio-suggestion-image';
const textClassName = item.section === 'Products' ? 'cio-product-text' : 'cio-suggestion-text';
let displayImage = false;

if (item.section === 'Products' && item.data?.image_url) {
displayImage = true;
}

if (item.section === 'Search Suggestions') {
if (displaySearchSuggestionImages && item.data?.image_url) {
displayImage = true;
}
}

return (
<div {...getItemProps(item)} key={item?.id}>
{displayImage && (
<img
src={item.data?.image_url}
alt={item.value}
className={imageClassName}
data-testid='cio-img'
/>
)}
{item.groupName ? (
<p className='cio-term-in-group'>in {item.groupName}</p>
) : (
<p className={textClassName}>{item.value}</p>
)}
{displaySearchSuggestionResultCounts && item.data?.total_num_results && (
<p className='cio-suggestion-count'>({item.data?.total_num_results})</p>
)}
</div>
);
};

return (
<div className={autocompleteClassName}>
<form {...getFormProps()}>
<label {...getLabelProps()} hidden>
Search
<label htmlFor='cio-input' {...getLabelProps()}>
<input id='cio-input' {...inputProps} />
</label>
<input {...inputProps} />
<button
className='cio-clear-btn'
data-testid='cio-clear-btn'
Expand All @@ -148,7 +214,7 @@ function YourComponent() {
height='1em'
width='1em'
xmlns='http://www.w3.org/2000/svg'>
<path d='M289.94 256l95-95A24 24 0 00351 127l-95 95-95-95a24 24 0 00-34 34l95 95-95 95a24 24 0 1034 34l95-95 95 95a24 24 0 0034-34z'></path>
<path d='M289.94 256l95-95A24 24 0 00351 127l-95 95-95-95a24 24 0 00-34 34l95 95-95 95a24 24 0 1034 34l95-95 95 95a24 24 0 0034-34z' />
</svg>
</div>
</button>
Expand All @@ -167,46 +233,29 @@ function YourComponent() {
height='1em'
width='1em'
xmlns='http://www.w3.org/2000/svg'>
<path d='M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z'></path>
<path d='M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z' />
</svg>
</div>
</button>
</form>
<div {...getMenuProps()}>
{isOpen && (
<>
{sections?.map((section) => !section?.data?.length ? null : (
{isOpen &&
sections?.map((section) =>
!section?.data?.length ? null : (
<div key={section.identifier} className={section.identifier}>
<div className='cio-section'>
<h5 className='cio-sectionName'>{section?.displayName || section.identifier}</h5>
<div className='cio-section-items'>
{section?.data?.map((item) => (
<div {...getItemProps(item)} key={item?.id}>
{item.data?.image_url && (
<img
width='100%'
src={item.data?.image_url}
alt=''
data-testid='cio-img'
/>
)}
{item.groupName ? (
<p className='cio-term-in-group'>in {item.groupName}</p>
) : (
<p>{item.value}</p>
)}
</div>
))}
{section?.data?.map((item) => renderItem(item))}
</div>
</div>
</div>
))}
</>
)}
)
)}
</div>
</div>
);
};
}
`;

const importHook = `import { useCioAutocomplete } from '@constructor-io/constructorio-ui-autocomplete';`;
Expand Down
26 changes: 22 additions & 4 deletions src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,11 @@
padding: 0;
}

.cio-autocomplete .cio-item-SearchSuggestions {
flex-direction: column;
.cio-autocomplete .cio-item.cio-item-SearchSuggestions {
flex-direction: row;
min-width: 160px;
justify-content: space-between;
align-items: center;
}

.cio-autocomplete .cio-item {
Expand Down Expand Up @@ -103,12 +105,12 @@
padding: 5px 0;
}

.cio-autocomplete .cio-item p {
.cio-autocomplete .cio-item .cio-product-text {
margin: 0;
overflow: hidden;
}

.cio-autocomplete .cio-item img {
.cio-autocomplete .cio-item .cio-product-image {
width: 100%;
max-width: 100px;
max-height: 100px;
Expand All @@ -117,3 +119,19 @@
.cio-autocomplete .cio-term-in-group {
padding-left: 10px;
}

.cio-autocomplete .cio-suggestion-image {
height: 32px;
width: 32px;
margin-right: 8px;
object-fit: contain;
}

.cio-autocomplete .cio-suggestion-text {
flex-grow: 1;
}

.cio-autocomplete .cio-suggestion-count {
font-size: 0.8rem;
margin-left: 8px;
}
Loading