<commit_before>import React from "react";
import PropTypes from "prop-types";
import { MenuItem, DropdownButton } from "react-bootstrap";

import CheckboxRowContainer from "../containers/checkbox_row_container";
import SettingsItem from "./settings_item";
import PlaceAutocomplete from "../../../observations/identify/components/place_autocomplete";

/* global TIMEZONES */

const Account = ( {
  profile,
  handleCustomDropdownSelect,
  handleInputChange,
  handlePlaceAutocomplete,
  setModalState,
  sites
} ) => {
  const currentNetworkAffiliation = sites.filter( site => site.id === profile.site_id )[0];

  // these locales are not available for all regions (like "en-US")
  // so taking the list of keys from the english version
  const localeListKeys = Object.keys( I18n.t( "locales", { locale: "en" } ) );

  const setLocale = ( ) => {
    const { locale } = profile;

    if ( localeListKeys.includes( locale ) ) {
      return locale;
    }
    // this provides fallbacks with users for unsupported locales, like "en-US"
    const twoLetterLanguageCode = locale.split( "-" )[0];
    return localeListKeys.includes( twoLetterLanguageCode ) ? twoLetterLanguageCode : "en";
  };

  const localeList = Object.keys( I18n.t( "locales", { locale: setLocale( ) } ) );

  const createTimeZoneList = ( ) => (
    TIMEZONES.map( zone => <option value={zone.value} key={zone.value}>{zone.label}</option> )
  );

  const createLocaleList = ( ) => localeList.map( locale => (
    <option value={locale} key={locale}>
      {I18n.t( `locales.${locale}`, { locale } )}
    </option>
  ) );

  const showNetworkLogo = ( id, logo ) => <img className="network-logo" alt={`inat-affiliation-logo-${id}`} src={logo} />;

  const showCurrentNetwork = id => (
    <div className="current-network">
      {showNetworkLogo( id, currentNetworkAffiliation.icon_url )}
      <div className="text-muted current-network-name">
        {sites.filter( site => site.id === id )[0].name}
      </div>
      <div className="caret" />
    </div>
  );

  const createINatAffiliationList = ( ) => sites.map( site => {
    const { id, name } = site;

    return (
      <MenuItem
        key={`inat-affiliation-logo-${id}`}
        eventKey={id}
      >
        {showNetworkLogo( id, site.icon_url )}
        <div className="text-muted">{name}</div>
        {profile.site_id === id && <i className="fa fa-check blue-checkmark" aria-hidden="true" />}
      </MenuItem>
    );
  } );

  return (
    <div className="row">
      <div className="col-md-5 col-sm-10">
        <h4>{I18n.t( "account" )}</h4>
        <SettingsItem header={I18n.t( "place_geo.geo_planet_place_types.Time_Zone" )} htmlFor="user_time_zone">
          <p className="text-muted">{I18n.t( "all_your_observations_will_default_this_time_zone" )}</p>
          <select id="user_time_zone" className="form-control dropdown" value={profile.time_zone} name="time_zone" onChange={handleInputChange}>
            {createTimeZoneList( )}
          </select>
        </SettingsItem>
        <SettingsItem header={I18n.t( "language_slash_locale" )} htmlFor="user_locale">
          <p className="text-muted">{I18n.t( "language_slash_locale_description" )}</p>
          <select id="user_locale" className="form-control dropdown" value={setLocale( )} name="locale" onChange={handleInputChange}>
            {createLocaleList( )}
          </select>
        </SettingsItem>
        <SettingsItem header={I18n.t( "default_search_place" )} htmlFor="user_search_place_id">
          <p className="text-muted">{I18n.t( "default_search_place_description" )}</p>
          <PlaceAutocomplete
            resetOnChange={false}
            initialPlaceID={profile.search_place_id}
            bootstrapClear
            afterSelect={e => handlePlaceAutocomplete( e, "search_place_id" )}
            afterClear={( ) => handlePlaceAutocomplete( { item: { id: 0 } }, "search_place_id" )}
          />
        </SettingsItem>
        <SettingsItem header={I18n.t( "privacy" )} htmlFor="user_prefers_no_tracking">
          <CheckboxRowContainer
            name="prefers_no_tracking"
            label={I18n.t( "views.users.edit.prefers_no_tracking_label" )}
          />
          <button type="button" className="btn btn-link btn-tracking" onClick={( ) => setModalState( { show: true } )}>
            <i className="fa fa-info-circle" />
            {` ${I18n.t( "learn_about_third_party_tracking" )}`}
          </button>
        </SettingsItem>
        <SettingsItem header={I18n.t( "danger_zone" )} htmlFor="user_delete_account">
          <p>
            <a href="/users/delete" id="user_delete_account">{I18n.t( "delete_your_account" )}</a>
          </p>
        </SettingsItem>
      </div>
      <div className="col-md-1" />
      <div className="col-md-5 col-sm-10">
        <SettingsItem header={I18n.t( "inaturalist_network_affiliation" )} htmlFor="user_site_id">
          <div className="stacked" id="AffiliationList">
            <DropdownButton
              id="user_site_id"
              onSelect={e => handleCustomDropdownSelect( e, "site_id" )}
              title={showCurrentNetwork( profile.site_id )}
              noCaret
            >
              {createINatAffiliationList( )}
            </DropdownButton>
          </div>
          <p
            className="text-muted"
            // eslint-disable-next-line react/no-danger
            dangerouslySetInnerHTML={{
              __html: I18n.t( "views.users.edit.inaturalist_network_affiliation_desc_html", {
                url: "https://www.inaturalist.org/sites/network"
              } )
            }}
          />
        </SettingsItem>
      </div>
    </div>
  );
};

Account.propTypes = {
  profile: PropTypes.object,
  handleCustomDropdownSelect: PropTypes.func,
  handleInputChange: PropTypes.func,
  handlePlaceAutocomplete: PropTypes.func,
  setModalState: PropTypes.func,
  sites: PropTypes.array
};
<commit_msg>Fall back to default iNat site when user has site_id set to null<commit_after>import React from "react";
import PropTypes from "prop-types";
import { MenuItem, DropdownButton } from "react-bootstrap";

import CheckboxRowContainer from "../containers/checkbox_row_container";
import SettingsItem from "./settings_item";
import PlaceAutocomplete from "../../../observations/identify/components/place_autocomplete";

/* global TIMEZONES */

const Account = ( {
  profile,
  handleCustomDropdownSelect,
  handleInputChange,
  handlePlaceAutocomplete,
  setModalState,
  sites
} ) => {
  const siteId = profile.site_id || 1;
  const currentNetworkAffiliation = sites.filter( site => site.id === siteId )[0];

  // these locales are not available for all regions (like "en-US")
  // so taking the list of keys from the english version
  const localeListKeys = Object.keys( I18n.t( "locales", { locale: "en" } ) );

  const setLocale = ( ) => {
    const { locale } = profile;

    if ( localeListKeys.includes( locale ) ) {
      return locale;
    }
    // this provides fallbacks with users for unsupported locales, like "en-US"
    const twoLetterLanguageCode = locale.split( "-" )[0];
    return localeListKeys.includes( twoLetterLanguageCode ) ? twoLetterLanguageCode : "en";
  };

  const localeList = Object.keys( I18n.t( "locales", { locale: setLocale( ) } ) );

  const createTimeZoneList = ( ) => (
    TIMEZONES.map( zone => <option value={zone.value} key={zone.value}>{zone.label}</option> )
  );

  const createLocaleList = ( ) => localeList.map( locale => (
    <option value={locale} key={locale}>
      {I18n.t( `locales.${locale}`, { locale } )}
    </option>
  ) );

  const showNetworkLogo = ( id, logo ) => <img className="network-logo" alt={`inat-affiliation-logo-${id}`} src={logo} />;

  const showCurrentNetwork = ( ) => (
    <div className="current-network">
      {showNetworkLogo( siteId, currentNetworkAffiliation.icon_url )}
      <div className="text-muted current-network-name">
        {currentNetworkAffiliation.name}
      </div>
      <div className="caret" />
    </div>
  );

  const createINatAffiliationList = ( ) => sites.map( site => {
    const { id, name } = site;

    return (
      <MenuItem
        key={`inat-affiliation-logo-${id}`}
        eventKey={id}
      >
        {showNetworkLogo( id, site.icon_url )}
        <div className="text-muted">{name}</div>
        {siteId === id && <i className="fa fa-check blue-checkmark" aria-hidden="true" />}
      </MenuItem>
    );
  } );

  return (
    <div className="row">
      <div className="col-md-5 col-sm-10">
        <h4>{I18n.t( "account" )}</h4>
        <SettingsItem header={I18n.t( "place_geo.geo_planet_place_types.Time_Zone" )} htmlFor="user_time_zone">
          <p className="text-muted">{I18n.t( "all_your_observations_will_default_this_time_zone" )}</p>
          <select id="user_time_zone" className="form-control dropdown" value={profile.time_zone} name="time_zone" onChange={handleInputChange}>
            {createTimeZoneList( )}
          </select>
        </SettingsItem>
        <SettingsItem header={I18n.t( "language_slash_locale" )} htmlFor="user_locale">
          <p className="text-muted">{I18n.t( "language_slash_locale_description" )}</p>
          <select id="user_locale" className="form-control dropdown" value={setLocale( )} name="locale" onChange={handleInputChange}>
            {createLocaleList( )}
          </select>
        </SettingsItem>
        <SettingsItem header={I18n.t( "default_search_place" )} htmlFor="user_search_place_id">
          <p className="text-muted">{I18n.t( "default_search_place_description" )}</p>
          <PlaceAutocomplete
            resetOnChange={false}
            initialPlaceID={profile.search_place_id}
            bootstrapClear
            afterSelect={e => handlePlaceAutocomplete( e, "search_place_id" )}
            afterClear={( ) => handlePlaceAutocomplete( { item: { id: 0 } }, "search_place_id" )}
          />
        </SettingsItem>
        <SettingsItem header={I18n.t( "privacy" )} htmlFor="user_prefers_no_tracking">
          <CheckboxRowContainer
            name="prefers_no_tracking"
            label={I18n.t( "views.users.edit.prefers_no_tracking_label" )}
          />
          <button type="button" className="btn btn-link btn-tracking" onClick={( ) => setModalState( { show: true } )}>
            <i className="fa fa-info-circle" />
            {` ${I18n.t( "learn_about_third_party_tracking" )}`}
          </button>
        </SettingsItem>
        <SettingsItem header={I18n.t( "danger_zone" )} htmlFor="user_delete_account">
          <p>
            <a href="/users/delete" id="user_delete_account">{I18n.t( "delete_your_account" )}</a>
          </p>
        </SettingsItem>
      </div>
      <div className="col-md-1" />
      <div className="col-md-5 col-sm-10">
        <SettingsItem header={I18n.t( "inaturalist_network_affiliation" )} htmlFor="user_site_id">
          <div className="stacked" id="AffiliationList">
            <DropdownButton
              id="user_site_id"
              onSelect={e => handleCustomDropdownSelect( e, "site_id" )}
              title={showCurrentNetwork( )}
              noCaret
            >
              {createINatAffiliationList( )}
            </DropdownButton>
          </div>
          <p
            className="text-muted"
            // eslint-disable-next-line react/no-danger
            dangerouslySetInnerHTML={{
              __html: I18n.t( "views.users.edit.inaturalist_network_affiliation_desc_html", {
                url: "https://www.inaturalist.org/sites/network"
              } )
            }}
          />
        </SettingsItem>
      </div>
    </div>
  );
};

Account.propTypes = {
  profile: PropTypes.object,
  handleCustomDropdownSelect: PropTypes.func,
  handleInputChange: PropTypes.func,
  handlePlaceAutocomplete: PropTypes.func,
  setModalState: PropTypes.func,
  sites: PropTypes.array
};

{'fraction_non_alphanumeric': 0.14516264604522147, 'fraction_numerical': 0.00790115155081113, 'mean_word_length': 2.8171318575553417, 'pattern_counts': {'":': 0, '<': 123, '<?xml version=': 0, '>': 154, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2003', 'n_tokens_mistral': 3784, 'n_tokens_neox': 3692, 'n_words': 672}