Skip to content

Instantly share code, notes, and snippets.

@gregveres
Last active January 19, 2022 22:14
Show Gist options
  • Save gregveres/2e24931280749fc5dca828780bedf7dc to your computer and use it in GitHub Desktop.
Save gregveres/2e24931280749fc5dca828780bedf7dc to your computer and use it in GitHub Desktop.
<script lang="ts">
import { convertDayStringToDate, formatDate, monthDay } from '@helpers/DateFormatter';
import { defineComponent, ref } from '@vue/composition-api';
import { VHover } from 'vuetify/lib';
export default defineComponent({
name: 'VDateTimePicker',
components: { VHover },
props: {
date: {
type: String,
required: true
},
time: {
type: String,
required: true
}
},
setup(props, { emit }) {
const internalDate = ref(props.date);
const internalTime = ref(props.time);
const showTime = ref(false);
const datePicker = ref('DATE');
const formattedDate = ref<string>('');
const year = ref<number>(0);
const updateDate = (str: string) => {
const date = convertDayStringToDate(str);
formattedDate.value = formatDate(date, monthDay);
year.value = date.getFullYear();
};
updateDate(props.date);
const formattedTime = ref<string>('');
const pm = ref<boolean>(false);
const updateTime = (changePeriod: boolean, usePM: boolean) => {
const [, h, min] = internalTime.value.match(/^(\d+)[:](\d+)$/) || new Array(3);
let hour = parseInt(h, 10);
if (changePeriod) {
if (usePM && h < 12) hour += 12;
if (!usePM && h > 12) hour -= 12;
internalTime.value = `${hour}:${min}`;
}
pm.value = hour >= 12;
if (hour === 0) hour = 12;
formattedTime.value = `${hour > 12 ? hour - 12 : hour}:${min}`;
};
updateTime(false, false);
const sendUpdate = () => {
emit('update', internalDate.value, internalTime.value);
};
const dateChange = (newDate: string) => {
updateDate(newDate);
sendUpdate();
showTime.value = true;
};
const timeChange = (newTime: string) => {
console.log(newTime);
internalTime.value = newTime;
updateTime(false, false);
sendUpdate();
};
const selectYear = () => {
datePicker.value = 'YEAR';
showTime.value = false;
};
const selectDate = () => {
showTime.value = false;
};
const selectTime = () => {
showTime.value = true;
};
const switchToPM = () => {
updateTime(true, true);
sendUpdate();
};
const switchToAM = () => {
updateTime(true, false);
sendUpdate();
};
return {
internalDate,
internalTime,
formattedDate,
year,
updateDate,
formattedTime,
pm,
updateTime,
dateChange,
timeChange,
showTime,
datePicker,
selectYear,
selectDate,
selectTime,
switchToAM,
switchToPM
};
}
});
</script>
<template>
<div>
<div class="primary pa-3">
<VHover v-slot="{ hover }">
<span class="head_small primary pa-1" :class="{ 'darken-1': hover }" @click="selectYear">{{ year }}</span>
</VHover>
<div class="d-flex align-center">
<VHover v-slot="{ hover }">
<div class="head_title primary pa-1" :class="{ 'darken-1': hover }" @click="selectDate">{{
formattedDate
}}</div>
</VHover>
<v-spacer />
<VHover v-slot="{ hover }">
<div class="head_title primary pa-1" :class="{ 'darken-1': hover }" @click="selectTime">{{
formattedTime
}}</div>
</VHover>
<div>
<VHover v-slot="{ hover }">
<div class="head_small primary px-3" :class="{ dim: pm, 'darken-1': hover }" @click="switchToAM">AM</div>
</VHover>
<VHover v-slot="{ hover }">
<div class="head_small primary px-3" :class="{ dim: !pm, 'darken-1': hover }" @click="switchToPM">PM</div>
</VHover>
</div>
</div>
</div>
<div class="text-center">
<v-date-picker
v-show="!showTime"
v-model="internalDate"
:active-picker="datePicker"
no-title
show-adjacent-months
@change="dateChange"
/>
<v-time-picker v-show="showTime" v-model="internalTime" scrollable no-title format="ampm" @input="timeChange" />
</div>
</div>
</template>
<style lang="scss" scoped>
.head_title {
font-size: 2.5rem;
font-weight: 500;
overflow: hidden;
color: white;
cursor: pointer;
}
.head_small {
font-size: 0.8rem;
font-weight: 500;
color: white;
cursor: pointer;
&.dim {
opacity: 0.5;
}
}
</style>
import dayjs, { Dayjs } from 'dayjs';
export const monthDay = 'MMM DD'; // August 2021
export function formatDate(date: Date, formatStr = 'PP'): string {
return dayjs(date).format(formatStr);
}
export function convertDayStringToDate(day: string): Date {
const [, year, month, date] = day.trim().match(/^(\d+)[/-](\d+)[/-](\d+)$/) || new Array(4);
return new Date(year, month - 1, date);
}
@gregveres
Copy link
Author

I have added a PR to add active-picker as a prop for the v-time-picker. If this gets accepted, then I will update the gist to use the active-picker prop so that the user will be able to switch between minutes and hours on the time. Without this prop, the user is stuck on the minutes picker for the time once they have made their first selection of the hour.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment