diff --git a/assets/javascripts/discourse/components/wizard-custom-field.js.es6 b/assets/javascripts/discourse/components/wizard-custom-field.js.es6 index bd44fde0..7ddd34b2 100644 --- a/assets/javascripts/discourse/components/wizard-custom-field.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-field.js.es6 @@ -25,6 +25,11 @@ export default Component.extend(UndoChanges, { showAdvanced: alias('field.type'), messageUrl: 'https://thepavilion.io/t/2809', + @discourseComputed('field.type') + isDateTime(type) { + return ['date_time', 'date', 'time'].indexOf(type) > -1; + }, + @discourseComputed('field.type') messageKey(type) { let key = 'type'; diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-field.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-field.hbs index c7827c1e..8e673247 100644 --- a/assets/javascripts/discourse/templates/components/wizard-custom-field.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-custom-field.hbs @@ -110,6 +110,19 @@ {{/if}} +{{#if isDateTime}} +
+
+ +
+ +
+ {{input value=field.format class="medium"}} + +
+
+{{/if}} + {{#if showPrefill}}
diff --git a/assets/javascripts/wizard-custom.js b/assets/javascripts/wizard-custom.js index 89bc06ef..cb863912 100644 --- a/assets/javascripts/wizard-custom.js +++ b/assets/javascripts/wizard-custom.js @@ -89,6 +89,9 @@ //= require discourse/app/components/emoji-picker //= require discourse/app/components/input-tip //= require discourse/app/components/date-picker +//= require discourse/app/components/time-input +//= require discourse/app/components/date-input +//= require discourse/app/components/date-time-input //= require discourse/app/components/text-field //= require discourse/app/components/d-textarea @@ -96,6 +99,9 @@ //= require discourse/app/templates/components/d-button //= require discourse/app/templates/components/d-editor //= require discourse/app/templates/components/date-picker +//= require discourse/app/templates/components/date-input +//= require discourse/app/templates/components/time-input +//= require discourse/app/templates/components/date-time-input //= require discourse/app/templates/components/emoji-picker //= require discourse/app/templates/components/popup-input-tip //= require discourse/app/templates/category-tag-autocomplete diff --git a/assets/javascripts/wizard/components/wizard-field-date-time.js.es6 b/assets/javascripts/wizard/components/wizard-field-date-time.js.es6 new file mode 100644 index 00000000..53eea3ba --- /dev/null +++ b/assets/javascripts/wizard/components/wizard-field-date-time.js.es6 @@ -0,0 +1,15 @@ +import Component from "@ember/component"; +import { observes } from 'discourse-common/utils/decorators'; + +export default Component.extend({ + @observes('dateTime') + setValue() { + this.set('field.value', this.dateTime.format(this.field.format)); + }, + + actions: { + onChange(value) { + this.set('dateTime', moment(value)); + } + } +}); \ No newline at end of file diff --git a/assets/javascripts/wizard/components/wizard-field-date.js.es6 b/assets/javascripts/wizard/components/wizard-field-date.js.es6 new file mode 100644 index 00000000..59032128 --- /dev/null +++ b/assets/javascripts/wizard/components/wizard-field-date.js.es6 @@ -0,0 +1,15 @@ +import Component from "@ember/component"; +import { observes } from 'discourse-common/utils/decorators'; + +export default Component.extend({ + @observes('date') + setValue() { + this.set('field.value', this.date.format(this.field.format)); + }, + + actions: { + onChange(value) { + this.set('date', moment(value)); + } + } +}); \ No newline at end of file diff --git a/assets/javascripts/wizard/components/wizard-field-time.js.es6 b/assets/javascripts/wizard/components/wizard-field-time.js.es6 new file mode 100644 index 00000000..1309c397 --- /dev/null +++ b/assets/javascripts/wizard/components/wizard-field-time.js.es6 @@ -0,0 +1,20 @@ +import Component from "@ember/component"; +import { observes } from 'discourse-common/utils/decorators'; + +export default Component.extend({ + @observes('time') + setValue() { + this.set('field.value', this.time.format(this.field.format)); + }, + + actions: { + onChange(value) { + this.set('time', + moment({ + hours: value.hours, + minutes: value.minutes + }) + ) + } + } +}); \ No newline at end of file diff --git a/assets/javascripts/wizard/initializers/custom.js.es6 b/assets/javascripts/wizard/initializers/custom.js.es6 index ae4c9d19..777ddd6d 100644 --- a/assets/javascripts/wizard/initializers/custom.js.es6 +++ b/assets/javascripts/wizard/initializers/custom.js.es6 @@ -171,7 +171,7 @@ export default { fields[f.id] = f.value; } }); - + return ajax({ url: `/w/${wizardId}/steps/${this.get('id')}`, type: 'PUT', @@ -241,7 +241,10 @@ export default { 'text_only', 'composer', 'category', - 'group' + 'group', + 'date', + 'time', + 'date_time' ]; FieldModel.reopen({ @@ -269,7 +272,7 @@ export default { } else if (type === 'url') { valid = true; } - + this.setValid(valid); return valid; diff --git a/assets/javascripts/wizard/templates/components/wizard-field-date-time.hbs b/assets/javascripts/wizard/templates/components/wizard-field-date-time.hbs new file mode 100644 index 00000000..b0381c8e --- /dev/null +++ b/assets/javascripts/wizard/templates/components/wizard-field-date-time.hbs @@ -0,0 +1,4 @@ +{{date-time-input + date=dateTime + onChange=(action "onChange") +}} \ No newline at end of file diff --git a/assets/javascripts/wizard/templates/components/wizard-field-date.hbs b/assets/javascripts/wizard/templates/components/wizard-field-date.hbs index b2ac15d8..3f5c2e01 100644 --- a/assets/javascripts/wizard/templates/components/wizard-field-date.hbs +++ b/assets/javascripts/wizard/templates/components/wizard-field-date.hbs @@ -1,4 +1,4 @@ -{{date-picker - value=field.value - id=field.id +{{date-input + date=date + onChange=(action "onChange") }} \ No newline at end of file diff --git a/assets/javascripts/wizard/templates/components/wizard-field-time.hbs b/assets/javascripts/wizard/templates/components/wizard-field-time.hbs new file mode 100644 index 00000000..c657000b --- /dev/null +++ b/assets/javascripts/wizard/templates/components/wizard-field-time.hbs @@ -0,0 +1,4 @@ +{{time-input + date=time + onChange=(action "onChange") +}} \ No newline at end of file diff --git a/assets/stylesheets/wizard/wizard_custom.scss b/assets/stylesheets/wizard/wizard_custom.scss index f2d131fe..924292a5 100644 --- a/assets/stylesheets/wizard/wizard_custom.scss +++ b/assets/stylesheets/wizard/wizard_custom.scss @@ -300,6 +300,27 @@ } } +input.date-picker { + font-size: 1.1487em; + padding: 6px; + border: 1px solid $primary; + transition: border-color 0.5s; +} + +.pika-single.is-bound { + width: fit-content; + position: absolute !important; +} + +.d-time-input .select-kit.combo-box .select-kit-header { + font-size: 1.1487em; + padding: 6px; +} + +.d-date-time-input { + display: flex; +} + .step-message { text-align: center; transition: all .2s; diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index ca231362..65e31c96 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -150,6 +150,9 @@ en: property: "Property" prefill: "Prefill" content: "Content" + date_time_format: + label: "Format" + instructions: "Moment.js format" type: text: "Text" @@ -166,6 +169,8 @@ en: group: Group user_selector: User Selector date: Date + time: Time + date_time: Date & Time connector: and: "and" diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index b027a2da..2fcfe687 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -11,6 +11,8 @@ en: required: "%{label} is required." not_url: "%{label} must be a valid url" invalid_file: "%{label} must be a %{types}" + invalid_date: "Invalid date" + invalid_time: "Invalid time" none: "We couldn't find a wizard at that address." no_skip: "Wizard can't be skipped" diff --git a/controllers/custom_wizard/admin/wizard.rb b/controllers/custom_wizard/admin/wizard.rb index bf62d1a4..84b09595 100644 --- a/controllers/custom_wizard/admin/wizard.rb +++ b/controllers/custom_wizard/admin/wizard.rb @@ -101,6 +101,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController :type, :min_length, :file_types, + :format, :limit, :property, prefill: mapped_params, diff --git a/extensions/wizard_field.rb b/extensions/wizard_field.rb index 87864032..f44e44bb 100644 --- a/extensions/wizard_field.rb +++ b/extensions/wizard_field.rb @@ -5,6 +5,7 @@ module CustomWizardFieldExtension :key, :min_length, :file_types, + :format, :limit, :property, :content @@ -17,6 +18,7 @@ module CustomWizardFieldExtension @key = attrs[:key] @min_length = attrs[:min_length] @file_types = attrs[:file_types] + @format = attrs[:format] @limit = attrs[:limit] @property = attrs[:property] @content = attrs[:content] diff --git a/lib/custom_wizard/builder.rb b/lib/custom_wizard/builder.rb index ebe24a4a..0af53245 100644 --- a/lib/custom_wizard/builder.rb +++ b/lib/custom_wizard/builder.rb @@ -232,6 +232,10 @@ class CustomWizard::Builder params[:file_types] = field_template['file_types'] end + if ['date', 'time', 'date_time'].include?(field_template['type']) + params[:format] = field_template['format'] + end + if field_template['type'] === 'category' || field_template['type'] === 'tag' params[:limit] = field_template['limit'] end @@ -306,6 +310,7 @@ class CustomWizard::Builder id = field['id'].to_s min_length = field['min_length'] if is_text_type(field) file_types = field['file_types'] + format = field['format'] if required && !value updater.errors.add(id, I18n.t('wizard.field.required', label: label)) @@ -327,9 +332,13 @@ class CustomWizard::Builder updater.errors.add(id, I18n.t('wizard.field.invalid_file', label: label, types: file_types)) end - if type === 'date' && value.present? && !validate_date(value) + if ['date', 'date_time'].include?(type) && value.present? && !validate_date(value) updater.errors.add(id, I18n.t('wizard.field.invalid_date')) end + + if type === 'time' && value.present? && !validate_time(value) + updater.errors.add(id, I18n.t('wizard.field.invalid_time')) + end CustomWizard::Builder.field_validators.each do |validator| if type === validator[:type] @@ -352,6 +361,15 @@ class CustomWizard::Builder false end end + + def validate_time(value) + begin + Time.parse(value) + true + rescue ArgumentError + false + end + end def is_text_type(field) ['text', 'textarea'].include? field['type'] diff --git a/lib/custom_wizard/field.rb b/lib/custom_wizard/field.rb index 9e7fe5bb..534e4824 100644 --- a/lib/custom_wizard/field.rb +++ b/lib/custom_wizard/field.rb @@ -13,7 +13,15 @@ class CustomWizard::Field min_length: nil }, text_only: {}, - date: {}, + date: { + format: "YYYY-MM-DD" + }, + time: { + format: "HH:mm" + }, + date_time: { + format: "" + }, number: {}, checkbox: {}, url: { diff --git a/lib/custom_wizard/mapper.rb b/lib/custom_wizard/mapper.rb index e06a9da9..f497b2d6 100644 --- a/lib/custom_wizard/mapper.rb +++ b/lib/custom_wizard/mapper.rb @@ -249,6 +249,7 @@ class CustomWizard::Mapper end def recurse(data, keys) + return nil if data.nil? k = keys.shift result = data[k] keys.empty? ? result : self.recurse(result, keys) diff --git a/serializers/custom_wizard/wizard_field_serializer.rb b/serializers/custom_wizard/wizard_field_serializer.rb index c03628db..c331dda2 100644 --- a/serializers/custom_wizard/wizard_field_serializer.rb +++ b/serializers/custom_wizard/wizard_field_serializer.rb @@ -4,6 +4,7 @@ class CustomWizard::FieldSerializer < ::WizardFieldSerializer attributes :image, :file_types, + :format, :limit, :property, :content @@ -34,6 +35,10 @@ class CustomWizard::FieldSerializer < ::WizardFieldSerializer object.file_types end + def format + object.format + end + def limit object.limit end