Skip to content

Commit

Permalink
➕ Move calendar event classes into corresponding components
Browse files Browse the repository at this point in the history
  • Loading branch information
devmount committed May 29, 2024
1 parent 3a29e9e commit 41526f1
Show file tree
Hide file tree
Showing 9 changed files with 262 additions and 191 deletions.
6 changes: 2 additions & 4 deletions frontend/src/components/CalendarMiniMonth.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,8 @@
</template>

<script setup>
import {
ref, computed, inject, watch,
} from 'vue';
import CalendarMiniMonthDay from '@/elements/CalendarMiniMonthDay';
import { ref, computed, inject, watch } from 'vue';
import CalendarMiniMonthDay from '@/elements/calendar/CalendarMiniMonthDay';
// icons
import {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/CalendarQalendar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
} from 'vue';
import { Qalendar } from 'qalendar';
import 'qalendar/dist/style.css';
import CalendarEvent from '@/elements/CalendarEvent.vue';
import CalendarEvent from '@/elements/calendar/CalendarEvent.vue';
import {
appointmentState,
bookingStatus,
Expand Down
186 changes: 0 additions & 186 deletions frontend/src/elements/CalendarEvent.vue

This file was deleted.

109 changes: 109 additions & 0 deletions frontend/src/elements/calendar/CalendarEvent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<template>
<div
:class="{ 'text-gray-400 cursor-not-allowed': disabled, 'h-full': !monthView }"
@mouseleave="popup = {...initialEventPopupData}"
>
<div class="flex flex-col gap-1.5 overflow-y-auto"
:class="{
'h-full': !monthView,
'px-1' : isBusy,
}"
:style="`height: ${elementHeight}px`"
>
<!-- placeholder event for availability bookings -->
<calendar-event-placeholder
v-if="placeholder"
:is-busy="isBusy"
:is-selected="isSelected"
:is-month-view="monthView"
:label="formattedTimeRange(event)"
@click="emit('eventSelected', day)"
/>

<!-- remote event (can be normal, all_day or tentative) -->
<calendar-event-remote
v-else-if="eventData.remote"
:is-month-view="monthView"
:event="eventData"
:label="event.title"
@mouseenter="element => showDetails ? popup=showEventPopup(element, event, popupPosition) : null"
/>

<!-- live preview event (e.g. for schedule calendar) -->
<calendar-event-preview
v-else-if="eventData.preview"
:is-month-view="monthView"
:event="eventData"
:label="formattedTimeRange(event)"
@mouseenter="element => showDetails ? popup=showEventPopup(element, event, popupPosition) : null"
/>

<!-- scheduled event -->
<calendar-event-scheduled
v-else
:is-month-view="monthView"
:event="eventData"
:label="event.title"
@mouseenter="element => showDetails ? popup=showEventPopup(element, event, popupPosition) : null"
/>

</div>
<event-popup
v-if="(event && showDetails)"
:style="{
display: popup.display,
top: popup.top,
left: popup.left,
right: popup.right,
}"
:event="popup.event"
:position="popupPosition"
/>
</div>
</template>

<script setup>
import { bookingStatus } from '@/definitions';
import { computed, inject, ref, toRefs } from 'vue';
import { timeFormat, initialEventPopupData, showEventPopup } from '@/utils';
import CalendarEventPlaceholder from '@/elements/calendar/CalendarEventPlaceholder';
import CalendarEventPreview from '@/elements/calendar/CalendarEventPreview';
import CalendarEventRemote from '@/elements/calendar/CalendarEventRemote';
import CalendarEventScheduled from '@/elements/calendar/CalendarEventScheduled';
import EventPopup from '@/elements/EventPopup';
const dj = inject('dayjs');
// component properties
const props = defineProps({
day: String, // number of day in its month
isSelected: Boolean, // flag showing if the event is currently selected by user
placeholder: Boolean, // flag formating events as placeholder
monthView: Boolean, // flag, are we in month view?
event: Object, // the event to show
showDetails: Boolean, // flag enabling event popups with details
popupPosition: String, // currently supported: right, left, top
disabled: Boolean, // flag making this day non-selectable and inactive
timeSlotDuration: Number, // minimum time shown: [15, 30, 60]
timeSlotHeight: Number, // height in pixels of each minimum time instance.
});
const { event, timeSlotDuration, timeSlotHeight } = toRefs(props);
const eventData = event.value.customData;
const elementHeight = computed(() => (eventData.duration / timeSlotDuration.value) * timeSlotHeight.value);
const isBusy = computed(() => eventData.slot_status === bookingStatus.booked);
// component emits
const emit = defineEmits(['eventSelected']);
// event details
const popup = ref({ ...initialEventPopupData });
// formatted time range
const formattedTimeRange = (eventObj) => {
const start = dj(eventObj.time.start);
const end = dj(eventObj.time.end);
return `${start.format(timeFormat())} - ${end.format(timeFormat())}`;
};
</script>
42 changes: 42 additions & 0 deletions frontend/src/elements/calendar/CalendarEventPlaceholder.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<template>
<div
class="m-auto size-[95%] shrink-0 text-sm text-gray-700 hover:shadow-md dark:text-gray-200"
:class="{
'group/event cursor-pointer rounded-md p-1 hover:bg-gradient-to-b hover:shadow-lg': !isBusy,
'bg-teal-50 hover:from-teal-500 hover:to-sky-600 hover:!text-white dark:bg-teal-800': !isBusy,
'bg-gradient-to-b from-teal-500 to-sky-600 shadow-lg': isSelected,
'h-full rounded': !isMonthView,
'!cursor-not-allowed rounded-md bg-gray-100 p-1 dark:bg-gray-600': isBusy,
}"
>
<div class="grid">
<div
class="
truncate rounded h-full p-1 font-semibold border-2 border-dashed
border-teal-500 group-hover/event:border-white"
:class="{
'!border-none': isBusy,
'border-white': isSelected,
}"
>
<template v-if="isBusy">{{ t('label.busy') }}</template>
<template v-else>{{ label }}</template>
</div>
</div>
</div>
</template>

<script setup>
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
// component properties
const props = defineProps({
isBusy: Boolean, // flag showing this event as busy and non-selectable
isSelected: Boolean, // flag showing if the event is currently selected by user
isMonthView: Boolean, // flag, are we in month view?
label: String, // event title
});
</script>
30 changes: 30 additions & 0 deletions frontend/src/elements/calendar/CalendarEventPreview.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<template>
<div
class="
m-auto size-[95%] shrink-0 text-sm text-gray-700 hover:shadow-md dark:text-gray-200
flex items-center rounded border-l-4 border-teal-400 px-2
"
:class="{ 'h-full': !isMonthView }"
:style="{
borderColor: eventColor(event, false).border,
backgroundColor: isMonthView ? eventColor(event, false).background : event.calendar_color,
color: !isMonthView ? getAccessibleColor(event.calendar_color) : null,
}"
>
<div class="grid">
<div class="truncate rounded">
{{ label }}
</div>
</div>
</div>
</template>
<script setup>
import { eventColor, getAccessibleColor } from '@/utils';
// component properties
const props = defineProps({
isMonthView: Boolean, // flag, are we in month view?
event: Object, // the event to show
label: String, // event title
});
</script>
Loading

0 comments on commit 41526f1

Please sign in to comment.