first commit
This commit is contained in:
132
app/components/home/HomeDateRangePicker.vue
Normal file
132
app/components/home/HomeDateRangePicker.vue
Normal file
@@ -0,0 +1,132 @@
|
||||
<script setup lang="ts">
|
||||
import { DateFormatter, getLocalTimeZone, CalendarDate, today } from '@internationalized/date'
|
||||
import type { Range } from '~/types'
|
||||
|
||||
const df = new DateFormatter('en-US', {
|
||||
dateStyle: 'medium'
|
||||
})
|
||||
|
||||
const selected = defineModel<Range>({ required: true })
|
||||
|
||||
const ranges = [
|
||||
{ label: 'Last 7 days', days: 7 },
|
||||
{ label: 'Last 14 days', days: 14 },
|
||||
{ label: 'Last 30 days', days: 30 },
|
||||
{ label: 'Last 3 months', months: 3 },
|
||||
{ label: 'Last 6 months', months: 6 },
|
||||
{ label: 'Last year', years: 1 }
|
||||
]
|
||||
|
||||
const toCalendarDate = (date: Date) => {
|
||||
return new CalendarDate(
|
||||
date.getFullYear(),
|
||||
date.getMonth() + 1,
|
||||
date.getDate()
|
||||
)
|
||||
}
|
||||
|
||||
const calendarRange = computed({
|
||||
get: () => ({
|
||||
start: selected.value.start ? toCalendarDate(selected.value.start) : undefined,
|
||||
end: selected.value.end ? toCalendarDate(selected.value.end) : undefined
|
||||
}),
|
||||
set: (newValue: { start: CalendarDate | null, end: CalendarDate | null }) => {
|
||||
selected.value = {
|
||||
start: newValue.start ? newValue.start.toDate(getLocalTimeZone()) : new Date(),
|
||||
end: newValue.end ? newValue.end.toDate(getLocalTimeZone()) : new Date()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const isRangeSelected = (range: { days?: number, months?: number, years?: number }) => {
|
||||
if (!selected.value.start || !selected.value.end) return false
|
||||
|
||||
const currentDate = today(getLocalTimeZone())
|
||||
let startDate = currentDate.copy()
|
||||
|
||||
if (range.days) {
|
||||
startDate = startDate.subtract({ days: range.days })
|
||||
} else if (range.months) {
|
||||
startDate = startDate.subtract({ months: range.months })
|
||||
} else if (range.years) {
|
||||
startDate = startDate.subtract({ years: range.years })
|
||||
}
|
||||
|
||||
const selectedStart = toCalendarDate(selected.value.start)
|
||||
const selectedEnd = toCalendarDate(selected.value.end)
|
||||
|
||||
return selectedStart.compare(startDate) === 0 && selectedEnd.compare(currentDate) === 0
|
||||
}
|
||||
|
||||
const selectRange = (range: { days?: number, months?: number, years?: number }) => {
|
||||
const endDate = today(getLocalTimeZone())
|
||||
let startDate = endDate.copy()
|
||||
|
||||
if (range.days) {
|
||||
startDate = startDate.subtract({ days: range.days })
|
||||
} else if (range.months) {
|
||||
startDate = startDate.subtract({ months: range.months })
|
||||
} else if (range.years) {
|
||||
startDate = startDate.subtract({ years: range.years })
|
||||
}
|
||||
|
||||
selected.value = {
|
||||
start: startDate.toDate(getLocalTimeZone()),
|
||||
end: endDate.toDate(getLocalTimeZone())
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UPopover :content="{ align: 'start' }" :modal="true">
|
||||
<UButton
|
||||
color="neutral"
|
||||
variant="ghost"
|
||||
icon="i-lucide-calendar"
|
||||
class="data-[state=open]:bg-elevated group"
|
||||
>
|
||||
<span class="truncate">
|
||||
<template v-if="selected.start">
|
||||
<template v-if="selected.end">
|
||||
{{ df.format(selected.start) }} - {{ df.format(selected.end) }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ df.format(selected.start) }}
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
Pick a date
|
||||
</template>
|
||||
</span>
|
||||
|
||||
<template #trailing>
|
||||
<UIcon name="i-lucide-chevron-down" class="shrink-0 text-dimmed size-5 group-data-[state=open]:rotate-180 transition-transform duration-200" />
|
||||
</template>
|
||||
</UButton>
|
||||
|
||||
<template #content>
|
||||
<div class="flex items-stretch sm:divide-x divide-default">
|
||||
<div class="hidden sm:flex flex-col justify-center">
|
||||
<UButton
|
||||
v-for="(range, index) in ranges"
|
||||
:key="index"
|
||||
:label="range.label"
|
||||
color="neutral"
|
||||
variant="ghost"
|
||||
class="rounded-none px-4"
|
||||
:class="[isRangeSelected(range) ? 'bg-elevated' : 'hover:bg-elevated/50']"
|
||||
truncate
|
||||
@click="selectRange(range)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<UCalendar
|
||||
v-model="calendarRange"
|
||||
class="p-2"
|
||||
:number-of-months="2"
|
||||
range
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</UPopover>
|
||||
</template>
|
||||
Reference in New Issue
Block a user