361 lines
13 KiB
JavaScript
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);
|
|
}
|
|
});
|
|
});
|
|
|
|
});
|