feat: Replace vue-datepicker-next from codebase
This commit is contained in:
@@ -12,9 +12,6 @@
|
||||
// Base styles for elements
|
||||
@import 'base';
|
||||
|
||||
// Plugins
|
||||
@import 'plugins/date-picker';
|
||||
|
||||
html,
|
||||
body {
|
||||
font-family:
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import {
|
||||
startOfMonth,
|
||||
addMonths,
|
||||
subMonths,
|
||||
startOfDay,
|
||||
isSameDay,
|
||||
addHours,
|
||||
addYears,
|
||||
subYears,
|
||||
setMonth,
|
||||
setYear,
|
||||
} from 'date-fns';
|
||||
import { CALENDAR_TYPES, CALENDAR_PERIODS } from './helpers/DatePickerHelper';
|
||||
import CalendarYear from './components/CalendarYear.vue';
|
||||
import CalendarMonth from './components/CalendarMonth.vue';
|
||||
import CalendarWeek from './components/CalendarWeek.vue';
|
||||
import CalendarFooter from './components/CalendarFooter.vue';
|
||||
import TimePicker from './components/TimePicker.vue';
|
||||
|
||||
defineProps({
|
||||
minDate: {
|
||||
type: Date,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['apply', 'clear']);
|
||||
|
||||
const { START_CALENDAR } = CALENDAR_TYPES;
|
||||
const { WEEK, MONTH, YEAR } = CALENDAR_PERIODS;
|
||||
|
||||
const currentDate = ref(new Date());
|
||||
const selectedDate = ref(null);
|
||||
|
||||
const getCurrentTime = () => {
|
||||
const now = new Date();
|
||||
return {
|
||||
hour: now.getHours(),
|
||||
minute: now.getMinutes(),
|
||||
second: now.getSeconds(),
|
||||
};
|
||||
};
|
||||
|
||||
const selectedTime = ref(getCurrentTime());
|
||||
const calendarView = ref(WEEK);
|
||||
const calendarDate = ref(startOfMonth(currentDate.value));
|
||||
|
||||
const getMinTimeForToday = () => addHours(new Date(), 1);
|
||||
|
||||
const minTime = computed(() => {
|
||||
if (!selectedDate.value) return null;
|
||||
if (!isSameDay(selectedDate.value, currentDate.value)) return null;
|
||||
return getMinTimeForToday();
|
||||
});
|
||||
|
||||
const selectedDateTime = computed(() => {
|
||||
if (!selectedDate.value) return null;
|
||||
const date = new Date(selectedDate.value);
|
||||
date.setHours(
|
||||
selectedTime.value.hour,
|
||||
selectedTime.value.minute,
|
||||
selectedTime.value.second,
|
||||
0
|
||||
);
|
||||
return date;
|
||||
});
|
||||
|
||||
const selectDate = day => {
|
||||
selectedDate.value = startOfDay(day);
|
||||
if (isSameDay(day, currentDate.value)) {
|
||||
const minDate = getMinTimeForToday();
|
||||
selectedTime.value = {
|
||||
hour: minDate.getHours(),
|
||||
minute: minDate.getMinutes(),
|
||||
second: 0,
|
||||
};
|
||||
} else {
|
||||
selectedTime.value = { hour: 0, minute: 0, second: 0 };
|
||||
}
|
||||
};
|
||||
|
||||
const moveCalendar = (direction, period = MONTH) => {
|
||||
const adjust =
|
||||
period === YEAR
|
||||
? { prev: subYears, next: addYears }
|
||||
: { prev: subMonths, next: addMonths };
|
||||
calendarDate.value = adjust[direction](calendarDate.value, 1);
|
||||
};
|
||||
|
||||
const setViewMode = (_calendar, mode) => {
|
||||
calendarView.value = mode;
|
||||
};
|
||||
|
||||
const openCalendar = (index, _calendarType, period = MONTH) => {
|
||||
calendarDate.value =
|
||||
period === MONTH
|
||||
? setMonth(startOfMonth(calendarDate.value), index)
|
||||
: setYear(calendarDate.value, index);
|
||||
calendarView.value = period === MONTH ? WEEK : MONTH;
|
||||
};
|
||||
|
||||
const onApply = () => {
|
||||
if (selectedDateTime.value) {
|
||||
emit('apply', selectedDateTime.value);
|
||||
}
|
||||
};
|
||||
|
||||
const isDefaultState = computed(
|
||||
() => !selectedDate.value && calendarView.value === WEEK
|
||||
);
|
||||
|
||||
const resetState = () => {
|
||||
selectedDate.value = null;
|
||||
selectedTime.value = getCurrentTime();
|
||||
calendarDate.value = startOfMonth(currentDate.value);
|
||||
calendarView.value = WEEK;
|
||||
};
|
||||
|
||||
const onClear = () => {
|
||||
if (isDefaultState.value) {
|
||||
emit('clear');
|
||||
return;
|
||||
}
|
||||
resetState();
|
||||
};
|
||||
|
||||
defineExpose({ resetState });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col select-none font-inter">
|
||||
<div class="flex w-full gap-3 justify-between">
|
||||
<div class="flex justify-center py-5">
|
||||
<div class="flex flex-col items-center gap-2 min-w-[300px]">
|
||||
<CalendarYear
|
||||
v-if="calendarView === YEAR"
|
||||
:calendar-type="START_CALENDAR"
|
||||
:start-current-date="calendarDate"
|
||||
:end-current-date="addMonths(calendarDate, 1)"
|
||||
@select-year="openCalendar($event, START_CALENDAR, YEAR)"
|
||||
/>
|
||||
<CalendarMonth
|
||||
v-else-if="calendarView === MONTH"
|
||||
:calendar-type="START_CALENDAR"
|
||||
:start-current-date="calendarDate"
|
||||
:end-current-date="addMonths(calendarDate, 1)"
|
||||
@select-month="openCalendar($event, START_CALENDAR)"
|
||||
@set-view="setViewMode"
|
||||
@prev="moveCalendar('prev', YEAR)"
|
||||
@next="moveCalendar('next', YEAR)"
|
||||
/>
|
||||
<CalendarWeek
|
||||
v-else
|
||||
:calendar-type="START_CALENDAR"
|
||||
:current-date="currentDate"
|
||||
:start-current-date="calendarDate"
|
||||
:end-current-date="addMonths(calendarDate, 1)"
|
||||
:selected-start-date="selectedDate"
|
||||
:selected-end-date="selectedDate"
|
||||
:selecting-end-date="false"
|
||||
:hovered-end-date="null"
|
||||
:min-date="minDate"
|
||||
@select-date="selectDate"
|
||||
@set-view="setViewMode"
|
||||
@prev="moveCalendar('prev')"
|
||||
@next="moveCalendar('next')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex justify-center py-2 w-full transition-opacity ltr:border-l rtl:border-r border-n-strong"
|
||||
:class="selectedDate ? 'opacity-100' : 'opacity-40 pointer-events-none'"
|
||||
>
|
||||
<TimePicker v-model="selectedTime" :min-time="minTime" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-t border-n-strong">
|
||||
<CalendarFooter @change="onApply" @clear="onClear" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
+15
-1
@@ -1,4 +1,5 @@
|
||||
<script setup>
|
||||
import { startOfDay } from 'date-fns';
|
||||
import {
|
||||
monthName,
|
||||
yearName,
|
||||
@@ -28,6 +29,10 @@ const props = defineProps({
|
||||
selectingEndDate: Boolean,
|
||||
selectedEndDate: Date,
|
||||
hoveredEndDate: Date,
|
||||
minDate: {
|
||||
type: Date,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits([
|
||||
@@ -41,11 +46,18 @@ const emit = defineEmits([
|
||||
const { START_CALENDAR } = CALENDAR_TYPES;
|
||||
const { MONTH } = CALENDAR_PERIODS;
|
||||
|
||||
const isDayDisabled = day => {
|
||||
if (!props.minDate) return false;
|
||||
return startOfDay(day) < startOfDay(props.minDate);
|
||||
};
|
||||
|
||||
const emitHoveredEndDate = day => {
|
||||
if (isDayDisabled(day)) return;
|
||||
emit('updateHoveredEndDate', day);
|
||||
};
|
||||
|
||||
const emitSelectDate = day => {
|
||||
if (isDayDisabled(day)) return;
|
||||
emit('selectDate', day);
|
||||
};
|
||||
const onClickPrev = () => {
|
||||
@@ -108,8 +120,10 @@ const isNextDayInRange = day => {
|
||||
|
||||
const dayClasses = day => ({
|
||||
'text-n-slate-10 pointer-events-none': !isInCurrentMonth(day),
|
||||
'text-n-slate-10 pointer-events-none opacity-40':
|
||||
isInCurrentMonth(day) && isDayDisabled(day),
|
||||
'text-n-slate-12 hover:text-n-slate-12 hover:bg-n-blue-6 dark:hover:bg-n-blue-7':
|
||||
isInCurrentMonth(day),
|
||||
isInCurrentMonth(day) && !isDayDisabled(day),
|
||||
'bg-n-brand text-white':
|
||||
isSelectedStartOrEndDate(day) && isInCurrentMonth(day),
|
||||
'bg-n-blue-4 dark:bg-n-blue-5':
|
||||
@@ -0,0 +1,430 @@
|
||||
<script setup>
|
||||
import { ref, reactive, computed, watch, onMounted } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import TabBar from 'dashboard/components-next/tabbar/TabBar.vue';
|
||||
import {
|
||||
TIME_COLUMNS,
|
||||
TIME_PERIODS,
|
||||
TIME_FORMATS,
|
||||
} from '../helpers/DatePickerHelper';
|
||||
|
||||
const props = defineProps({
|
||||
minTime: { type: Date, default: null },
|
||||
});
|
||||
|
||||
const model = defineModel({
|
||||
type: Object,
|
||||
default: () => ({ hour: 9, minute: 0, second: 0 }),
|
||||
});
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const { HOUR, HOUR_12, MINUTE, SECOND, PERIOD } = TIME_COLUMNS;
|
||||
const { AM, PM } = TIME_PERIODS;
|
||||
const { H24, H12 } = TIME_FORMATS;
|
||||
|
||||
const ITEM_HEIGHT = 40;
|
||||
const CENTER_ROW = 2;
|
||||
const VISIBLE_ROWS = 5;
|
||||
const SNAP_DELAY = 120;
|
||||
const SEPARATOR = ':';
|
||||
|
||||
const is24HourFormat = ref(false);
|
||||
const selectedTime = reactive({
|
||||
hour: model.value.hour,
|
||||
minute: model.value.minute,
|
||||
second: model.value.second ?? 0,
|
||||
});
|
||||
const activeIndex = reactive({});
|
||||
const dragOffset = reactive({});
|
||||
const interactionMode = reactive({});
|
||||
const touchStartY = {};
|
||||
const snapTimers = {};
|
||||
const columnRefs = reactive({});
|
||||
const focusedColumn = ref(null);
|
||||
|
||||
const period = computed(() => (selectedTime.hour >= 12 ? PM : AM));
|
||||
const showPeriod = computed(() => !is24HourFormat.value);
|
||||
|
||||
const minBound = computed(() => {
|
||||
if (!props.minTime) return null;
|
||||
const d = props.minTime;
|
||||
return { h: d.getHours(), m: d.getMinutes(), s: d.getSeconds() };
|
||||
});
|
||||
|
||||
const toTimeNumber = (h, m, s) => h * 3600 + m * 60 + s;
|
||||
|
||||
const convertTo12Hour = hour => {
|
||||
if (hour === 0) return 12;
|
||||
return hour > 12 ? hour - 12 : hour;
|
||||
};
|
||||
|
||||
const convertTo24Hour = (hour12, timePeriod) => {
|
||||
if (timePeriod === AM) return hour12 === 12 ? 0 : hour12;
|
||||
return hour12 === 12 ? 12 : hour12 + 12;
|
||||
};
|
||||
|
||||
const isItemDisabled = (key, val) => {
|
||||
const mb = minBound.value;
|
||||
if (!mb) return false;
|
||||
const minVal = toTimeNumber(mb.h, mb.m, mb.s);
|
||||
const { hour, minute } = selectedTime;
|
||||
if (key === HOUR) return toTimeNumber(val, 0, 0) < toTimeNumber(mb.h, 0, 0);
|
||||
if (key === MINUTE) return toTimeNumber(hour, val, 0) < minVal;
|
||||
if (key === SECOND) return toTimeNumber(hour, minute, val) < minVal;
|
||||
return false;
|
||||
};
|
||||
|
||||
const formatLabel = value => String(value).padStart(2, '0');
|
||||
|
||||
const buildItems = (count, key) =>
|
||||
Array.from({ length: count }, (_, i) => ({
|
||||
value: i,
|
||||
label: formatLabel(i),
|
||||
disabled: isItemDisabled(key, i),
|
||||
}));
|
||||
|
||||
const buildHour12Items = () =>
|
||||
Array.from({ length: 12 }, (_, i) => {
|
||||
const display = i === 0 ? 12 : i;
|
||||
return {
|
||||
value: display,
|
||||
label: formatLabel(display),
|
||||
disabled: isItemDisabled(HOUR, convertTo24Hour(display, period.value)),
|
||||
};
|
||||
});
|
||||
|
||||
const periodItems = computed(() => [
|
||||
{ value: AM, label: AM, disabled: minBound.value?.h >= 12 },
|
||||
{ value: PM, label: PM, disabled: false },
|
||||
]);
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
key: is24HourFormat.value ? HOUR : HOUR_12,
|
||||
label: t('DATE_PICKER.HOUR'),
|
||||
items: is24HourFormat.value ? buildItems(24, HOUR) : buildHour12Items(),
|
||||
},
|
||||
{
|
||||
key: MINUTE,
|
||||
label: t('DATE_PICKER.MINUTE'),
|
||||
items: buildItems(60, MINUTE),
|
||||
},
|
||||
{
|
||||
key: SECOND,
|
||||
label: t('DATE_PICKER.SECOND'),
|
||||
items: buildItems(60, SECOND),
|
||||
},
|
||||
{ key: PERIOD, label: '', items: periodItems.value },
|
||||
]);
|
||||
|
||||
const findColumn = key => columns.value.find(c => c.key === key);
|
||||
|
||||
const findNearestEnabled = (items, index) => {
|
||||
for (let d = 0; d < items.length; d += 1) {
|
||||
if (index + d < items.length && !items[index + d].disabled)
|
||||
return index + d;
|
||||
if (index - d >= 0 && !items[index - d].disabled) return index - d;
|
||||
}
|
||||
return index;
|
||||
};
|
||||
|
||||
const getActiveIndex = key => {
|
||||
if (key === HOUR) return selectedTime.hour;
|
||||
if (key === HOUR_12) {
|
||||
const h = convertTo12Hour(selectedTime.hour);
|
||||
return h === 12 ? 0 : h;
|
||||
}
|
||||
if (key === PERIOD) return period.value === AM ? 0 : 1;
|
||||
return selectedTime[key];
|
||||
};
|
||||
|
||||
const getColumnTranslateY = key => {
|
||||
const idx = -(activeIndex[key] ?? 0) * ITEM_HEIGHT;
|
||||
return CENTER_ROW * ITEM_HEIGHT + idx + (dragOffset[key] ?? 0);
|
||||
};
|
||||
|
||||
const getMaxDragOffset = key => {
|
||||
const column = findColumn(key);
|
||||
if (!column) return { maxDown: 0, maxUp: 0 };
|
||||
const currentIdx = activeIndex[key] ?? 0;
|
||||
const firstEnabled = column.items.findIndex(i => !i.disabled);
|
||||
const lastEnabled = column.items.findLastIndex(i => !i.disabled);
|
||||
if (firstEnabled === -1) return { maxDown: 0, maxUp: 0 };
|
||||
return {
|
||||
maxDown: (currentIdx - firstEnabled) * ITEM_HEIGHT,
|
||||
maxUp: (lastEnabled - currentIdx) * ITEM_HEIGHT,
|
||||
};
|
||||
};
|
||||
|
||||
const clampDragOffset = (key, rawOffset) => {
|
||||
const { maxDown, maxUp } = getMaxDragOffset(key);
|
||||
return Math.max(-maxUp, Math.min(maxDown, rawOffset));
|
||||
};
|
||||
|
||||
let lastEmittedSignature = '';
|
||||
const emitTimeValue = () => {
|
||||
const sig = `${selectedTime.hour}:${selectedTime.minute}:${selectedTime.second}`;
|
||||
if (sig === lastEmittedSignature) return;
|
||||
lastEmittedSignature = sig;
|
||||
model.value = { ...selectedTime };
|
||||
};
|
||||
|
||||
const applySelection = (key, item) => {
|
||||
if (key === HOUR_12) {
|
||||
selectedTime.hour = convertTo24Hour(item.value, period.value);
|
||||
} else if (key === PERIOD) {
|
||||
selectedTime.hour = convertTo24Hour(
|
||||
convertTo12Hour(selectedTime.hour),
|
||||
item.value
|
||||
);
|
||||
} else {
|
||||
selectedTime[key] = item.value;
|
||||
}
|
||||
emitTimeValue();
|
||||
};
|
||||
|
||||
const selectIndex = (key, targetIndex) => {
|
||||
const column = findColumn(key);
|
||||
if (!column) return;
|
||||
const clamped = Math.max(0, Math.min(targetIndex, column.items.length - 1));
|
||||
const resolved = column.items[clamped]?.disabled
|
||||
? findNearestEnabled(column.items, clamped)
|
||||
: clamped;
|
||||
activeIndex[key] = resolved;
|
||||
const item = column.items[resolved];
|
||||
if (item) applySelection(key, item);
|
||||
};
|
||||
|
||||
const selectByValue = (key, value) => {
|
||||
const column = findColumn(key);
|
||||
if (!column) return;
|
||||
const idx = column.items.findIndex(i => i.value === value && !i.disabled);
|
||||
if (idx !== -1) selectIndex(key, idx);
|
||||
};
|
||||
|
||||
const snapToNearest = key => {
|
||||
const offset = dragOffset[key] ?? 0;
|
||||
const steps = Math.round(-offset / ITEM_HEIGHT);
|
||||
dragOffset[key] = 0;
|
||||
interactionMode[key] = null;
|
||||
if (steps !== 0) selectIndex(key, (activeIndex[key] ?? 0) + steps);
|
||||
};
|
||||
|
||||
const isItemSelected = (key, val) => {
|
||||
if (key === HOUR_12) return convertTo12Hour(selectedTime.hour) === val;
|
||||
if (key === PERIOD) return period.value === val;
|
||||
return selectedTime[key] === val;
|
||||
};
|
||||
|
||||
const isColumnHidden = key => key === PERIOD && !showPeriod.value;
|
||||
|
||||
const onWheelScroll = (key, event) => {
|
||||
event.preventDefault();
|
||||
interactionMode[key] = 'wheel';
|
||||
dragOffset[key] = clampDragOffset(key, (dragOffset[key] ?? 0) - event.deltaY);
|
||||
clearTimeout(snapTimers[key]);
|
||||
snapTimers[key] = setTimeout(() => snapToNearest(key), SNAP_DELAY);
|
||||
};
|
||||
|
||||
const onTouchStart = (key, event) => {
|
||||
interactionMode[key] = 'touch';
|
||||
touchStartY[key] = event.touches[0].clientY;
|
||||
dragOffset[key] = 0;
|
||||
};
|
||||
|
||||
const onTouchMove = (key, event) => {
|
||||
event.preventDefault();
|
||||
dragOffset[key] = clampDragOffset(
|
||||
key,
|
||||
event.touches[0].clientY - touchStartY[key]
|
||||
);
|
||||
};
|
||||
|
||||
const onTouchEnd = key => snapToNearest(key);
|
||||
|
||||
const visibleColumnKeys = computed(() =>
|
||||
columns.value.filter(col => !isColumnHidden(col.key)).map(col => col.key)
|
||||
);
|
||||
|
||||
const onKeyDown = (key, event) => {
|
||||
const { key: pressed, shiftKey } = event;
|
||||
if (pressed === 'ArrowUp' || pressed === 'ArrowDown') {
|
||||
event.preventDefault();
|
||||
selectIndex(
|
||||
key,
|
||||
(activeIndex[key] ?? 0) + (pressed === 'ArrowDown' ? 1 : -1)
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (pressed === 'Tab') {
|
||||
const keys = visibleColumnKeys.value;
|
||||
const next = keys.indexOf(key) + (shiftKey ? -1 : 1);
|
||||
if (next >= 0 && next < keys.length) {
|
||||
event.preventDefault();
|
||||
columnRefs[keys[next]]?.focus();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const syncAllColumns = () => {
|
||||
columns.value.forEach(col => {
|
||||
activeIndex[col.key] = getActiveIndex(col.key);
|
||||
});
|
||||
};
|
||||
|
||||
const formatTabs = [
|
||||
{ label: t('DATE_PICKER.FORMAT_24H'), value: H24 },
|
||||
{ label: t('DATE_PICKER.FORMAT_12H'), value: H12 },
|
||||
];
|
||||
const activeFormatTab = computed(() => (is24HourFormat.value ? 0 : 1));
|
||||
|
||||
const onFormatChange = tab => {
|
||||
is24HourFormat.value = tab.value === H24;
|
||||
syncAllColumns();
|
||||
};
|
||||
|
||||
watch(model, v => {
|
||||
selectedTime.hour = v.hour;
|
||||
selectedTime.minute = v.minute;
|
||||
selectedTime.second = v.second ?? 0;
|
||||
syncAllColumns();
|
||||
});
|
||||
|
||||
onMounted(syncAllColumns);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative flex flex-col items-center py-2 w-full">
|
||||
<div class="mb-4">
|
||||
<TabBar
|
||||
:tabs="formatTabs"
|
||||
:initial-active-tab="activeFormatTab"
|
||||
@tab-changed="onFormatChange"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center z-[1] mb-1">
|
||||
<template v-for="(col, colIdx) in columns" :key="`label-${col.key}`">
|
||||
<span
|
||||
class="text-center text-xs font-medium text-n-slate-11 transition-all duration-300 ease-in-out overflow-hidden"
|
||||
:class="
|
||||
isColumnHidden(col.key) ? 'w-0 opacity-0' : 'w-14 opacity-100'
|
||||
"
|
||||
>
|
||||
{{ col.label }}
|
||||
</span>
|
||||
<span
|
||||
v-if="colIdx < columns.length - 1"
|
||||
class="text-lg font-520 text-transparent transition-all duration-300 ease-in-out overflow-hidden"
|
||||
:class="
|
||||
isColumnHidden(columns[colIdx + 1]?.key)
|
||||
? 'w-0 opacity-0'
|
||||
: 'opacity-100'
|
||||
"
|
||||
>
|
||||
{{ SEPARATOR }}
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
<div class="relative w-full">
|
||||
<div
|
||||
class="absolute inset-x-6 h-10 rounded-2xl bg-n-solid-active outline outline-1 -outline-offset-1 outline-n-weak pointer-events-none shadow-inner"
|
||||
:style="{ top: `${CENTER_ROW * ITEM_HEIGHT}px` }"
|
||||
/>
|
||||
<div class="flex items-center justify-center z-[1] relative">
|
||||
<template v-for="(col, colIdx) in columns" :key="col.key">
|
||||
<div
|
||||
:ref="
|
||||
el => {
|
||||
if (el) columnRefs[col.key] = el;
|
||||
}
|
||||
"
|
||||
:tabindex="isColumnHidden(col.key) ? -1 : 0"
|
||||
class="time-wheel relative overflow-hidden transition-all duration-300 ease-in-out outline-none"
|
||||
:class="
|
||||
isColumnHidden(col.key) ? 'w-0 opacity-0' : 'w-14 opacity-100'
|
||||
"
|
||||
:style="{ height: `${VISIBLE_ROWS * ITEM_HEIGHT}px` }"
|
||||
@wheel.prevent="onWheelScroll(col.key, $event)"
|
||||
@touchstart="onTouchStart(col.key, $event)"
|
||||
@touchmove.prevent="onTouchMove(col.key, $event)"
|
||||
@touchend="onTouchEnd(col.key)"
|
||||
@keydown="onKeyDown(col.key, $event)"
|
||||
@focus="focusedColumn = col.key"
|
||||
@blur="focusedColumn = null"
|
||||
>
|
||||
<div
|
||||
class="flex flex-col items-center"
|
||||
:class="{
|
||||
'transition-transform duration-200 ease-out':
|
||||
!interactionMode[col.key],
|
||||
'transition-transform duration-100 ease-out':
|
||||
interactionMode[col.key] === 'wheel',
|
||||
}"
|
||||
:style="{
|
||||
transform: `translateY(${getColumnTranslateY(col.key)}px)`,
|
||||
}"
|
||||
>
|
||||
<button
|
||||
v-for="item in col.items"
|
||||
:key="item.value"
|
||||
:disabled="item.disabled"
|
||||
tabindex="-1"
|
||||
class="flex items-center justify-center w-14 shrink-0 text-base font-semibold transition-colors outline-none"
|
||||
:style="{ height: `${ITEM_HEIGHT}px` }"
|
||||
:class="[
|
||||
isItemSelected(col.key, item.value)
|
||||
? 'text-n-slate-12'
|
||||
: 'text-n-slate-9',
|
||||
item.disabled
|
||||
? 'opacity-20 cursor-not-allowed'
|
||||
: 'cursor-pointer',
|
||||
isItemSelected(col.key, item.value) &&
|
||||
focusedColumn === col.key
|
||||
? 'outline outline-1 outline-n-brand -outline-offset-4 rounded-xl'
|
||||
: '',
|
||||
]"
|
||||
@click="selectByValue(col.key, item.value)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
v-if="colIdx < columns.length - 1 && col.key !== SECOND"
|
||||
class="text-lg font-520 text-n-slate-11"
|
||||
>
|
||||
{{ SEPARATOR }}
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.time-wheel {
|
||||
mask-image: linear-gradient(
|
||||
to bottom,
|
||||
transparent 0%,
|
||||
rgba(0, 0, 0, 0.3) 15%,
|
||||
rgba(0, 0, 0, 0.7) 30%,
|
||||
black 40%,
|
||||
black 60%,
|
||||
rgba(0, 0, 0, 0.7) 70%,
|
||||
rgba(0, 0, 0, 0.3) 85%,
|
||||
transparent 100%
|
||||
);
|
||||
-webkit-mask-image: linear-gradient(
|
||||
to bottom,
|
||||
transparent 0%,
|
||||
rgba(0, 0, 0, 0.3) 15%,
|
||||
rgba(0, 0, 0, 0.7) 30%,
|
||||
black 40%,
|
||||
black 60%,
|
||||
rgba(0, 0, 0, 0.7) 70%,
|
||||
rgba(0, 0, 0, 0.3) 85%,
|
||||
transparent 100%
|
||||
);
|
||||
}
|
||||
</style>
|
||||
+18
@@ -81,6 +81,24 @@ export const CALENDAR_PERIODS = {
|
||||
YEAR: 'year',
|
||||
};
|
||||
|
||||
export const TIME_COLUMNS = {
|
||||
HOUR: 'hour',
|
||||
HOUR_12: 'hour12',
|
||||
MINUTE: 'minute',
|
||||
SECOND: 'second',
|
||||
PERIOD: 'period',
|
||||
};
|
||||
|
||||
export const TIME_PERIODS = {
|
||||
AM: 'AM',
|
||||
PM: 'PM',
|
||||
};
|
||||
|
||||
export const TIME_FORMATS = {
|
||||
H24: '24h',
|
||||
H12: '12h',
|
||||
};
|
||||
|
||||
// Utility functions for date operations
|
||||
export const monthName = currentDate => format(currentDate, 'MMMM');
|
||||
export const yearName = currentDate => format(currentDate, 'yyyy');
|
||||
@@ -107,7 +107,7 @@ defineExpose({ open, close });
|
||||
<TeleportWithDirection to="body">
|
||||
<dialog
|
||||
ref="dialogRef"
|
||||
class="w-full transition-all duration-300 ease-in-out shadow-xl rounded-xl"
|
||||
class="w-full transition-all duration-300 ease-in-out shadow-xl rounded-xl focus-within:outline-none focus-within:outline-0"
|
||||
:class="[
|
||||
maxWidthClass,
|
||||
positionClass,
|
||||
|
||||
@@ -1,77 +1,52 @@
|
||||
<script>
|
||||
import DatePicker from 'vue-datepicker-next';
|
||||
import NextButton from 'dashboard/components-next/button/Button.vue';
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import Dialog from 'dashboard/components-next/dialog/Dialog.vue';
|
||||
import DatePicker from 'dashboard/components-next/DatePicker/DatePicker.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
DatePicker,
|
||||
NextButton,
|
||||
},
|
||||
emits: ['close', 'chooseTime'],
|
||||
const emit = defineEmits(['chooseTime']);
|
||||
|
||||
data() {
|
||||
return {
|
||||
snoozeTime: null,
|
||||
lang: {
|
||||
days: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
||||
yearFormat: 'YYYY',
|
||||
monthFormat: 'MMMM',
|
||||
},
|
||||
};
|
||||
},
|
||||
const dialogRef = ref(null);
|
||||
const datePickerRef = ref(null);
|
||||
const today = new Date();
|
||||
|
||||
methods: {
|
||||
onClose() {
|
||||
this.$emit('close');
|
||||
},
|
||||
chooseTime() {
|
||||
this.$emit('chooseTime', this.snoozeTime);
|
||||
},
|
||||
disabledDate(date) {
|
||||
// Disable all the previous dates
|
||||
const yesterday = new Date();
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
return date < yesterday;
|
||||
},
|
||||
disabledTime(date) {
|
||||
// Allow only time after 1 hour
|
||||
const now = new Date();
|
||||
now.setHours(now.getHours() + 1);
|
||||
return date < now;
|
||||
},
|
||||
},
|
||||
const onApply = dateTime => {
|
||||
dialogRef.value?.close();
|
||||
emit('chooseTime', dateTime);
|
||||
};
|
||||
|
||||
const onClear = () => {
|
||||
dialogRef.value?.close();
|
||||
};
|
||||
|
||||
const onDialogClose = () => {
|
||||
datePickerRef.value?.resetState();
|
||||
};
|
||||
|
||||
const open = () => {
|
||||
dialogRef.value?.open();
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
dialogRef.value?.close();
|
||||
};
|
||||
|
||||
defineExpose({ open, close });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col">
|
||||
<woot-modal-header :header-title="$t('CONVERSATION.CUSTOM_SNOOZE.TITLE')" />
|
||||
<form
|
||||
class="modal-content w-full pt-2 px-5 pb-6"
|
||||
@submit.prevent="chooseTime"
|
||||
>
|
||||
<DatePicker
|
||||
v-model:value="snoozeTime"
|
||||
type="datetime"
|
||||
inline
|
||||
input-class="mx-input "
|
||||
:lang="lang"
|
||||
:disabled-date="disabledDate"
|
||||
:disabled-time="disabledTime"
|
||||
/>
|
||||
<div class="flex flex-row justify-end w-full gap-2 px-0 py-2">
|
||||
<NextButton
|
||||
faded
|
||||
slate
|
||||
type="reset"
|
||||
:label="$t('CONVERSATION.CUSTOM_SNOOZE.CANCEL')"
|
||||
@click.prevent="onClose"
|
||||
/>
|
||||
<NextButton
|
||||
type="submit"
|
||||
:label="$t('CONVERSATION.CUSTOM_SNOOZE.APPLY')"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<Dialog
|
||||
ref="dialogRef"
|
||||
:title="$t('CONVERSATION.CUSTOM_SNOOZE.TITLE')"
|
||||
:show-confirm-button="false"
|
||||
:show-cancel-button="false"
|
||||
width="2xl"
|
||||
@close="onDialogClose"
|
||||
>
|
||||
<DatePicker
|
||||
ref="datePickerRef"
|
||||
:min-date="today"
|
||||
@apply="onApply"
|
||||
@clear="onClear"
|
||||
/>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
@@ -17,7 +17,6 @@ import Modal from './Modal.vue';
|
||||
import Spinner from 'shared/components/Spinner.vue';
|
||||
import Tabs from './ui/Tabs/Tabs.vue';
|
||||
import TabsItem from './ui/Tabs/TabsItem.vue';
|
||||
import DatePicker from './ui/DatePicker/DatePicker.vue';
|
||||
|
||||
const WootUIKit = {
|
||||
Code,
|
||||
@@ -37,7 +36,6 @@ const WootUIKit = {
|
||||
Spinner,
|
||||
Tabs,
|
||||
TabsItem,
|
||||
DatePicker,
|
||||
install(Vue) {
|
||||
const keys = Object.keys(this);
|
||||
keys.pop(); // remove 'install' from keys
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
<script>
|
||||
import DatePicker from 'vue-datepicker-next';
|
||||
export default {
|
||||
components: { DatePicker },
|
||||
props: {
|
||||
confirmText: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
emits: ['change'],
|
||||
methods: {
|
||||
handleChange(value) {
|
||||
this.$emit('change', value);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="date-picker">
|
||||
<DatePicker
|
||||
range
|
||||
confirm
|
||||
:clearable="false"
|
||||
:editable="false"
|
||||
:confirm-text="confirmText"
|
||||
:placeholder="placeholder"
|
||||
:value="value"
|
||||
@change="handleChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,48 +0,0 @@
|
||||
<script>
|
||||
import addDays from 'date-fns/addDays';
|
||||
import DatePicker from 'vue-datepicker-next';
|
||||
export default {
|
||||
components: { DatePicker },
|
||||
props: {
|
||||
confirmText: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
value: {
|
||||
type: Date,
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
emits: ['change'],
|
||||
|
||||
methods: {
|
||||
handleChange(value) {
|
||||
this.$emit('change', value);
|
||||
},
|
||||
disableBeforeToday(date) {
|
||||
const yesterdayDate = addDays(new Date(), -1);
|
||||
return date < yesterdayDate;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="date-picker">
|
||||
<DatePicker
|
||||
type="datetime"
|
||||
confirm
|
||||
:clearable="false"
|
||||
:editable="false"
|
||||
:confirm-text="confirmText"
|
||||
:placeholder="placeholder"
|
||||
:value="value"
|
||||
:disabled-date="disableBeforeToday"
|
||||
@change="handleChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
+2
-15
@@ -65,7 +65,6 @@ export default {
|
||||
showLabelActions: false,
|
||||
showTeamsList: false,
|
||||
popoverPositions: {},
|
||||
showCustomTimeSnoozeModal: false,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
@@ -99,7 +98,7 @@ export default {
|
||||
methods: {
|
||||
onCmdSnoozeConversation(snoozeType) {
|
||||
if (snoozeType === wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME) {
|
||||
this.showCustomTimeSnoozeModal = true;
|
||||
this.$refs.snoozeModalRef?.open();
|
||||
} else if (typeof snoozeType === 'number') {
|
||||
this.updateConversations('snoozed', snoozeType);
|
||||
} else {
|
||||
@@ -113,14 +112,10 @@ export default {
|
||||
this.updateConversations('resolved', null);
|
||||
},
|
||||
customSnoozeTime(customSnoozedTime) {
|
||||
this.showCustomTimeSnoozeModal = false;
|
||||
if (customSnoozedTime) {
|
||||
this.updateConversations('snoozed', getUnixTime(customSnoozedTime));
|
||||
}
|
||||
},
|
||||
hideCustomSnoozeModal() {
|
||||
this.showCustomTimeSnoozeModal = false;
|
||||
},
|
||||
selectAll(e) {
|
||||
this.$emit('selectAllConversations', e.target.checked);
|
||||
},
|
||||
@@ -251,15 +246,7 @@ export default {
|
||||
<div v-if="allConversationsSelected" class="bulk-action__alert">
|
||||
{{ $t('BULK_ACTION.ALL_CONVERSATIONS_SELECTED_ALERT') }}
|
||||
</div>
|
||||
<woot-modal
|
||||
v-model:show="showCustomTimeSnoozeModal"
|
||||
:on-close="hideCustomSnoozeModal"
|
||||
>
|
||||
<CustomSnoozeModal
|
||||
@close="hideCustomSnoozeModal"
|
||||
@choose-time="customSnoozeTime"
|
||||
/>
|
||||
</woot-modal>
|
||||
<CustomSnoozeModal ref="snoozeModalRef" @choose-time="customSnoozeTime" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
"WEEK_NUMBER": "Week #{weekNumber}",
|
||||
"APPLY_BUTTON": "Apply",
|
||||
"CLEAR_BUTTON": "Clear",
|
||||
"HOUR": "Hour",
|
||||
"MINUTE": "Min",
|
||||
"SECOND": "Sec",
|
||||
"FORMAT_12H": "12h",
|
||||
"FORMAT_24H": "24h",
|
||||
"DATE_RANGE_INPUT": {
|
||||
"START": "Start Date",
|
||||
"END": "End Date"
|
||||
|
||||
@@ -13,7 +13,7 @@ import CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal.vue';
|
||||
const store = useStore();
|
||||
const getters = useStoreGetters();
|
||||
const { t } = useI18n();
|
||||
const showCustomSnoozeModal = ref(false);
|
||||
const snoozeModalRef = ref(null);
|
||||
|
||||
const selectedChat = computed(() => getters.getSelectedChat.value);
|
||||
const contextMenuChatId = computed(() => getters.getContextMenuChatId.value);
|
||||
@@ -30,7 +30,7 @@ const toggleStatus = async (status, snoozedUntil) => {
|
||||
|
||||
const onCmdSnoozeConversation = snoozeType => {
|
||||
if (snoozeType === wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME) {
|
||||
showCustomSnoozeModal.value = true;
|
||||
snoozeModalRef.value?.open();
|
||||
} else if (typeof snoozeType === 'number') {
|
||||
toggleStatus(wootConstants.STATUS_TYPE.SNOOZED, snoozeType);
|
||||
} else {
|
||||
@@ -42,7 +42,7 @@ const onCmdSnoozeConversation = snoozeType => {
|
||||
};
|
||||
|
||||
const chooseSnoozeTime = customSnoozeTime => {
|
||||
showCustomSnoozeModal.value = false;
|
||||
store.dispatch('setContextMenuChatId', null);
|
||||
if (customSnoozeTime) {
|
||||
toggleStatus(
|
||||
wootConstants.STATUS_TYPE.SNOOZED,
|
||||
@@ -51,24 +51,9 @@ const chooseSnoozeTime = customSnoozeTime => {
|
||||
}
|
||||
};
|
||||
|
||||
const hideCustomSnoozeModal = () => {
|
||||
// if we select custom snooze and the custom snooze modal is open
|
||||
// Then if the custom snooze modal is closed then set the context menu chat id to null
|
||||
store.dispatch('setContextMenuChatId', null);
|
||||
showCustomSnoozeModal.value = false;
|
||||
};
|
||||
|
||||
useEmitter(CMD_SNOOZE_CONVERSATION, onCmdSnoozeConversation);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<woot-modal
|
||||
v-model:show="showCustomSnoozeModal"
|
||||
:on-close="hideCustomSnoozeModal"
|
||||
>
|
||||
<CustomSnoozeModal
|
||||
@close="hideCustomSnoozeModal"
|
||||
@choose-time="chooseSnoozeTime"
|
||||
/>
|
||||
</woot-modal>
|
||||
<CustomSnoozeModal ref="snoozeModalRef" @choose-time="chooseSnoozeTime" />
|
||||
</template>
|
||||
|
||||
@@ -34,9 +34,6 @@ export default {
|
||||
},
|
||||
},
|
||||
emits: ['next', 'prev'],
|
||||
data() {
|
||||
return { showCustomSnoozeModal: false };
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({ meta: 'notifications/getMeta' }),
|
||||
},
|
||||
@@ -51,9 +48,6 @@ export default {
|
||||
const ninja = document.querySelector('ninja-keys');
|
||||
ninja.open({ parent: 'snooze_notification' });
|
||||
},
|
||||
hideCustomSnoozeModal() {
|
||||
this.showCustomSnoozeModal = false;
|
||||
},
|
||||
async snoozeNotification(snoozedUntil) {
|
||||
try {
|
||||
await this.$store.dispatch('notifications/snooze', {
|
||||
@@ -68,7 +62,7 @@ export default {
|
||||
},
|
||||
onCmdSnoozeNotification(snoozeType) {
|
||||
if (snoozeType === wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME) {
|
||||
this.showCustomSnoozeModal = true;
|
||||
this.$refs.snoozeModalRef?.open();
|
||||
} else if (typeof snoozeType === 'number') {
|
||||
this.snoozeNotification(snoozeType);
|
||||
} else {
|
||||
@@ -77,7 +71,6 @@ export default {
|
||||
}
|
||||
},
|
||||
scheduleCustomSnooze(customSnoozeTime) {
|
||||
this.showCustomSnoozeModal = false;
|
||||
if (customSnoozeTime) {
|
||||
const snoozedUntil = getUnixTime(customSnoozeTime) || null;
|
||||
this.snoozeNotification(snoozedUntil);
|
||||
@@ -147,14 +140,9 @@ export default {
|
||||
@click="deleteNotification"
|
||||
/>
|
||||
</div>
|
||||
<woot-modal
|
||||
v-model:show="showCustomSnoozeModal"
|
||||
:on-close="hideCustomSnoozeModal"
|
||||
>
|
||||
<CustomSnoozeModal
|
||||
@close="hideCustomSnoozeModal"
|
||||
@choose-time="scheduleCustomSnooze"
|
||||
/>
|
||||
</woot-modal>
|
||||
<CustomSnoozeModal
|
||||
ref="snoozeModalRef"
|
||||
@choose-time="scheduleCustomSnooze"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
+3
-3
@@ -14,13 +14,13 @@ import {
|
||||
import FilterButton from 'dashboard/components/ui/Dropdown/DropdownButton.vue';
|
||||
import ActiveFilterChip from '../Filters/v3/ActiveFilterChip.vue';
|
||||
import AddFilterChip from '../Filters/v3/AddFilterChip.vue';
|
||||
import WootDatePicker from 'dashboard/components/ui/DatePicker/DatePicker.vue';
|
||||
import DateRangePicker from 'dashboard/components-next/DatePicker/DateRangePicker.vue';
|
||||
import {
|
||||
parseReportURLParams,
|
||||
parseFilterURLParams,
|
||||
generateCompleteURLParams,
|
||||
} from '../../helpers/reportFilterHelper';
|
||||
import { DATE_RANGE_TYPES } from 'dashboard/components/ui/DatePicker/helpers/DatePickerHelper';
|
||||
import { DATE_RANGE_TYPES } from 'dashboard/components-next/DatePicker/helpers/DatePickerHelper.js';
|
||||
|
||||
const props = defineProps({
|
||||
showTeamFilter: {
|
||||
@@ -254,7 +254,7 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col flex-wrap w-full gap-3 md:flex-row">
|
||||
<WootDatePicker
|
||||
<DateRangePicker
|
||||
v-model:date-range="customDateRange"
|
||||
v-model:range-type="selectedDateRange"
|
||||
@date-range-changed="onDateRangeChange"
|
||||
|
||||
+3
-3
@@ -3,13 +3,13 @@ import { ref, onMounted } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { getUnixStartOfDay, getUnixEndOfDay } from 'helpers/DateHelper';
|
||||
import subDays from 'date-fns/subDays';
|
||||
import WootDatePicker from 'dashboard/components/ui/DatePicker/DatePicker.vue';
|
||||
import DateRangePicker from 'dashboard/components-next/DatePicker/DateRangePicker.vue';
|
||||
import ToggleSwitch from 'dashboard/components-next/switch/Switch.vue';
|
||||
import {
|
||||
generateReportURLParams,
|
||||
parseReportURLParams,
|
||||
} from '../helpers/reportFilterHelper';
|
||||
import { DATE_RANGE_TYPES } from 'dashboard/components/ui/DatePicker/helpers/DatePickerHelper';
|
||||
import { DATE_RANGE_TYPES } from 'dashboard/components-next/DatePicker/helpers/DatePickerHelper.js';
|
||||
|
||||
defineProps({
|
||||
disabled: {
|
||||
@@ -91,7 +91,7 @@ onMounted(() => {
|
||||
:class="{ 'pointer-events-none opacity-50': disabled }"
|
||||
>
|
||||
<div class="flex flex-col flex-wrap items-start gap-2 md:flex-row">
|
||||
<WootDatePicker
|
||||
<DateRangePicker
|
||||
v-model:date-range="customDateRange"
|
||||
v-model:range-type="selectedDateRange"
|
||||
@date-range-changed="onDateRangeChange"
|
||||
|
||||
+3
-3
@@ -7,10 +7,10 @@ import { getUnixStartOfDay, getUnixEndOfDay } from 'helpers/DateHelper';
|
||||
import subDays from 'date-fns/subDays';
|
||||
import differenceInDays from 'date-fns/differenceInDays';
|
||||
import ActiveFilterChip from './Filters/v3/ActiveFilterChip.vue';
|
||||
import WootDatePicker from 'dashboard/components/ui/DatePicker/DatePicker.vue';
|
||||
import DateRangePicker from 'dashboard/components-next/DatePicker/DateRangePicker.vue';
|
||||
import ToggleSwitch from 'dashboard/components-next/switch/Switch.vue';
|
||||
import { GROUP_BY_FILTER } from '../constants';
|
||||
import { DATE_RANGE_TYPES } from 'dashboard/components/ui/DatePicker/helpers/DatePickerHelper';
|
||||
import { DATE_RANGE_TYPES } from 'dashboard/components-next/DatePicker/helpers/DatePickerHelper.js';
|
||||
import {
|
||||
generateReportURLParams,
|
||||
parseReportURLParams,
|
||||
@@ -320,7 +320,7 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col w-full gap-3 lg:flex-row">
|
||||
<WootDatePicker
|
||||
<DateRangePicker
|
||||
v-model:date-range="customDateRange"
|
||||
v-model:range-type="selectedDateRange"
|
||||
@date-range-changed="onDateRangeChange"
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import SLAFilter from '../SLA/SLAFilter.vue';
|
||||
import WootDatePicker from 'dashboard/components/ui/DatePicker/DatePicker.vue';
|
||||
import DateRangePicker from 'dashboard/components-next/DatePicker/DateRangePicker.vue';
|
||||
import { subDays, fromUnixTime } from 'date-fns';
|
||||
import { getUnixStartOfDay, getUnixEndOfDay } from 'helpers/DateHelper';
|
||||
import {
|
||||
@@ -88,7 +88,7 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col flex-wrap w-full gap-3 md:flex-row">
|
||||
<WootDatePicker
|
||||
<DateRangePicker
|
||||
v-model:date-range="customDateRange"
|
||||
v-model:range-type="selectedDateRange"
|
||||
@date-range-changed="onDateRangeChange"
|
||||
|
||||
Reference in New Issue
Block a user