-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #24255 from Skalakid/16297-migrate-TimezoneSelectPage
16297 - Migrate TimezoneSelectPage.js to function component
- Loading branch information
Showing
1 changed file
with
54 additions
and
100 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,135 +1,89 @@ | ||
import lodashGet from 'lodash/get'; | ||
import React, {Component} from 'react'; | ||
import React, {useState, useRef} from 'react'; | ||
import _ from 'underscore'; | ||
import moment from 'moment-timezone'; | ||
import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps} from '../../../components/withCurrentUserPersonalDetails'; | ||
import ScreenWrapper from '../../../components/ScreenWrapper'; | ||
import HeaderWithBackButton from '../../../components/HeaderWithBackButton'; | ||
import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize'; | ||
import CONST from '../../../CONST'; | ||
import * as PersonalDetails from '../../../libs/actions/PersonalDetails'; | ||
import compose from '../../../libs/compose'; | ||
import Navigation from '../../../libs/Navigation/Navigation'; | ||
import ROUTES from '../../../ROUTES'; | ||
import SelectionListRadio from '../../../components/SelectionListRadio'; | ||
import useLocalize from '../../../hooks/useLocalize'; | ||
|
||
const propTypes = { | ||
...withLocalizePropTypes, | ||
...withCurrentUserPersonalDetailsPropTypes, | ||
}; | ||
|
||
const defaultProps = { | ||
...withCurrentUserPersonalDetailsDefaultProps, | ||
}; | ||
|
||
class TimezoneSelectPage extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.saveSelectedTimezone = this.saveSelectedTimezone.bind(this); | ||
this.filterShownTimezones = this.filterShownTimezones.bind(this); | ||
this.getTimezoneOption = this.getTimezoneOption.bind(this); | ||
|
||
this.timezone = this.getUserTimezone(props.currentUserPersonalDetails); | ||
this.allTimezones = _.chain(moment.tz.names()) | ||
.filter((timezone) => !timezone.startsWith('Etc/GMT')) | ||
.map(this.getTimezoneOption) | ||
.value(); | ||
|
||
this.state = { | ||
timezoneInputText: this.timezone.selected, | ||
timezoneOptions: this.allTimezones, | ||
}; | ||
} | ||
|
||
componentDidUpdate() { | ||
// componentDidUpdate is added in order to update the timezone options when automatic is toggled on/off as | ||
// navigating back doesn't unmount the page, thus it won't update the timezone options & stay disabled without this. | ||
const newTimezone = this.getUserTimezone(this.props.currentUserPersonalDetails); | ||
if (_.isEqual(this.timezone, newTimezone)) { | ||
return; | ||
} | ||
this.timezone = newTimezone; | ||
this.allTimezones = _.map(this.allTimezones, (timezone) => { | ||
const text = timezone.text.split('-')[0]; | ||
return this.getTimezoneOption(text); | ||
}); | ||
|
||
this.setState({ | ||
timezoneInputText: this.timezone.selected, | ||
timezoneOptions: this.allTimezones, | ||
}); | ||
} | ||
|
||
/** | ||
* We add the current time to the key to fix a bug where the list options don't update unless the key is updated. | ||
* @param {String} text | ||
* @return {string} key for list item | ||
*/ | ||
getKey(text) { | ||
return `${text}-${new Date().getTime()}`; | ||
} | ||
|
||
/** | ||
* Get timezone option object for the list. | ||
* @param {String} text | ||
* @return {Object} Timezone list option | ||
*/ | ||
getTimezoneOption(text) { | ||
return { | ||
text, | ||
keyForList: this.getKey(text), | ||
isSelected: text === this.timezone.selected, | ||
}; | ||
} | ||
|
||
/** | ||
* @param {Object} currentUserPersonalDetails | ||
* @return {Object} user's timezone data | ||
*/ | ||
getUserTimezone(currentUserPersonalDetails) { | ||
return lodashGet(currentUserPersonalDetails, 'timezone', CONST.DEFAULT_TIME_ZONE); | ||
} | ||
/** | ||
* We add the current time to the key to fix a bug where the list options don't update unless the key is updated. | ||
* @param {String} text | ||
* @return {string} key for list item | ||
*/ | ||
const getKey = (text) => `${text}-${new Date().getTime()}`; | ||
|
||
/** | ||
* @param {Object} currentUserPersonalDetails | ||
* @return {Object} user's timezone data | ||
*/ | ||
const getUserTimezone = (currentUserPersonalDetails) => lodashGet(currentUserPersonalDetails, 'timezone', CONST.DEFAULT_TIME_ZONE); | ||
|
||
function TimezoneSelectPage(props) { | ||
const {translate} = useLocalize(); | ||
const timezone = useRef(getUserTimezone(props.currentUserPersonalDetails)); | ||
const allTimezones = useRef( | ||
_.chain(moment.tz.names()) | ||
.filter((tz) => !tz.startsWith('Etc/GMT')) | ||
.map((text) => ({ | ||
text, | ||
keyForList: getKey(text), | ||
isSelected: text === timezone.current.selected, | ||
})) | ||
.value(), | ||
); | ||
const [timezoneInputText, setTimezoneInputText] = useState(timezone.current.selected); | ||
const [timezoneOptions, setTimezoneOptions] = useState(allTimezones.current); | ||
|
||
/** | ||
* @param {Object} timezone | ||
* @param {String} timezone.text | ||
*/ | ||
saveSelectedTimezone({text}) { | ||
const saveSelectedTimezone = ({text}) => { | ||
PersonalDetails.updateSelectedTimezone(text); | ||
} | ||
}; | ||
|
||
/** | ||
* @param {String} searchText | ||
*/ | ||
filterShownTimezones(searchText) { | ||
this.setState({ | ||
timezoneInputText: searchText, | ||
timezoneOptions: _.filter(this.allTimezones, (tz) => tz.text.toLowerCase().includes(searchText.trim().toLowerCase())), | ||
}); | ||
} | ||
|
||
render() { | ||
return ( | ||
<ScreenWrapper includeSafeAreaPaddingBottom={false}> | ||
<HeaderWithBackButton | ||
title={this.props.translate('timezonePage.timezone')} | ||
onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_TIMEZONE)} | ||
/> | ||
<SelectionListRadio | ||
textInputLabel={this.props.translate('timezonePage.timezone')} | ||
textInputValue={this.state.timezoneInputText} | ||
onChangeText={this.filterShownTimezones} | ||
onSelectRow={this.saveSelectedTimezone} | ||
sections={[{data: this.state.timezoneOptions, indexOffset: 0, isDisabled: this.timezone.automatic}]} | ||
initiallyFocusedOptionKey={_.get(_.filter(this.state.timezoneOptions, (tz) => tz.text === this.timezone.selected)[0], 'keyForList')} | ||
/> | ||
</ScreenWrapper> | ||
); | ||
} | ||
const filterShownTimezones = (searchText) => { | ||
setTimezoneInputText(searchText); | ||
setTimezoneOptions(_.filter(allTimezones.current, (tz) => tz.text.toLowerCase().includes(searchText.trim().toLowerCase()))); | ||
}; | ||
|
||
return ( | ||
<ScreenWrapper includeSafeAreaPaddingBottom={false}> | ||
<HeaderWithBackButton | ||
title={translate('timezonePage.timezone')} | ||
onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_TIMEZONE)} | ||
/> | ||
<SelectionListRadio | ||
textInputLabel={translate('timezonePage.timezone')} | ||
textInputValue={timezoneInputText} | ||
onChangeText={filterShownTimezones} | ||
onSelectRow={saveSelectedTimezone} | ||
sections={[{data: timezoneOptions, indexOffset: 0, isDisabled: timezone.current.automatic}]} | ||
initiallyFocusedOptionKey={_.get(_.filter(timezoneOptions, (tz) => tz.text === timezone.current.selected)[0], 'keyForList')} | ||
/> | ||
</ScreenWrapper> | ||
); | ||
} | ||
|
||
TimezoneSelectPage.propTypes = propTypes; | ||
TimezoneSelectPage.defaultProps = defaultProps; | ||
|
||
export default compose(withLocalize, withCurrentUserPersonalDetails)(TimezoneSelectPage); | ||
export default withCurrentUserPersonalDetails(TimezoneSelectPage); |