From 9704e1ee5dc83ce3c66b763f14155a5b7510d0a1 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Thu, 27 Oct 2022 19:06:35 +0200 Subject: [PATCH 01/23] Set up routes for new Timezone pages --- src/ROUTES.js | 2 ++ .../AppNavigator/ModalStackNavigators.js | 14 ++++++++++++++ src/libs/Navigation/linkingConfig.js | 8 ++++++++ 3 files changed, 24 insertions(+) diff --git a/src/ROUTES.js b/src/ROUTES.js index 0cd8b4164a8e..a5463c49c384 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -22,6 +22,8 @@ export default { HOME: '', SETTINGS: 'settings', SETTINGS_PROFILE: 'settings/profile', + SETTINGS_TIMEZONE_INITIAL: 'settings/profile/timezone', + SETTINGS_TIMEZONE_SELECT: 'settings/profile/timezone/select', SETTINGS_PREFERENCES: 'settings/preferences', SETTINGS_SECURITY: 'settings/security', SETTINGS_CLOSE: 'settings/security/closeAccount', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index 6702b90769d8..3b5b1e903a1a 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -210,6 +210,20 @@ const SettingsModalStackNavigator = createModalStackNavigator([ }, name: 'Settings_Profile', }, + { + getComponent: () => { + const SettingsTimezoneInitialPage = require('../../../pages/settings/Profile/TimezoneInitialPage').default; + return SettingsTimezoneInitialPage; + }, + name: 'Settings_Timezone_Init', + }, + { + getComponent: () => { + const SettingsTimezoneSelectPage = require('../../../pages/settings/Profile/TimezoneSelectPage').default; + return SettingsTimezoneSelectPage; + }, + name: 'Settings_Timezone_Select', + }, { getComponent: () => { const SettingsAddSecondaryLoginPage = require('../../../pages/settings/AddSecondaryLoginPage').default; diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 23cfa9ea349c..de7631fdbee8 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -84,6 +84,14 @@ export default { path: ROUTES.SETTINGS_PROFILE, exact: true, }, + Settings_Timezone_Init: { + path: ROUTES.SETTINGS_TIMEZONE_INITIAL, + exact: true, + }, + Settings_Timezone_Select: { + path: ROUTES.SETTINGS_TIMEZONE_SELECT, + exact: true, + }, Settings_About: { path: ROUTES.SETTINGS_ABOUT, exact: true, From c9cad55f08f8c662b743cce6bd854f7e394dbd2a Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Thu, 27 Oct 2022 19:06:45 +0200 Subject: [PATCH 02/23] New timezone initial page --- .../settings/Profile/TimezoneInitialPage.js | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/pages/settings/Profile/TimezoneInitialPage.js diff --git a/src/pages/settings/Profile/TimezoneInitialPage.js b/src/pages/settings/Profile/TimezoneInitialPage.js new file mode 100644 index 000000000000..aeae3d00c644 --- /dev/null +++ b/src/pages/settings/Profile/TimezoneInitialPage.js @@ -0,0 +1,84 @@ +import lodashGet from 'lodash/get'; +import React from 'react'; +import {View} from 'react-native'; +import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps} from '../../../components/withCurrentUserPersonalDetails'; +import ScreenWrapper from '../../../components/ScreenWrapper'; +import HeaderWithCloseButton from '../../../components/HeaderWithCloseButton'; +import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize'; +import ROUTES from '../../../ROUTES'; +import CONST from '../../../CONST'; +import Text from '../../../components/Text'; +import styles from '../../../styles/styles'; +import Navigation from '../../../libs/Navigation/Navigation'; +import * as PersonalDetails from '../../../libs/actions/PersonalDetails'; +import compose from '../../../libs/compose'; +import Switch from '../../../components/Switch'; +import MenuItemWithTopDescription from '../../../components/MenuItemWithTopDescription'; +import moment from 'moment-timezone'; + +const propTypes = { + ...withLocalizePropTypes, + ...withCurrentUserPersonalDetailsPropTypes, +}; + +const defaultProps = { + ...withCurrentUserPersonalDetailsDefaultProps, +}; + +const TimezoneInitialPage = (props) => { + const timezone = lodashGet(props.currentUserPersonalDetails, 'timezone', CONST.DEFAULT_TIME_ZONE); + + /** + * Updates setting for timezone updating automatically. + * Note: If we are updating automatically, we'll immediately caltulate user timezone. + * + * @param {Boolean} isAutomatic + */ + const updateAutomaticTimezone = (isAutomatic) => { + PersonalDetails.updateAutomaticTimezone({ + automatic: isAutomatic, + selected: isAutomatic ? moment.tz.guess() : timezone.selected, + }); + }; + + return ( + + Navigation.navigate(ROUTES.SETTINGS_PROFILE)} + onCloseButtonPress={() => Navigation.dismissModal(true)} + /> + + + {props.translate('timezonePage.isShownOnProfile')} + + + + {props.translate('timezonePage.getLocationAutomatically')} + + + + + Navigation.navigate(ROUTES.SETTINGS_TIMEZONE_SELECT)} + /> + + ); +} + +TimezoneInitialPage.propTypes = propTypes; +TimezoneInitialPage.defaultProps = defaultProps; + +export default compose( + withLocalize, + withCurrentUserPersonalDetails, +)(TimezoneInitialPage); From bcae5803cfc351f97752885ce183a9be36b3f4cd Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Thu, 27 Oct 2022 19:06:56 +0200 Subject: [PATCH 03/23] New timezone select page --- .../settings/Profile/TimezoneSelectPage.js | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 src/pages/settings/Profile/TimezoneSelectPage.js diff --git a/src/pages/settings/Profile/TimezoneSelectPage.js b/src/pages/settings/Profile/TimezoneSelectPage.js new file mode 100644 index 000000000000..ebcb588dd25d --- /dev/null +++ b/src/pages/settings/Profile/TimezoneSelectPage.js @@ -0,0 +1,98 @@ +import lodashGet from 'lodash/get'; +import React, {Component} from 'react'; +import {View} from 'react-native'; +import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps} from '../../../components/withCurrentUserPersonalDetails'; +import ScreenWrapper from '../../../components/ScreenWrapper'; +import HeaderWithCloseButton from '../../../components/HeaderWithCloseButton'; +import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize'; +import ROUTES from '../../../ROUTES'; +import CONST from '../../../CONST'; +import Text from '../../../components/Text'; +import styles from '../../../styles/styles'; +import Navigation from '../../../libs/Navigation/Navigation'; +import * as PersonalDetails from '../../../libs/actions/PersonalDetails'; +import compose from '../../../libs/compose'; +import MenuItemWithTopDescription from '../../../components/MenuItemWithTopDescription'; +import TextInput from '../../../components/TextInput'; +import OptionsList from '../../../components/OptionsList'; + +const propTypes = { + ...withLocalizePropTypes, + ...withCurrentUserPersonalDetailsPropTypes, +}; + +const defaultProps = { + ...withCurrentUserPersonalDetailsDefaultProps, +}; + +class TimezoneSelectPage extends Component { + constructor(props) { + super(props); + + this.updateSelectedTimezone = this.updateSelectedTimezone.bind(this); + + this.state = { + selectedTimezone: lodashGet(props.currentUserPersonalDetails, 'timezone.selected', CONST.DEFAULT_TIME_ZONE.selected), + } + } + + updateSelectedTimezone(newSelectedTimezone) { + PersonalDetails.updateSelectedTimezone(newSelectedTimezone); + }; + + render() { + return ( + + Navigation.navigate(ROUTES.SETTINGS_PROFILE)} + onCloseButtonPress={() => Navigation.dismissModal(true)} + /> + + + console.log('select', something)} + sections={[ + { + title: undefined, + data: [ + { + text: 'text', + subtitle: 'subtitle', + }, + { + text: 'text', + subtitle: 'subtitle', + }, + { + text: 'text', + subtitle: 'subtitle', + }, + { + text: 'text', + subtitle: 'subtitle', + }, + ], + indexOffset: 0, + }, + ]} + // focusedIndex={} + // selectedOptions={} + /> + + + ); + } +} + +TimezoneSelectPage.propTypes = propTypes; +TimezoneSelectPage.defaultProps = defaultProps; + +export default compose( + withLocalize, + withCurrentUserPersonalDetails, +)(TimezoneSelectPage); From b173e215e0f7950ece54e622272763881469f093 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Thu, 27 Oct 2022 19:07:11 +0200 Subject: [PATCH 04/23] New translations --- src/languages/en.js | 5 +++++ src/languages/es.js | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/languages/en.js b/src/languages/en.js index f52283b44a6b..2b33ca21992b 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -301,6 +301,11 @@ export default { offline: 'Offline', syncing: 'Syncing', }, + timezonePage: { + timezone: 'Timezone', + isShownOnProfile: 'Your timezone is shown on your profile.', + getLocationAutomatically: 'Automatically determine your location.', + }, addSecondaryLoginPage: { addPhoneNumber: 'Add phone number', addEmailAddress: 'Add email address', diff --git a/src/languages/es.js b/src/languages/es.js index 5a08975a0220..ec9b1cab7838 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -301,6 +301,11 @@ export default { offline: 'Desconectado', syncing: 'Sincronizando', }, + timezonePage: { + timezone: 'Zona horaria', + isShownOnProfile: '', + getLocationAutomatically: '', + }, addSecondaryLoginPage: { addPhoneNumber: 'Agregar número de teléfono', addEmailAddress: 'Agregar dirección de email', From f1bc673529e48472ce137c2836bd5aadee8edba2 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Thu, 27 Oct 2022 19:07:16 +0200 Subject: [PATCH 05/23] New timezone commands --- src/libs/actions/PersonalDetails.js | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index 903ec76b4839..3df5591d0cf1 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -285,6 +285,43 @@ function updateProfile(firstName, lastName, pronouns, timezone) { }); } +/** + * @param {Boolean} isAutomatic Does the timezone update automatically. + */ +function updateAutomaticTimezone(timezone) { + API.write('UpdateAutomaticTimezone', { + timezone: JSON.stringify(timezone), + }, { + optimisticData: [{ + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: ONYXKEYS.PERSONAL_DETAILS, + value: { + [currentUserEmail]: { + timezone, + }, + }, + }], + }); +} + +function updateSelectedTimezone(selectedTimezone) { + API.write('UpdateSelectedTimezone', { + text: selectedTimezone, + }, { + optimisticData: [{ + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: ONYXKEYS.PERSONAL_DETAILS, + value: { + [currentUserEmail]: { + timezone: { + selected: selectedTimezone, + }, + }, + }, + }], + }); +} + /** * Fetches the local currency based on location and sets currency code/symbol to Onyx */ @@ -398,4 +435,6 @@ export { extractFirstAndLastNameFromAvailableDetails, updateProfile, clearAvatarErrors, + updateAutomaticTimezone, + updateSelectedTimezone, }; From 8e3bf2e36693d863d082fc9caeb6117baabc5dbe Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Fri, 28 Oct 2022 13:51:12 +0200 Subject: [PATCH 06/23] Add vertical padding to timezone button --- src/pages/settings/Profile/TimezoneInitialPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Profile/TimezoneInitialPage.js b/src/pages/settings/Profile/TimezoneInitialPage.js index aeae3d00c644..cc7ba3730fd6 100644 --- a/src/pages/settings/Profile/TimezoneInitialPage.js +++ b/src/pages/settings/Profile/TimezoneInitialPage.js @@ -67,7 +67,7 @@ const TimezoneInitialPage = (props) => { title={timezone.selected} description={props.translate('timezonePage.timezone')} shouldShowRightIcon - wrapperStyle={[styles.pv0, styles.ph2, styles.mb3]} + wrapperStyle={[styles.ph2, styles.mb3]} disabled={timezone.automatic} onPress={() => Navigation.navigate(ROUTES.SETTINGS_TIMEZONE_SELECT)} /> From b9fd35a7a063a61c0324e5fb283ce158e70958ef Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Fri, 28 Oct 2022 13:52:16 +0200 Subject: [PATCH 07/23] Update selected tz then nav to tz init page --- src/libs/actions/PersonalDetails.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index 3df5591d0cf1..cce8ff7a69c4 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -12,6 +12,8 @@ import * as LoginUtils from '../LoginUtils'; import * as ReportUtils from '../ReportUtils'; import Growl from '../Growl'; import * as Localize from '../Localize'; +import ROUTES from '../../ROUTES'; +import Navigation from '../Navigation/Navigation'; let currentUserEmail = ''; Onyx.connect({ @@ -304,6 +306,9 @@ function updateAutomaticTimezone(timezone) { }); } +/** + * @param {String} selectedTimezone + */ function updateSelectedTimezone(selectedTimezone) { API.write('UpdateSelectedTimezone', { text: selectedTimezone, @@ -320,6 +325,7 @@ function updateSelectedTimezone(selectedTimezone) { }, }], }); + Navigation.navigate(ROUTES.SETTINGS_TIMEZONE_INITIAL); } /** From 2221e5692391c257d3c15adf6051e6b649015a7a Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Fri, 28 Oct 2022 13:56:20 +0200 Subject: [PATCH 08/23] Fill out timezone select page & filtering --- .../settings/Profile/TimezoneSelectPage.js | 98 +++++++++---------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/src/pages/settings/Profile/TimezoneSelectPage.js b/src/pages/settings/Profile/TimezoneSelectPage.js index ebcb588dd25d..1213743ca117 100644 --- a/src/pages/settings/Profile/TimezoneSelectPage.js +++ b/src/pages/settings/Profile/TimezoneSelectPage.js @@ -1,20 +1,18 @@ import lodashGet from 'lodash/get'; import React, {Component} from 'react'; -import {View} from 'react-native'; +import _ from 'underscore'; +import moment from 'moment-timezone'; import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps} from '../../../components/withCurrentUserPersonalDetails'; import ScreenWrapper from '../../../components/ScreenWrapper'; import HeaderWithCloseButton from '../../../components/HeaderWithCloseButton'; import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize'; import ROUTES from '../../../ROUTES'; import CONST from '../../../CONST'; -import Text from '../../../components/Text'; import styles from '../../../styles/styles'; import Navigation from '../../../libs/Navigation/Navigation'; import * as PersonalDetails from '../../../libs/actions/PersonalDetails'; import compose from '../../../libs/compose'; -import MenuItemWithTopDescription from '../../../components/MenuItemWithTopDescription'; -import TextInput from '../../../components/TextInput'; -import OptionsList from '../../../components/OptionsList'; +import OptionsSelector from '../../../components/OptionsSelector'; const propTypes = { ...withLocalizePropTypes, @@ -29,61 +27,63 @@ class TimezoneSelectPage extends Component { constructor(props) { super(props); - this.updateSelectedTimezone = this.updateSelectedTimezone.bind(this); + this.saveSelectedTimezone = this.saveSelectedTimezone.bind(this); + this.filterShownTimezones = this.filterShownTimezones.bind(this); + + this.currentSelectedTimezone = lodashGet(props.currentUserPersonalDetails, 'timezone.selected', CONST.DEFAULT_TIME_ZONE.selected); + this.allTimezones = _.chain(moment.tz.names()) + .filter(timezone => !timezone.startsWith('Etc/GMT')) + .map(timezone => ({ + text: timezone, + keyForList: timezone, + + // Add green checkmark icon & bold the timezone text + isSelected: timezone === this.currentSelectedTimezone, + isUnread: timezone === this.currentSelectedTimezone, + })) + .value(); this.state = { - selectedTimezone: lodashGet(props.currentUserPersonalDetails, 'timezone.selected', CONST.DEFAULT_TIME_ZONE.selected), - } + timezoneInputText: this.currentSelectedTimezone, + timezoneOptions: this.allTimezones, + }; + } + + /** + * @param {Object} timezone + * @param {String} timezone.label + */ + saveSelectedTimezone({label}) { + PersonalDetails.updateSelectedTimezone(label); } - - updateSelectedTimezone(newSelectedTimezone) { - PersonalDetails.updateSelectedTimezone(newSelectedTimezone); - }; - + + /** + * @param {String} searchText + */ + filterShownTimezones(searchText) { + this.setState({ + timezoneInputText: searchText, + timezoneOptions: _.filter(this.allTimezones, (tz => tz.text.toLowerCase().startsWith(searchText.toLowerCase()))), + }); + } + render() { return ( Navigation.navigate(ROUTES.SETTINGS_PROFILE)} + onBackButtonPress={() => Navigation.navigate(ROUTES.SETTINGS_TIMEZONE_INITIAL)} onCloseButtonPress={() => Navigation.dismissModal(true)} /> - - - console.log('select', something)} - sections={[ - { - title: undefined, - data: [ - { - text: 'text', - subtitle: 'subtitle', - }, - { - text: 'text', - subtitle: 'subtitle', - }, - { - text: 'text', - subtitle: 'subtitle', - }, - { - text: 'text', - subtitle: 'subtitle', - }, - ], - indexOffset: 0, - }, - ]} - // focusedIndex={} - // selectedOptions={} - /> - + ); } From 06dfa1d4e51f39fec89238dd78a143395ed8dc77 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Fri, 28 Oct 2022 14:10:29 +0200 Subject: [PATCH 09/23] Move custom icon to Option props --- src/components/OptionRow.js | 7 +++++++ src/components/optionPropTypes.js | 6 ++++++ src/pages/settings/Profile/TimezoneSelectPage.js | 6 +++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/components/OptionRow.js b/src/components/OptionRow.js index 9e0c56a8cb94..c2b8c64805d2 100644 --- a/src/components/OptionRow.js +++ b/src/components/OptionRow.js @@ -25,6 +25,7 @@ import OfflineWithFeedback from './OfflineWithFeedback'; import CONST from '../CONST'; import * as ReportUtils from '../libs/ReportUtils'; import variables from '../styles/variables'; +import themeColors from '../styles/themes/default'; const propTypes = { /** The accessibility hint for the entire option row. Primarily used for unit testing to identify the component */ @@ -140,6 +141,7 @@ const OptionRow = (props) => { {hovered => ( @@ -266,6 +268,11 @@ const OptionRow = (props) => { )} + {Boolean(props.option.customIcon) && ( + + + + )} )} diff --git a/src/components/optionPropTypes.js b/src/components/optionPropTypes.js index 345e5b556023..3ef7b74a7657 100644 --- a/src/components/optionPropTypes.js +++ b/src/components/optionPropTypes.js @@ -39,6 +39,12 @@ export default PropTypes.shape({ // Whether the option has an outstanding IOU hasOutstandingIOU: PropTypes.bool, + // Custom icon to render on the right side of the option + customIcon: PropTypes.shape({ + src: PropTypes.func, + color: PropTypes.string, + }), + // List of participants of the report participantsList: PropTypes.arrayOf(participantPropTypes), diff --git a/src/pages/settings/Profile/TimezoneSelectPage.js b/src/pages/settings/Profile/TimezoneSelectPage.js index 1213743ca117..e5e936465627 100644 --- a/src/pages/settings/Profile/TimezoneSelectPage.js +++ b/src/pages/settings/Profile/TimezoneSelectPage.js @@ -13,6 +13,8 @@ import Navigation from '../../../libs/Navigation/Navigation'; import * as PersonalDetails from '../../../libs/actions/PersonalDetails'; import compose from '../../../libs/compose'; import OptionsSelector from '../../../components/OptionsSelector'; +import themeColors from '../../../styles/themes/default'; +import * as Expensicons from '../../../components/Icon/Expensicons'; const propTypes = { ...withLocalizePropTypes, @@ -38,7 +40,9 @@ class TimezoneSelectPage extends Component { keyForList: timezone, // Add green checkmark icon & bold the timezone text - isSelected: timezone === this.currentSelectedTimezone, + customIcon: timezone === this.currentSelectedTimezone + ? {src: Expensicons.Checkmark, color: themeColors.textSuccess} + : null, isUnread: timezone === this.currentSelectedTimezone, })) .value(); From 05e67bf43bb47ed22fd2164d9a1beed7380aa571 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Fri, 28 Oct 2022 14:19:40 +0200 Subject: [PATCH 10/23] Fix where timezone comes from --- src/pages/settings/Profile/TimezoneSelectPage.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/settings/Profile/TimezoneSelectPage.js b/src/pages/settings/Profile/TimezoneSelectPage.js index e5e936465627..058b4c84597a 100644 --- a/src/pages/settings/Profile/TimezoneSelectPage.js +++ b/src/pages/settings/Profile/TimezoneSelectPage.js @@ -55,10 +55,10 @@ class TimezoneSelectPage extends Component { /** * @param {Object} timezone - * @param {String} timezone.label + * @param {String} timezone.text */ - saveSelectedTimezone({label}) { - PersonalDetails.updateSelectedTimezone(label); + saveSelectedTimezone({text}) { + PersonalDetails.updateSelectedTimezone(text); } /** From d2afbd979a808f93802f2761a41b0220aa428196 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Fri, 28 Oct 2022 14:22:39 +0200 Subject: [PATCH 11/23] Fix lots of lint issues --- src/components/OptionRow.js | 1 - src/libs/actions/PersonalDetails.js | 7 ++++++- src/pages/settings/Profile/TimezoneInitialPage.js | 7 ++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/components/OptionRow.js b/src/components/OptionRow.js index c2b8c64805d2..a7fe4df1a457 100644 --- a/src/components/OptionRow.js +++ b/src/components/OptionRow.js @@ -25,7 +25,6 @@ import OfflineWithFeedback from './OfflineWithFeedback'; import CONST from '../CONST'; import * as ReportUtils from '../libs/ReportUtils'; import variables from '../styles/variables'; -import themeColors from '../styles/themes/default'; const propTypes = { /** The accessibility hint for the entire option row. Primarily used for unit testing to identify the component */ diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index cce8ff7a69c4..a7d8afef19f1 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -288,7 +288,12 @@ function updateProfile(firstName, lastName, pronouns, timezone) { } /** - * @param {Boolean} isAutomatic Does the timezone update automatically. + * Updates timezone's 'automatic' setting, and updates + * selected timezone if set to automatically update. + * + * @param {Object} timezone + * @param {Boolean} timezone.automatic + * @param {String} timezone.selected */ function updateAutomaticTimezone(timezone) { API.write('UpdateAutomaticTimezone', { diff --git a/src/pages/settings/Profile/TimezoneInitialPage.js b/src/pages/settings/Profile/TimezoneInitialPage.js index cc7ba3730fd6..42f68e0ea2f3 100644 --- a/src/pages/settings/Profile/TimezoneInitialPage.js +++ b/src/pages/settings/Profile/TimezoneInitialPage.js @@ -1,6 +1,7 @@ import lodashGet from 'lodash/get'; import React from 'react'; import {View} from 'react-native'; +import moment from 'moment-timezone'; import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps} from '../../../components/withCurrentUserPersonalDetails'; import ScreenWrapper from '../../../components/ScreenWrapper'; import HeaderWithCloseButton from '../../../components/HeaderWithCloseButton'; @@ -14,7 +15,6 @@ import * as PersonalDetails from '../../../libs/actions/PersonalDetails'; import compose from '../../../libs/compose'; import Switch from '../../../components/Switch'; import MenuItemWithTopDescription from '../../../components/MenuItemWithTopDescription'; -import moment from 'moment-timezone'; const propTypes = { ...withLocalizePropTypes, @@ -34,7 +34,7 @@ const TimezoneInitialPage = (props) => { * * @param {Boolean} isAutomatic */ - const updateAutomaticTimezone = (isAutomatic) => { + const updateAutomaticTimezone = (isAutomatic) => { PersonalDetails.updateAutomaticTimezone({ automatic: isAutomatic, selected: isAutomatic ? moment.tz.guess() : timezone.selected, @@ -73,10 +73,11 @@ const TimezoneInitialPage = (props) => { /> ); -} +}; TimezoneInitialPage.propTypes = propTypes; TimezoneInitialPage.defaultProps = defaultProps; +TimezoneInitialPage.displayName = 'TimezoneInitialPage'; export default compose( withLocalize, From c2c7e705809a285e60e468426cef69ce56411e60 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Fri, 28 Oct 2022 16:13:49 +0200 Subject: [PATCH 12/23] Add prop for option separator --- src/components/OptionRow.js | 6 +++++- src/components/OptionsList/BaseOptionsList.js | 1 + src/components/OptionsList/optionsListPropTypes.js | 4 ++++ src/components/OptionsSelector/BaseOptionsSelector.js | 1 + src/components/OptionsSelector/optionsSelectorPropTypes.js | 4 ++++ src/pages/settings/Profile/TimezoneSelectPage.js | 1 + 6 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/components/OptionRow.js b/src/components/OptionRow.js index a7fe4df1a457..f3f806b9b6df 100644 --- a/src/components/OptionRow.js +++ b/src/components/OptionRow.js @@ -70,6 +70,9 @@ const propTypes = { /** Whether this option should be disabled */ isDisabled: PropTypes.bool, + /** Whether to show a line separating options in list */ + shouldHaveOptionSeparator: PropTypes.bool, + style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]), ...withLocalizePropTypes, @@ -90,6 +93,7 @@ const defaultProps = { isDisabled: false, optionIsFocused: false, style: null, + shouldHaveOptionSeparator: false, }; const OptionRow = (props) => { @@ -140,7 +144,6 @@ const OptionRow = (props) => { {hovered => ( @@ -165,6 +168,7 @@ const OptionRow = (props) => { props.optionIsFocused ? styles.sidebarLinkActive : null, hovered && !props.optionIsFocused ? props.hoverStyle : null, props.isDisabled && styles.cursorDisabled, + props.shouldHaveOptionSeparator && styles.borderTop, ]} > diff --git a/src/components/OptionsList/BaseOptionsList.js b/src/components/OptionsList/BaseOptionsList.js index c8337b87acab..b1625c10191a 100644 --- a/src/components/OptionsList/BaseOptionsList.js +++ b/src/components/OptionsList/BaseOptionsList.js @@ -181,6 +181,7 @@ class BaseOptionsList extends Component { hideAdditionalOptionStates={this.props.hideAdditionalOptionStates} forceTextUnreadStyle={this.props.forceTextUnreadStyle} isDisabled={this.props.isDisabled || section.isDisabled} + shouldHaveOptionSeparator={this.props.shouldHaveOptionSeparator} /> ); } diff --git a/src/components/OptionsList/optionsListPropTypes.js b/src/components/OptionsList/optionsListPropTypes.js index b51fc14d64d7..c4ab5a3f301e 100644 --- a/src/components/OptionsList/optionsListPropTypes.js +++ b/src/components/OptionsList/optionsListPropTypes.js @@ -78,6 +78,9 @@ const propTypes = { /** Callback to execute when the SectionList lays out */ onLayout: PropTypes.func, + + /** Whether to show a line separating options in list */ + shouldHaveOptionSeparator: PropTypes.bool, }; const defaultProps = { @@ -100,6 +103,7 @@ const defaultProps = { optionMode: undefined, isDisabled: false, onLayout: undefined, + shouldHaveOptionSeparator: false, }; export {propTypes, defaultProps}; diff --git a/src/components/OptionsSelector/BaseOptionsSelector.js b/src/components/OptionsSelector/BaseOptionsSelector.js index 7fce40647c3f..0475b87b6b8e 100755 --- a/src/components/OptionsSelector/BaseOptionsSelector.js +++ b/src/components/OptionsSelector/BaseOptionsSelector.js @@ -264,6 +264,7 @@ class BaseOptionsSelector extends Component { forceTextUnreadStyle={this.props.forceTextUnreadStyle} showTitleTooltip={this.props.showTitleTooltip} isDisabled={this.props.isDisabled} + shouldHaveOptionSeparator={this.props.shouldHaveOptionSeparator} /> ) : ; return ( diff --git a/src/components/OptionsSelector/optionsSelectorPropTypes.js b/src/components/OptionsSelector/optionsSelectorPropTypes.js index ae41fe0f8190..885a09e553a4 100644 --- a/src/components/OptionsSelector/optionsSelectorPropTypes.js +++ b/src/components/OptionsSelector/optionsSelectorPropTypes.js @@ -89,6 +89,9 @@ const propTypes = { /** Whether to show options list */ shouldShowOptions: PropTypes.bool, + + /** Whether to show a line separating options in list */ + shouldHaveOptionSeparator: PropTypes.bool, }; const defaultProps = { @@ -113,6 +116,7 @@ const defaultProps = { shouldShowOptions: true, disableArrowKeysActions: false, isDisabled: false, + shouldHaveOptionSeparator: false, }; export {propTypes, defaultProps}; diff --git a/src/pages/settings/Profile/TimezoneSelectPage.js b/src/pages/settings/Profile/TimezoneSelectPage.js index 058b4c84597a..755ecac9f89a 100644 --- a/src/pages/settings/Profile/TimezoneSelectPage.js +++ b/src/pages/settings/Profile/TimezoneSelectPage.js @@ -87,6 +87,7 @@ class TimezoneSelectPage extends Component { onSelectRow={this.saveSelectedTimezone} optionHoveredStyle={styles.hoveredComponentBG} sections={[{data: this.state.timezoneOptions}]} + shouldHaveOptionSeparator /> ); From 45951b44136e43f825378426e0596edf46a963bb Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Mon, 31 Oct 2022 17:56:40 +0200 Subject: [PATCH 13/23] Add all prop comments --- src/components/optionPropTypes.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/optionPropTypes.js b/src/components/optionPropTypes.js index 3ef7b74a7657..32a4cc76cc66 100644 --- a/src/components/optionPropTypes.js +++ b/src/components/optionPropTypes.js @@ -41,7 +41,10 @@ export default PropTypes.shape({ // Custom icon to render on the right side of the option customIcon: PropTypes.shape({ + // The icon source src: PropTypes.func, + + // The color of the icon color: PropTypes.string, }), From c51cc5712714962a9d58315094386ba6bd7e3d44 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Mon, 31 Oct 2022 17:56:55 +0200 Subject: [PATCH 14/23] Get icon props safely --- src/components/OptionRow.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/OptionRow.js b/src/components/OptionRow.js index f3f806b9b6df..29c27cf57960 100644 --- a/src/components/OptionRow.js +++ b/src/components/OptionRow.js @@ -273,7 +273,12 @@ const OptionRow = (props) => { )} {Boolean(props.option.customIcon) && ( - + )} From a7758c8aca08e464e784ed9e1a84704a09d7675e Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Mon, 31 Oct 2022 17:59:27 +0200 Subject: [PATCH 15/23] Add function description --- src/libs/actions/PersonalDetails.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index a7d8afef19f1..055362c3ea5e 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -312,6 +312,9 @@ function updateAutomaticTimezone(timezone) { } /** + * Updates user's 'selected' timezone, then navigates to the + * initial Timezone page. + * * @param {String} selectedTimezone */ function updateSelectedTimezone(selectedTimezone) { From c02e8028dbcfc4e5e6da38a2987dbe5a22b8b5d0 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Mon, 31 Oct 2022 18:00:23 +0200 Subject: [PATCH 16/23] Match any timezone that includes searched timezone text --- src/pages/settings/Profile/TimezoneSelectPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Profile/TimezoneSelectPage.js b/src/pages/settings/Profile/TimezoneSelectPage.js index 755ecac9f89a..b60a0ec1bbd6 100644 --- a/src/pages/settings/Profile/TimezoneSelectPage.js +++ b/src/pages/settings/Profile/TimezoneSelectPage.js @@ -67,7 +67,7 @@ class TimezoneSelectPage extends Component { filterShownTimezones(searchText) { this.setState({ timezoneInputText: searchText, - timezoneOptions: _.filter(this.allTimezones, (tz => tz.text.toLowerCase().startsWith(searchText.toLowerCase()))), + timezoneOptions: _.filter(this.allTimezones, (tz => tz.text.toLowerCase().includes(searchText.toLowerCase()))), }); } From d61aac06b1aea636343a745bc2557a28bfb648db Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Mon, 21 Nov 2022 15:53:58 +0200 Subject: [PATCH 17/23] Fix updateSelectedTimezone operation in PersonalDetails. --- src/libs/actions/PersonalDetails.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index d1d220b28371..4ed6b9524c0d 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -368,17 +368,16 @@ function updateAutomaticTimezone(timezone) { * @param {String} selectedTimezone */ function updateSelectedTimezone(selectedTimezone) { + const timezone = { selected: selectedTimezone, }; API.write('UpdateSelectedTimezone', { - text: selectedTimezone, + timezone: JSON.stringify(timezone), }, { optimisticData: [{ onyxMethod: CONST.ONYX.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS, value: { [currentUserEmail]: { - timezone: { - selected: selectedTimezone, - }, + timezone, }, }, }], From 467760bcb4ed11a6736f0fd8f439322f29174970 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Mon, 21 Nov 2022 16:47:26 +0200 Subject: [PATCH 18/23] Fix js lint errors --- src/libs/actions/PersonalDetails.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index 4ed6b9524c0d..b93be359d86b 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -368,7 +368,9 @@ function updateAutomaticTimezone(timezone) { * @param {String} selectedTimezone */ function updateSelectedTimezone(selectedTimezone) { - const timezone = { selected: selectedTimezone, }; + const timezone = { + selected: selectedTimezone, + }; API.write('UpdateSelectedTimezone', { timezone: JSON.stringify(timezone), }, { From 818ac838408463a2c9ef3cec9929f790cabdb48f Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Tue, 22 Nov 2022 11:46:32 +0200 Subject: [PATCH 19/23] Update src/languages/es.js Co-authored-by: Alex Beaman --- src/languages/es.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/languages/es.js b/src/languages/es.js index 03cd037a31d4..fad97b65bb37 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -333,8 +333,8 @@ export default { }, timezonePage: { timezone: 'Zona horaria', - isShownOnProfile: '', - getLocationAutomatically: '', + isShownOnProfile: 'Tu zona horaria se muestra en tu perfil.', + getLocationAutomatically: 'Detecta tu ubicación automáticamente.', }, addSecondaryLoginPage: { addPhoneNumber: 'Agregar número de teléfono', From f13ab5f2623f2b20dec9c36170d4ce8ccaa218bf Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Tue, 22 Nov 2022 12:12:43 +0200 Subject: [PATCH 20/23] Rename routing constants --- src/ROUTES.js | 2 +- src/libs/Navigation/AppNavigator/ModalStackNavigators.js | 2 +- src/libs/Navigation/linkingConfig.js | 4 ++-- src/libs/actions/PersonalDetails.js | 2 +- src/pages/settings/Profile/TimezoneSelectPage.js | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ROUTES.js b/src/ROUTES.js index a84014774684..470ea9d99eb7 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -23,7 +23,7 @@ export default { SETTINGS: 'settings', SETTINGS_PROFILE: 'settings/profile', SETTINGS_DISPLAY_NAME: 'settings/profile/display-name', - SETTINGS_TIMEZONE_INITIAL: 'settings/profile/timezone', + SETTINGS_TIMEZONE: 'settings/profile/timezone', SETTINGS_TIMEZONE_SELECT: 'settings/profile/timezone/select', SETTINGS_PRONOUNS: 'settings/profile/pronouns', SETTINGS_PREFERENCES: 'settings/preferences', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index 816006e37ab3..e95581674fab 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -236,7 +236,7 @@ const SettingsModalStackNavigator = createModalStackNavigator([ const SettingsTimezoneInitialPage = require('../../../pages/settings/Profile/TimezoneInitialPage').default; return SettingsTimezoneInitialPage; }, - name: 'Settings_Timezone_Init', + name: 'Settings_Timezone', }, { getComponent: () => { diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index a04a776bce53..c44a28bcc10e 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -96,8 +96,8 @@ export default { path: ROUTES.SETTINGS_DISPLAY_NAME, exact: true, }, - Settings_Timezone_Init: { - path: ROUTES.SETTINGS_TIMEZONE_INITIAL, + Settings_Timezone: { + path: ROUTES.SETTINGS_TIMEZONE, exact: true, }, Settings_Timezone_Select: { diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index b93be359d86b..b779aa63a286 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -384,7 +384,7 @@ function updateSelectedTimezone(selectedTimezone) { }, }], }); - Navigation.navigate(ROUTES.SETTINGS_TIMEZONE_INITIAL); + Navigation.navigate(ROUTES.SETTINGS_TIMEZONE); } /** diff --git a/src/pages/settings/Profile/TimezoneSelectPage.js b/src/pages/settings/Profile/TimezoneSelectPage.js index b60a0ec1bbd6..97a38b98dbb2 100644 --- a/src/pages/settings/Profile/TimezoneSelectPage.js +++ b/src/pages/settings/Profile/TimezoneSelectPage.js @@ -77,7 +77,7 @@ class TimezoneSelectPage extends Component { Navigation.navigate(ROUTES.SETTINGS_TIMEZONE_INITIAL)} + onBackButtonPress={() => Navigation.navigate(ROUTES.SETTINGS_TIMEZONE)} onCloseButtonPress={() => Navigation.dismissModal(true)} /> Date: Tue, 22 Nov 2022 20:29:23 +0200 Subject: [PATCH 21/23] Update doc in TimezoneInitialPage.js Co-authored-by: Nikki Wines --- src/pages/settings/Profile/TimezoneInitialPage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/settings/Profile/TimezoneInitialPage.js b/src/pages/settings/Profile/TimezoneInitialPage.js index 42f68e0ea2f3..7606a16582ca 100644 --- a/src/pages/settings/Profile/TimezoneInitialPage.js +++ b/src/pages/settings/Profile/TimezoneInitialPage.js @@ -29,8 +29,8 @@ const TimezoneInitialPage = (props) => { const timezone = lodashGet(props.currentUserPersonalDetails, 'timezone', CONST.DEFAULT_TIME_ZONE); /** - * Updates setting for timezone updating automatically. - * Note: If we are updating automatically, we'll immediately caltulate user timezone. + * Updates setting for automatic timezone selection. + * Note: If we are updating automatically, we'll immediately calculate the user's timezone.``` * * @param {Boolean} isAutomatic */ From 2be55f9365bc4169db4c60ecfd19717ed6b0f9ef Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Mon, 28 Nov 2022 22:32:35 +0200 Subject: [PATCH 22/23] Fix checkmark color in timezone selector page. --- src/pages/settings/Profile/TimezoneSelectPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Profile/TimezoneSelectPage.js b/src/pages/settings/Profile/TimezoneSelectPage.js index 97a38b98dbb2..62cb212d60a4 100644 --- a/src/pages/settings/Profile/TimezoneSelectPage.js +++ b/src/pages/settings/Profile/TimezoneSelectPage.js @@ -41,7 +41,7 @@ class TimezoneSelectPage extends Component { // Add green checkmark icon & bold the timezone text customIcon: timezone === this.currentSelectedTimezone - ? {src: Expensicons.Checkmark, color: themeColors.textSuccess} + ? {src: Expensicons.Checkmark, color: themeColors.success} : null, isUnread: timezone === this.currentSelectedTimezone, })) From 717fbc4a63ef7f4d05f206a6e8300e85e918824b Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Thu, 1 Dec 2022 14:10:30 +0200 Subject: [PATCH 23/23] Update doc in TimezoneInitialPage.js Co-authored-by: Nikki Wines --- src/pages/settings/Profile/TimezoneInitialPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Profile/TimezoneInitialPage.js b/src/pages/settings/Profile/TimezoneInitialPage.js index 7606a16582ca..260820710cd8 100644 --- a/src/pages/settings/Profile/TimezoneInitialPage.js +++ b/src/pages/settings/Profile/TimezoneInitialPage.js @@ -30,7 +30,7 @@ const TimezoneInitialPage = (props) => { /** * Updates setting for automatic timezone selection. - * Note: If we are updating automatically, we'll immediately calculate the user's timezone.``` + * Note: If we are updating automatically, we'll immediately calculate the user's timezone. * * @param {Boolean} isAutomatic */