Merge pull request #833 from matrix-org/luke/improve-country-dd

Improve country dropdown UX and expose +prefix
This commit is contained in:
Luke Barnard 2017-04-26 10:25:10 +01:00 committed by GitHub
commit 4207bf31f2
5 changed files with 60 additions and 33 deletions

View file

@ -114,8 +114,11 @@ export default class Dropdown extends React.Component {
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if (!nextProps.children || nextProps.children.length === 0) {
return;
}
this._reindexChildren(nextProps.children); this._reindexChildren(nextProps.children);
const firstChild = React.Children.toArray(nextProps.children)[0]; const firstChild = nextProps.children[0];
this.setState({ this.setState({
highlightedOption: firstChild ? firstChild.key : null, highlightedOption: firstChild ? firstChild.key : null,
}); });

View file

@ -37,6 +37,7 @@ export default class CountryDropdown extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this._onSearchChange = this._onSearchChange.bind(this); this._onSearchChange = this._onSearchChange.bind(this);
this._onOptionChange = this._onOptionChange.bind(this);
this.state = { this.state = {
searchQuery: '', searchQuery: '',
@ -48,7 +49,7 @@ export default class CountryDropdown extends React.Component {
// If no value is given, we start with the first // If no value is given, we start with the first
// country selected, but our parent component // country selected, but our parent component
// doesn't know this, therefore we do this. // doesn't know this, therefore we do this.
this.props.onOptionChange(COUNTRIES[0].iso2); this.props.onOptionChange(COUNTRIES[0]);
} }
} }
@ -58,6 +59,10 @@ export default class CountryDropdown extends React.Component {
}); });
} }
_onOptionChange(iso2) {
this.props.onOptionChange(COUNTRIES_BY_ISO2[iso2]);
}
_flagImgForIso2(iso2) { _flagImgForIso2(iso2) {
// Unicode Regional Indicator Symbol letter 'A' // Unicode Regional Indicator Symbol letter 'A'
const RIS_A = 0x1F1E6; const RIS_A = 0x1F1E6;
@ -102,9 +107,11 @@ export default class CountryDropdown extends React.Component {
// values between mounting and the initial value propgating // values between mounting and the initial value propgating
const value = this.props.value || COUNTRIES[0].iso2; const value = this.props.value || COUNTRIES[0].iso2;
const getShortOption = this.props.isSmall ? this._flagImgForIso2 : undefined;
return <Dropdown className={this.props.className} return <Dropdown className={this.props.className}
onOptionChange={this.props.onOptionChange} onSearchChange={this._onSearchChange} onOptionChange={this._onOptionChange} onSearchChange={this._onSearchChange}
menuWidth={298} getShortOption={this._flagImgForIso2} menuWidth={298} getShortOption={getShortOption}
value={value} searchEnabled={true} value={value} searchEnabled={true}
> >
{options} {options}
@ -114,6 +121,7 @@ export default class CountryDropdown extends React.Component {
CountryDropdown.propTypes = { CountryDropdown.propTypes = {
className: React.PropTypes.string, className: React.PropTypes.string,
isSmall: React.PropTypes.bool,
onOptionChange: React.PropTypes.func.isRequired, onOptionChange: React.PropTypes.func.isRequired,
value: React.PropTypes.string, value: React.PropTypes.string,
}; };

View file

@ -90,8 +90,11 @@ class PasswordLogin extends React.Component {
} }
onPhoneCountryChanged(country) { onPhoneCountryChanged(country) {
this.setState({phoneCountry: country}); this.setState({
this.props.onPhoneCountryChanged(country); phoneCountry: country.iso2,
phonePrefix: country.prefix,
});
this.props.onPhoneCountryChanged(country.iso2);
} }
onPhoneNumberChanged(ev) { onPhoneNumberChanged(ev) {
@ -121,16 +124,17 @@ class PasswordLogin extends React.Component {
const mxidInputClasses = classNames({ const mxidInputClasses = classNames({
"mx_Login_field": true, "mx_Login_field": true,
"mx_Login_username": true, "mx_Login_username": true,
"mx_Login_field_has_prefix": true,
"mx_Login_field_has_suffix": Boolean(this.props.hsDomain), "mx_Login_field_has_suffix": Boolean(this.props.hsDomain),
}); });
let suffix = null; let suffix = null;
if (this.props.hsDomain) { if (this.props.hsDomain) {
suffix = <div className="mx_Login_username_suffix"> suffix = <div className="mx_Login_field_suffix">
:{this.props.hsDomain} :{this.props.hsDomain}
</div>; </div>;
} }
return <div className="mx_Login_username_group"> return <div className="mx_Login_field_group">
<div className="mx_Login_username_prefix">@</div> <div className="mx_Login_field_prefix">@</div>
<input <input
className={mxidInputClasses} className={mxidInputClasses}
key="username_input" key="username_input"
@ -145,6 +149,7 @@ class PasswordLogin extends React.Component {
</div>; </div>;
case PasswordLogin.LOGIN_FIELD_PHONE: case PasswordLogin.LOGIN_FIELD_PHONE:
const CountryDropdown = sdk.getComponent('views.login.CountryDropdown'); const CountryDropdown = sdk.getComponent('views.login.CountryDropdown');
const prefix = this.state.phonePrefix;
return <div className="mx_Login_phoneSection"> return <div className="mx_Login_phoneSection">
<CountryDropdown <CountryDropdown
className="mx_Login_phoneCountry" className="mx_Login_phoneCountry"
@ -152,8 +157,10 @@ class PasswordLogin extends React.Component {
onOptionChange={this.onPhoneCountryChanged} onOptionChange={this.onPhoneCountryChanged}
value={this.state.phoneCountry} value={this.state.phoneCountry}
/> />
<div className="mx_Login_field_group">
<div className="mx_Login_field_prefix">+{prefix}</div>
<input <input
className="mx_Login_phoneNumberField mx_Login_field" className="mx_Login_phoneNumberField mx_Login_field mx_Login_field_has_prefix"
ref="phoneNumber" ref="phoneNumber"
key="phone_input" key="phone_input"
type="text" type="text"
@ -163,6 +170,7 @@ class PasswordLogin extends React.Component {
value={this.state.phoneNumber} value={this.state.phoneNumber}
autoFocus autoFocus
/> />
</div>
</div>; </div>;
} }
} }

View file

@ -270,7 +270,8 @@ module.exports = React.createClass({
_onPhoneCountryChange(newVal) { _onPhoneCountryChange(newVal) {
this.setState({ this.setState({
phoneCountry: newVal, phoneCountry: newVal.iso2,
phonePrefix: newVal.prefix,
}); });
}, },
@ -316,16 +317,22 @@ module.exports = React.createClass({
className="mx_Login_phoneCountry" className="mx_Login_phoneCountry"
value={this.state.phoneCountry} value={this.state.phoneCountry}
/> />
<div className="mx_Login_field_group">
<div className="mx_Login_field_prefix">+{this.state.phonePrefix}</div>
<input type="text" ref="phoneNumber" <input type="text" ref="phoneNumber"
placeholder="Mobile phone number (optional)" placeholder="Mobile phone number (optional)"
defaultValue={this.props.defaultPhoneNumber} defaultValue={this.props.defaultPhoneNumber}
className={this._classForField( className={this._classForField(
FIELD_PHONE_NUMBER, 'mx_Login_phoneNumberField', 'mx_Login_field' FIELD_PHONE_NUMBER,
'mx_Login_phoneNumberField',
'mx_Login_field',
'mx_Login_field_has_prefix'
)} )}
onBlur={function() {self.validateField(FIELD_PHONE_NUMBER);}} onBlur={function() {self.validateField(FIELD_PHONE_NUMBER);}}
value={self.state.phoneNumber} value={self.state.phoneNumber}
/> />
</div> </div>
</div>
); );
const registerButton = ( const registerButton = (

View file

@ -50,7 +50,7 @@ export default WithMatrixClient(React.createClass({
}, },
_onPhoneCountryChange: function(phoneCountry) { _onPhoneCountryChange: function(phoneCountry) {
this.setState({ phoneCountry: phoneCountry }); this.setState({ phoneCountry: phoneCountry.iso2 });
}, },
_onPhoneNumberChange: function(ev) { _onPhoneNumberChange: function(ev) {
@ -149,10 +149,11 @@ export default WithMatrixClient(React.createClass({
<div className="mx_UserSettings_profileLabelCell"> <div className="mx_UserSettings_profileLabelCell">
</div> </div>
<div className="mx_UserSettings_profileInputCell"> <div className="mx_UserSettings_profileInputCell">
<div className="mx_Login_phoneSection"> <div className="mx_UserSettings_phoneSection">
<CountryDropdown onOptionChange={this._onPhoneCountryChange} <CountryDropdown onOptionChange={this._onPhoneCountryChange}
className="mx_Login_phoneCountry" className="mx_UserSettings_phoneCountry"
value={this.state.phoneCountry} value={this.state.phoneCountry}
isSmall={true}
/> />
<input type="text" <input type="text"
ref={this._collectAddMsisdnInput} ref={this._collectAddMsisdnInput}