@@ -15,12 +15,14 @@ See the License for the specific language governing permissions and
15
15
limitations under the License.
16
16
*/
17
17
18
- import React , { useCallback , useEffect , useState } from "react" ;
18
+ import React , { ReactElement , useCallback , useEffect , useState } from "react" ;
19
19
20
+ import { NonEmptyArray } from "../../../../../@types/common" ;
20
21
import { _t , getCurrentLanguage } from "../../../../../languageHandler" ;
21
22
import { UseCase } from "../../../../../settings/enums/UseCase" ;
22
23
import SettingsStore from "../../../../../settings/SettingsStore" ;
23
24
import Field from "../../../elements/Field" ;
25
+ import Dropdown from "../../../elements/Dropdown" ;
24
26
import { SettingLevel } from "../../../../../settings/SettingLevel" ;
25
27
import SettingsFlag from "../../../elements/SettingsFlag" ;
26
28
import AccessibleButton from "../../../elements/AccessibleButton" ;
@@ -38,12 +40,16 @@ import PlatformPeg from "../../../../../PlatformPeg";
38
40
import { IS_MAC } from "../../../../../Keyboard" ;
39
41
import SpellCheckSettings from "../../SpellCheckSettings" ;
40
42
import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch" ;
43
+ import * as TimezoneHandler from "../../../../../TimezoneHandler" ;
41
44
42
45
interface IProps {
43
46
closeSettingsFn ( success : boolean ) : void ;
44
47
}
45
48
46
49
interface IState {
50
+ timezone : string | undefined ;
51
+ timezones : string [ ] ;
52
+ timezoneSearch : string | undefined ;
47
53
autocompleteDelay : string ;
48
54
readMarkerInViewThresholdMs : string ;
49
55
readMarkerOutOfViewThresholdMs : string ;
@@ -68,7 +74,7 @@ const LanguageSection: React.FC = () => {
68
74
) ;
69
75
70
76
return (
71
- < div className = "mx_SettingsSubsection_contentStretch " >
77
+ < div className = "mx_SettingsSubsection_dropdown " >
72
78
{ _t ( "settings|general|application_language" ) }
73
79
< LanguageDropdown onOptionChange = { onLanguageChange } value = { language } />
74
80
< div className = "mx_PreferencesUserSettingsTab_section_hint" >
@@ -173,6 +179,9 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
173
179
super ( props ) ;
174
180
175
181
this . state = {
182
+ timezone : TimezoneHandler . getUserTimezone ( ) ,
183
+ timezones : TimezoneHandler . getAllTimezones ( ) ,
184
+ timezoneSearch : undefined ,
176
185
autocompleteDelay : SettingsStore . getValueAt ( SettingLevel . DEVICE , "autocompleteDelay" ) . toString ( 10 ) ,
177
186
readMarkerInViewThresholdMs : SettingsStore . getValueAt (
178
187
SettingLevel . DEVICE ,
@@ -185,6 +194,25 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
185
194
} ;
186
195
}
187
196
197
+ private onTimezoneChange = ( tz : string ) : void => {
198
+ this . setState ( { timezone : tz } ) ;
199
+ TimezoneHandler . setUserTimezone ( tz ) ;
200
+ } ;
201
+
202
+ /**
203
+ * If present filter the time zones matching the search term
204
+ */
205
+ private onTimezoneSearchChange = ( search : string ) : void => {
206
+ const timezoneSearch = search . toLowerCase ( ) ;
207
+ const timezones = timezoneSearch
208
+ ? TimezoneHandler . getAllTimezones ( ) . filter ( ( tz ) => {
209
+ return tz . toLowerCase ( ) . includes ( timezoneSearch ) ;
210
+ } )
211
+ : TimezoneHandler . getAllTimezones ( ) ;
212
+
213
+ this . setState ( { timezones, timezoneSearch } ) ;
214
+ } ;
215
+
188
216
private onAutocompleteDelayChange = ( e : React . ChangeEvent < HTMLInputElement > ) : void => {
189
217
this . setState ( { autocompleteDelay : e . target . value } ) ;
190
218
SettingsStore . setValue ( "autocompleteDelay" , null , SettingLevel . DEVICE , e . target . value ) ;
@@ -217,6 +245,16 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
217
245
// Only show the user onboarding setting if the user should see the user onboarding page
218
246
. filter ( ( it ) => it !== "FTUE.userOnboardingButton" || showUserOnboardingPage ( useCase ) ) ;
219
247
248
+ const browserTimezoneLabel : string = _t ( "settings|preferences|default_timezone" , {
249
+ timezone : TimezoneHandler . shortBrowserTimezone ( ) ,
250
+ } ) ;
251
+
252
+ // Always Preprend the default option
253
+ const timezones = this . state . timezones . map ( ( tz ) => {
254
+ return < div key = { tz } > { tz } </ div > ;
255
+ } ) ;
256
+ timezones . unshift ( < div key = "" > { browserTimezoneLabel } </ div > ) ;
257
+
220
258
return (
221
259
< SettingsTab data-testid = "mx_PreferencesUserSettingsTab" >
222
260
< SettingsSection >
@@ -254,6 +292,23 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
254
292
</ SettingsSubsection >
255
293
256
294
< SettingsSubsection heading = { _t ( "settings|preferences|time_heading" ) } >
295
+ < div className = "mx_SettingsSubsection_dropdown" >
296
+ { _t ( "settings|preferences|user_timezone" ) }
297
+ < Dropdown
298
+ id = "mx_dropdownUserTimezone"
299
+ className = "mx_dropdownUserTimezone"
300
+ data-testid = "mx_dropdownUserTimezone"
301
+ searchEnabled = { true }
302
+ value = { this . state . timezone }
303
+ label = { _t ( "settings|preferences|user_timezone" ) }
304
+ placeholder = { browserTimezoneLabel }
305
+ onOptionChange = { this . onTimezoneChange }
306
+ onSearchChange = { this . onTimezoneSearchChange }
307
+ >
308
+ { timezones as NonEmptyArray < ReactElement & { key : string } > }
309
+ </ Dropdown >
310
+ </ div >
311
+
257
312
{ this . renderGroup ( PreferencesUserSettingsTab . TIME_SETTINGS ) }
258
313
</ SettingsSubsection >
259
314
0 commit comments