From ea9c82978591c213504c065848998cd63bf2f78c Mon Sep 17 00:00:00 2001 From: maftalion Date: Sat, 13 Mar 2021 13:38:21 -0800 Subject: [PATCH 01/18] Add new profile page --- src/components/Checkbox.js | 46 ++++++ src/pages/settings/ProfilePage.js | 244 ++++++++++++++++++++++++++++-- src/styles/styles.js | 52 +++++-- src/styles/utilities/flex.js | 4 + 4 files changed, 321 insertions(+), 25 deletions(-) create mode 100644 src/components/Checkbox.js diff --git a/src/components/Checkbox.js b/src/components/Checkbox.js new file mode 100644 index 000000000000..579e247ee980 --- /dev/null +++ b/src/components/Checkbox.js @@ -0,0 +1,46 @@ +import React from 'react'; +import {View, Pressable, Text} from 'react-native'; +import PropTypes from 'prop-types'; +import styles from '../styles/styles'; +import Icon from './Icon'; +import {Checkmark} from './Icon/Expensicons'; + +const propTypes = { + // Whether checkbox is checked + isChecked: PropTypes.bool.isRequired, + + // A function that is called when the box/label is clicked on + onClick: PropTypes.func.isRequired, + + // Text that appears next to check box + label: PropTypes.string, +}; + +const defaultProps = { + label: '', +}; + +const Checkbox = ({ + isChecked, onClick, label, +}) => ( + + onClick(!isChecked)}> + + + + + {label ? ( + onClick(!isChecked)}> + + {label} + + + ) : null} + +); + + +Checkbox.defaultProps = defaultProps; +Checkbox.propTypes = propTypes; + +export default Checkbox; diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index 70cb60dedab6..61dc868a9fd5 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -1,24 +1,236 @@ -import React from 'react'; +import React, {Component} from 'react'; +import {withOnyx} from 'react-native-onyx'; +import PropTypes from 'prop-types'; +import { + View, + TextInput, +} from 'react-native'; +import RNPickerSelect from 'react-native-picker-select'; +import Str from 'expensify-common/lib/str'; +import moment from 'moment-timezone'; + import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import Navigation from '../../libs/Navigation/Navigation'; import ScreenWrapper from '../../components/ScreenWrapper'; +import {setPersonalDetails} from '../../libs/actions/PersonalDetails'; import ROUTES from '../../ROUTES'; +import ONYXKEYS from '../../ONYXKEYS'; +import CONST from '../../CONST'; +import Avatar from '../../components/Avatar'; +import styles from '../../styles/styles'; +import Text from '../../components/Text'; +import {DownArrow} from '../../components/Icon/Expensicons'; +import Icon from '../../components/Icon'; +import Checkbox from '../../components/Checkbox'; +import ButtonWithLoader from '../../components/ButtonWithLoader'; + +const propTypes = { + /* Onyx Props */ + // The personal details of the person who is logged in + myPersonalDetails: PropTypes.shape({ + // Email/Phone login of the current user from their personal details + login: PropTypes.string, + + // Display first name of the current user from their personal details + firstName: PropTypes.string, + + // Display last name of the current user from their personal details + lastName: PropTypes.string, + + // Avatar URL of the current user from their personal details + avatarURL: PropTypes.string, + + // Pronouns of the current user from their personal details + pronouns: PropTypes.string, + + // timezone of the current user from their personal details + timezone: PropTypes.shape({ + + // Value of selected timezone + selected: PropTypes.string, + + // Whether timezone is automatically set + automatic: PropTypes.bool, + }), + }), +}; + +const defaultProps = { + myPersonalDetails: {}, +}; + +const pronounsMap = { + theyThemTheirs: 'They/them/theirs', + sheHerHers: 'She/her/hers', + heHimHis: 'He/him/his', + zeHirHirs: 'Ze/hir/hirs', + selfSelect: 'Self-select', + callMeByMyName: 'Call me by my name', +}; + +const timezones = moment.tz.names() + .map(timezone => ({ + value: timezone, + label: timezone, + })); + +class ProfilePage extends Component { + constructor(props) { + super(props); + + const { + firstName, lastName, pronouns, timezone = {}, + } = props.myPersonalDetails; + + this.state = { + firstName, + lastName, + pronouns, + selfSelectedPronouns: '', + selectedTimezone: timezone.selected ?? CONST.DEFAULT_TIME_ZONE.selected, + isAutomaticTimezone: timezone.automatic ?? CONST.DEFAULT_TIME_ZONE.automatic, + }; + + this.pronounDropdownValues = Object.values(pronounsMap).map(pronoun => ({value: pronoun, label: pronoun})); + this.updatePersonalDetails = this.updatePersonalDetails.bind(this); + } + + updatePersonalDetails() { + const { + firstName, lastName, pronouns, selfSelectedPronouns, selectedTimezone, isAutomaticTimezone, + } = this.state; + + setPersonalDetails({ + firstName, + lastName, + pronouns: pronouns === pronounsMap.selfSelect ? selfSelectedPronouns : pronouns, + timezone: { + automatic: isAutomaticTimezone, + selected: selectedTimezone, + }, + }); + } + + render() { + return ( + + {() => ( + <> + Navigation.navigate(ROUTES.SETTINGS)} + onCloseButtonPress={Navigation.dismissModal} + /> + + + + Tell us about yourself, we would love to get to know you! + + + + First Name + this.setState({firstName})} + placeholder="John" + /> + + + Last Name + this.setState({lastName})} + placeholder="Doe" + /> + + + + Preferred Pronouns + + this.setState({pronouns, selfSelectedPronouns: ''})} + items={this.pronounDropdownValues} + style={styles.picker} + useNativeAndroidPickerStyle={false} + placeholder={{ + value: '', + label: 'Select your pronouns', + }} + value={this.state.pronouns} + Icon={() => } + /> + + {this.state.pronouns === pronounsMap.selfSelect ? ( + this.setState({selfSelectedPronouns})} + placeholder="Self-select your pronoun" + /> + ) : null} + + + + {Str.isSMSLogin(this.props.myPersonalDetails.login) + ? 'Phone Number' : 'Email Address'} + + + + + Timezone + this.setState({selectedTimezone})} + items={timezones} + style={this.state.isAutomaticTimezone ? { + ...styles.picker, + inputIOS: [styles.picker.inputIOS, styles.textInput, styles.disabledTextInput], + inputAndroid: [ + styles.picker.inputAndroid, styles.textInput, styles.disabledTextInput, + ], + inputWeb: [styles.picker.inputWeb, styles.textInput, styles.disabledTextInput], + } : styles.picker} + useNativeAndroidPickerStyle={false} + value={this.state.selectedTimezone} + Icon={() => } + disabled={this.state.isAutomaticTimezone} + /> + + this.setState({isAutomaticTimezone})} + /> + + + + + + )} + + ); + } +} -const ProfilePage = () => ( - - {() => ( - <> - Navigation.navigate(ROUTES.SETTINGS)} - onCloseButtonPress={() => Navigation.dismissModal()} - /> - - )} - -); +ProfilePage.propTypes = propTypes; +ProfilePage.defaultProps = defaultProps; ProfilePage.displayName = 'ProfilePage'; -export default ProfilePage; +export default withOnyx({ + myPersonalDetails: { + key: ONYXKEYS.MY_PERSONAL_DETAILS, + }, +})(ProfilePage); diff --git a/src/styles/styles.js b/src/styles/styles.js index a63bf3039626..f87e2dd5f10a 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -159,6 +159,14 @@ const styles = { color: themeColors.textReversed, }, + fixedBottomButton: { + position: 'absolute', + bottom: 0, + width: '100%', + padding: 20, + backgroundColor: 'white', + }, + hoveredComponentBG: { backgroundColor: themeColors.hoverComponentBG, }, @@ -175,36 +183,42 @@ const styles = { inputIOS: { fontFamily: fontFamily.GTA, fontSize: variables.fontSizeNormal, - paddingVertical: 12, - paddingHorizontal: 10, + paddingLeft: 12, + paddingRight: 12, + paddingTop: 10, + paddingBottom: 10, borderRadius: variables.componentBorderRadius, borderWidth: 1, borderColor: themeColors.border, color: themeColors.text, - paddingRight: 30, + height: variables.componentSizeNormal, }, inputWeb: { fontFamily: fontFamily.GTA, fontSize: variables.fontSizeNormal, - paddingVertical: 12, - paddingHorizontal: 10, + paddingLeft: 12, + paddingRight: 12, + paddingTop: 10, + paddingBottom: 10, borderWidth: 1, borderRadius: variables.componentBorderRadius, borderColor: themeColors.border, color: themeColors.text, - paddingRight: 30, appearance: 'none', + height: variables.componentSizeNormal, }, inputAndroid: { fontFamily: fontFamily.GTA, fontSize: variables.fontSizeNormal, - paddingHorizontal: 10, - paddingVertical: 8, + paddingLeft: 12, + paddingRight: 12, + paddingTop: 10, + paddingBottom: 10, borderWidth: 1, borderRadius: variables.componentBorderRadius, borderColor: themeColors.border, color: themeColors.text, - paddingRight: 30, + height: variables.componentSizeNormal, }, iconContainer: { top: 12, @@ -287,6 +301,11 @@ const styles = { textAlignVertical: 'center', }, + disabledTextInput: { + backgroundColor: colors.gray1, + color: colors.gray3, + }, + textInputReversed: addOutlineWidth({ backgroundColor: themeColors.heading, borderColor: themeColors.text, @@ -1092,6 +1111,21 @@ const styles = { height: 24, lineHeight: 20, }, + + checkboxContainer: { + backgroundColor: themeColors.componentBG, + borderRadius: 2, + height: 20, + width: 20, + borderColor: themeColors.border, + borderWidth: 1, + justifyContent: 'center', + alignItems: 'center', + }, + + checkedContainer: { + backgroundColor: colors.blue, + }, }; const baseCodeTagStyles = { diff --git a/src/styles/utilities/flex.js b/src/styles/utilities/flex.js index 1508fbba8c61..6a66532e0601 100644 --- a/src/styles/utilities/flex.js +++ b/src/styles/utilities/flex.js @@ -40,6 +40,10 @@ export default { alignSelf: 'stretch', }, + alignSelfCenter: { + alignSelf: 'center', + }, + alignItemsCenter: { alignItems: 'center', }, From 70f9e93411e8afc320b5f5508e43be3486c6fcbf Mon Sep 17 00:00:00 2001 From: maftalion Date: Mon, 15 Mar 2021 08:42:02 -0700 Subject: [PATCH 02/18] updates styles --- src/components/Checkbox.js | 2 +- src/pages/settings/ProfilePage.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/Checkbox.js b/src/components/Checkbox.js index 579e247ee980..3bda0f29367a 100644 --- a/src/components/Checkbox.js +++ b/src/components/Checkbox.js @@ -31,7 +31,7 @@ const Checkbox = ({ {label ? ( onClick(!isChecked)}> - + {label} diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index 61dc868a9fd5..775e8a65a513 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -127,12 +127,12 @@ class ProfilePage extends Component { style={[styles.avatarLarge, styles.alignSelfCenter]} source={this.props.myPersonalDetails.avatarURL} /> - + Tell us about yourself, we would love to get to know you! - First Name + First Name - Last Name + Last Name - Preferred Pronouns + Preferred Pronouns this.setState({pronouns, selfSelectedPronouns: ''})} @@ -176,7 +176,7 @@ class ProfilePage extends Component { ) : null} - + {Str.isSMSLogin(this.props.myPersonalDetails.login) ? 'Phone Number' : 'Email Address'} @@ -187,7 +187,7 @@ class ProfilePage extends Component { /> - Timezone + Timezone this.setState({selectedTimezone})} items={timezones} From 41083e560e4892067b09c641ddfee998bcd7966e Mon Sep 17 00:00:00 2001 From: maftalion Date: Mon, 15 Mar 2021 13:09:14 -0700 Subject: [PATCH 03/18] small refactors --- src/CONST.js | 8 ++++++++ src/components/Checkbox.js | 10 ++++++---- src/pages/settings/ProfilePage.js | 15 +++------------ 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index 6e4841f27de4..7185b865b2ec 100644 --- a/src/CONST.js +++ b/src/CONST.js @@ -66,6 +66,14 @@ const CONST = { TIMEZONE: 'timeZone', }, DEFAULT_TIME_ZONE: {automatic: true, selected: 'America/Los_Angeles'}, + PRONOUNS: { + THEY_THEM_THEIRS: 'They/them/theirs', + SHE_HER_HERS: 'She/her/hers', + HE_HIM_HIS: 'He/him/his', + ZE_HIR_HIRS: 'Ze/hir/hirs', + SELF_SELECT: 'Self-select', + CALL_ME_BY_MY_NAME: 'Call me by my name', + }, }; export default CONST; diff --git a/src/components/Checkbox.js b/src/components/Checkbox.js index 3bda0f29367a..54ca9b8d31c8 100644 --- a/src/components/Checkbox.js +++ b/src/components/Checkbox.js @@ -21,7 +21,9 @@ const defaultProps = { }; const Checkbox = ({ - isChecked, onClick, label, + isChecked, + onClick, + label, }) => ( onClick(!isChecked)}> @@ -29,18 +31,18 @@ const Checkbox = ({ - {label ? ( + {label && ( onClick(!isChecked)}> {label} - ) : null} + )} ); - Checkbox.defaultProps = defaultProps; Checkbox.propTypes = propTypes; +Checkbox.displayName = 'Checkbox'; export default Checkbox; diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index 775e8a65a513..42e69eeb2d4e 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -59,15 +59,6 @@ const defaultProps = { myPersonalDetails: {}, }; -const pronounsMap = { - theyThemTheirs: 'They/them/theirs', - sheHerHers: 'She/her/hers', - heHimHis: 'He/him/his', - zeHirHirs: 'Ze/hir/hirs', - selfSelect: 'Self-select', - callMeByMyName: 'Call me by my name', -}; - const timezones = moment.tz.names() .map(timezone => ({ value: timezone, @@ -103,7 +94,7 @@ class ProfilePage extends Component { setPersonalDetails({ firstName, lastName, - pronouns: pronouns === pronounsMap.selfSelect ? selfSelectedPronouns : pronouns, + pronouns: pronouns === CONST.PRONOUNS.SELF_SELECT ? selfSelectedPronouns : pronouns, timezone: { automatic: isAutomaticTimezone, selected: selectedTimezone, @@ -166,14 +157,14 @@ class ProfilePage extends Component { Icon={() => } /> - {this.state.pronouns === pronounsMap.selfSelect ? ( + {this.state.pronouns === CONST.PRONOUNS.SELF_SELECT && ( this.setState({selfSelectedPronouns})} placeholder="Self-select your pronoun" /> - ) : null} + )} From b0c00630127d8bcbcc6053ba2c69162e68bb94af Mon Sep 17 00:00:00 2001 From: maftalion Date: Mon, 15 Mar 2021 13:09:30 -0700 Subject: [PATCH 04/18] set initial pronouns --- src/pages/settings/ProfilePage.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index 42e69eeb2d4e..4d1c3046e222 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -72,17 +72,26 @@ class ProfilePage extends Component { const { firstName, lastName, pronouns, timezone = {}, } = props.myPersonalDetails; + const pronounValues = Object.values(CONST.PRONOUNS); + + let initialPronouns = pronouns; + let initialSelfSelectedPronouns = ''; + + if (pronouns && !pronounValues.includes(pronouns)) { + initialPronouns = CONST.PRONOUNS.SELF_SELECT; + initialSelfSelectedPronouns = pronouns; + } this.state = { firstName, lastName, - pronouns, - selfSelectedPronouns: '', + pronouns: initialPronouns, + selfSelectedPronouns: initialSelfSelectedPronouns, selectedTimezone: timezone.selected ?? CONST.DEFAULT_TIME_ZONE.selected, isAutomaticTimezone: timezone.automatic ?? CONST.DEFAULT_TIME_ZONE.automatic, }; - this.pronounDropdownValues = Object.values(pronounsMap).map(pronoun => ({value: pronoun, label: pronoun})); + this.pronounDropdownValues = pronounValues.map(pronoun => ({value: pronoun, label: pronoun})); this.updatePersonalDetails = this.updatePersonalDetails.bind(this); } From aef240fe1354393cc9bb2c4579ea3bbc3532772c Mon Sep 17 00:00:00 2001 From: maftalion Date: Mon, 15 Mar 2021 14:43:24 -0700 Subject: [PATCH 05/18] update checkbox prop --- src/components/Checkbox.js | 8 ++++---- src/pages/settings/ProfilePage.js | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/components/Checkbox.js b/src/components/Checkbox.js index 54ca9b8d31c8..674240f3f2e6 100644 --- a/src/components/Checkbox.js +++ b/src/components/Checkbox.js @@ -10,7 +10,7 @@ const propTypes = { isChecked: PropTypes.bool.isRequired, // A function that is called when the box/label is clicked on - onClick: PropTypes.func.isRequired, + onCheckboxClick: PropTypes.func.isRequired, // Text that appears next to check box label: PropTypes.string, @@ -22,17 +22,17 @@ const defaultProps = { const Checkbox = ({ isChecked, - onClick, + onCheckboxClick, label, }) => ( - onClick(!isChecked)}> + onCheckboxClick(!isChecked)}> {label && ( - onClick(!isChecked)}> + onCheckboxClick(!isChecked)}> {label} diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index 4d1c3046e222..cf2e94288899 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -208,7 +208,7 @@ class ProfilePage extends Component { this.setState({isAutomaticTimezone})} + onCheckboxClick={isAutomaticTimezone => this.setState({isAutomaticTimezone})} /> @@ -224,7 +224,6 @@ class ProfilePage extends Component { } } - ProfilePage.propTypes = propTypes; ProfilePage.defaultProps = defaultProps; ProfilePage.displayName = 'ProfilePage'; From a16209fe65a1ba8dd8e3a92b96dc60d20d9df3cf Mon Sep 17 00:00:00 2001 From: maftalion Date: Tue, 16 Mar 2021 09:41:20 -0700 Subject: [PATCH 06/18] lint --- src/pages/settings/ProfilePage.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index cf2e94288899..2aa8a887f5cf 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -70,7 +70,10 @@ class ProfilePage extends Component { super(props); const { - firstName, lastName, pronouns, timezone = {}, + firstName, + lastName, + pronouns, + timezone = {}, } = props.myPersonalDetails; const pronounValues = Object.values(CONST.PRONOUNS); @@ -97,7 +100,12 @@ class ProfilePage extends Component { updatePersonalDetails() { const { - firstName, lastName, pronouns, selfSelectedPronouns, selectedTimezone, isAutomaticTimezone, + firstName, + lastName, + pronouns, + selfSelectedPronouns, + selectedTimezone, + isAutomaticTimezone, } = this.state; setPersonalDetails({ From 7daf23593b19b2128cbef23dbb54e06f381f6c91 Mon Sep 17 00:00:00 2001 From: maftalion Date: Tue, 16 Mar 2021 21:47:20 -0700 Subject: [PATCH 07/18] refactors, set tz automatically --- src/pages/settings/ProfilePage.js | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index 2aa8a887f5cf..314bba568a8f 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -38,7 +38,7 @@ const propTypes = { lastName: PropTypes.string, // Avatar URL of the current user from their personal details - avatarURL: PropTypes.string, + avatar: PropTypes.string, // Pronouns of the current user from their personal details pronouns: PropTypes.string, @@ -75,12 +75,13 @@ class ProfilePage extends Component { pronouns, timezone = {}, } = props.myPersonalDetails; - const pronounValues = Object.values(CONST.PRONOUNS); + const pronounsList = Object.values(CONST.PRONOUNS); let initialPronouns = pronouns; let initialSelfSelectedPronouns = ''; - if (pronouns && !pronounValues.includes(pronouns)) { + // This handles populating the self-selected pronouns in the form + if (pronouns && !pronounsList.includes(pronouns)) { initialPronouns = CONST.PRONOUNS.SELF_SELECT; initialSelfSelectedPronouns = pronouns; } @@ -94,8 +95,16 @@ class ProfilePage extends Component { isAutomaticTimezone: timezone.automatic ?? CONST.DEFAULT_TIME_ZONE.automatic, }; - this.pronounDropdownValues = pronounValues.map(pronoun => ({value: pronoun, label: pronoun})); + this.pronounDropdownValues = pronounsList.map(pronoun => ({value: pronoun, label: pronoun})); this.updatePersonalDetails = this.updatePersonalDetails.bind(this); + this.setAutomaticTimezone = this.setAutomaticTimezone.bind(this); + } + + setAutomaticTimezone(isAutomaticTimezone) { + this.setState(({selectedTimezone}) => ({ + isAutomaticTimezone, + selectedTimezone: isAutomaticTimezone ? moment.tz.guess() : selectedTimezone, + })); } updatePersonalDetails() { @@ -133,7 +142,7 @@ class ProfilePage extends Component { Tell us about yourself, we would love to get to know you! @@ -190,7 +199,9 @@ class ProfilePage extends Component { @@ -216,7 +227,7 @@ class ProfilePage extends Component { this.setState({isAutomaticTimezone})} + onCheckboxClick={this.setAutomaticTimezone} /> From 727602141a706d1e34311cbeae126165b839f866 Mon Sep 17 00:00:00 2001 From: maftalion Date: Wed, 17 Mar 2021 06:50:09 -0700 Subject: [PATCH 08/18] add checkbox margin --- src/pages/settings/ProfilePage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index 314bba568a8f..7192d29391ee 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -205,7 +205,7 @@ class ProfilePage extends Component { editable={false} /> - + Timezone this.setState({selectedTimezone})} From 513a460f9a4e7380ef3e027296babc71bf077f79 Mon Sep 17 00:00:00 2001 From: maftalion Date: Wed, 17 Mar 2021 16:14:12 -0700 Subject: [PATCH 09/18] update placeholder text color --- src/components/OptionsSelector.js | 2 +- src/pages/home/report/ReportActionCompose.js | 2 +- src/pages/settings/ProfilePage.js | 10 +++++++--- src/pages/signin/LoginForm/LoginFormNarrow.js | 2 +- src/pages/signin/PasswordForm.js | 2 +- src/styles/themes/default.js | 1 + 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/components/OptionsSelector.js b/src/components/OptionsSelector.js index d90d1a7686a7..effeff3cef65 100644 --- a/src/components/OptionsSelector.js +++ b/src/components/OptionsSelector.js @@ -175,7 +175,7 @@ class OptionsSelector extends Component { onChangeText={this.props.onChangeText} onKeyPress={this.handleKeyPress} placeholder={this.props.placeholderText} - placeholderTextColor={themeColors.textSupporting} + placeholderTextColor={themeColors.placeholderText} /> this.textInput = el} textAlignVertical="top" placeholder="Write something..." - placeholderTextColor={themeColors.textSupporting} + placeholderTextColor={themeColors.placeholderText} onChangeText={this.updateComment} onKeyPress={this.triggerSubmitShortcut} onDragEnter={() => this.setState({isDraggingOver: true})} diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index 7192d29391ee..53ea1ef3faae 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -23,6 +23,7 @@ import {DownArrow} from '../../components/Icon/Expensicons'; import Icon from '../../components/Icon'; import Checkbox from '../../components/Checkbox'; import ButtonWithLoader from '../../components/ButtonWithLoader'; +import themeColors from '../../styles/themes/default'; const propTypes = { /* Onyx Props */ @@ -77,19 +78,19 @@ class ProfilePage extends Component { } = props.myPersonalDetails; const pronounsList = Object.values(CONST.PRONOUNS); - let initialPronouns = pronouns; + let currentUserPronouns = pronouns; let initialSelfSelectedPronouns = ''; // This handles populating the self-selected pronouns in the form if (pronouns && !pronounsList.includes(pronouns)) { - initialPronouns = CONST.PRONOUNS.SELF_SELECT; + currentUserPronouns = CONST.PRONOUNS.SELF_SELECT; initialSelfSelectedPronouns = pronouns; } this.state = { firstName, lastName, - pronouns: initialPronouns, + pronouns: currentUserPronouns, selfSelectedPronouns: initialSelfSelectedPronouns, selectedTimezone: timezone.selected ?? CONST.DEFAULT_TIME_ZONE.selected, isAutomaticTimezone: timezone.automatic ?? CONST.DEFAULT_TIME_ZONE.automatic, @@ -155,6 +156,7 @@ class ProfilePage extends Component { value={this.state.firstName} onChangeText={firstName => this.setState({firstName})} placeholder="John" + placeholderTextColor={themeColors.placeholderText} /> @@ -164,6 +166,7 @@ class ProfilePage extends Component { value={this.state.lastName} onChangeText={lastName => this.setState({lastName})} placeholder="Doe" + placeholderTextColor={themeColors.placeholderText} /> @@ -189,6 +192,7 @@ class ProfilePage extends Component { value={this.state.selfSelectedPronouns} onChangeText={selfSelectedPronouns => this.setState({selfSelectedPronouns})} placeholder="Self-select your pronoun" + placeholderTextColor={themeColors.placeholderText} /> )} diff --git a/src/pages/signin/LoginForm/LoginFormNarrow.js b/src/pages/signin/LoginForm/LoginFormNarrow.js index ba6c78b1b012..1477fba04416 100644 --- a/src/pages/signin/LoginForm/LoginFormNarrow.js +++ b/src/pages/signin/LoginForm/LoginFormNarrow.js @@ -74,7 +74,7 @@ class LoginFormNarrow extends React.Component { onSubmitEditing={this.validateAndSubmitForm} autoCapitalize="none" placeholder="Email or phone" - placeholderTextColor={themeColors.textSupporting} + placeholderTextColor={themeColors.placeholderText} /> diff --git a/src/pages/signin/PasswordForm.js b/src/pages/signin/PasswordForm.js index 55dbdebceffc..270fa192be06 100644 --- a/src/pages/signin/PasswordForm.js +++ b/src/pages/signin/PasswordForm.js @@ -88,7 +88,7 @@ class PasswordForm extends React.Component { style={[styles.textInput]} value={this.state.twoFactorAuthCode} placeholder="Required when 2FA is enabled" - placeholderTextColor={themeColors.textSupporting} + placeholderTextColor={themeColors.placeholderText} onChangeText={text => this.setState({twoFactorAuthCode: text})} onSubmitEditing={this.validateAndSubmitForm} /> diff --git a/src/styles/themes/default.js b/src/styles/themes/default.js index 3c4ba846a6e7..73b82ded23ab 100644 --- a/src/styles/themes/default.js +++ b/src/styles/themes/default.js @@ -34,4 +34,5 @@ export default { buttonHoveredBG: colors.gray1, spinner: colors.gray4, unreadIndicator: colors.green, + placeholderText: colors.gray3, }; From 7f2f542478043cf3e79a8b9b5e57ac83cc7541e7 Mon Sep 17 00:00:00 2001 From: maftalion Date: Wed, 17 Mar 2021 16:35:46 -0700 Subject: [PATCH 10/18] set full opacity on picker --- src/styles/styles.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/styles/styles.js b/src/styles/styles.js index f87e2dd5f10a..9522a851e8fd 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -192,6 +192,7 @@ const styles = { borderColor: themeColors.border, color: themeColors.text, height: variables.componentSizeNormal, + opacity: 1, }, inputWeb: { fontFamily: fontFamily.GTA, @@ -206,6 +207,7 @@ const styles = { color: themeColors.text, appearance: 'none', height: variables.componentSizeNormal, + opacity: 1, }, inputAndroid: { fontFamily: fontFamily.GTA, @@ -219,6 +221,7 @@ const styles = { borderColor: themeColors.border, color: themeColors.text, height: variables.componentSizeNormal, + opacity: 1, }, iconContainer: { top: 12, From 57679e0c347328ff2791dada9bfb29ca1206eec9 Mon Sep 17 00:00:00 2001 From: maftalion Date: Thu, 18 Mar 2021 15:42:04 -0700 Subject: [PATCH 11/18] fix button styling --- src/pages/settings/ProfilePage.js | 34 +++++++++++++++---------------- src/styles/styles.js | 8 -------- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index b783629ac08e..c022d9e515df 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -132,14 +132,14 @@ class ProfilePage extends Component { render() { return ( - <> - Navigation.navigate(ROUTES.SETTINGS)} - onCloseButtonPress={Navigation.dismissModal} - /> - + Navigation.navigate(ROUTES.SETTINGS)} + onCloseButtonPress={Navigation.dismissModal} + /> + + {this.state.pronouns === CONST.PRONOUNS.SELF_SELECT && ( - this.setState({selfSelectedPronouns})} - placeholder="Self-select your pronoun" - placeholderTextColor={themeColors.placeholderText} - /> + this.setState({selfSelectedPronouns})} + placeholder="Self-select your pronoun" + placeholderTextColor={themeColors.placeholderText} + /> )} @@ -233,13 +233,13 @@ class ProfilePage extends Component { onCheckboxClick={this.setAutomaticTimezone} /> - + - + ); } diff --git a/src/styles/styles.js b/src/styles/styles.js index 9522a851e8fd..bd5a47172546 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -159,14 +159,6 @@ const styles = { color: themeColors.textReversed, }, - fixedBottomButton: { - position: 'absolute', - bottom: 0, - width: '100%', - padding: 20, - backgroundColor: 'white', - }, - hoveredComponentBG: { backgroundColor: themeColors.hoverComponentBG, }, From a3796ad720bdb70a768da30db015b372a414207c Mon Sep 17 00:00:00 2001 From: maftalion Date: Thu, 18 Mar 2021 17:36:38 -0700 Subject: [PATCH 12/18] remove line --- src/pages/settings/ProfilePage.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index c022d9e515df..c3cdcba8d9d1 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -8,7 +8,6 @@ import { import RNPickerSelect from 'react-native-picker-select'; import Str from 'expensify-common/lib/str'; import moment from 'moment-timezone'; - import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import Navigation from '../../libs/Navigation/Navigation'; import ScreenWrapper from '../../components/ScreenWrapper'; From 5b5071264cfde26e052b17fdb7a1ee4d23a17b38 Mon Sep 17 00:00:00 2001 From: maftalion Date: Fri, 19 Mar 2021 18:28:14 -0700 Subject: [PATCH 13/18] make button fixed & add disable --- src/pages/settings/ProfilePage.js | 183 ++++++++++++++++-------------- 1 file changed, 100 insertions(+), 83 deletions(-) diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index c3cdcba8d9d1..8d7abeceb0cc 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -4,6 +4,7 @@ import PropTypes from 'prop-types'; import { View, TextInput, + Pressable, } from 'react-native'; import RNPickerSelect from 'react-native-picker-select'; import Str from 'expensify-common/lib/str'; @@ -129,6 +130,13 @@ class ProfilePage extends Component { } render() { + const isButtonDisabled = (this.props.myPersonalDetails.firstName === this.state.firstName) + && (this.props.myPersonalDetails.lastName === this.state.lastName) + && (this.props.myPersonalDetails.timezone.selected === this.state.selectedTimezone) + && (this.props.myPersonalDetails.timezone.automatic === this.state.isAutomaticTimezone) + && (this.props.myPersonalDetails.pronouns === this.state.pronouns + || this.props.myPersonalDetails.pronouns === this.state.selfSelectedPronouns); + console.log(this.props.myPersonalDetails.pronouns === this.state.selfSelectedPronouns) return ( - - - - Tell us about yourself, we would love to get to know you! - - - - First Name - this.setState({firstName})} - placeholder="John" - placeholderTextColor={themeColors.placeholderText} - /> - - - Last Name - this.setState({lastName})} - placeholder="Doe" - placeholderTextColor={themeColors.placeholderText} - /> - - - - Preferred Pronouns - - this.setState({pronouns, selfSelectedPronouns: ''})} - items={this.pronounDropdownValues} - style={styles.picker} - useNativeAndroidPickerStyle={false} - placeholder={{ - value: '', - label: 'Select your pronouns', - }} - value={this.state.pronouns} - Icon={() => } - /> - - {this.state.pronouns === CONST.PRONOUNS.SELF_SELECT && ( + + + Tell us about yourself, we would love to get to know you! + + + + First Name this.setState({selfSelectedPronouns})} - placeholder="Self-select your pronoun" + value={this.state.firstName} + onChangeText={firstName => this.setState({firstName})} + placeholder="John" placeholderTextColor={themeColors.placeholderText} /> - )} - - - {Str.isSMSLogin(this.props.myPersonalDetails.login) - ? 'Phone Number' : 'Email Address'} - + + Last Name this.setState({lastName})} + placeholder="Doe" + placeholderTextColor={themeColors.placeholderText} /> - - Timezone + + + Preferred Pronouns + this.setState({selectedTimezone})} - items={timezones} - style={this.state.isAutomaticTimezone ? { - ...styles.picker, - inputIOS: [styles.picker.inputIOS, styles.textInput, styles.disabledTextInput], - inputAndroid: [ - styles.picker.inputAndroid, styles.textInput, styles.disabledTextInput, - ], - inputWeb: [styles.picker.inputWeb, styles.textInput, styles.disabledTextInput], - } : styles.picker} + onValueChange={pronouns => this.setState({pronouns, selfSelectedPronouns: ''})} + items={this.pronounDropdownValues} + style={styles.picker} useNativeAndroidPickerStyle={false} - value={this.state.selectedTimezone} + placeholder={{ + value: '', + label: 'Select your pronouns', + }} + value={this.state.pronouns} Icon={() => } - disabled={this.state.isAutomaticTimezone} /> - this.setState({selfSelectedPronouns})} + placeholder="Self-select your pronoun" + placeholderTextColor={themeColors.placeholderText} /> + )} - - + + {Str.isSMSLogin(this.props.myPersonalDetails.login) + ? 'Phone Number' : 'Email Address'} + + + + + Timezone + this.setState({selectedTimezone})} + items={timezones} + style={this.state.isAutomaticTimezone ? { + ...styles.picker, + inputIOS: [styles.picker.inputIOS, styles.textInput, styles.disabledTextInput], + inputAndroid: [ + styles.picker.inputAndroid, styles.textInput, styles.disabledTextInput, + ], + inputWeb: [styles.picker.inputWeb, styles.textInput, styles.disabledTextInput], + } : styles.picker} + useNativeAndroidPickerStyle={false} + value={this.state.selectedTimezone} + Icon={() => } + disabled={this.state.isAutomaticTimezone} /> + + + + [ + styles.button, + styles.buttonSuccess, + styles.w100, + hovered && styles.buttonSuccessHovered, + isButtonDisabled && styles.buttonDisable, + ]} + > + + Save + + ); From f1b8baf1e20256022b7212a8f572c9099f98e22e Mon Sep 17 00:00:00 2001 From: maftalion Date: Fri, 19 Mar 2021 18:30:38 -0700 Subject: [PATCH 14/18] remove log --- src/pages/settings/ProfilePage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index 8d7abeceb0cc..28bbbfda0a8f 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -136,7 +136,7 @@ class ProfilePage extends Component { && (this.props.myPersonalDetails.timezone.automatic === this.state.isAutomaticTimezone) && (this.props.myPersonalDetails.pronouns === this.state.pronouns || this.props.myPersonalDetails.pronouns === this.state.selfSelectedPronouns); - console.log(this.props.myPersonalDetails.pronouns === this.state.selfSelectedPronouns) + return ( Date: Fri, 19 Mar 2021 18:32:50 -0700 Subject: [PATCH 15/18] lint --- src/pages/settings/ProfilePage.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index 28bbbfda0a8f..8a494a8acb46 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -22,7 +22,6 @@ import Text from '../../components/Text'; import {DownArrow} from '../../components/Icon/Expensicons'; import Icon from '../../components/Icon'; import Checkbox from '../../components/Checkbox'; -import ButtonWithLoader from '../../components/ButtonWithLoader'; import themeColors from '../../styles/themes/default'; const propTypes = { From b5b65e8b657bbfcaabaa892141b0f4496ab1ef05 Mon Sep 17 00:00:00 2001 From: maftalion Date: Fri, 19 Mar 2021 18:57:01 -0700 Subject: [PATCH 16/18] small fixes --- src/pages/settings/ProfilePage.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index 8a494a8acb46..ad1fbd9661e4 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -91,7 +91,7 @@ class ProfilePage extends Component { lastName, pronouns: currentUserPronouns, selfSelectedPronouns: initialSelfSelectedPronouns, - selectedTimezone: timezone.selected ?? CONST.DEFAULT_TIME_ZONE.selected, + selectedTimezone: timezone.selected || CONST.DEFAULT_TIME_ZONE.selected, isAutomaticTimezone: timezone.automatic ?? CONST.DEFAULT_TIME_ZONE.automatic, }; @@ -129,6 +129,7 @@ class ProfilePage extends Component { } render() { + // Disables button if none of the form values have changed const isButtonDisabled = (this.props.myPersonalDetails.firstName === this.state.firstName) && (this.props.myPersonalDetails.lastName === this.state.lastName) && (this.props.myPersonalDetails.timezone.selected === this.state.selectedTimezone) From 51ff53b2245ffce3c5027e77da32f9a3dfbee810 Mon Sep 17 00:00:00 2001 From: maftalion Date: Mon, 22 Mar 2021 08:50:04 -0700 Subject: [PATCH 17/18] fix pronouns disabling form --- src/pages/settings/ProfilePage.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index ad1fbd9661e4..813ae55e0ddd 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -135,7 +135,8 @@ class ProfilePage extends Component { && (this.props.myPersonalDetails.timezone.selected === this.state.selectedTimezone) && (this.props.myPersonalDetails.timezone.automatic === this.state.isAutomaticTimezone) && (this.props.myPersonalDetails.pronouns === this.state.pronouns - || this.props.myPersonalDetails.pronouns === this.state.selfSelectedPronouns); + || (this.props.myPersonalDetails.pronouns + && this.props.myPersonalDetails.pronouns === this.state.selfSelectedPronouns)); return ( From a193424aaed9f9348be8c85c2b753e2601842e23 Mon Sep 17 00:00:00 2001 From: maftalion Date: Mon, 22 Mar 2021 18:49:22 -0700 Subject: [PATCH 18/18] clarify disabled value --- src/pages/settings/ProfilePage.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index 813ae55e0ddd..1939a775de77 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -129,14 +129,17 @@ class ProfilePage extends Component { } render() { + // Determines if the pronouns/selected pronouns have changed + const arePronounsUnchanged = this.props.myPersonalDetails.pronouns === this.state.pronouns + || (this.props.myPersonalDetails.pronouns + && this.props.myPersonalDetails.pronouns === this.state.selfSelectedPronouns); + // Disables button if none of the form values have changed const isButtonDisabled = (this.props.myPersonalDetails.firstName === this.state.firstName) && (this.props.myPersonalDetails.lastName === this.state.lastName) && (this.props.myPersonalDetails.timezone.selected === this.state.selectedTimezone) && (this.props.myPersonalDetails.timezone.automatic === this.state.isAutomaticTimezone) - && (this.props.myPersonalDetails.pronouns === this.state.pronouns - || (this.props.myPersonalDetails.pronouns - && this.props.myPersonalDetails.pronouns === this.state.selfSelectedPronouns)); + && arePronounsUnchanged; return (