reworked coodle timeslot creation

This commit is contained in:
adisposkofh
2026-06-25 15:26:00 +02:00
parent a9ffdc2457
commit 80f46ae7e9
7 changed files with 89 additions and 45 deletions
+5
View File
@@ -880,4 +880,9 @@ html {
.coodleCalendarTimeslotCardIcon:hover {
color: var(--fhc-primary);
}
#coodleCalendar .fhc-calendar-base .part-body,
#coodleCalendar .fhc-calendar-base .fhc-calendar-base-grid-line-background {
z-index: 1 !important;
}
+3 -2
View File
@@ -116,7 +116,8 @@ export default {
"update:date",
"update:mode",
"update:range",
"drop"
"drop",
"emptyClicked",
],
data() {
return {
@@ -297,10 +298,10 @@ export default {
:is="modes ? modes[cMode] : null || 'div'"
ref="mode"
v-model:current-date="cDate"
@emptyCellClicked="$emit('emptyCellClicked', $event)"
@update:range="$emit('update:range', $event)"
@request-modal-open="showEventModal"
@request-modal-close="hideEventModal"
@emptyClicked="$emit('emptyClicked', $event)"
v-bind="modeOptions ? modeOptions[cMode] : null || {}"
>
<template v-slot="slot"><slot v-bind="slot" /></template>
+2 -1
View File
@@ -2,6 +2,7 @@ import GridLine from './Grid/Line.js';
import GridLineEvent from './Grid/Line/Event.js';
import CalDnd from '../../../directives/Calendar/DragAndDrop.js';
import CalClick from '../../../directives/Calendar/Click.js';
export default {
name: "CalendarGrid",
@@ -10,7 +11,7 @@ export default {
GridLineEvent
},
directives: {
CalDnd
CalDnd,
},
inject: {
originalEvents: "events",
@@ -83,11 +83,8 @@ export default {
<template #part-body="params">
<slot name="part-body">
<div
@click="($event) => {
$event.params = params;
$emit('emptyCellClicked', $event)
}"
class="position-absolute h-100 w-100" style="z-index:1"></div>
@click="$emit('emptyClicked', { event: $event, params })"
class="position-absolute h-100 w-100"></div>
</slot>
</template>
<template #event="slot">
@@ -55,13 +55,13 @@ export default {
events() {
let events = this.timeslotCalendarEvents;
const participantWithVisibleSchedules =
const participantsWithDisplayedSchedules =
this.$props.surveyFormDataParticipants.filter(
(participant) => participant.isCalendarShown,
);
participantWithVisibleSchedules.forEach((participant) => {
participantsWithDisplayedSchedules.forEach((participant) => {
let participantEvents =
cachedParticipantSchedules[participant.uid] ?? [];
this.cachedParticipantSchedules[participant.uid] ?? [];
participantEvents = participantEvents.map((event) => {
event.farbe =
this.$props.participantScheduleColors.find(
@@ -158,6 +158,20 @@ export default {
},
deep: true,
},
surveyFormDataParticipants: {
handler() {
let participantsWithDisplayedSchedules =
this.$props.surveyFormDataParticipants.filter(
(participant) => participant.isCalendarShown,
);
participantsWithDisplayedSchedules.forEach((participant) => {
if (!this.cachedParticipantSchedules[participant.uid]) {
this.fetchParticipantSchedule(participant.uid);
}
});
},
deep: true,
},
},
methods: {
setTimeslotCalendarEvents() {
@@ -167,13 +181,13 @@ export default {
return this.generateTimeslotCalendarEvent(startDate);
}) ?? [];
},
addTimeslotOnCalendarClick(clickEvent) {
addTimeslotOnCalendarClick(event) {
if (this.timeslotCalendarEvents.length >= 50) {
return;
}
const elementRectangle = clickEvent.target.getBoundingClientRect();
const relativeClickLocation = clickEvent.y - elementRectangle.top;
const elementRectangle = event.event.target.getBoundingClientRect();
const relativeClickLocation = event.event.y - elementRectangle.top;
let minutes =
Math.floor(
(relativeClickLocation / elementRectangle.height) * 12,
@@ -182,12 +196,12 @@ export default {
minutes = 0;
}
let hours = clickEvent.params?.part?.values?.hours ?? 12;
let hours = event.params?.part?.values?.hours ?? 12;
if (hours < 7 || hours > 22) {
hours = 12;
}
let start = new Date(clickEvent.params.date.ts);
let start = new Date(event.params.date.ts);
start.setHours(hours);
start.setMinutes(minutes);
@@ -291,6 +305,9 @@ export default {
);
this.isTimeslotCardEditInProgress = false;
},
fetchParticipantSchedule(uid) {
// todo: fetch, format as events, add as array with uid as key to cachedParticipantSchedules
},
getEventStyle(event) {
if (!event.farbe) return undefined;
return "--event-bg:#" + event.farbe;
@@ -300,33 +317,33 @@ export default {
this.setTimeslotCalendarEvents();
},
template: /*html*/ `
<div class="d-flex flex-column gap-3">
<div id="coodleCalendar" class="d-flex flex-column gap-3">
<div class="d-flex flex-column">
<span class="fw-bold">{{ "Timeslot selection" }}</span>
<span class="fst-italic">{{ "You can add timeslots directly to the calendar or from the list down below." }}</span>
</div>
<div style="height:800px;">
<fhc-calendar
@emptyCellClicked="addTimeslotOnCalendarClick($event)"
:ref="'coodleCalendar'"
:timezone="timezone"
:modes="modes"
:modeOptions="modeOptions"
:mode="'Week'"
:timeGrid="null"
:locale="$p.user_locale.value"
:events="events"
:backgrounds="backgrounds"
:draggableEvents="true"
:droppableEvents="true"
:onDrop="true"
:isAutoScrollEnabled="false"
>
<div style="height:800px;">
<fhc-calendar
@emptyClicked="addTimeslotOnCalendarClick($event)"
:ref="'coodleCalendar'"
:timezone="timezone"
:modes="modes"
:modeOptions="modeOptions"
:mode="'Week'"
:timeGrid="null"
:locale="$p.user_locale.value"
:events="events"
:backgrounds="backgrounds"
:draggableEvents="true"
:droppableEvents="true"
:onDrop="true"
:isAutoScrollEnabled="false"
>
<template v-slot="{ event, mode }">
<div
:class="'event-type-' + event.type + ' ' + mode + 'PageContainer'"
:type="mode == 'day' ? 'button' : undefined"
:style="getEventStyle(event)"
:style="getEventStyle(event)"
>
<component
v-if="mode == 'event'"
@@ -347,8 +364,8 @@ export default {
></component>
</div>
</template>
</fhc-calendar>
</div>
</fhc-calendar>
</div>
<div class="row">
<div v-for="timeslot in sortedTimeslotCalendarEvents.concat([null])" class="col-12 col-md-6 col-xl-4">
<coodle-survey-calendar-timeslot-card
@@ -64,11 +64,15 @@ export default {
},
isMaxDisplayedParticipantSchedulesReached() {
return (
this.participants.filter(
(participant) => participant.isCalendarShown,
).length >= this.participantScheduleColors.length
this.displayedParticipantSchedulesCount >=
this.participantScheduleColors.length
);
},
displayedParticipantSchedulesCount() {
return this.participants.filter(
(participant) => participant.isCalendarShown,
).length;
},
},
watch: {
searchInput() {
@@ -143,7 +147,7 @@ export default {
if (!occupiedParticipantColor) return;
occupiedParticipantColor.uid = null;
},
showCalendar(participantForCalendarToBeDisplayed) {
showSchedule(participantForCalendarToBeDisplayed) {
if (this.isMaxDisplayedParticipantSchedulesReached) return;
this.participants = this.participants.map((participant) => {
@@ -160,7 +164,7 @@ export default {
(participantColor) => !participantColor.uid,
).uid = participantForCalendarToBeDisplayed.uid;
},
hideCalendar(participant) {
hideSchedule(participant) {
participant.isCalendarShown = false;
let occupiedParticipantColor = this.participantScheduleColors.find(
@@ -169,6 +173,14 @@ export default {
if (!occupiedParticipantColor) return;
occupiedParticipantColor.uid = null;
},
hideAllSchedules() {
this.participants.forEach((participant) => {
participant.isCalendarShown = false;
});
this.participantScheduleColors.forEach((participantColor) => {
participantColor.uid = null;
});
},
getParticipantScheduleColor(participant) {
return this.participantScheduleColors.find(
(participantColor) => participantColor.uid === participant.uid,
@@ -229,7 +241,7 @@ export default {
<div class="d-flex flex-row align-items-center gap-3">
<i
v-if="participant.isCalendarShown"
@click="hideCalendar(participant)"
@click="hideSchedule(participant)"
type="button"
class="fa-solid fa-calendar"
:style="{color: getParticipantScheduleColor(participant)}"
@@ -240,7 +252,7 @@ export default {
></i>
<i
v-else
@click="showCalendar(participant)"
@click="showSchedule(participant)"
type="button"
class="fa-regular fa-calendar"
></i>
@@ -251,6 +263,14 @@ export default {
<span v-if="isMaxDisplayedParticipantSchedulesReached" class="fst-italic">
{{ "You can display no more participant schedules!" }}
</span>
<span
v-if="displayedParticipantSchedulesCount"
@click="hideAllSchedules()"
type="button"
class="text-decoration-underline"
>
{{ "Hide all participant schedules" }}
</span>
</div>
`,
};
+4 -1
View File
@@ -9,10 +9,13 @@ function saveAddClickListener(el, source, value) {
const listener = evt => {
evt.preventDefault();
evt.stopPropagation();
if (typeof value === "function") {
value = value(evt);
}
const customEvent = new CustomEvent('cal-click', {
cancelable: true,
bubbles: true,
detail: { source, value }
detail: { source, value },
});
evt.target.dispatchEvent(customEvent);
}