<div data-react="search-widget" data-props="{&quot;endpoint&quot;:&quot;/mocks/api/search-results.json&quot;,&quot;searchPageUrl&quot;:&quot;https://int.swegon.com/sv/product-search/&quot;,&quot;form&quot;:{&quot;method&quot;:&quot;GET&quot;,&quot;body&quot;:{&quot;language&quot;:&quot;sv&quot;,&quot;includeOnlyBuyable&quot;:&quot;false&quot;}},&quot;className&quot;:&quot;search-field--big&quot;,&quot;seeMoreText&quot;:&quot;Visa alla&quot;,&quot;placeholderText&quot;:&quot;Sök produkter&quot;}"></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"
  }
}
  • Content:
    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;
    
  • URL: /components/raw/search-widget/SearchWidget.jsx
  • Filesystem Path: src/components/search-widget/SearchWidget.jsx
  • Size: 3.9 KB
  • Content:
    .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;
    }
    
  • URL: /components/raw/search-widget/search-widget.scss
  • Filesystem Path: src/components/search-widget/search-widget.scss
  • Size: 637 Bytes

No notes defined.