refactor: event instances
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
+35
-38
@@ -45,18 +45,18 @@
|
||||
<div class="all-day-events-overlay">
|
||||
<div
|
||||
v-for="segment in allDaySegments.segments"
|
||||
:key="segment.occurrence.key"
|
||||
:key="segment.instance.key"
|
||||
class="all-day-event"
|
||||
:class="{
|
||||
'is-start': segment.isStart,
|
||||
'is-end': segment.isEnd,
|
||||
}"
|
||||
:style="getAllDayEventStyle(segment)"
|
||||
@click="emit('event-click', segment.occurrence.entity)"
|
||||
@mouseenter="emit('event-hover', { event: $event, entity: segment.occurrence.entity })"
|
||||
@click="emit('event-click', segment.instance.entity)"
|
||||
@mouseenter="emit('event-hover', { event: $event, entity: segment.instance.entity })"
|
||||
@mouseleave="emit('event-hover-end')"
|
||||
>
|
||||
<span v-if="segment.isStart" class="event-label">{{ segment.occurrence.label || 'Untitled' }}</span>
|
||||
<span v-if="segment.isStart" class="event-label">{{ segment.instance.label || 'Untitled' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -73,22 +73,22 @@
|
||||
<div v-for="day in visibleDates" :key="day.toISOString()" class="day-column" :class="{ 'single-day': daysCount === 1 }">
|
||||
<div class="day-events" @click="handleDayClick($event, day)">
|
||||
<div
|
||||
v-for="occurrence in getTimedEvents(day)"
|
||||
:key="occurrence.key"
|
||||
v-for="instance in getTimedEvents(day)"
|
||||
:key="instance.key"
|
||||
class="day-event"
|
||||
:style="getEventStyle(occurrence)"
|
||||
@click.stop="emit('event-click', occurrence.entity)"
|
||||
@mouseenter="emit('event-hover', { event: $event, entity: occurrence.entity })"
|
||||
:style="getEventStyle(instance)"
|
||||
@click.stop="emit('event-click', instance.entity)"
|
||||
@mouseenter="emit('event-hover', { event: $event, entity: instance.entity })"
|
||||
@mouseleave="emit('event-hover-end')"
|
||||
>
|
||||
<template v-if="daysCount <= 3">
|
||||
<div class="event-time">
|
||||
{{ formatOccurrenceTime(occurrence.startMs) }} - {{ formatOccurrenceTime(occurrence.endMs) }}
|
||||
{{ formatInstanceTime(instance.startMs) }} - {{ formatInstanceTime(instance.endMs) }}
|
||||
</div>
|
||||
<div class="event-title">{{ occurrence.label || 'Untitled' }}</div>
|
||||
<div class="event-title">{{ instance.label || 'Untitled' }}</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="event-title-compact">{{ occurrence.label || 'Untitled' }}</div>
|
||||
<div class="event-title-compact">{{ instance.label || 'Untitled' }}</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -101,17 +101,13 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import {
|
||||
startOfDay,
|
||||
getMultiDaySegments,
|
||||
type MultiDaySegment,
|
||||
} from '@/utils/calendarHelpers';
|
||||
import { shiftLocalDays } from '@/utils/dateRanges';
|
||||
import { layoutMultiDayLanes, type MultiDaySegment } from '@/utils/multiDayLanes';
|
||||
import { shiftLocalDays, startOfLocalDay } from '@/utils/date';
|
||||
import { DAYS_VIEW_SPANS, spanToDays, type DaysViewSpan } from '@/types/spans';
|
||||
import type { EntityObject } from '@ChronoManager/models/entity';
|
||||
import type { CollectionObject } from '@ChronoManager/models/collection';
|
||||
import { occurrencesForDay, occurrencesForRange } from '@/utils/occurrenceIndex';
|
||||
import type { CalendarOccurrence, CalendarOccurrenceIndex } from '@/types/occurrence';
|
||||
import { useChronoInstancesStore } from '@/stores/chronoInstancesStore';
|
||||
import type { CalendarInstance } from '@/types/instance';
|
||||
|
||||
const ALL_DAY_EVENT_HEIGHT = 24;
|
||||
|
||||
@@ -120,11 +116,12 @@ type CalendarCollection = CollectionObject;
|
||||
|
||||
const props = defineProps<{
|
||||
currentDate: Date;
|
||||
occurrenceIndex: CalendarOccurrenceIndex;
|
||||
calendars: CalendarCollection[];
|
||||
initialSpan?: DaysViewSpan;
|
||||
}>();
|
||||
|
||||
const instancesStore = useChronoInstancesStore();
|
||||
|
||||
const selectedSpan = ref<DaysViewSpan>(props.initialSpan ?? '7d');
|
||||
const daysCount = computed(() => spanToDays(selectedSpan.value));
|
||||
|
||||
@@ -197,20 +194,20 @@ const allDaySegments = computed(() => {
|
||||
return { segments: [], laneCount: 0 };
|
||||
}
|
||||
|
||||
const rangeStart = startOfDay(visibleDates.value[0]);
|
||||
const rangeEnd = startOfDay(visibleDates.value[visibleDates.value.length - 1]);
|
||||
const rangeStart = startOfLocalDay(visibleDates.value[0]);
|
||||
const rangeEnd = startOfLocalDay(visibleDates.value[visibleDates.value.length - 1]);
|
||||
|
||||
const getColumnIndex = (date: Date): number => {
|
||||
const targetDay = startOfDay(date);
|
||||
return visibleDates.value.findIndex(d => startOfDay(d).getTime() === targetDay.getTime());
|
||||
const targetDay = startOfLocalDay(date);
|
||||
return visibleDates.value.findIndex(d => startOfLocalDay(d).getTime() === targetDay.getTime());
|
||||
};
|
||||
|
||||
const occurrences = occurrencesForRange(props.occurrenceIndex, {
|
||||
const instances = instancesStore.instancesForRange({
|
||||
startMs: rangeStart.getTime(),
|
||||
endMs: shiftLocalDays(rangeEnd, 1).getTime(),
|
||||
});
|
||||
|
||||
return getMultiDaySegments(occurrences, rangeStart, rangeEnd, daysCount.value, getColumnIndex);
|
||||
return layoutMultiDayLanes(instances, rangeStart, rangeEnd, daysCount.value, getColumnIndex);
|
||||
});
|
||||
|
||||
function isToday(date: Date): boolean {
|
||||
@@ -218,34 +215,34 @@ function isToday(date: Date): boolean {
|
||||
return date.toDateString() === today.toDateString();
|
||||
}
|
||||
|
||||
function getTimedEvents(date: Date): CalendarOccurrence[] {
|
||||
return occurrencesForDay(props.occurrenceIndex, date).filter(occurrence => !occurrence.timeless);
|
||||
function getTimedEvents(date: Date): CalendarInstance[] {
|
||||
return instancesStore.instancesForDay(date).filter(instance => !instance.timeless);
|
||||
}
|
||||
|
||||
function getEventColor(occurrence: CalendarOccurrence): string {
|
||||
if (occurrence.color) return occurrence.color;
|
||||
const calendar = props.calendars.find(cal => cal.identifier === occurrence.entity.collection);
|
||||
function getEventColor(instance: CalendarInstance): string {
|
||||
if (instance.color) return instance.color;
|
||||
const calendar = props.calendars.find(cal => cal.identifier === instance.entity.collection);
|
||||
return calendar?.properties?.color || '#1976D2';
|
||||
}
|
||||
|
||||
function getAllDayEventStyle(segment: MultiDaySegment) {
|
||||
return {
|
||||
backgroundColor: getEventColor(segment.occurrence),
|
||||
backgroundColor: getEventColor(segment.instance),
|
||||
left: `calc(${segment.startCol} / ${daysCount.value} * 100% + 4px)`,
|
||||
width: `calc(${segment.span} / ${daysCount.value} * 100% - 8px)`,
|
||||
top: `${segment.lane * ALL_DAY_EVENT_HEIGHT}px`,
|
||||
};
|
||||
}
|
||||
|
||||
function getEventStyle(occurrence: CalendarOccurrence) {
|
||||
const startTime = new Date(occurrence.startMs);
|
||||
function getEventStyle(instance: CalendarInstance) {
|
||||
const startTime = new Date(instance.startMs);
|
||||
const start = startTime.getHours() * 60 + startTime.getMinutes();
|
||||
const duration = occurrence.durationMs / (1000 * 60);
|
||||
const duration = instance.durationMs / (1000 * 60);
|
||||
|
||||
return {
|
||||
top: `${(start / 1440) * 100}%`,
|
||||
height: `${(duration / 1440) * 100}%`,
|
||||
backgroundColor: getEventColor(occurrence),
|
||||
backgroundColor: getEventColor(instance),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -259,7 +256,7 @@ function formatTime(date: Date): string {
|
||||
return date.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' });
|
||||
}
|
||||
|
||||
function formatOccurrenceTime(timestamp: number): string {
|
||||
function formatInstanceTime(timestamp: number): string {
|
||||
return formatTime(new Date(timestamp));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user