enh: Move to native datetime picker component
Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
@@ -35,7 +35,7 @@
|
|||||||
@select="assignUserToCard"
|
@select="assignUserToCard"
|
||||||
@remove="removeUserFromCard" />
|
@remove="removeUserFromCard" />
|
||||||
|
|
||||||
<DueDateSelector :card="card" :can-edit="canEdit && !saving" @change="updateCardDue" />
|
<DueDateSelector :card="card" :can-edit="canEdit" @change="updateCardDue" />
|
||||||
|
|
||||||
<div v-if="projectsEnabled" class="section-wrapper">
|
<div v-if="projectsEnabled" class="section-wrapper">
|
||||||
<CollectionList v-if="card.id"
|
<CollectionList v-if="card.id"
|
||||||
@@ -85,7 +85,6 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
saving: false,
|
|
||||||
addedLabelToCard: null,
|
addedLabelToCard: null,
|
||||||
copiedCard: null,
|
copiedCard: null,
|
||||||
locale: getLocale(),
|
locale: getLocale(),
|
||||||
@@ -105,7 +104,6 @@ export default {
|
|||||||
this.$store.dispatch('setConfig', { cardDetailsInModal: newValue })
|
this.$store.dispatch('setConfig', { cardDetailsInModal: newValue })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
labelsSorted() {
|
labelsSorted() {
|
||||||
return [...this.currentBoard.labels].sort((a, b) => (a.title < b.title) ? -1 : 1)
|
return [...this.currentBoard.labels].sort((a, b) => (a.title < b.title) ? -1 : 1)
|
||||||
},
|
},
|
||||||
@@ -133,15 +131,6 @@ export default {
|
|||||||
localStorage.setItem('deck.selectedStackId', this.card.stackId)
|
localStorage.setItem('deck.selectedStackId', this.card.stackId)
|
||||||
},
|
},
|
||||||
|
|
||||||
async updateCardDue(val) {
|
|
||||||
this.saving = true
|
|
||||||
await this.$store.dispatch('updateCardDue', {
|
|
||||||
...this.copiedCard,
|
|
||||||
duedate: val ? (new Date(val)).toISOString() : null,
|
|
||||||
})
|
|
||||||
this.saving = false
|
|
||||||
},
|
|
||||||
|
|
||||||
assignUserToCard(user) {
|
assignUserToCard(user) {
|
||||||
this.$store.dispatch('assignCardToUser', {
|
this.$store.dispatch('assignCardToUser', {
|
||||||
card: this.copiedCard,
|
card: this.copiedCard,
|
||||||
@@ -162,6 +151,13 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updateCardDue(val) {
|
||||||
|
this.$store.dispatch('updateCardDue', {
|
||||||
|
...this.copiedCard,
|
||||||
|
duedate: val ? (new Date(val)).toISOString() : null,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
addLabelToCard(newLabel) {
|
addLabelToCard(newLabel) {
|
||||||
this.copiedCard.labels.push(newLabel)
|
this.copiedCard.labels.push(newLabel)
|
||||||
const data = {
|
const data = {
|
||||||
@@ -205,15 +201,6 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
.section-wrapper:deep(.mx-datepicker-main.mx-datepicker-popup) {
|
|
||||||
left: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-wrapper:deep(.mx-datepicker-main.mx-datepicker-popup.mx-datepicker-sidebar) {
|
|
||||||
padding: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-wrapper {
|
.section-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
@@ -266,9 +253,3 @@ export default {
|
|||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<style>
|
|
||||||
.mx-datepicker-main.mx-datepicker-popup {
|
|
||||||
/* above the modal */
|
|
||||||
z-index: 9999 !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -4,19 +4,34 @@
|
|||||||
<Calendar :size="20" />
|
<Calendar :size="20" />
|
||||||
</div>
|
</div>
|
||||||
<div class="duedate-selector">
|
<div class="duedate-selector">
|
||||||
<NcDatetimePicker v-model="duedate"
|
<NcDateTimePickerNative v-if="duedate"
|
||||||
|
id="card-duedate-picker"
|
||||||
|
v-model="duedate"
|
||||||
:placeholder="t('deck', 'Set a due date')"
|
:placeholder="t('deck', 'Set a due date')"
|
||||||
type="datetime"
|
:hide-label="true"
|
||||||
:minute-step="5"
|
type="datetime-local" />
|
||||||
:show-second="false"
|
<NcActions v-if="canEdit" :menu-title="!duedate ? t('deck', 'Add due date') : null" type="tertiary">
|
||||||
:lang="lang"
|
<template v-if="!duedate" #icon>
|
||||||
:formatter="format"
|
<Plus :size="20" />
|
||||||
:disabled="!canEdit"
|
</template>
|
||||||
:shortcuts="shortcuts"
|
<NcActionButton v-for="shortcut in reminderOptions"
|
||||||
:append-to-body="true"
|
:key="shortcut.key"
|
||||||
confirm />
|
close-after-click
|
||||||
<NcActions v-if="canEdit">
|
@click="() => selectShortcut(shortcut)">
|
||||||
<NcActionButton v-if="duedate" icon="icon-delete" @click="removeDue()">
|
{{ shortcut.label }}
|
||||||
|
</NcActionButton>
|
||||||
|
<NcActionSeparator />
|
||||||
|
|
||||||
|
<NcActionButton v-if="!duedate" close-after-click @click="initDate">
|
||||||
|
<template #icon>
|
||||||
|
<Plus :size="20" />
|
||||||
|
</template>
|
||||||
|
{{ t('deck', 'Choose a date') }}
|
||||||
|
</NcActionButton>
|
||||||
|
<NcActionButton v-else
|
||||||
|
icon="icon-delete"
|
||||||
|
close-after-click
|
||||||
|
@click="removeDue">
|
||||||
{{ t('deck', 'Remove due date') }}
|
{{ t('deck', 'Remove due date') }}
|
||||||
</NcActionButton>
|
</NcActionButton>
|
||||||
</NcActions>
|
</NcActions>
|
||||||
@@ -26,17 +41,21 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
import { NcActionButton, NcActions, NcDatetimePicker } from '@nextcloud/vue'
|
import { NcActionButton, NcActions, NcActionSeparator, NcDateTimePickerNative } from '@nextcloud/vue'
|
||||||
import { getDayNamesMin, getFirstDay, getMonthNamesShort } from '@nextcloud/l10n'
|
import { getDayNamesMin, getFirstDay, getMonthNamesShort } from '@nextcloud/l10n'
|
||||||
|
import Plus from 'vue-material-design-icons/Plus.vue'
|
||||||
import Calendar from 'vue-material-design-icons/Calendar.vue'
|
import Calendar from 'vue-material-design-icons/Calendar.vue'
|
||||||
|
import moment from '@nextcloud/moment'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'DueDateSelector',
|
name: 'DueDateSelector',
|
||||||
components: {
|
components: {
|
||||||
|
Plus,
|
||||||
Calendar,
|
Calendar,
|
||||||
NcActions,
|
NcActions,
|
||||||
NcActionButton,
|
NcActionButton,
|
||||||
NcDatetimePicker,
|
NcActionSeparator,
|
||||||
|
NcDateTimePickerNative,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
card: {
|
card: {
|
||||||
@@ -64,64 +83,81 @@ export default defineComponent({
|
|||||||
stringify: this.stringify,
|
stringify: this.stringify,
|
||||||
parse: this.parse,
|
parse: this.parse,
|
||||||
},
|
},
|
||||||
shortcuts: [
|
|
||||||
{
|
|
||||||
text: t('deck', 'Today'),
|
|
||||||
onClick() {
|
|
||||||
const date = new Date()
|
|
||||||
date.setDate(date.getDate())
|
|
||||||
date.setHours(23)
|
|
||||||
date.setMinutes(59)
|
|
||||||
return date
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: t('deck', 'Tomorrow'),
|
|
||||||
onClick() {
|
|
||||||
const date = new Date()
|
|
||||||
date.setDate(date.getDate() + 1)
|
|
||||||
date.setHours(23)
|
|
||||||
date.setMinutes(59)
|
|
||||||
return date
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: t('deck', 'Next week'),
|
|
||||||
onClick() {
|
|
||||||
const date = new Date()
|
|
||||||
date.setDate(date.getDate() + 7)
|
|
||||||
date.setHours(23)
|
|
||||||
date.setMinutes(59)
|
|
||||||
return date
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: t('deck', 'Next month'),
|
|
||||||
onClick() {
|
|
||||||
const date = new Date()
|
|
||||||
date.setDate(date.getDate() + 30)
|
|
||||||
date.setHours(23)
|
|
||||||
date.setMinutes(59)
|
|
||||||
return date
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
duedate: {
|
duedate: {
|
||||||
get() {
|
get() {
|
||||||
return this.card.duedate ? new Date(this.card.duedate) : null
|
return this.card?.duedate ? new Date(this.card.duedate) : null
|
||||||
},
|
},
|
||||||
set(val) {
|
set(val) {
|
||||||
this.$emit('change', val)
|
this.$emit('change', val ? new Date(val) : null)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
reminderOptions() {
|
||||||
|
const currentDateTime = moment()
|
||||||
|
// Same day 18:00 PM (or hidden)
|
||||||
|
const laterTodayTime = (currentDateTime.hour() < 18)
|
||||||
|
? moment().hour(18)
|
||||||
|
: null
|
||||||
|
// Tomorrow 08:00 AM
|
||||||
|
const tomorrowTime = moment().add(1, 'days').hour(8)
|
||||||
|
// Saturday 08:00 AM (or hidden)
|
||||||
|
const thisWeekendTime = (currentDateTime.day() !== 6 && currentDateTime.day() !== 0)
|
||||||
|
? moment().day(6).hour(8)
|
||||||
|
: null
|
||||||
|
// Next Monday 08:00 AM
|
||||||
|
const nextWeekTime = moment().add(1, 'weeks').day(1).hour(8)
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
key: 'laterToday',
|
||||||
|
timestamp: this.getTimestamp(laterTodayTime),
|
||||||
|
label: t('deck', 'Later today – {timeLocale}', { timeLocale: laterTodayTime?.format('LT') }),
|
||||||
|
ariaLabel: t('deck', 'Set due date for later today'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'tomorrow',
|
||||||
|
timestamp: this.getTimestamp(tomorrowTime),
|
||||||
|
label: t('deck', 'Tomorrow – {timeLocale}', { timeLocale: tomorrowTime?.format('ddd LT') }),
|
||||||
|
ariaLabel: t('deck', 'Set due date for tomorrow'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'thisWeekend',
|
||||||
|
timestamp: this.getTimestamp(thisWeekendTime),
|
||||||
|
label: t('deck', 'This weekend – {timeLocale}', { timeLocale: thisWeekendTime?.format('ddd LT') }),
|
||||||
|
ariaLabel: t('deck', 'Set due date for this weekend'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'nextWeek',
|
||||||
|
timestamp: this.getTimestamp(nextWeekTime),
|
||||||
|
label: t('deck', 'Next week – {timeLocale}', { timeLocale: nextWeekTime?.format('ddd LT') }),
|
||||||
|
ariaLabel: t('deck', 'Set due date for next week'),
|
||||||
|
},
|
||||||
|
].filter(option => option.timestamp !== null)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
initDate() {
|
||||||
|
if (this.duedate === null) {
|
||||||
|
// We initialize empty dates with a time once clicked to make picking a day easier
|
||||||
|
const now = new Date()
|
||||||
|
now.setDate(now.getDate() + 1)
|
||||||
|
now.setHours(8)
|
||||||
|
now.setMinutes(0)
|
||||||
|
now.setMilliseconds(0)
|
||||||
|
this.duedate = now
|
||||||
|
}
|
||||||
|
},
|
||||||
removeDue() {
|
removeDue() {
|
||||||
this.duedate = null
|
this.duedate = null
|
||||||
},
|
},
|
||||||
|
selectShortcut(shortcut) {
|
||||||
|
this.duedate = shortcut.timestamp
|
||||||
|
},
|
||||||
|
getTimestamp(momentObject) {
|
||||||
|
return momentObject?.minute(0).second(0).millisecond(0).toDate() || null
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user