All files / language-select language-select.js

100% Statements 25/25
83.33% Branches 5/6
100% Functions 8/8
100% Lines 25/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141        1x                                             1x 36x                                 1x 33x                                               1x 1x 1x 1x       1x   1x 2x         1x 1x   1x       1x 1x   1x       1x       3x 3x   3x             33x                       1x       1x                      
import React from 'react';
import PropTypes from 'prop-types';
 
// Add new flag emoji here
const flags = {
  en: '🇬🇧',
  fr: '🇫🇷',
  de: '🇩🇪',
  es: '🇪🇸',
  hi: '🇮🇳',
  id: '🇮🇩',
  it: '🇮🇹',
  ja: '🇯🇵',
  mr: '🇮🇳',
  my: '🇲🇲',
  pt: '🇵🇹',
};
 
/**
 * Renders the flag emoji and display name for a given language
 *
 * @param object props
 *   @param string name language display name
 *   @param string flag flag emoji
 *
 * @returns component stateless
 */
const LanguageNode = ({ name, flag }) => (
  <>
    <span className='flag'>{flag}</span>
    {name}
  </>
);
 
/**
 * Renders a selectable language option in the languages dropdown
 *
 * @param object props
 *   @param object language language object
 *   @param string value language value
 *   @param string selectedLanguage selected language value
 *   @param function onClick click handler from LanguageSelect instance
 *
 * @returns component stateless
 */
const LanguageOption = ({ language, value, selectedLanguage, onClick }) => (
  <li className={selectedLanguage === value ? 'selected' : null}>
    <a onClick={onClick} data-language={value}>
      <LanguageNode name={language.inLocal} flag={language.flag} />
    </a>
  </li>
);
 
 
/**
 * Presentational component
 * A dropdown to select a language. Clicking/tapping the dropdown trigger
 * opens a dropdown list of languages that render flag icons and the language
 * name written in its native language.
 *
 * @param object languages - object map of language values
 * input object example:
 * { 'en': { inEnglish: 'English', inLocal: 'English', flag: '🇬🇧' } }
 * @param function onSelect - event handler
 * @param string selectedLanguage - language that is selected
 *
 * @returns component
 */
class LanguageSelect extends React.Component {
  constructor(props) {
    const { languages, selectedLanguage, onSelect } = props;
    super(props);
    this.languages = languages;
    this.state = {
      selectedLanguage,
      dropdownOpen: false,
    };
    this.onSelect = onSelect;
 
    ['toggleDropdown', 'selectLanguage'].forEach((method) => {
      this[method] = this[method].bind(this);
    });
  }
 
  toggleDropdown(e) {
    e.preventDefault();
    const isOpened = !this.state.dropdownOpen;
 
    this.setState({ dropdownOpen: isOpened });
  }
 
  selectLanguage(e) {
    e.preventDefault();
    const selectedLanguage = e.target.dataset.language;
 
    this.setState({
      dropdownOpen: false,
      selectedLanguage,
    });
    this.onSelect(selectedLanguage);
  }
 
  render() {
    const { selectedLanguage, dropdownOpen } = this.state;
    const selectedOption = this.languages[selectedLanguage] || this.languages[Object.keys(this.languages)[0]];
 
    return (
      <div className='language_select'>
        <a onClick={this.toggleDropdown}>
          <LanguageNode name={selectedOption.inLocal} flag={selectedOption.flag} />
        </a>
        <ul className={dropdownOpen ? 'visible' : null}>
          {Object.keys(this.languages).map((language) => (
            <LanguageOption
               key={`language_${language}`}
               language={this.languages[language]}
               value={language}
               selectedLanguage={selectedLanguage}
               onClick={this.selectLanguage} />))}
        </ul>
      </div>
    );
  }
}
 
LanguageSelect.defaultProps = {
  selectedLanguage: '',
};
 
LanguageSelect.propTypes = {
  languages: PropTypes.objectOf(PropTypes.shape({
    inEnglish: PropTypes.string,
    inLocal: PropTypes.string,
    flag: PropTypes.string,
  })).isRequired,
  selectedLanguage: PropTypes.string,
  onSelect: PropTypes.func,
};
 
export default LanguageSelect;