Files
on-motorrad-buchungs-plugin/assets/js/script.js

361 lines
13 KiB
JavaScript

jQuery(document).ready(function ($) {
// --- VARIABLES ---
const modal = $('#onModalOverlay');
const form = $('#onBookingForm');
const feedback = $('#formFeedback');
// --- MODAL LOGIC ---
// Move Modals to Body to prevent Stacking Context issues
$('#onModalOverlay').appendTo('body');
$('#onStatusModalOverlay').appendTo('body');
$('#onSuccessModalOverlay').appendTo('body');
// Fix desktop scroll: prevent wheel events from bubbling to body
$('.on-modal-content').on('wheel', function (e) {
e.stopPropagation();
});
// Use Event Delegation for Booking Trigger
$(document).on('click', '.js-open-booking', function (e) {
e.preventDefault();
modal.addClass('is-open');
$('body').addClass('on-modal-open');
});
function closeFrontendModal() {
modal.removeClass('is-open');
$('body').removeClass('on-modal-open'); // Unlock Scroll
}
$('#onCloseModal').on('click', closeFrontendModal);
modal.on('click', function (e) {
if ($(e.target).is(modal)) {
closeFrontendModal();
}
});
// --- SUCCESS MODAL ---
const successModal = $('#onSuccessModalOverlay');
function closeSuccessModal() {
successModal.removeClass('is-open');
$('body').removeClass('on-modal-open');
}
$('#onCloseSuccessModal, #onSuccessCloseBtn').on('click', closeSuccessModal);
successModal.on('click', function (e) {
if ($(e.target).is(successModal)) {
closeSuccessModal();
}
});
// --- SERVICE SELECTION - STEP 1 ---
let selectedServiceId = null;
let selectedServiceDuration = null;
$('#serviceSelect').on('change', function () {
selectedServiceId = $(this).val();
const selectedOption = $(this).find(':selected');
selectedServiceDuration = selectedOption.data('duration') || 30;
// Store duration in hidden field
$('#serviceDuration').val(selectedServiceDuration);
// Show calendar step
$('#stepCalendar').slideDown();
// Reset subsequent steps
$('#timeSection').slideUp();
$('#stepDetails').slideUp();
$('#selectedDate').val('');
$('#selectedTime').val('');
$('.on-day').removeClass('selected');
$('.on-time-slot').removeClass('selected');
// Render calendar
renderCalendar();
});
// --- CALENDAR LOGIC - STEP 2 ---
const monthNames = ["JAN", "FEB", "MÄR", "APR", "MAI", "JUN", "JUL", "AUG", "SEP", "OKT", "NOV", "DEZ"];
let currentDate = new Date();
function renderCalendar() {
const year = currentDate.getFullYear();
const month = currentDate.getMonth();
$('#monthYear').text(`${monthNames[month]} ${year}`);
const grid = $('#calendarGrid');
grid.empty();
grid.append('<div class="on-day-name">Mo</div><div class="on-day-name">Di</div><div class="on-day-name">Mi</div><div class="on-day-name">Do</div><div class="on-day-name">Fr</div><div class="on-day-name">Sa</div><div class="on-day-name">So</div>');
const firstDay = new Date(year, month, 1);
const daysInMonth = new Date(year, month + 1, 0).getDate();
let offset = (firstDay.getDay() + 6) % 7;
for (let i = 0; i < offset; i++) {
grid.append('<div class="on-day empty"></div>');
}
for (let i = 1; i <= daysInMonth; i++) {
const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(i).padStart(2, '0')}`;
const $day = $(`<div class="on-day" data-date="${dateStr}">${i}</div>`);
const checkDate = new Date(year, month, i);
const today = new Date();
today.setHours(0, 0, 0, 0);
if (checkDate < today) {
$day.addClass('disabled');
} else {
$day.on('click', function () {
if ($(this).hasClass('disabled')) return;
$('.on-day').removeClass('selected');
$(this).addClass('selected');
$('#selectedDate').val(dateStr);
// Fetch slots using service-based endpoint
fetchSlotsForService(dateStr);
});
}
grid.append($day);
}
}
$('#prevMonth').on('click', function () {
currentDate.setMonth(currentDate.getMonth() - 1);
renderCalendar();
});
$('#nextMonth').on('click', function () {
currentDate.setMonth(currentDate.getMonth() + 1);
renderCalendar();
});
// Don't render calendar on load - wait for service selection
// renderCalendar();
// --- SLOT FETCHING - STEP 3 ---
function fetchSlotsForService(date) {
const timeSection = $('#timeSection');
const timeGrid = $('#timeGrid');
// Hide details section when date changes
$('#stepDetails').slideUp();
$('#selectedTime').val('');
// AJAX Call to get slots based on service duration
$.ajax({
url: onBookingData.ajaxurl,
type: 'POST',
data: {
action: 'on_get_slots_for_service',
service_id: selectedServiceId,
date: date,
nonce: onBookingData.nonce
},
success: function (response) {
if (response.success) {
timeGrid.empty();
const slots = response.data.slots;
if (slots.length === 0) {
timeGrid.append('<div style="grid-column: 1/-1; text-align:center; color:#888;">Keine Termine verfügbar.</div>');
} else {
slots.forEach(slot => {
const $slot = $(`<div class="on-time-slot" data-time="${slot}">${slot}</div>`);
$slot.on('click', function () {
$('.on-time-slot').removeClass('selected');
$(this).addClass('selected');
$('#selectedTime').val(slot);
// Show details section - Step 4
$('#stepDetails').slideDown();
});
timeGrid.append($slot);
});
}
timeSection.slideDown();
} else {
alert('Fehler beim Laden der Zeiten: ' + (response.data.message || ''));
}
}
});
}
// --- STATUS CHECK LOGIC ---
const statusModal = $('#onStatusModalOverlay');
// Force Uppercase on Input
$('#onTrackingIdInput').on('input', function () {
$(this).val($(this).val().toUpperCase());
});
// Use Event Delegation for Status Trigger
$(document).on('click', '.js-open-status', function (e) {
e.preventDefault();
statusModal.addClass('is-open');
$('body').addClass('on-modal-open');
console.log('Status Modal Open - Scroll Locked');
});
function closeStatusModal() {
statusModal.removeClass('is-open');
$('body').removeClass('on-modal-open');
$('#statusResult').empty();
$('#onTrackingIdInput').val('');
console.log('Status Modal Closed - Scroll Unlocked');
}
$('#onCloseStatusModal').on('click', closeStatusModal);
statusModal.on('click', function (e) {
if ($(e.target).is(statusModal)) {
closeStatusModal();
}
});
$('#onCheckStatusBtn').on('click', function (e) {
e.preventDefault();
const trackingId = $('#onTrackingIdInput').val().trim();
const resultDiv = $('#statusResult');
if (!trackingId) {
resultDiv.text('Bitte ID eingeben.').css('color', '#ff3333');
return;
}
resultDiv.text('Lade...').css('color', 'var(--on-text)');
$.ajax({
url: onBookingData.ajaxurl,
type: 'POST',
data: {
action: 'on_check_tracking_status',
tracking_id: trackingId,
nonce: onBookingData.nonce
},
success: function (response) {
if (response.success) {
// Map status to colors
const statusColors = {
'Warten': '#0061ff', // Blue
'In Bearbeitung': '#ff9500', // Orange
'Abholbereit': '#34c759' // Green
};
const statusColor = statusColors[response.data.status] || '#0061ff';
let notesHtml = '';
if (response.data.notes) {
notesHtml = '<div class="on-status-notes" style="margin-top:10px; padding:10px; background:rgba(255,255,255,0.1); border-radius:4px; font-size:0.9em; text-align:left;"><strong>Notiz:</strong><br>' + response.data.notes + '</div>';
}
resultDiv.html(`Status: <span style="color:${statusColor}; font-weight:bold;">${response.data.status}</span><br><small>${response.data.date} um ${response.data.time}</small>${notesHtml}`).css('color', 'var(--on-text)').removeClass('on-error-msg');
} else {
resultDiv.text(response.data.message || 'Nicht gefunden.').css('color', '#ff3333').addClass('on-error-msg');
}
},
error: function () {
resultDiv.text('Fehler beim Abfragen.').css('color', '#ff3333').addClass('on-error-msg');
}
});
});
// --- FORM SUBMISSION ---
form.on('submit', function (e) {
e.preventDefault();
// Validation (skip service/date/time checks in simple mode)
if (!onBookingData.simpleMode) {
if (!$('#serviceSelect').val()) {
alert('Bitte wähle einen Service aus.');
return;
}
if (!$('#selectedDate').val() || !$('#selectedTime').val()) {
alert('Bitte wähle ein Datum und eine Uhrzeit aus.');
return;
}
}
// File size check (max 10MB)
const fileInput = this.querySelector('input[type="file"]');
if (fileInput && fileInput.files.length > 0) {
const maxSize = 10 * 1024 * 1024; // 10MB
if (fileInput.files[0].size > maxSize) {
alert('Das Bild ist zu groß (max. 10 MB). Bitte wähle ein kleineres Bild.');
return;
}
}
const formData = new FormData(this);
formData.append('action', 'on_submit_booking');
formData.append('nonce', onBookingData.nonce);
const submitBtn = $('#submitBtn');
const originalText = submitBtn.html();
submitBtn.prop('disabled', true).html('<span>Sende...</span>');
feedback.hide().removeClass('on-error-msg on-success-msg');
$.ajax({
url: onBookingData.ajaxurl,
type: 'POST',
data: formData,
processData: false,
contentType: false,
success: function (response) {
if (response.success) {
form.find('input:not([type=hidden]), select, textarea').val('');
$('.on-day').removeClass('selected');
$('.on-time-slot').removeClass('selected');
// Reset all steps (skip stepDetails in simple mode)
if (!onBookingData.simpleMode) {
$('#stepCalendar').hide();
$('#timeSection').hide();
$('#stepDetails').hide();
}
// Reset selection variables
selectedServiceId = null;
selectedServiceDuration = null;
// Close the booking modal
closeFrontendModal();
// Show success modal with tracking ID
if (response.data.tracking_id) {
$('#successTrackingId').text(response.data.tracking_id);
} else {
$('#successTrackingId').text('N/A');
}
// Show upload warning if present
if (response.data.upload_warning) {
alert(response.data.upload_warning);
}
successModal.addClass('is-open');
$('body').addClass('on-modal-open');
} else {
feedback.addClass('on-error-msg').text(response.data.message || 'Ein Fehler ist aufgetreten.').slideDown();
}
},
error: function () {
feedback.addClass('on-error-msg').text('Server-Fehler. Bitte später erneut versuchen.').slideDown();
},
complete: function () {
submitBtn.prop('disabled', false).html(originalText);
}
});
});
});