UX: full revamp of local-dates form (#7357)

UX: full revamp of local-dates form (#7357)

diff --git a/app/assets/javascripts/select-kit/components/timezone-input.js.es6 b/app/assets/javascripts/select-kit/components/timezone-input.js.es6
new file mode 100644
index 0000000..e141839
--- /dev/null
+++ b/app/assets/javascripts/select-kit/components/timezone-input.js.es6
@@ -0,0 +1,31 @@
+import ComboBoxComponent from "select-kit/components/combo-box";
+import { default as computed } from "ember-addons/ember-computed-decorators";
+
+export default ComboBoxComponent.extend({
+  pluginApiIdentifiers: ["timezone-input"],
+  classNames: "timezone-input",
+  allowAutoSelectFirst: false,
+  fullWidthOnMobile: true,
+  filterable: true,
+  allowAny: false,
+
+  @computed
+  content() {
+    let timezones;
+
+    if (
+      moment.locale() !== "en" &&
+      typeof moment.tz.localizedNames === "function"
+    ) {
+      timezones = moment.tz.localizedNames();
+    }
+    timezones = moment.tz.names();
+
+    return timezones.map(t => {
+      return {
+        id: t,
+        name: t
+      };
+    });
+  }
+});
diff --git a/plugins/discourse-local-dates/assets/javascripts/discourse/components/discourse-local-dates-create-form.js.es6 b/plugins/discourse-local-dates/assets/javascripts/discourse/components/discourse-local-dates-create-form.js.es6
index 3274b72..fcf9bbe 100644
--- a/plugins/discourse-local-dates/assets/javascripts/discourse/components/discourse-local-dates-create-form.js.es6
+++ b/plugins/discourse-local-dates/assets/javascripts/discourse/components/discourse-local-dates-create-form.js.es6
@@ -1,3 +1,6 @@
+/* global Pikaday:true */
+import { propertyNotEqual } from "discourse/lib/computed";
+import loadScript from "discourse/lib/load-script";
 import { default as computed } from "ember-addons/ember-computed-decorators";
 import { cookAsync } from "discourse/lib/text";
 import debounce from "discourse/lib/debounce";
@@ -16,11 +19,16 @@ export default Ember.Component.extend({
   advancedMode: false,
   isValid: true,
   timezone: null,
-  timezones: null,
+  fromSelected: null,
+  fromFilled: Ember.computed.notEmpty("date"),
+  toSelected: null,
+  toFilled: Ember.computed.notEmpty("toDate"),
 
   init() {
     this._super(...arguments);
 
+    this._picker = null;
+
     this.setProperties({
       timezones: [],
       formats: (this.siteSettings.discourse_local_dates_default_formats || "")
@@ -34,7 +42,10 @@ export default Ember.Component.extend({
   didInsertElement() {
     this._super(...arguments);
 
-    this._renderPreview();
+    this._setupPicker().then(picker => {
+      this._picker = picker;
+      this.send("focusFrom");
+    });
   },
 
   _renderPreview: debounce(function() {
@@ -167,6 +178,11 @@ export default Ember.Component.extend({
     return moment.tz.guess();
   },
 
+  timezoneIsDifferentFromUserTimezone: propertyNotEqual(
+    "currentUserTimezone",
+    "options.timezone"
+  ),
+
   @computed("currentUserTimezone")
   formatedCurrentUserTimezone(timezone) {
     return timezone
@@ -225,17 +241,6 @@ export default Ember.Component.extend({
     ];
   },
 
-  @computed()
-  allTimezones() {
-    if (
-      moment.locale() !== "en" &&
-      typeof moment.tz.localizedNames === "function"
-    ) {
-      return moment.tz.localizedNames();
-    }
-    return moment.tz.names();
-  },
-
   _generateDateMarkup(config, options, isRange) {
     let text = `[date=${config.date}`;
 
@@ -287,7 +292,36 @@ export default Ember.Component.extend({
     return text;
   },
 
+  @computed("fromConfig.dateTime")
+  formattedFrom(dateTime) {
+    return dateTime.format("LLLL");
+  },
+
+  @computed("toConfig.dateTime", "toSelected")
+  formattedTo(dateTime, toSelected) {
+    const emptyText = toSelected
+      ? " "
+      : I18n.t("discourse_local_dates.create.form.until");
+
+    return dateTime.isValid() ? dateTime.format("LLLL") : emptyText;
+  },
+
   actions: {
+    eraseToDateTime() {
+      this.setProperties({ toDate: null, toTime: null });
+      this._setPickerDate(null);
+    },
+
+    focusFrom() {
+      this.setProperties({ fromSelected: true, toSelected: false });
+      this._setPickerDate(this.get("fromConfig.date"));
+    },
+
+    focusTo() {
+      this.setProperties({ toSelected: true, fromSelected: false });
+      this._setPickerDate(this.get("toConfig.date"));
+    },
+
     advancedMode() {
       this.toggleProperty("advancedMode");
     },
@@ -306,6 +340,53 @@ export default Ember.Component.extend({
     }
   },
 
+  _setupPicker() {
+    return new Ember.RSVP.Promise(resolve => {
+      loadScript("/javascripts/pikaday.js").then(() => {
+        const options = {
+          field: this.$(`.fake-input`)[0],
+          container: this.$(`#picker-container-${this.elementId}`)[0],
+          bound: false,
+          format: "YYYY-MM-DD",
+          reposition: false,
+          firstDay: 1,
+          defaultDate: moment(this.get("date"), this.dateFormat).toDate(),
+          setDefaultDate: true,
+          i18n: {
+            previousMonth: I18n.t("dates.previous_month"),
+            nextMonth: I18n.t("dates.next_month"),
+            months: moment.months(),
+            weekdays: moment.weekdays(),
+            weekdaysShort: moment.weekdaysShort()
+          },
+          onSelect: date => {
+            const formattedDate = moment(date).format("YYYY-MM-DD");
+
+            if (this.get("fromSelected")) {
+              this.set("date", formattedDate);
+            }
+
+            if (this.get("toSelected")) {
+              this.set("toDate", formattedDate);
+            }
+          }
+        };
+
+        resolve(new Pikaday(options));
+      });
+    });
+  },
+
+  _setPickerDate(date) {
+    if (date && !moment(date, this.dateFormat).isValid()) {
+      date = null;
+    }
+
+    Ember.run.schedule("afterRender", () => {
+      this._picker.setDate(date, true);
+    });
+  },
+
   _closeModal() {
     const composer = Discourse.__container__.lookup("controller:composer");
     composer.send("closeModal");
diff --git a/plugins/discourse-local-dates/assets/javascripts/discourse/templates/components/discourse-local-dates-create-form.hbs b/plugins/discourse-local-dates/assets/javascripts/discourse/templates/components/discourse-local-dates-create-form.hbs
index 3ed2875..f18ec65 100644
--- a/plugins/discourse-local-dates/assets/javascripts/discourse/templates/components/discourse-local-dates-create-form.hbs
+++ b/plugins/discourse-local-dates/assets/javascripts/discourse/templates/components/discourse-local-dates-create-form.hbs
@@ -9,83 +9,71 @@
         {{i18n "discourse_local_dates.create.form.invalid_date"}}
       </div>
     {{else}}
-      <div class="preview alert alert-info">
-        <b>{{formatedCurrentUserTimezone}} </b>{{currentPreview}}
-      </div>
+      {{#if timezoneIsDifferentFromUserTimezone}}
+        <div class="preview alert alert-info">
+          <b>{{formatedCurrentUserTimezone}} </b>{{currentPreview}}
+        </div>
+      {{/if}}
     {{/unless}}
 
     {{computeDate}}
 
     <div class="date-time-configuration">
-      <div class="range">
-        <div class="from">
-          <div class="control-group date">
-            <label class="control-label">
-              {{i18n "discourse_local_dates.create.form.date_title"}}
-            </label>
-            <div class="controls">
-              {{date-picker
-                onSelect=(action (mut date))
-                class="date-input"
-                value=date
-                defaultDate="DD-MM-YYYY"}}
-            </div>
-          </div>
-
-          <div class="control-group time">
-            <label class="control-label">
-              {{i18n "discourse_local_dates.create.form.time_title"}}
-            </label>
-            <div class="controls">
-              {{input input=(mut time) type="time" value=time class="time-input"}}
-            </div>
-          </div>
+      <div class="inputs-panel">
+        <div class="date-time-control from {{if fromSelected 'is-selected'}} {{if fromFilled 'is-filled'}}">

[... diff too long, it was truncated ...]

GitHub sha: 7226240d

2 Likes

looking really good!

1 Like