diff options
author | René Gieling <github@dartcafe.de> | 2021-04-18 23:12:36 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-18 23:12:36 +0300 |
commit | cbeba6e6fcf83dd655a4b9a24afc6ebcf1569bdc (patch) | |
tree | 988435536a81c4c735c420c109edff175f83556a /src/js/components/Options/OptionsDateAdd.vue | |
parent | 373eab67e7d338c7fa949b8ade9992fce73d066e (diff) |
Enhancement/option date picker (#1543)
* changed picker selection #1506
* changed design of picker buttons
Diffstat (limited to 'src/js/components/Options/OptionsDateAdd.vue')
-rw-r--r-- | src/js/components/Options/OptionsDateAdd.vue | 268 |
1 files changed, 208 insertions, 60 deletions
diff --git a/src/js/components/Options/OptionsDateAdd.vue b/src/js/components/Options/OptionsDateAdd.vue index 3eb5b125..7a7161b9 100644 --- a/src/js/components/Options/OptionsDateAdd.vue +++ b/src/js/components/Options/OptionsDateAdd.vue @@ -21,22 +21,43 @@ --> <template> - <DatetimePicker v-model="pickedOption" - v-bind="optionDatePicker" + <DatetimePicker v-model="pickerSelection" + v-bind="pickerOptions" :open.sync="pickerOpen" style="width: inherit;" + @change="changedDate" @pick="pickedDate"> - <template slot="footer"> + <template #input> + <ButtonDiv :title="t('polls', 'Add new date option')" /> + </template> + <template #footer> + <div v-if="dateOption.isValid" class="selection"> + <div> + {{ dateOption.text }} + </div> + <Spacer /> + <button v-if="dateOption.option.duration >= 0 && !added" class="primary" @click="addOption"> + {{ t('polls', 'Add') }} + </button> + <div v-if="added" v-tooltip.auto="t('polls', 'added')" class="icon-polls-yes" /> + </div> + <div v-else> + {{ t('polls', 'Pick a day.') }} + </div> + </template> + <template #header> <CheckBoxDiv v-model="useRange" class="range" :label="t('polls', 'Select range')" /> - <button v-if="!showTimePanel" class="mx-btn" @click="toggleTimePanel"> - {{ t('polls', 'Add time') }} - </button> - <button v-else class="mx-btn" @click="toggleTimePanel"> - {{ t('polls', 'Remove time') }} - </button> - <button class="mx-btn" @click="addOption"> - {{ t('polls', 'OK') }} - </button> + <div class="picker-buttons"> + <button v-if="useTime" @click="toggleTimePanel"> + {{ t('polls', showTimePanel ? 'Change date': 'Change time') }} + </button> + <button v-if="useTime" @click="removeTime"> + {{ t('polls', 'Remove time') }} + </button> + <button v-else @click="addTime"> + {{ t('polls', 'Add time') }} + </button> + </div> </template> </DateTimePicker> </template> @@ -44,59 +65,115 @@ <script> import CheckBoxDiv from '../Base/CheckBoxDiv' +import { showError, showSuccess } from '@nextcloud/dialogs' import moment from '@nextcloud/moment' import { DatetimePicker } from '@nextcloud/vue' +import ButtonDiv from '../Base/ButtonDiv' +import Spacer from '../Base/Spacer' export default { name: 'OptionsDateAdd', components: { CheckBoxDiv, + ButtonDiv, DatetimePicker, + Spacer, }, data() { return { - pickedOption: null, + pickerSelection: null, + firstPick: true, + changed: false, + imcomplete: true, lastPickedOption: null, - startDate: moment(), - endDate: moment(), pickerOpen: false, useRange: false, + useTime: false, showTimePanel: false, + keepRange: true, + preservedTimeFrom: moment(), + preservedTimeTo: moment(), + lastPickedDate: moment(0), + timeValues: moment(), + added: false, } }, computed: { - tempFormat() { - if (this.showTimePanel) { - return moment.localeData().longDateFormat('L LT') + dateOption() { + let from = moment() + let to = moment() + let text = '' + + if (Array.isArray(this.pickerSelection)) { + from = moment(this.pickerSelection[0]) + to = moment(this.pickerSelection[1]) + + // if a sigle day is selected while useRange is true and the paicker did not return a + // valid selection, use the single selected day + if (this.useRange && this.lastPickedDate) { + from = moment(this.lastPickedDate).hour(from.hour()).minute(from.minute()) + to = moment(this.lastPickedDate).hour(to.hour()).minute(to.minute()) + } } else { - return moment.localeData().longDateFormat('L') + from = moment(this.pickerSelection).startOf(this.useTime ? 'minute' : 'day') + to = moment(this.pickerSelection).startOf(this.useTime ? 'minute' : 'day') } - }, - dateOption() { - const timeToAdd = this.showTimePanel ? 0 : 86400 - - const startDate = this.useRange ? moment(this.pickedOption[0]) : moment(this.pickedOption) - const endDate = this.useRange ? moment(this.pickedOption[1]).add(timeToAdd, 'seconds') : moment(this.pickedOption).add(timeToAdd, 'seconds') - const pollOptionTextStart = startDate.utc().format(moment.defaultFormat) - const pollOptionTextEnd = startDate === endDate ? '' : ' - ' + endDate.utc().format(moment.defaultFormat) + if (this.useRange) { + if (this.useTime) { + if (moment(from).startOf('day').valueOf() === moment(to).startOf('day').valueOf()) { + text = from.format('ll LT') + ' - ' + to.format('LT') + } else { + text = from.format('ll LT') + ' - ' + to.format('ll LT') + } + } else { + from = from.startOf('day') + to = to.startOf('day') + if (moment(from).startOf('day').valueOf() === moment(to).startOf('day').valueOf()) { + text = from.format('ll') + } else { + text = from.format('ll') + ' - ' + to.format('ll') + } + } + } else { + if (this.useTime) { + text = from.format('ll LT') + } else { + text = from.startOf('day').format('ll') + } + } return { - timestamp: startDate.unix(), - pollOptionText: pollOptionTextStart + pollOptionTextEnd, - duration: endDate.unix() - startDate.unix(), + isValid: from._isValid && to._isValid, + from, + to, + text, + option: { + timestamp: from.unix(), + duration: moment(to).add(this.useTime ? 0 : 1, 'day').unix() - from.unix(), + }, + } + }, + + tempFormat() { + if (this.useTime) { + return moment.localeData().longDateFormat('L LT') + } else { + return moment.localeData().longDateFormat('L') } }, - optionDatePicker() { + pickerOptions() { return { + appendToBody: true, editable: false, minuteStep: 5, - type: this.showTimePanel ? 'datetime' : 'date', + type: this.useTime ? 'datetime' : 'date', range: this.useRange, + showSecond: false, showTimePanel: this.showTimePanel, valueType: 'timestamp', format: this.tempFormat, @@ -116,54 +193,125 @@ export default { watch: { useRange() { - if (this.useRange) { - if (!Array.isArray(this.pickedOption)) { - this.pickedOption = [this.pickedOption, this.pickedOption] - } - } else { - if (Array.isArray(this.pickedOption)) { - this.pickedOption = this.pickedOption[0] - } + if (this.useRange && !Array.isArray(this.pickerSelection)) { + this.pickerSelection = [this.pickerSelection, this.pickerSelection] + } else if (!this.useRange && Array.isArray(this.pickerSelection)) { + this.pickerSelection = this.pickerSelection[0] } }, }, methods: { - toggleTimePanel() { - if (this.useRange) { - if (Array.isArray(this.pickedOption)) { - if (this.lastPickedOption !== this.pickedOption[0] - && this.lastPickedOption !== this.pickedOption[1]) { - this.pickedOption = [this.lastPickedOption, this.lastPickedOption] - } - } else { - if (this.lastPickedOption) { - this.pickedOption = [this.lastPickedOption, this.lastPickedOption] - } - } - } - this.showTimePanel = !this.showTimePanel + // if picker returned a valid selection + changedDate(value, type) { + this.added = false + this.changed = true }, + // The date picker does not update the values, if useRange is true and + // a single day is selected without a second click. Therfore we store + // the picked day to define the correct date selection inside the + // computed dateOptions property pickedDate(value) { - if (this.optionDatePicker.valueType === 'timestamp') { - this.lastPickedOption = moment(value).valueOf() + // we rely on the behavior, that the changed event is fired before the picked event + // if the picker already returned a valid selection before, ignore picked date + this.added = false + if (this.changed) { + // reset changed status + this.changed = false + // reset the last picked date + this.lastPickedDate = null } else { - this.lastPickedOption = value + // otherwise store the selection of the picked date + this.lastPickedDate = moment(value) } + // keep picker open this.pickerOpen = true }, - addOption() { - this.pickerOpen = false - this.$store.dispatch('options/add', this.dateOption) + addTime() { + this.added = false + if (this.useRange) { + // make sure, the pickerSelection is set to the last displayed status + this.pickerSelection = [this.dateOption.from.valueOf(), this.dateOption.to.valueOf()] + } + this.useTime = true + this.showTimePanel = true + }, + + removeTime() { + this.added = false + if (this.useRange) { + // make sure, the pickerSelection is set to the last displayed status + this.pickerSelection = [this.dateOption.from.valueOf(), this.dateOption.to.valueOf()] + } + this.useTime = false + this.showTimePanel = false + }, + + toggleTimePanel() { + if (this.showTimePanel) { + this.changed = false + } else if (this.useRange) { + // make sure, the pickerSelection is set to the last displayed status + this.pickerSelection = [this.dateOption.from.valueOf(), this.dateOption.to.valueOf()] + } + this.showTimePanel = !this.showTimePanel + }, + + async addOption() { + if (this.useRange) { + // make sure, the pickerSelection is set to the last displayed status + this.pickerSelection = [this.dateOption.from.valueOf(), this.dateOption.to.valueOf()] + } + try { + await this.$store.dispatch('options/add', this.dateOption.option) + this.added = true + showSuccess(t('polls', '{optionText} added', { optionText: this.dateOption.text })) + } catch (e) { + if (e.response.status === 409) { + showError(t('polls', '{optionText} already exists', { optionText: this.dateOption.text })) + } else { + showError(t('polls', 'Error adding {optionText}', { optionText: this.dateOption.text })) + } + } }, }, } </script> +<style lang="scss"> +.mx-datepicker { + width: 100% !important; +} + +.mx-input-wrapper { + &> button { + width: 100%; + } + .mx-icon-calendar { + display: none; + } +} +</style> + <style lang="scss" scoped> +.icon-polls-yes { + padding: 5px 1px 5px 1px; + height: 34px; + margin: 3px 0; +} + +.picker-buttons { + display: flex; + justify-content: flex-end; +} + +.selection { + display: flex; + align-items: center; +} .range { flex: 1; |