import React from 'react'; import { Icon, IconButton } from '@edx/paragon'; import { ExpandLess, ExpandMore } from '@edx/paragon/icons'; import PropTypes from 'prop-types'; import onClickOutside from 'react-onclickoutside'; import { FormGroup } from '../common-components'; import { COUNTRY_CODE_KEY, COUNTRY_DISPLAY_KEY, FORM_SUBMISSION_ERROR } from './data/constants'; class CountryDropdown extends React.Component { constructor(props) { super(props); this.handleFocus = this.handleFocus.bind(this); this.handleOnBlur = this.handleOnBlur.bind(this); this.state = { displayValue: '', icon: this.expandMoreButton(), errorMessage: '', showFieldError: true, }; } shouldComponentUpdate(nextProps) { const selectedCountry = this.props.options.find((o) => o[COUNTRY_CODE_KEY] === nextProps.value); if (this.props.value !== nextProps.value) { if (selectedCountry) { this.setState({ displayValue: selectedCountry[COUNTRY_DISPLAY_KEY], showFieldError: false, errorMessage: nextProps.errorMessage, }); return false; } // Set persisted country value as display value. this.setState({ displayValue: nextProps.value, showFieldError: true, errorMessage: nextProps.errorMessage }); return false; // eslint-disable-next-line no-else-return } else if (nextProps.value && selectedCountry && this.state.displayValue === nextProps.value) { // Handling a case here where user enters a valid country code that needs to be // evaluated and set its display value. this.setState({ displayValue: selectedCountry[COUNTRY_DISPLAY_KEY] }); return false; } if (this.props.errorCode !== nextProps.errorCode && nextProps.errorCode === 'invalid-country') { this.setState({ showFieldError: true, errorMessage: nextProps.errorMessage }); return false; } if (this.state.errorMessage !== nextProps.errorMessage) { this.setState({ showFieldError: true, errorMessage: nextProps.errorMessage }); return false; } return true; } static getDerivedStateFromProps(props, state) { if (props.errorCode === FORM_SUBMISSION_ERROR && state.showFieldError) { return { errorMessage: props.errorMessage }; } return null; } getItems(strToFind = '') { let { options } = this.props; if (strToFind.length > 0) { options = options.filter((option) => (option.name.toLowerCase().includes(strToFind.toLowerCase()))); } return options.map((opt) => { const value = opt[COUNTRY_CODE_KEY]; const displayValue = opt[COUNTRY_DISPLAY_KEY]; return ( ); }); } handleOnChange = (e) => { const filteredItems = this.getItems(e.target.value); this.setState({ dropDownItems: filteredItems, displayValue: e.target.value, }); } handleClickOutside = () => { if (this.state.dropDownItems?.length > 0) { this.setState(() => ({ icon: this.expandMoreButton(), dropDownItems: '', })); } } handleExpandLess() { this.setState({ dropDownItems: '', icon: this.expandMoreButton() }); } handleExpandMore() { this.setState(prevState => ({ dropDownItems: this.getItems(prevState.displayValue), icon: this.expandLessButton(), errorMessage: '', showFieldError: false, })); } handleFocus(e) { const { name, value } = e.target; this.setState(prevState => ({ dropDownItems: this.getItems(name === 'country' ? value : prevState.displayValue), icon: this.expandLessButton(), errorMessage: '', showFieldError: false, })); if (this.props.handleFocus) { this.props.handleFocus(e); } } handleOnBlur(e, itemClicked = false, country = '') { const { name } = e.target; let countryValue = ''; if (country) { countryValue = country; } else { countryValue = itemClicked ? e.target.value : this.state.displayValue; } // For a better user experience, do not validate when focus out from 'country' field // and focus on 'countryItem' or 'countryExpand' button. if (e.relatedTarget && e.relatedTarget.name === 'countryItem' && (name === 'country' || name === 'countryExpand')) { return; } const normalized = countryValue.toLowerCase(); const selectedCountry = this.props.options.find((o) => o[COUNTRY_DISPLAY_KEY].toLowerCase() === normalized); if (!selectedCountry) { this.setState({ errorMessage: this.props.errorMessage, showFieldError: true }); } if (this.props.handleBlur) { this.props.handleBlur({ target: { name: 'country', value: countryValue } }); } } handleItemClick(e) { let countryValue = ''; if (!e.target.value) { countryValue = e.target.parentElement.parentElement.value; } this.setState({ dropDownItems: '', icon: this.expandMoreButton() }); this.handleOnBlur(e, true, countryValue); } expandMoreButton() { return ( { this.handleExpandMore(e); }} /> ); } expandLessButton() { return ( { this.handleExpandLess(e); }} /> ); } render() { return (
{ this.state.dropDownItems?.length > 0 ? this.state.dropDownItems : null }
); } } CountryDropdown.defaultProps = { options: null, floatingLabel: null, handleFocus: null, handleBlur: null, value: null, errorMessage: null, errorCode: null, }; CountryDropdown.propTypes = { options: PropTypes.arrayOf(PropTypes.object), floatingLabel: PropTypes.string, handleFocus: PropTypes.func, handleBlur: PropTypes.func, value: PropTypes.string, errorMessage: PropTypes.string, errorCode: PropTypes.string, name: PropTypes.string.isRequired, }; export default onClickOutside(CountryDropdown);