Files
old-zsterminator/app/javascript/controllers/main_calendar_controller.js

257 lines
8.0 KiB
JavaScript
Raw Normal View History

2024-08-11 14:18:36 +02:00
import {Controller} from "@hotwired/stimulus"
// Connects to data-controller="main-calendar"
export default class extends Controller {
2025-02-27 07:45:54 +01:00
static targets = ["dateDisplay", "navigation"]
2024-08-11 14:18:36 +02:00
connect() {
2025-02-27 07:45:54 +01:00
// Set height to full viewport
document.getElementById('main-calendar').style.height = '100vh';
document.getElementById('main-calendar').style.width = '100vw';
2024-08-24 07:06:09 +02:00
const calendar = new tui.Calendar(document.getElementById('main-calendar'), {
2024-08-11 14:18:36 +02:00
defaultView: 'week',
usageStatistics: false,
week: {
taskView: false,
2024-08-24 07:06:09 +02:00
scheduleView: false,
eventView: ['time'],
2025-02-27 07:45:54 +01:00
startDayOfWeek: 1, // Start week on Monday
2024-08-24 07:06:09 +02:00
hourStart: 4,
hourEnd: 21,
},
timezone: {
zones: [
{
timezoneName: 'UTC',
displayLabel: 'UTC' // Optional: Label for the timezone
}
]
// You might need `primaryTimezone: 'UTC'` here as well,
// depending on the exact library version and desired behavior.
// Let's start with just zones.
},
2025-02-27 07:45:54 +01:00
// This is important - set the height to 100%
height: '100%',
// Make sure it takes full width
width: '100%',
2024-08-24 07:06:09 +02:00
template: {
timegridDisplayPrimaryTime({time}) {
return `${time.getHours()} sati`;
2025-02-27 07:45:54 +01:00
},
popupDetailLocation(eventObj) {
return ''; // Empty location as requested
},
popupDetailAttendees(eventObj) {
return eventObj.attendees[0]; // Show team name
},
popupDetailState(eventObj) {
return '';
},
popupDetailBody(eventObj) {
return '';
2024-08-24 07:06:09 +02:00
}
2024-08-11 14:18:36 +02:00
},
calendars: [
{
id: 'cal1',
name: 'Work',
backgroundColor: '#00a9ff',
},
],
2025-02-27 07:45:54 +01:00
// Enable the built-in popup
useDetailPopup: true,
2024-08-11 14:18:36 +02:00
});
// Listener for clicks on empty time slots
calendar.on('selectDateTime', (eventData) => {
const startTime = new Date(eventData.start);
const endTime = new Date(startTime.getTime() + 30 * 60000); // Add 30 minutes
const formatForUrl = (date) => {
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
const hours = date.getHours().toString().padStart(2, '0');
const minutes = date.getMinutes().toString().padStart(2, '0');
return `${year}-${month}-${day}T${hours}:${minutes}:00`;
};
const startTimeParam = formatForUrl(startTime);
const endTimeParam = formatForUrl(endTime);
const newReservationUrl = `/reservations/new?start_time=${encodeURIComponent(startTimeParam)}&end_time=${encodeURIComponent(endTimeParam)}`;
if (window.Turbo) {
Turbo.visit(newReservationUrl);
} else {
window.location.href = newReservationUrl; // Fallback: Full page reload
}
// Prevent TUI Calendar from creating its default event/guide element
return false;
});
// Listener for delete button in popup
calendar.on('beforeDeleteEvent', async (eventObj) => {
const reservationId = eventObj.id;
const calendarId = eventObj.calendarId;
if (!reservationId) {
console.error("Reservation ID not found in event object.");
return false;
}
const csrfToken = this.getCsrfToken();
if (!csrfToken) {
console.error("CSRF token not found.");
alert("Error: Could not verify request security token.");
return false;
}
try {
const response = await fetch(`/reservations/${reservationId}`, {
method: 'DELETE',
headers: {
'X-CSRF-Token': csrfToken,
'Accept': 'application/json'
}
});
if (response.ok) {
calendar.deleteEvent(reservationId, calendarId);
alert('Reservation deleted.');
} else {
console.error(`Failed to delete reservation ${reservationId}. Status: ${response.status}`);
let errorMessage = 'Error deleting reservation.';
try {
const errorData = await response.json();
errorMessage += ` Server says: ${errorData.error || JSON.stringify(errorData)}`;
} catch (e) { /* Ignore */ }
alert(errorMessage);
}
} catch (error) {
console.error("Network error or exception during delete:", error);
alert("Error deleting reservation due to a network or script issue.");
}
return false; // Prevent TUI default delete handling
});
// Listener for edit button in popup (or drag/resize completion)
calendar.on('beforeUpdateEvent', (eventInfo) => {
const eventId = eventInfo.event?.id;
if (!eventId) {
console.error("Cannot edit: Event ID not found.");
return false;
}
// Navigate to edit page for both edit clicks and drag/resize events
const editUrl = `/reservations/${eventId}/edit`;
if (window.Turbo) {
Turbo.visit(editUrl);
} else {
window.location.href = editUrl;
}
// Prevent TUI's default update action
return false;
2024-08-11 14:18:36 +02:00
});
2024-09-08 14:00:15 +02:00
window.calendar = calendar;
2024-08-24 07:06:09 +02:00
this.getCalendardata();
2025-02-27 07:45:54 +01:00
2024-08-11 14:18:36 +02:00
calendar.render();
2025-02-27 07:45:54 +01:00
// Update the date display after rendering
this.updateDateDisplay();
2024-08-11 14:18:36 +02:00
}
2024-08-24 07:06:09 +02:00
getCalendardata() {
var reservations = JSON.parse(document.querySelector("#main-calendar").dataset.reservations);
window.reservations = reservations;
reservations.forEach(reservation => {
2024-09-08 14:00:15 +02:00
window.calendar.createEvents([
2024-08-24 07:06:09 +02:00
{
id: reservation.id,
calendarId: 'cal1',
2025-02-27 07:45:54 +01:00
title: reservation.customer.first_name + ' ' + reservation.customer.surname + ' (' + reservation.customer.phone + ')',
2024-08-24 07:06:09 +02:00
category: 'time',
dueDateClass: reservation.dueDateClass,
2025-02-27 07:45:54 +01:00
location: '', // Empty location as requested
attendees: [reservation.team.name], // Team name as attendee
2024-08-24 07:06:09 +02:00
start: reservation.start_time,
end: reservation.end_time
}
])
});
}
2025-02-27 07:45:54 +01:00
// Helper function to get CSRF token from meta tag
getCsrfToken() {
const token = document.querySelector('meta[name="csrf-token"]')?.content;
return token;
}
2025-02-27 07:45:54 +01:00
// Navigation methods - using the global window.calendar
prev() {
window.calendar.prev();
this.updateDateDisplay();
}
next() {
window.calendar.next();
this.updateDateDisplay();
}
today() {
window.calendar.today();
this.updateDateDisplay();
}
// Helper for updating the date display
updateDateDisplay() {
if (this.hasDateDisplayTarget) {
const calendar = window.calendar;
const currentDate = calendar.getDate();
// Format the date range based on the current view
const view = calendar.getViewName();
if (view === 'day') {
this.dateDisplayTarget.textContent = this.formatDate(currentDate);
} else if (view === 'week') {
// For week view, show range (e.g., "Aug 1 - 7, 2023")
const weekStart = new Date(currentDate);
weekStart.setDate(weekStart.getDate() - weekStart.getDay() + (weekStart.getDay() === 0 ? -6 : 1));
const weekEnd = new Date(weekStart);
weekEnd.setDate(weekStart.getDate() + 6);
this.dateDisplayTarget.textContent = `${this.formatDateShort(weekStart)} - ${this.formatDateShort(weekEnd)}`;
} else if (view === 'month') {
// For month view, show month and year (e.g., "August 2023")
this.dateDisplayTarget.textContent = currentDate.toLocaleString('default', { month: 'long', year: 'numeric' });
}
}
}
// Helper for formatting dates
formatDate(date) {
return date.toLocaleDateString('default', {
weekday: 'short',
month: 'short',
day: 'numeric',
year: 'numeric'
});
}
formatDateShort(date) {
return date.toLocaleDateString('default', {
month: 'short',
day: 'numeric'
});
}
}