Files
chrono/src/components/editors/EventEditorDates.vue
T
2026-02-10 20:08:03 -05:00

191 lines
4.9 KiB
Vue

<script setup lang="ts">
import { ref, computed, watch } from 'vue'
interface Props {
mode: 'edit' | 'view'
startsOn?: string | null
endsOn?: string | null
timeless?: boolean | null
timeZone?: string | null
}
const props = defineProps<Props>()
const emit = defineEmits<{
'update:startsOn': [date: string | null]
'update:endsOn': [date: string | null]
'update:timeless': [timeless: boolean | null]
'update:timeZone': [timeZone: string | null]
}>()
const timelessValue = computed({
get: () => props.timeless ?? false,
set: (value) => emit('update:timeless', value)
})
const timeZoneValue = computed({
get: () => props.timeZone ?? '',
set: (value) => emit('update:timeZone', value || null)
})
// Format helpers
const formatDate = (date: Date): string => {
return date.toISOString().split('T')[0]
}
const formatTime = (date: Date): string => {
return date.toTimeString().slice(0, 5)
}
const formatDateTime = (isoString: string | null | undefined): string => {
if (!isoString) return 'Not set'
const date = new Date(isoString)
return date.toLocaleString()
}
const parseDateTime = (date: string, time: string): Date => {
if (timelessValue.value) {
return new Date(date)
}
return new Date(`${date}T${time}`)
}
// Date/time fields
const startDate = ref('')
const startTime = ref('')
const endDate = ref('')
const endTime = ref('')
// Initialize date/time from props
watch(() => props.startsOn, (newValue) => {
if (newValue) {
const start = new Date(newValue)
startDate.value = formatDate(start)
startTime.value = formatTime(start)
} else {
const now = new Date()
startDate.value = formatDate(now)
startTime.value = formatTime(now)
}
}, { immediate: true })
watch(() => props.endsOn, (newValue) => {
if (newValue) {
const end = new Date(newValue)
endDate.value = formatDate(end)
endTime.value = formatTime(end)
} else {
const later = new Date(Date.now() + 60 * 60 * 1000)
endDate.value = formatDate(later)
endTime.value = formatTime(later)
}
}, { immediate: true })
// Update parent when date/time changes
watch([startDate, startTime], () => {
if (props.mode === 'edit') {
emit('update:startsOn', parseDateTime(startDate.value, startTime.value).toISOString())
}
})
watch([endDate, endTime], () => {
if (props.mode === 'edit') {
emit('update:endsOn', parseDateTime(endDate.value, endTime.value).toISOString())
}
})
</script>
<template>
<div class="event-editor-section">
<div class="text-subtitle-1 mb-2">Date & Time</div>
<!-- Read-only view -->
<div v-if="mode === 'view'">
<div class="mb-2 pa-2">
<div class="mb-1"><strong>Starts:</strong> {{ formatDateTime(startsOn) }}</div>
<div class="mb-1"><strong>Ends:</strong> {{ formatDateTime(endsOn) }}</div>
<div v-if="timelessValue" class="mb-1">
<v-chip size="small" color="info" variant="tonal">
<v-icon start size="small">mdi-calendar-blank</v-icon>
All Day Event
</v-chip>
</div>
<div v-if="timeZoneValue" class="text-caption text-grey">Time Zone: {{ timeZoneValue }}</div>
</div>
</div>
<!-- Edit view -->
<div v-else>
<v-checkbox
v-model="timelessValue"
label="All day event"
density="compact"
class="mb-2"
/>
<div class="mb-3">
<div class="text-subtitle-2 mb-2">Start</div>
<v-row dense>
<v-col cols="12" md="6">
<v-text-field
v-model="startDate"
label="Start Date"
type="date"
variant="outlined"
density="compact"
/>
</v-col>
<v-col v-if="!timelessValue" cols="12" md="6">
<v-text-field
v-model="startTime"
label="Start Time"
type="time"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
</div>
<div class="mb-3">
<div class="text-subtitle-2 mb-2">End</div>
<v-row dense>
<v-col cols="12" md="6">
<v-text-field
v-model="endDate"
label="End Date"
type="date"
variant="outlined"
density="compact"
/>
</v-col>
<v-col v-if="!timelessValue" cols="12" md="6">
<v-text-field
v-model="endTime"
label="End Time"
type="time"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
</div>
<v-text-field
v-model="timeZoneValue"
label="Time Zone"
variant="outlined"
density="compact"
hint="e.g., America/New_York"
persistent-hint
/>
</div>
</div>
</template>
<style scoped>
.event-editor-section {
margin-bottom: 1.5rem;
}
</style>