UNPKG

@shopgate/engage

Version:
192 lines (185 loc) • 6.58 kB
import React, { memo, useCallback, useContext, useEffect, useLayoutEffect, useRef, useState } from 'react'; import PropTypes from 'prop-types'; import { i18n } from '@shopgate/engage/core'; import { InfoIcon, LocatorIcon, MagnifierIcon, MessageBar, SurroundPortals } from '@shopgate/engage/components'; import { useCountriesNames } from '@shopgate/engage/i18n'; import StoreListSearchRadius from "./StoreListSearchRadius"; import { FulfillmentContext, StoreFinderContext } from "../../locations.context"; import connect from "./StoreListSearch.connector"; import { container, countriesCell, inputCell, radiusCell, inputIcon, iconClass, input, inputContainer, select, selectContainer } from "./StoreListSearch.style"; import { FULFILLMENT_SHEET_SEARCH } from "../../constants/Portals"; /** * @param {Function} getProductLocations getProductLocations. * @param {Function} storeSearch . * @param {Object} search . * @returns {JSX} */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; function StoreListSearch({ postalCode, countryCode, setPostalCode, setCountryCode, setGeolocation, isStoreFinder }) { const { isLoading, setIsLoading, locations, shopSettings: { supportedCountries } = {}, product } = useContext(isStoreFinder ? StoreFinderContext : FulfillmentContext); const [message, setMessage] = useState(''); const [inputPostalCode, setInputPostalCode] = useState(postalCode || ''); const isMounted = useRef(false); const productId = product?.id || null; const inputEl = useRef(null); useEffect(() => { isMounted.current = true; return function cleanup() { isMounted.current = false; }; }); useLayoutEffect(() => { if (!isLoading && (!locations || locations.length === 0)) { // Set a message when a location search resulted in zero locations. setMessage('locations.error_no_store_found'); } else { setMessage(''); } }, [isLoading, locations, message]); /** * Triggers an update when the value of the country selector changed. * @param {SyntheticEvent} event A React event object. */ const handleCountrySelectChange = useCallback(event => { setCountryCode(event.target.value, productId, isStoreFinder); }, [isStoreFinder, productId, setCountryCode]); useEffect(() => { if (!Array.isArray(supportedCountries) || !supportedCountries.length) { return; } // Check if current countryCode is included in supportedCountries. Update the code to a valid // one if nothing was found. if (!supportedCountries.includes(countryCode)) { handleCountrySelectChange({ target: { value: supportedCountries[0] } }); } }, [countryCode, handleCountrySelectChange, supportedCountries]); /** * Blurs the postal code input to trigger an update. * @param {SyntheticEvent} event A React event object. */ const handlePostalCodeSubmitKeyDown = useCallback(event => { if (event.keyCode === 13) { inputEl.current.blur(); } }, []); /** * Triggers an update when the input blurs. */ const handlePostalCodeBlur = useCallback(() => { setPostalCode(inputPostalCode, productId, isStoreFinder); }, [inputPostalCode, isStoreFinder, productId, setPostalCode]); /** * Triggers an update when the locate me button was pressed. Also clears the local state for the * postal code input. */ const handleLocateMeButton = useCallback(async () => { setInputPostalCode(''); setIsLoading(true); await setGeolocation({ productId, isStoreFinder }); setIsLoading(false); }, [isStoreFinder, productId, setGeolocation, setIsLoading]); /** * Updates the local state for the postal code input. * @param {SyntheticEvent} event A React event object */ const handlePostalCodeChange = event => { setInputPostalCode(event.target.value); }; const countries = useCountriesNames(supportedCountries); const hasSupportedCountries = supportedCountries && supportedCountries.length > 1; return /*#__PURE__*/_jsxs(SurroundPortals, { portalName: FULFILLMENT_SHEET_SEARCH, portalProps: { product }, children: [/*#__PURE__*/_jsxs("div", { className: container, children: [hasSupportedCountries && /*#__PURE__*/_jsx("div", { className: countriesCell, children: /*#__PURE__*/_jsx("div", { className: selectContainer, children: /*#__PURE__*/_jsx("select", { name: "countryCode", value: countryCode, onChange: handleCountrySelectChange, className: select, children: Object.keys(countries).map(key => /*#__PURE__*/_jsx("option", { className: "option", value: key, children: countries[key] }, key)) }) }) }), /*#__PURE__*/_jsx("div", { className: inputCell, children: /*#__PURE__*/_jsxs("div", { className: inputContainer, children: [/*#__PURE__*/_jsx("span", { className: inputIcon, "aria-hidden": true, children: /*#__PURE__*/_jsx(MagnifierIcon, {}) }), /*#__PURE__*/_jsx("input", { ref: inputEl, name: "postalCode", className: input, value: inputPostalCode, onChange: handlePostalCodeChange, onBlur: handlePostalCodeBlur, onKeyDown: handlePostalCodeSubmitKeyDown, disabled: isLoading, type: "search", autoComplete: "off", autoCorrect: "off", placeholder: i18n.text('locations.search_placeholder'), "aria-label": i18n.text('locations.search_placeholder') }), /*#__PURE__*/_jsx("button", { onClick: handleLocateMeButton, type: "button", className: inputIcon, "aria-label": i18n.text('locations.stores_near.location'), children: /*#__PURE__*/_jsx(LocatorIcon, {}) })] }) }), /*#__PURE__*/_jsx("div", { className: radiusCell, children: isStoreFinder && /*#__PURE__*/_jsx(StoreListSearchRadius, {}) })] }), message && /*#__PURE__*/_jsx(MessageBar, { messages: [{ type: 'error', message, icon: InfoIcon }], classNames: { icon: iconClass } })] }); } StoreListSearch.defaultProps = { postalCode: null, isStoreFinder: false }; export default connect(/*#__PURE__*/memo(StoreListSearch));