<div data-react="search-widget" data-props="{"endpoint":"/mocks/api/search-results.json","searchPageUrl":"https://int.swegon.com/sv/product-search/","form":{"method":"GET","body":{"language":"sv","includeOnlyBuyable":"false"}},"className":"search-field--big","seeMoreText":"Visa alla","placeholderText":"Sök produkter"}"></div>
<div data-react="search-widget" data-props="{{jsonEncode props}}"></div>
{
"props": {
"endpoint": "/mocks/api/search-results.json",
"searchPageUrl": "https://int.swegon.com/sv/product-search/",
"form": {
"method": "GET",
"body": {
"language": "sv",
"includeOnlyBuyable": "false"
}
},
"className": "search-field--big",
"seeMoreText": "Visa alla",
"placeholderText": "Sök produkter"
}
}
import React from 'react';
import PropTypes from 'prop-types';
import SearchField from '../search-field';
import Spinner from '../spinner';
import debounce from 'lodash/debounce';
const ItemComponent = (props) => (
<a href={props.url} className="search-widget__result-link">
<div className="search-widget__result-thumbnail" style={{ backgroundImage: `url(${props.thumbnailUrl})` }}></div>
<div className="search-widget__result-body">
{props.title}
<span className="search-widget__result-description">{props.description}</span>
</div>
</a>
);
const SearchWidget = (props) => {
const [searchResult, setSearchResult] = React.useState([]);
const [seeMoreLink, setSeeMoreLink] = React.useState(null);
const [loading, setLoading] = React.useState(false);
const onSubmit = e => {
e.preventDefault();
window.location.replace([
`${props.searchPageUrl}?`,
`${props.searchQueryKey}=`,
e.target.elements.q.value
].join(''));
};
const fetchAndSetSearchResult = debounce(
async (searchQuery) => {
const { body, ...formProps } = props.form;
setLoading(true);
let opts = {
credentials: 'include',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json'
},
...formProps
};
if (formProps.method.toUpperCase() === 'POST') {
opts.body = JSON.stringify({
...body,
searchQuery
});
};
const r = await fetch(props.endpoint, opts);
const data = await r.json();
setLoading(false);
setSearchResult(() => (
data && data.hits && data.hits.length > 0
? data.hits
: []
));
setSeeMoreLink(() => data.seeMoreLink);
}
, props.debounceTimeout);
const updateSearchResult = async (e) => {
const input = e.target.value.trim() || '';
if (input.length >= props.minQueryLength) {
fetchAndSetSearchResult(input);
} else if (input.length === 0) {
// Reset state when there's no search result
setTimeout(() => {
setSearchResult(() => []);
}, props.debounceTimeout);
}
};
return (
<SearchField
items={searchResult}
onInputChange={updateSearchResult}
onSubmit={onSubmit}
itemStyle="search-widget__result"
className={props.className}
itemComponent={ItemComponent}
inputPlaceholder={props.placeholderText}
preSelectedFirstItem={false}
onChange={(e) => window.location.replace(e.url)}
itemStyle="search-widget__result"
seeMoreLink={seeMoreLink}
seeMoreText={props.seeMoreText}
>
{loading && <Spinner additionalClasses="search-widget__spinner" />}
</SearchField>
);
};
SearchWidget.propTypes = {
searchPageUrl: PropTypes.string.isRequired,
endpoint: PropTypes.string.isRequired,
searchQueryKey: PropTypes.string,
className: PropTypes.string,
form: PropTypes.shape({
method: PropTypes.string.isRequired,
body: PropTypes.shape({})
}),
debounceTimeout: PropTypes.number,
minQueryLength: PropTypes.number,
seeMoreText: PropTypes.string
};
SearchWidget.defaultProps = {
searchQueryKey: 'qp',
form: {
method: 'POST',
body: {
includeOnlyBuyable: false
}
},
debounceTimeout: 200,
minQueryLength: 2,
seeMoreText: 'See more'
};
export default SearchWidget;
.search-widget__result-link {
display: flex;
width: 100%;
padding: size(1.5);
&:hover {
text-decoration: none;
}
}
.search-widget__result-thumbnail {
margin-right: size(2);
min-width: size(8);
background-repeat: no-repeat;
background-position: center cetner;
background-size: contain;
}
.search-widget__result-body {
display: flex;
flex-direction: column;
align-content: flex-start;
color: $color-black;
font-weight: $font-weight-bold;
}
.search-widget__result-description {
color: $color-gray-4;
font-size: size(2);
font-weight: $font-weight-normal;
}
No notes defined.