From 96f2d4088f69f7d823a7cbbedff91c35bd644d4b Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Tue, 26 Jul 2016 11:24:37 +0100 Subject: [PATCH] Handle automatic timezone override refs https://github.com/TryGhost/Ghost/pull/7142, https://github.com/TryGhost/Ghost/pull/7143 - moves timezone selection template and logic into a component - detect if the current `activeTimezone` is not in our pre-defined list of timezones, if it isn't: - add a line indicating that there has been an override with the current `activeTimezone` value - add a blank option to the timezone select list --- app/components/gh-timezone-select.js | 61 +++++++++++++++ app/controllers/settings/general.js | 16 ---- .../components/gh-timezone-select.hbs | 16 ++++ app/templates/settings/general.hbs | 19 +---- .../components/gh-timezone-select-test.js | 78 +++++++++++++++++++ 5 files changed, 159 insertions(+), 31 deletions(-) create mode 100644 app/components/gh-timezone-select.js create mode 100644 app/templates/components/gh-timezone-select.hbs create mode 100644 tests/integration/components/gh-timezone-select-test.js diff --git a/app/components/gh-timezone-select.js b/app/components/gh-timezone-select.js new file mode 100644 index 0000000000..ee361ad8bd --- /dev/null +++ b/app/components/gh-timezone-select.js @@ -0,0 +1,61 @@ +import Component from 'ember-component'; +import computed, {mapBy} from 'ember-computed'; +import injectService from 'ember-service/inject'; +import {invokeAction} from 'ember-invoke-action'; + +export default Component.extend({ + classNames: ['form-group', 'for-select'], + + activeTimezone: null, + availableTimezones: null, + + clock: injectService(), + + availableTimezoneNames: mapBy('availableTimezones', 'name'), + + hasTimezoneOverride: computed('activeTimezone', 'availableTimezoneNames', function () { + let activeTimezone = this.get('activeTimezone'); + let availableTimezoneNames = this.get('availableTimezoneNames'); + + return !availableTimezoneNames.contains(activeTimezone); + }), + + selectedTimezone: computed('activeTimezone', 'availableTimezones', 'hasTimezoneOverride', function () { + let hasTimezoneOverride = this.get('hasTimezoneOverride'); + let activeTimezone = this.get('activeTimezone'); + let availableTimezones = this.get('availableTimezones'); + + if (hasTimezoneOverride) { + return {name: '', label: ''}; + } + + return availableTimezones + .filterBy('name', activeTimezone) + .get('firstObject'); + }), + + selectableTimezones: computed('availableTimezones', 'hasTimezoneOverride', function () { + let hasTimezoneOverride = this.get('hasTimezoneOverride'); + let availableTimezones = this.get('availableTimezones'); + + if (hasTimezoneOverride) { + return [{name: '', label: ''}, ...availableTimezones]; + } + + return availableTimezones; + }), + + localTime: computed('hasTimezoneOverride', 'activeTimezone', 'selectedTimezone', 'clock.second', function () { + let hasTimezoneOverride = this.get('hasTimezoneOverride'); + let timezone = hasTimezoneOverride ? this.get('activeTimezone') : this.get('selectedTimezone.name'); + + this.get('clock.second'); + return timezone ? moment().tz(timezone).format('HH:mm:ss') : moment().utc().format('HH:mm:ss'); + }), + + actions: { + setTimezone(timezone) { + invokeAction(this, 'update', timezone); + } + } +}); diff --git a/app/controllers/settings/general.js b/app/controllers/settings/general.js index 8080b55eaa..449f10f855 100644 --- a/app/controllers/settings/general.js +++ b/app/controllers/settings/general.js @@ -17,7 +17,6 @@ export default Controller.extend(SettingsSaveMixin, { config: injectService(), _scratchFacebook: null, _scratchTwitter: null, - clock: injectService(), selectedTheme: computed('model.activeTheme', 'themes', function () { let activeTheme = this.get('model.activeTheme'); @@ -33,15 +32,6 @@ export default Controller.extend(SettingsSaveMixin, { return selectedTheme; }), - selectedTimezone: computed('model.activeTimezone', 'availableTimezones', function () { - let activeTimezone = this.get('model.activeTimezone'); - let availableTimezones = this.get('availableTimezones'); - - return availableTimezones - .filterBy('name', activeTimezone) - .get('firstObject'); - }), - logoImageSource: computed('model.logo', function () { return this.get('model.logo') || ''; }), @@ -50,12 +40,6 @@ export default Controller.extend(SettingsSaveMixin, { return this.get('model.cover') || ''; }), - localTime: computed('selectedTimezone', 'clock.second', function () { - let timezone = this.get('selectedTimezone.name'); - this.get('clock.second'); - return timezone ? moment().tz(timezone).format('HH:mm:ss') : moment().utc().format('HH:mm:ss'); - }), - isDatedPermalinks: computed('model.permalinks', { set(key, value) { this.set('model.permalinks', value ? '/:year/:month/:day/:slug/' : '/:slug/'); diff --git a/app/templates/components/gh-timezone-select.hbs b/app/templates/components/gh-timezone-select.hbs new file mode 100644 index 0000000000..b8e84f71a8 --- /dev/null +++ b/app/templates/components/gh-timezone-select.hbs @@ -0,0 +1,16 @@ + + + {{gh-select-native + id="activeTimezone" + name="general[activeTimezone]" + content=selectableTimezones + optionValuePath="name" + optionLabelPath="label" + selection=selectedTimezone + action="setTimezone" + }} + +{{#if hasTimezoneOverride}} +

Your timezone has been automatically set to {{activeTimezone}}.

+{{/if}} +

The local time here is currently {{localTime}}

diff --git a/app/templates/settings/general.hbs b/app/templates/settings/general.hbs index 382e880edb..ff7c921965 100644 --- a/app/templates/settings/general.hbs +++ b/app/templates/settings/general.hbs @@ -113,21 +113,10 @@ {{/gh-form-group}} -
- - - {{gh-select-native - id="activeTimezone" - name="general[activeTimezone]" - content=availableTimezones - optionValuePath="name" - optionLabelPath="label" - selection=selectedTimezone - action="setTimezone" - }} - -

The local time here is currently {{localTime}}

-
+ {{gh-timezone-select + activeTimezone=model.activeTimezone + availableTimezones=availableTimezones + update=(action "setTimezone")}}
diff --git a/tests/integration/components/gh-timezone-select-test.js b/tests/integration/components/gh-timezone-select-test.js new file mode 100644 index 0000000000..ea6ad392b1 --- /dev/null +++ b/tests/integration/components/gh-timezone-select-test.js @@ -0,0 +1,78 @@ +/* jshint expr:true */ +import { expect } from 'chai'; +import { + describeComponent, + it +} from 'ember-mocha'; +import hbs from 'htmlbars-inline-precompile'; +import run from 'ember-runloop'; +import wait from 'ember-test-helpers/wait'; +import sinon from 'sinon'; + +describeComponent( + 'gh-timezone-select', + 'Integration: Component: gh-timezone-select', + { + integration: true + }, + function() { + beforeEach(function () { + this.set('availableTimezones', [ + {name: 'Pacific/Pago_Pago', label: '(GMT -11:00) Midway Island, Samoa'}, + {name: 'Etc/UTC', label: '(GMT) UTC'}, + {name: 'Pacific/Kwajalein', label: '(GMT +12:00) International Date Line West'} + ]); + this.set('activeTimezone', 'Etc/UTC'); + }); + + it('renders', function () { + this.render(hbs`{{gh-timezone-select + availableTimezones=availableTimezones + activeTimezone=activeTimezone}}`); + + expect(this.$(), 'top-level elements').to.have.length(1); + expect(this.$('option'), 'number of options').to.have.length(3); + expect(this.$('select').val(), 'selected option value').to.equal('Etc/UTC'); + }); + + it('handles an unknown timezone', function () { + this.set('activeTimezone', 'Europe/London'); + + this.render(hbs`{{gh-timezone-select + availableTimezones=availableTimezones + activeTimezone=activeTimezone}}`); + + // we have an additional blank option at the top + expect(this.$('option'), 'number of options').to.have.length(4); + // blank option is selected + expect(this.$('select').val(), 'selected option value').to.equal(''); + // we indicate the manual override + expect(this.$('p').text()).to.match(/Your timezone has been automatically set to Europe\/London/); + }); + + it('triggers update action on change', function (done) { + let update = sinon.spy(); + this.set('update', update); + + this.render(hbs`{{gh-timezone-select + availableTimezones=availableTimezones + activeTimezone=activeTimezone + update=(action update)}}`); + + run(() => { + this.$('select').val('Pacific/Pago_Pago').change(); + }); + + wait().then(() => { + expect(update.calledOnce, 'update was called once').to.be.true; + expect(update.firstCall.args[0].name, 'update was passed new timezone') + .to.equal('Pacific/Pago_Pago'); + done(); + }); + }); + + // TODO: mock clock service, fake the time, test we have the correct + // local time and it changes alongside selection changes + it('renders local time'); + } +);