feat: Enhance calendar display and event management
- Improve event display: Show only the first two events for each day in the calendar, with a "+X more" link to show the rest. - Add event details modal: Allows viewing and deleting events. - Enhance event creation modal: Improve user experience and add color selection for events. - Improve year view: Show the number of events for each month. - Improve day view: Display all day events separately. - Improve styling and layout: Enhance the visual appeal and responsiveness of the calendar.
This commit is contained in:
parent
58d1cde1ce
commit
45c4f4985e
@ -92,8 +92,9 @@
|
|||||||
<tr>
|
<tr>
|
||||||
{% for day_idx in range(start=0, end=7) %}
|
{% for day_idx in range(start=0, end=7) %}
|
||||||
{% set idx = week * 7 + day_idx %}
|
{% set idx = week * 7 + day_idx %}
|
||||||
<td class="calendar-day" onclick="openEventModalForDate(this)" {% if idx <
|
<td class="calendar-day {% if idx < calendar_days|length and calendar_days[idx].events|length > 2 %}has-more-events{% endif %}"
|
||||||
calendar_days|length %} data-day="{{ calendar_days[idx].day }}"
|
onclick="openEventModalForDate(this)" {% if idx < calendar_days|length %}
|
||||||
|
data-day="{{ calendar_days[idx].day }}"
|
||||||
data-is-current-month="{{ calendar_days[idx].is_current_month }}"
|
data-is-current-month="{{ calendar_days[idx].is_current_month }}"
|
||||||
data-date="{{ current_year }}-{{ current_month|format_hour }}-{{ calendar_days[idx].day|format_hour }}"
|
data-date="{{ current_year }}-{{ current_month|format_hour }}-{{ calendar_days[idx].day|format_hour }}"
|
||||||
{% else %} data-day="0" data-is-current-month="false" data-date="" {% endif %}>
|
{% else %} data-day="0" data-is-current-month="false" data-date="" {% endif %}>
|
||||||
@ -111,14 +112,24 @@
|
|||||||
{% if day.events|length > 0 %}
|
{% if day.events|length > 0 %}
|
||||||
<div class="calendar-events">
|
<div class="calendar-events">
|
||||||
{% for event in day.events %}
|
{% for event in day.events %}
|
||||||
{% if loop.index <= 2 %} <div class="event-preview text-truncate mb-1"
|
<div class="event-preview text-truncate mb-1 {% if loop.index > 2 %}d-none{% endif %}"
|
||||||
style="background-color: {{ event.color }}; color: white;">
|
style="background-color: {{ event.color }}; color: white;"
|
||||||
|
onclick="openEventDetails(event, '{{ event.id }}', '{{ event.title|escape }}', '{{ event.description|escape }}', '{{ event.color }}', {{ event.all_day }}, '{{ event.start_time }}', '{{ event.end_time }}')"
|
||||||
|
data-event-id="{{ event.id }}" data-event-title="{{ event.title|escape }}"
|
||||||
|
data-event-description="{{ event.description|escape }}"
|
||||||
|
data-event-color="{{ event.color }}"
|
||||||
|
data-event-all-day="{{ event.all_day }}"
|
||||||
|
data-event-start="{{ event.start_time }}"
|
||||||
|
data-event-end="{{ event.end_time }}" data-event-index="{{ loop.index }}"
|
||||||
|
title="{{ event.title|escape }}">
|
||||||
{{ event.title }}
|
{{ event.title }}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if day.events|length > 2 %}
|
{% if day.events|length > 2 %}
|
||||||
<div class="small text-muted text-center">+{{ day.events|length - 2 }} more</div>
|
<div class="small text-muted text-center more-events-link"
|
||||||
|
onclick="showMoreEventsForDay(event, '{{ current_year }}-{{ current_month|format_hour }}-{{ day.day|format_hour }}')">
|
||||||
|
+{{ day.events|length - 2 }} more
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -190,7 +201,8 @@
|
|||||||
{% if events is defined and events|length > 0 %}
|
{% if events is defined and events|length > 0 %}
|
||||||
{% for event in events %}
|
{% for event in events %}
|
||||||
{% if event.all_day %}
|
{% if event.all_day %}
|
||||||
<div class="alert" style="background-color: {{ event.color }}; color: white;">
|
<div class="alert" style="background-color: {{ event.color }}; color: white; cursor: pointer;"
|
||||||
|
onclick="openEventDetails(event, '{{ event.id }}', '{{ event.title|escape }}', '{{ event.description|escape }}', '{{ event.color }}', {{ event.all_day }}, '{{ event.start_time }}', '{{ event.end_time }}')">
|
||||||
<h5>{{ event.title }}</h5>
|
<h5>{{ event.title }}</h5>
|
||||||
<p>{{ event.description }}</p>
|
<p>{{ event.description }}</p>
|
||||||
</div>
|
</div>
|
||||||
@ -215,7 +227,8 @@
|
|||||||
{% if not event.all_day %}
|
{% if not event.all_day %}
|
||||||
{% set start_hour = event.start_time|extract_hour %}
|
{% set start_hour = event.start_time|extract_hour %}
|
||||||
{% if start_hour == hour|string %}
|
{% if start_hour == hour|string %}
|
||||||
<div class="alert mb-2" style="background-color: {{ event.color }}; color: white;">
|
<div class="alert mb-2" style="background-color: {{ event.color }}; color: white; cursor: pointer;"
|
||||||
|
onclick="openEventDetails(event, '{{ event.id }}', '{{ event.title|escape }}', '{{ event.description|escape }}', '{{ event.color }}', {{ event.all_day }}, '{{ event.start_time }}', '{{ event.end_time }}')">
|
||||||
<h5>{{ event.title }}</h5>
|
<h5>{{ event.title }}</h5>
|
||||||
<p>{{ event.start_time|format_time }} - {{ event.end_time|format_time }}</p>
|
<p>{{ event.start_time|format_time }} - {{ event.end_time|format_time }}</p>
|
||||||
<p>{{ event.description }}</p>
|
<p>{{ event.description }}</p>
|
||||||
@ -297,7 +310,8 @@
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="endTime" class="form-label">End Time *</label>
|
<label for="endTime" class="form-label">End Time *</label>
|
||||||
<input type="datetime-local" class="form-control" id="endTime" name="end_time" required>
|
<input type="datetime-local" class="form-control" id="endTime" name="end_time"
|
||||||
|
required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -313,6 +327,89 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Event Details Modal (Read-only) -->
|
||||||
|
<div class="modal fade" id="eventDetailsModal" tabindex="-1" aria-labelledby="eventDetailsModalLabel"
|
||||||
|
aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header bg-info text-white">
|
||||||
|
<h5 class="modal-title" id="eventDetailsModalLabel">
|
||||||
|
<i class="bi bi-calendar-event"></i> Event Details
|
||||||
|
</h5>
|
||||||
|
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"
|
||||||
|
aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">Event Title</label>
|
||||||
|
<div class="form-control-plaintext border rounded p-2 bg-light" id="detailsEventTitle">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">Color</label>
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div id="detailsEventColorBox" class="me-2"
|
||||||
|
style="width: 20px; height: 20px; border-radius: 3px;"></div>
|
||||||
|
<span id="detailsEventColor" class="form-control-plaintext"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">Description</label>
|
||||||
|
<div class="form-control-plaintext border rounded p-2 bg-light" id="detailsEventDescription"
|
||||||
|
style="min-height: 80px;"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="form-check">
|
||||||
|
<input type="checkbox" class="form-check-input" id="detailsAllDayEvent" disabled>
|
||||||
|
<label class="form-check-label fw-bold" for="detailsAllDayEvent">All Day Event</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row" id="detailsTimeInputs">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">Start Time</label>
|
||||||
|
<div class="form-control-plaintext border rounded p-2 bg-light" id="detailsStartTime">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">End Time</label>
|
||||||
|
<div class="form-control-plaintext border rounded p-2 bg-light" id="detailsEndTime">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||||
|
<button type="button" class="btn btn-danger" id="deleteEventBtn" onclick="deleteCurrentEvent()">
|
||||||
|
<i class="bi bi-trash"></i> Delete Event
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Events Popup for "+X more" -->
|
||||||
|
<div id="eventsPopup" class="position-absolute bg-white border rounded shadow-lg p-3"
|
||||||
|
style="display: none; z-index: 1050; min-width: 250px; max-width: 300px;">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||||
|
<h6 class="mb-0 fw-bold">Events</h6>
|
||||||
|
<button type="button" class="btn-close btn-sm" onclick="closeEventsPopup()"></button>
|
||||||
|
</div>
|
||||||
|
<div id="eventsPopupContent"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Floating Action Button (FAB) for mobile -->
|
<!-- Floating Action Button (FAB) for mobile -->
|
||||||
<button type="button" class="d-md-none position-fixed bottom-0 end-0 m-4 btn btn-primary rounded-circle shadow"
|
<button type="button" class="d-md-none position-fixed bottom-0 end-0 m-4 btn btn-primary rounded-circle shadow"
|
||||||
onclick="openEventModal()"
|
onclick="openEventModal()"
|
||||||
@ -326,6 +423,10 @@
|
|||||||
<style>
|
<style>
|
||||||
.calendar-table {
|
.calendar-table {
|
||||||
border: 2px solid #dee2e6;
|
border: 2px solid #dee2e6;
|
||||||
|
width: 100%;
|
||||||
|
table-layout: fixed;
|
||||||
|
/* Fixed table layout for consistent column widths */
|
||||||
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-table td {
|
.calendar-table td {
|
||||||
@ -343,9 +444,20 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.calendar-day {
|
.calendar-day {
|
||||||
|
height: 120px;
|
||||||
min-height: 120px;
|
min-height: 120px;
|
||||||
|
max-height: 120px;
|
||||||
|
width: 14.28%;
|
||||||
|
/* Fixed width for 7 columns */
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 30px !important;
|
padding: 8px !important;
|
||||||
|
overflow: hidden;
|
||||||
|
/* Prevent content from stretching the cell */
|
||||||
|
box-sizing: border-box;
|
||||||
|
vertical-align: top;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-day-header {
|
.calendar-day-header {
|
||||||
@ -360,6 +472,16 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.calendar-events {
|
||||||
|
max-height: 70px;
|
||||||
|
/* Fixed height for events container */
|
||||||
|
overflow-y: auto;
|
||||||
|
/* Scroll if too many events */
|
||||||
|
overflow-x: hidden;
|
||||||
|
margin-top: 4px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
.calendar-day[data-is-current-month="true"]:hover::after {
|
.calendar-day[data-is-current-month="true"]:hover::after {
|
||||||
content: "Click to add event";
|
content: "Click to add event";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -373,6 +495,12 @@
|
|||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide hint when cell has "+X more" link */
|
||||||
|
.calendar-day.has-more-events:hover::after {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-day[data-is-current-month="false"] {
|
.calendar-day[data-is-current-month="false"] {
|
||||||
@ -391,9 +519,7 @@
|
|||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-events {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-preview {
|
.event-preview {
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
@ -403,6 +529,14 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: opacity 0.2s;
|
transition: opacity 0.2s;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
/* Limit text length and prevent calendar stretching */
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
word-break: break-all;
|
||||||
|
/* Ensure consistent width */
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.event-preview:hover {
|
.event-preview:hover {
|
||||||
@ -421,6 +555,48 @@
|
|||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Events popup styles */
|
||||||
|
#eventsPopup {
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
background: white;
|
||||||
|
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-event-item {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
padding: 6px 8px;
|
||||||
|
margin: 2px 0;
|
||||||
|
border-radius: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
font-weight: 500;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-event-item:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
transform: translateX(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.more-events-link {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.more-events-link:hover {
|
||||||
|
color: #0056b3 !important;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark theme support for popup */
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
#eventsPopup {
|
||||||
|
background: #2d3748;
|
||||||
|
border-color: #4a5568;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@ -454,9 +630,9 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Handle form submission (ensure only one listener)
|
// Handle form submission (ensure only one listener)
|
||||||
|
if (!window.calendarFormInitialized) {
|
||||||
|
window.calendarFormInitialized = true;
|
||||||
const eventForm = document.getElementById('newEventForm');
|
const eventForm = document.getElementById('newEventForm');
|
||||||
if (!eventForm.hasAttribute('data-listener-added')) {
|
|
||||||
eventForm.setAttribute('data-listener-added', 'true');
|
|
||||||
eventForm.addEventListener('submit', function (e) {
|
eventForm.addEventListener('submit', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@ -554,9 +730,162 @@
|
|||||||
alert('Network error creating event. Please try again.');
|
alert('Network error creating event. Please try again.');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Global variable to store current event ID for deletion
|
||||||
|
window.currentEventId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete event function
|
// Open event details modal
|
||||||
|
function openEventDetails(clickEvent, eventId, title, description, color, allDay, startTime, endTime) {
|
||||||
|
// Prevent event bubbling to calendar day click
|
||||||
|
clickEvent.stopPropagation();
|
||||||
|
|
||||||
|
// Store event ID for potential deletion
|
||||||
|
window.currentEventId = eventId;
|
||||||
|
|
||||||
|
// Populate modal fields
|
||||||
|
document.getElementById('detailsEventTitle').textContent = title;
|
||||||
|
document.getElementById('detailsEventDescription').textContent = description || 'No description';
|
||||||
|
document.getElementById('detailsEventColorBox').style.backgroundColor = color;
|
||||||
|
document.getElementById('detailsEventColor').textContent = getColorName(color);
|
||||||
|
document.getElementById('detailsAllDayEvent').checked = allDay;
|
||||||
|
|
||||||
|
// Format and display times
|
||||||
|
if (allDay) {
|
||||||
|
document.getElementById('detailsTimeInputs').style.display = 'none';
|
||||||
|
} else {
|
||||||
|
document.getElementById('detailsTimeInputs').style.display = 'block';
|
||||||
|
document.getElementById('detailsStartTime').textContent = formatDateTime(startTime);
|
||||||
|
document.getElementById('detailsEndTime').textContent = formatDateTime(endTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show modal
|
||||||
|
const modal = new bootstrap.Modal(document.getElementById('eventDetailsModal'));
|
||||||
|
modal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show more events popup for a specific day
|
||||||
|
function showMoreEventsForDay(clickEvent, dateStr) {
|
||||||
|
// Prevent event bubbling to calendar day click
|
||||||
|
clickEvent.stopPropagation();
|
||||||
|
|
||||||
|
const popup = document.getElementById('eventsPopup');
|
||||||
|
const content = document.getElementById('eventsPopupContent');
|
||||||
|
|
||||||
|
// Clear previous content
|
||||||
|
content.innerHTML = '';
|
||||||
|
|
||||||
|
// Find the calendar day cell for this date
|
||||||
|
const dayCell = document.querySelector(`[data-date="${dateStr}"]`);
|
||||||
|
if (!dayCell) return;
|
||||||
|
|
||||||
|
// Get all event elements from this day (including hidden ones)
|
||||||
|
const eventElements = dayCell.querySelectorAll('.event-preview');
|
||||||
|
const allEvents = Array.from(eventElements).map(el => ({
|
||||||
|
id: el.getAttribute('data-event-id'),
|
||||||
|
title: el.getAttribute('data-event-title'),
|
||||||
|
description: el.getAttribute('data-event-description'),
|
||||||
|
color: el.getAttribute('data-event-color'),
|
||||||
|
all_day: el.getAttribute('data-event-all-day') === 'true',
|
||||||
|
start_time: el.getAttribute('data-event-start'),
|
||||||
|
end_time: el.getAttribute('data-event-end'),
|
||||||
|
index: parseInt(el.getAttribute('data-event-index'))
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Show only the hidden events (index > 2)
|
||||||
|
const hiddenEvents = allEvents.filter(event => event.index > 2);
|
||||||
|
|
||||||
|
hiddenEvents.forEach(event => {
|
||||||
|
const eventDiv = document.createElement('div');
|
||||||
|
eventDiv.className = 'popup-event-item text-truncate';
|
||||||
|
eventDiv.style.backgroundColor = event.color;
|
||||||
|
|
||||||
|
// Truncate title to 30 characters
|
||||||
|
const truncatedTitle = event.title.length > 30 ? event.title.substring(0, 27) + '...' : event.title;
|
||||||
|
eventDiv.textContent = truncatedTitle;
|
||||||
|
eventDiv.title = event.title; // Show full title on hover
|
||||||
|
|
||||||
|
eventDiv.onclick = (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
closeEventsPopup();
|
||||||
|
openEventDetails(e, event.id, event.title, event.description, event.color, event.all_day, event.start_time, event.end_time);
|
||||||
|
};
|
||||||
|
content.appendChild(eventDiv);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Position popup near the clicked element
|
||||||
|
const rect = clickEvent.target.getBoundingClientRect();
|
||||||
|
popup.style.left = (rect.left + window.scrollX) + 'px';
|
||||||
|
popup.style.top = (rect.bottom + window.scrollY + 5) + 'px';
|
||||||
|
popup.style.display = 'block';
|
||||||
|
|
||||||
|
// Close popup when clicking outside
|
||||||
|
setTimeout(() => {
|
||||||
|
document.addEventListener('click', closeEventsPopupOnOutsideClick);
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close events popup
|
||||||
|
function closeEventsPopup() {
|
||||||
|
document.getElementById('eventsPopup').style.display = 'none';
|
||||||
|
document.removeEventListener('click', closeEventsPopupOnOutsideClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close popup when clicking outside
|
||||||
|
function closeEventsPopupOnOutsideClick(event) {
|
||||||
|
const popup = document.getElementById('eventsPopup');
|
||||||
|
if (!popup.contains(event.target)) {
|
||||||
|
closeEventsPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete current event
|
||||||
|
function deleteCurrentEvent() {
|
||||||
|
if (!window.currentEventId) return;
|
||||||
|
|
||||||
|
if (confirm('Are you sure you want to delete this event?')) {
|
||||||
|
fetch(`/calendar/events/${window.currentEventId}/delete`, {
|
||||||
|
method: 'POST'
|
||||||
|
}).then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
window.location.reload();
|
||||||
|
} else {
|
||||||
|
alert('Error deleting event. Please try again.');
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('Error:', error);
|
||||||
|
alert('Error deleting event. Please try again.');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to get color name
|
||||||
|
function getColorName(colorCode) {
|
||||||
|
const colorMap = {
|
||||||
|
'#4285F4': 'Blue',
|
||||||
|
'#EA4335': 'Red',
|
||||||
|
'#34A853': 'Green',
|
||||||
|
'#FBBC05': 'Yellow',
|
||||||
|
'#A142F4': 'Purple',
|
||||||
|
'#24C1E0': 'Cyan'
|
||||||
|
};
|
||||||
|
return colorMap[colorCode] || 'Custom';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to format date/time
|
||||||
|
function formatDateTime(dateTimeStr) {
|
||||||
|
const date = new Date(dateTimeStr);
|
||||||
|
return date.toLocaleString('en-US', {
|
||||||
|
weekday: 'short',
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric',
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete event function (legacy - keeping for compatibility)
|
||||||
function deleteEvent(eventId) {
|
function deleteEvent(eventId) {
|
||||||
if (confirm('Are you sure you want to delete this event?')) {
|
if (confirm('Are you sure you want to delete this event?')) {
|
||||||
fetch(`/calendar/events/${eventId}/delete`, {
|
fetch(`/calendar/events/${eventId}/delete`, {
|
||||||
@ -719,8 +1048,22 @@
|
|||||||
bootstrapModal.show();
|
bootstrapModal.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Truncate event titles to prevent calendar stretching
|
||||||
|
function truncateEventTitles() {
|
||||||
|
const eventElements = document.querySelectorAll('.event-preview');
|
||||||
|
eventElements.forEach(element => {
|
||||||
|
const originalTitle = element.textContent.trim();
|
||||||
|
if (originalTitle.length > 30) {
|
||||||
|
element.textContent = originalTitle.substring(0, 27) + '...';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize calendar features
|
// Initialize calendar features
|
||||||
function initializeCalendar() {
|
function initializeCalendar() {
|
||||||
|
// Truncate long event titles
|
||||||
|
truncateEventTitles();
|
||||||
|
|
||||||
// Highlight today's date
|
// Highlight today's date
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
const todayStr = today.toISOString().split('T')[0];
|
const todayStr = today.toISOString().split('T')[0];
|
||||||
|
Loading…
Reference in New Issue
Block a user