Files
on-motorrad-buchungs-plugin/assets/js/admin-calendar.js

288 lines
12 KiB
JavaScript

document.addEventListener('DOMContentLoaded', function () {
var calendarEl = document.getElementById('on-admin-calendar');
if (!calendarEl) return;
// Modal Logic
var modal = document.getElementById('onAdminModal');
var closeBtn = document.getElementById('onAdminCloseModal');
var contentDiv = document.getElementById('onBookingDetailsContent');
var currentPostId = null;
function openModal() {
if (modal) modal.classList.add('is-open');
}
function closeModal() {
if (modal) modal.classList.remove('is-open');
currentPostId = null;
}
if (closeBtn) {
closeBtn.addEventListener('click', closeModal);
}
if (modal) {
modal.addEventListener('click', function (e) {
if (e.target === modal) closeModal();
});
}
// Helper: Format Date for Inputs
function formatDateISO(date) {
var d = new Date(date),
month = '' + (d.getMonth() + 1),
day = '' + d.getDate(),
year = d.getFullYear();
if (month.length < 2) month = '0' + month;
if (day.length < 2) day = '0' + day;
return [year, month, day].join('-');
}
var calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
locale: 'de',
height: window.innerHeight - 120, // Dynamic height: Viewport - WP Admin items
windowResize: function (view) {
calendar.setOption('height', window.innerHeight - 120);
},
editable: true, // Enable Drag & Drop
droppable: false,
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay'
},
events: {
url: ajaxurl,
method: 'POST',
extraParams: {
action: 'on_get_admin_bookings',
nonce: onBookingAdmin.nonce
}
},
eventDrop: function (info) {
// Handle Drag & Drop
if (!confirm("Möchtest du den Termin '" + info.event.title + "' wirklich verschieben auf " + info.event.start.toLocaleDateString() + "?")) {
info.revert();
return;
}
var newDate = formatDateISO(info.event.start);
var newTime = info.event.start.toTimeString().substring(0, 5); // HH:MM
// If dragged in month view, time might be messed up or set to 00:00.
// Ideally we keep original time if we don't have time view info?
// FullCalendar standard: strip time if dayGrid.
// Let's try to preserve time if possible or default to start time?
// Getting original time from oldEvent?
if (info.view.type === 'dayGridMonth' && info.event.allDay) {
// It might strip time. Let's assume we want to keep original time?
// But we don't have it easily if it became allDay.
// Actually, on backend we just updated the DATE.
// Let's check what we send.
// For now, let's just send the date and keep existing time if we pass empty time string?
// But if we drag to a timeSlot in week view, we definitely want the time.
if (!info.event.startStr.includes('T')) {
// It's a date string only
newTime = ''; // Backend should preserve old time if this is empty
}
}
jQuery.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'on_update_booking_date',
nonce: onBookingAdmin.nonce,
post_id: info.event.id,
new_date: newDate,
new_time: newTime
},
success: function (response) {
if (!response.success) {
alert('Fehler: ' + response.data.message);
info.revert();
}
},
error: function () {
alert('Verbindungsfehler.');
info.revert();
}
});
},
eventClick: function (info) {
info.jsEvent.preventDefault();
var postId = info.event.id;
if (postId) {
currentPostId = postId;
openModal();
contentDiv.innerHTML = '<div style="text-align:center; padding: 20px;">Lade Details...</div>';
// Fetch Details
jQuery.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'on_get_booking_details',
nonce: onBookingAdmin.nonce,
post_id: postId
},
success: function (response) {
if (response.success) {
var data = response.data;
var html = '<div>' + data.content + '</div>';
// Actions Area
html += '<div style="margin-top: 30px; padding-top: 20px; border-top: 1px solid #444; display: flex; gap: 10px; flex-wrap: wrap;">';
// Delete Button
html += '<button id="onBtnDelete" style="background:#d93025; color:#fff; border:none; padding:8px 15px; cursor:pointer; font-weight:bold;">Löschen</button>';
// Reschedule Toggle
html += '<button id="onBtnReschedule" style="background:#0061ff; color:#fff; border:none; padding:8px 15px; cursor:pointer; font-weight:bold;">Verschieben</button>';
html += '</div>';
// Reschedule Form (Hidden)
html += '<div id="onRescheduleForm" style="display:none; margin-top: 15px; background: rgba(255,255,255,0.05); padding: 15px; border: 1px solid #444;">';
html += '<h4 style="margin-top:0; color:#fff;">Neuer Termin</h4>';
html += '<label style="display:block; margin-bottom:5px;">Datum: <input type="date" id="onNewDate" value="' + (data.date || '') + '" style="width:100%; padding:8px;"></label>';
html += '<label style="display:block; margin-bottom:10px;">Zeit: <input type="time" id="onNewTime" value="' + (data.time || '') + '" style="width:100%; padding:8px;"></label>';
html += '<button id="onBtnSaveReschedule" style="background:#008000; color:#fff; border:none; padding:8px 15px; cursor:pointer; margin-right:5px;">Speichern</button>';
html += '<button id="onBtnCancelReschedule" style="background:#666; color:#fff; border:none; padding:8px 15px; cursor:pointer;">Abbrechen</button>';
html += '</div>';
contentDiv.innerHTML = html;
// Bind Events (jQuery Delegation for robustness when content is replaced)
// We can use direct clicks here since we just replaced HTML, but consistent jQuery is cleaner.
$('#onBtnDelete').off('click').on('click', function () {
if (confirm('Möchtest du diese Buchung wirklich unwiderruflich löschen?')) {
deleteBooking(currentPostId);
}
});
$('#onBtnReschedule').off('click').on('click', function () {
$('#onRescheduleForm').show();
$(this).hide();
});
$('#onBtnCancelReschedule').off('click').on('click', function () {
$('#onRescheduleForm').hide();
$('#onBtnReschedule').show();
});
$('#onBtnSaveReschedule').off('click').on('click', function () {
var nd = $('#onNewDate').val();
var nt = $('#onNewTime').val();
updateBooking(currentPostId, nd, nt);
});
// Save Notes Handler
$('#onSaveNotesBtnCalendar').off('click').on('click', function () {
var btn = $(this);
var notes = $('#onAdminNotesCalendar').val();
var msg = $('#onSaveNotesMsgCalendar');
btn.prop('disabled', true);
msg.text('Speichere...').css('color', '#333');
jQuery.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'on_update_booking_notes',
post_id: currentPostId,
notes: notes,
nonce: onBookingAdmin.nonce
},
success: function (response) {
if (response.success) {
msg.text('Gespeichert!').css('color', 'green');
} else {
msg.text('Fehler.').css('color', 'red');
}
},
error: function () {
msg.text('Fehler.').css('color', 'red');
},
complete: function () {
setTimeout(function () {
btn.prop('disabled', false);
msg.text('');
}, 2000);
}
});
});
} else {
contentDiv.innerHTML = 'Fehler: ' + (response.data.message || 'Unbekannt');
}
},
error: function () {
contentDiv.innerHTML = 'Verbindungsfehler.';
}
});
}
}
});
calendar.render();
// AJAX Actions
function deleteBooking(id) {
contentDiv.innerHTML = 'Lösche...';
jQuery.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'on_delete_booking',
nonce: onBookingAdmin.nonce,
post_id: id
},
success: function (res) {
if (res.success) {
closeModal();
calendar.refetchEvents(); // Refresh calendar
} else {
alert('Fehler: ' + res.data.message);
openModal(); // Re-open or keep open?
}
}
});
}
function updateBooking(id, date, time) {
if (!date || !time) {
alert('Bitte Datum und Zeit wählen.');
return;
}
var saveBtn = document.getElementById('onBtnSaveReschedule');
saveBtn.innerText = 'Speichere...';
jQuery.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'on_update_booking_date',
nonce: onBookingAdmin.nonce,
post_id: id,
new_date: date,
new_time: time
},
success: function (res) {
if (res.success) {
closeModal();
calendar.refetchEvents();
} else {
alert('Fehler: ' + res.data.message);
saveBtn.innerText = 'Speichern';
}
}
});
}
});