feat: datepicker script setup
continuous-integration/drone/pr Build is failing
Details
continuous-integration/drone/pr Build is failing
Details
This commit is contained in:
parent
2c270d063e
commit
f10849dbfd
|
@ -110,12 +110,13 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {defineComponent} from 'vue'
|
||||
<script lang="ts" setup>
|
||||
import {ref, computed, watch, onMounted, onBeforeUnmount} from 'vue'
|
||||
import {useI18n} from 'vue-i18n'
|
||||
import {useStore} from 'vuex'
|
||||
|
||||
import flatPickr from 'vue-flatpickr-component'
|
||||
import 'flatpickr/dist/flatpickr.css'
|
||||
import {i18n} from '@/i18n'
|
||||
|
||||
import {format} from 'date-fns'
|
||||
import {calculateDayInterval} from '@/helpers/time/calculateDayInterval'
|
||||
|
@ -123,139 +124,115 @@ import {calculateNearestHours} from '@/helpers/time/calculateNearestHours'
|
|||
import {closeWhenClickedOutside} from '@/helpers/closeWhenClickedOutside'
|
||||
import {createDateFromString} from '@/helpers/time/createDateFromString'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'datepicker',
|
||||
data() {
|
||||
return {
|
||||
date: null,
|
||||
show: false,
|
||||
changed: false,
|
||||
}
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: [Date, String],
|
||||
validator: prop => prop instanceof Date || prop === null || typeof prop === 'string',
|
||||
},
|
||||
components: {
|
||||
flatPickr,
|
||||
chooseDateLabel: {
|
||||
type: String,
|
||||
default: () => t('input.datepicker.chooseDate'),
|
||||
},
|
||||
props: {
|
||||
modelValue: {
|
||||
validator: prop => prop instanceof Date || prop === null || typeof prop === 'string',
|
||||
},
|
||||
chooseDateLabel: {
|
||||
type: String,
|
||||
default() {
|
||||
return i18n.global.t('input.datepicker.chooseDate')
|
||||
},
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue', 'change', 'close', 'close-on-change'],
|
||||
mounted() {
|
||||
document.addEventListener('click', this.hideDatePopup)
|
||||
},
|
||||
beforeUnmount() {
|
||||
document.removeEventListener('click', this.hideDatePopup)
|
||||
},
|
||||
watch: {
|
||||
modelValue: {
|
||||
handler: 'setDateValue',
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
flatPickerConfig() {
|
||||
return {
|
||||
altFormat: this.$t('date.altFormatLong'),
|
||||
altInput: true,
|
||||
dateFormat: 'Y-m-d H:i',
|
||||
enableTime: true,
|
||||
time_24hr: true,
|
||||
inline: true,
|
||||
locale: {
|
||||
firstDayOfWeek: this.$store.state.auth.settings.weekStart,
|
||||
},
|
||||
}
|
||||
},
|
||||
// Since flatpickr dates are strings, we need to convert them to native date objects.
|
||||
// To make that work, we need a separate variable since flatpickr does not have a change event.
|
||||
flatPickrDate: {
|
||||
set(newValue) {
|
||||
this.date = createDateFromString(newValue)
|
||||
this.updateData()
|
||||
},
|
||||
get() {
|
||||
if (!this.date) {
|
||||
return ''
|
||||
}
|
||||
|
||||
return format(this.date, 'yyy-LL-dd H:mm')
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setDateValue(newVal) {
|
||||
if (newVal === null) {
|
||||
this.date = null
|
||||
return
|
||||
}
|
||||
this.date = createDateFromString(newVal)
|
||||
},
|
||||
updateData() {
|
||||
this.changed = true
|
||||
this.$emit('update:modelValue', this.date)
|
||||
this.$emit('change', this.date)
|
||||
},
|
||||
toggleDatePopup() {
|
||||
if (this.disabled) {
|
||||
return
|
||||
}
|
||||
|
||||
this.show = !this.show
|
||||
},
|
||||
hideDatePopup(e) {
|
||||
if (this.show) {
|
||||
closeWhenClickedOutside(e, this.$refs.datepickerPopup, this.close)
|
||||
}
|
||||
},
|
||||
close() {
|
||||
// Kind of dirty, but the timeout allows us to enter a time and click on "confirm" without
|
||||
// having to click on another input field before it is actually used.
|
||||
setTimeout(() => {
|
||||
this.show = false
|
||||
this.$emit('close', this.changed)
|
||||
if (this.changed) {
|
||||
this.changed = false
|
||||
this.$emit('close-on-change', this.changed)
|
||||
}
|
||||
}, 200)
|
||||
},
|
||||
setDate(date) {
|
||||
if (this.date === null) {
|
||||
this.date = new Date()
|
||||
}
|
||||
|
||||
const interval = calculateDayInterval(date)
|
||||
const newDate = new Date()
|
||||
newDate.setDate(newDate.getDate() + interval)
|
||||
newDate.setHours(calculateNearestHours(newDate))
|
||||
newDate.setMinutes(0)
|
||||
newDate.setSeconds(0)
|
||||
this.date = newDate
|
||||
this.flatPickrDate = newDate
|
||||
this.updateData()
|
||||
},
|
||||
getDayIntervalFromString(date) {
|
||||
return calculateDayInterval(date)
|
||||
},
|
||||
getWeekdayFromStringInterval(date) {
|
||||
const interval = calculateDayInterval(date)
|
||||
const newDate = new Date()
|
||||
newDate.setDate(newDate.getDate() + interval)
|
||||
return format(newDate, 'E')
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue', 'change', 'close', 'close-on-change'])
|
||||
|
||||
const {t} = useI18n()
|
||||
const store = useStore()
|
||||
|
||||
const date = ref<Date>()
|
||||
const show = ref(false)
|
||||
const changed = ref(false)
|
||||
|
||||
onMounted(() => document.addEventListener('click', hideDatePopup))
|
||||
onBeforeUnmount(() => document.removeEventListener('click', hideDatePopup))
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(value) => setDateValue(value),
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
const flatPickerConfig = computed(() => ({
|
||||
altFormat: t('date.altFormatLong'),
|
||||
altInput: true,
|
||||
dateFormat: 'Y-m-d H:i',
|
||||
enableTime: true,
|
||||
time_24hr: true,
|
||||
inline: true,
|
||||
locale: {
|
||||
firstDayOfWeek: store.state.auth.settings.weekStart,
|
||||
},
|
||||
}))
|
||||
|
||||
function setDateValue(newVal) {
|
||||
if (newVal === null) {
|
||||
date.value = undefined
|
||||
return
|
||||
}
|
||||
date.value = createDateFromString(newVal)
|
||||
}
|
||||
|
||||
function updateData() {
|
||||
changed.value = true
|
||||
emit('update:modelValue', date.value)
|
||||
emit('change', date.value)
|
||||
}
|
||||
|
||||
function toggleDatePopup() {
|
||||
if (props.disabled) {
|
||||
return
|
||||
}
|
||||
|
||||
show.value = !show.value
|
||||
}
|
||||
|
||||
const datepickerPopup = ref<HTMLElement | null>(null)
|
||||
function hideDatePopup(e) {
|
||||
if (show.value) {
|
||||
closeWhenClickedOutside(e, datepickerPopup?.value, close)
|
||||
}
|
||||
}
|
||||
|
||||
function close() {
|
||||
// Kind of dirty, but the timeout allows us to enter a time and click on "confirm" without
|
||||
// having to click on another input field before it is actually used.
|
||||
setTimeout(() => {
|
||||
show.value = false
|
||||
emit('close', changed.value)
|
||||
if (changed.value) {
|
||||
changed.value = false
|
||||
emit('close-on-change', changed.value)
|
||||
}
|
||||
}, 200)
|
||||
}
|
||||
|
||||
const flatPickrDate = ref()
|
||||
function setDate(date) {
|
||||
if (date.value === null) {
|
||||
date.value = new Date()
|
||||
}
|
||||
|
||||
const interval = calculateDayInterval(date)
|
||||
const newDate = new Date()
|
||||
newDate.setDate(newDate.getDate() + interval)
|
||||
newDate.setHours(calculateNearestHours(newDate))
|
||||
newDate.setMinutes(0)
|
||||
newDate.setSeconds(0)
|
||||
date.value = newDate
|
||||
flatPickrDate.value = newDate
|
||||
updateData()
|
||||
}
|
||||
|
||||
function getWeekdayFromStringInterval(date) {
|
||||
const interval = calculateDayInterval(date)
|
||||
const newDate = new Date()
|
||||
newDate.setDate(newDate.getDate() + interval)
|
||||
return format(newDate, 'E')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
Reference in New Issue