added dialog for creating events
This commit is contained in:
@@ -4,10 +4,32 @@ import CalendarHeader from './CalendarHeader.vue';
|
||||
import CalendarCollumn from './CalendarCollumn.vue';
|
||||
import { Event } from '~/utils/event';
|
||||
import { DateTime } from 'luxon';
|
||||
import { UTextarea } from '#components';
|
||||
|
||||
const events = defineModel<Event[]>('events', { required: true })
|
||||
const date = defineModel<DateTime>('date', { required: true })
|
||||
const draggedEvent = ref<DraggedEvent | undefined>()
|
||||
const createModalOpened = ref(false)
|
||||
const createContext = ref<{ date: DateTime, timespan: Timespan } | undefined>(undefined)
|
||||
const createModal = {
|
||||
open: ref(false),
|
||||
fromTimeField: ref<string>(''),
|
||||
toTimeField: ref<string>(''),
|
||||
toDateField: ref<string>(''),
|
||||
fromDateField: ref<string>(''),
|
||||
nameField: ref<string>(''),
|
||||
descriptionField: ref<string>(''),
|
||||
clear: () => {
|
||||
createModal.nameField.value = ''
|
||||
createModal.fromDateField.value = ''
|
||||
createModal.toDateField.value = ''
|
||||
createModal.fromTimeField.value = ''
|
||||
createModal.toTimeField.value = ''
|
||||
createModal.descriptionField.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
const toast = useToast()
|
||||
|
||||
type Day = {
|
||||
date: DateTime
|
||||
@@ -87,33 +109,94 @@ const seperators = ref<Seperator[]>([
|
||||
{ text: '9 PM', time: hour(21) },
|
||||
])
|
||||
|
||||
|
||||
function quickCreate(date: DateTime, timespan: Timespan) {
|
||||
const eventTitle = prompt("Event title")
|
||||
|
||||
if (eventTitle === null) {
|
||||
return
|
||||
function openCreateModal(date: DateTime, timespan: Timespan) {
|
||||
createContext.value = {
|
||||
date: date,
|
||||
timespan: timespan
|
||||
}
|
||||
|
||||
const newEvent: Event = new Event(
|
||||
eventTitle,
|
||||
date.startOf('day').plus({ minutes: timespan.from * 24 * 60 }),
|
||||
date.startOf('day').plus({ minutes: timespan.to * 24 * 60 })
|
||||
)
|
||||
const from = date.startOf('day').plus({ minutes: timespan.from * 24 * 60 })
|
||||
const to = date.startOf('day').plus({ minutes: timespan.to * 24 * 60 })
|
||||
|
||||
emits('create', newEvent)
|
||||
events.value.push(newEvent)
|
||||
createModal.fromDateField.value = from.toISODate() ?? ''
|
||||
createModal.toDateField.value = to.toISODate() ?? ''
|
||||
createModal.fromTimeField.value = from.toFormat('HH:mm')
|
||||
createModal.toTimeField.value = to.toFormat('HH:mm')
|
||||
createModal.open.value = true
|
||||
}
|
||||
|
||||
function create() {
|
||||
const from = dateFromFields(createModal.fromDateField.value, createModal.fromTimeField.value)
|
||||
const to = dateFromFields(createModal.toDateField.value, createModal.toTimeField.value)
|
||||
|
||||
if (!from.isValid) {
|
||||
toast.add({
|
||||
title: 'Invalid `from` date format'
|
||||
})
|
||||
}
|
||||
|
||||
if (!to.isValid) {
|
||||
toast.add({
|
||||
title: 'Invalid `to` date format'
|
||||
})
|
||||
}
|
||||
|
||||
if (createModal.nameField.value.trim() === '') {
|
||||
toast.add({
|
||||
title: 'Name is required'
|
||||
})
|
||||
}
|
||||
|
||||
const event = new Event(createModal.nameField.value, from, to, createModal.descriptionField.value)
|
||||
emits('create', event)
|
||||
createModal.clear()
|
||||
createModal.open.value = false
|
||||
events.value.push(event)
|
||||
}
|
||||
|
||||
function dateFromFields(date: string, time: string) {
|
||||
return DateTime.fromFormat(`${date} ${time}`, 'yyyy-MM-dd HH:mm')
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-full h-full flex flex-col">
|
||||
<UModal v-model:open="createModal.open.value" title="Create Event"
|
||||
description="Set name and change time of event before creation">
|
||||
<template #body>
|
||||
<div class="flex flex-col gap-2">
|
||||
<UInput type="text" placeholder="Name" v-model="createModal.nameField.value" required />
|
||||
<div class="flex flex-row gap-2">
|
||||
<UInput class="grow" placeholder="2025-06-16" v-model="createModal.fromDateField.value"
|
||||
icon="i-lucide-calendar" required />
|
||||
<UInput class="grow" placeholder="15:34" v-model="createModal.fromTimeField.value"
|
||||
icon="i-lucide-clock" required />
|
||||
</div>
|
||||
<div class="flex flex-row gap-2">
|
||||
<UInput class="grow" placeholder="2025-06-16" v-model="createModal.toDateField.value"
|
||||
icon="i-lucide-calendar" required />
|
||||
<UInput class="grow" placeholder="15:34" v-model="createModal.toTimeField.value"
|
||||
icon="i-lucide-clock" required />
|
||||
</div>
|
||||
<UTextarea type="text" placeholder="Description" v-model="createModal.descriptionField.value"
|
||||
required />
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<UButton variant="solid" @click="create">
|
||||
Create
|
||||
</UButton>
|
||||
<UButton variant="soft">
|
||||
Cancel
|
||||
</UButton>
|
||||
</template>
|
||||
</UModal>
|
||||
<div class="calendar flex flex-row w-full flex-1 items-stretch divide-x divide-muted">
|
||||
<CalendarHeader :seperators="seperators" />
|
||||
|
||||
<CalendarCollumn v-for="day in days" :seperators="seperators" :day="day.date" :events="day.events"
|
||||
:date="date" v-model:draggedEvent="draggedEvent" @quick-create="quickCreate" />
|
||||
:date="date" v-model:draggedEvent="draggedEvent" @quick-create="openCreateModal" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,8 @@ export class Event {
|
||||
constructor(
|
||||
public readonly title: string,
|
||||
public from: DateTime,
|
||||
public to: DateTime
|
||||
public to: DateTime,
|
||||
public description: string
|
||||
) { }
|
||||
|
||||
|
||||
@@ -29,28 +30,29 @@ export class Event {
|
||||
}
|
||||
|
||||
static fromSimple(event: SimpleEvent): Event {
|
||||
return new Event(event.title, event.from, event.to)
|
||||
return new Event(event.title, event.from, event.to, event.description)
|
||||
}
|
||||
|
||||
static fromSerializable(event: SerializableEvent) {
|
||||
return new Event(event.title, DateTime.fromISO(event.from), DateTime.fromISO(event.to))
|
||||
return new Event(event.title, DateTime.fromISO(event.from), DateTime.fromISO(event.to), event.description)
|
||||
}
|
||||
|
||||
static fromPercentDimensions(title: string, dimensions: EventDimensions, date: DateTime): Event {
|
||||
static fromPercentDimensions(title: string, dimensions: EventDimensions, date: DateTime, description: string): Event {
|
||||
return new Event(
|
||||
title,
|
||||
date.startOf('day').plus({ minutes: (dimensions.from / 100) * Event.MINUTES_IN_DAY }),
|
||||
date.startOf('day').plus({ minutes: (dimensions.to / 100) * Event.MINUTES_IN_DAY })
|
||||
date.startOf('day').plus({ minutes: (dimensions.to / 100) * Event.MINUTES_IN_DAY }),
|
||||
description
|
||||
)
|
||||
}
|
||||
|
||||
static fromPixelDimensions(title: string, dimensions: EventDimensions, height: number, date: DateTime): Event {
|
||||
static fromPixelDimensions(title: string, dimensions: EventDimensions, height: number, date: DateTime, description: string): Event {
|
||||
const percentDimensions: EventDimensions = {
|
||||
from: dimensions.from * 100 / height,
|
||||
to: dimensions.to * 100 / height
|
||||
}
|
||||
|
||||
return Event.fromPercentDimensions(title, percentDimensions, date)
|
||||
return Event.fromPercentDimensions(title, percentDimensions, date, description)
|
||||
}
|
||||
|
||||
static fromDraggedEvent(draggedEvent: DraggedEvent, height: number): Event {
|
||||
@@ -59,7 +61,13 @@ export class Event {
|
||||
to: draggedEvent.top + draggedEvent.height
|
||||
}
|
||||
|
||||
return Event.fromPixelDimensions(draggedEvent.target.title, pixelDimensions, height, draggedEvent.date)
|
||||
return Event.fromPixelDimensions(
|
||||
draggedEvent.target.title,
|
||||
pixelDimensions,
|
||||
height,
|
||||
draggedEvent.date,
|
||||
draggedEvent.target.description
|
||||
)
|
||||
}
|
||||
|
||||
updateWithDraggedEvent(draggedEvent: DraggedEvent, height: number): Event {
|
||||
@@ -76,7 +84,8 @@ export class Event {
|
||||
return {
|
||||
title: this.title,
|
||||
from: this.from,
|
||||
to: this.to
|
||||
to: this.to,
|
||||
description: this.description
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +93,8 @@ export class Event {
|
||||
return {
|
||||
title: this.title,
|
||||
from: this.from.toISO() ?? '',
|
||||
to: this.to.toISO() ?? ''
|
||||
to: this.to.toISO() ?? '',
|
||||
description: this.description
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,12 +129,14 @@ export type SimpleEvent = {
|
||||
title: string,
|
||||
from: DateTime,
|
||||
to: DateTime
|
||||
description: string
|
||||
}
|
||||
|
||||
export type SerializableEvent = {
|
||||
title: string,
|
||||
from: string,
|
||||
to: string
|
||||
description: string
|
||||
}
|
||||
|
||||
export type CollissionWrapper = {
|
||||
|
||||
Reference in New Issue
Block a user