/**
* Booking JavaScript for handling JSON API calls
*/
// Store event data from template
let eventData = null;
const loader = function() {
// Booking form
const bookingForm = document.getElementById('booking-form');
if (bookingForm) {
bookingForm.addEventListener('submit', handleBookingFormSubmit);
}
};
document.addEventListener('DOMContentLoaded', loader);
/**
* Handle booking form submission
*/
async function handleBookingFormSubmit(e) {
e.preventDefault();
const submitBtn = e.target.querySelector('button[type="submit"]');
const originalHTML = submitBtn.innerHTML;
try {
// Show loading state
submitBtn.disabled = true;
submitBtn.innerHTML = 'Wird gesendet...';
// Get event slug from form
const eventSlug = e.target.getAttribute('data-event-slug');
// Build booking data from form
const bookingData = buildBookingDataFromForm(e.target);
// Send API request to prepare booking
const response = await fetch(`/api/events/${eventSlug}/prepareBooking`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(bookingData)
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.error || 'Unbekannter Fehler aufgetreten');
}
// Save token to localStorage
localStorage.setItem('bookingPreparationToken', result.data.token);
console.log(result.data.token);
// Create form to submit to confirmation page
const confirmForm = document.createElement('form');
confirmForm.method = 'POST';
confirmForm.action = `/event/${eventSlug}/confirm`;
const tokenInput = document.createElement('input');
tokenInput.type = 'hidden';
tokenInput.name = 'token';
tokenInput.value = result.data.token;
confirmForm.appendChild(tokenInput);
document.body.appendChild(confirmForm);
confirmForm.submit();
} catch (error) {
// Show error message
showErrorMessage(error.message);
// Reset button state
submitBtn.disabled = false;
submitBtn.innerHTML = originalHTML;
}
}
addEventListener("focusout", (event) => {
buildBookingDataFromForm(document.getElementById('booking-form'));
});
function elementChange(event) {
buildBookingDataFromForm(document.getElementById('booking-form'));
loadForm();
}
function updateAddon(btn) {
buildBookingDataFromForm(document.getElementById('booking-form'));
loadForm();
}
function addParticipant() {
buildBookingDataFromForm(document.getElementById('booking-form'));
var bookingDataStr = localStorage.getItem('bookingData');
var bookingData = JSON.parse(bookingDataStr);
bookingData.participants.push({})
localStorage.setItem('bookingData', JSON.stringify(bookingData));
loadForm();
}
function removeParticipant(btn) {
console.log(btn.dataset.participantDelete);
const delBtns = document.querySelectorAll("button[data-participant-delete]")
console.log(delBtns.length);
// Only remove if there is more than one participant
if (delBtns.length <= 1) {
return
}
// Manilupate the participant array
buildBookingDataFromForm(document.getElementById('booking-form'));
var bookingDataStr = localStorage.getItem('bookingData');
var bookingData = JSON.parse(bookingDataStr);
bookingData.participants.splice(btn.dataset.participantDelete, 1);
localStorage.setItem('bookingData', JSON.stringify(bookingData));
loadForm();
}
/**
* Build booking data object from form
*/
function buildBookingDataFromForm(form) {
// Contact information - backend expects these at root level, not nested in 'address'
const bookingData = {
email: form.querySelector('#email').value || '',
street: form.querySelector('#street').value || '',
postalCode: form.querySelector('#postal_code').value || '',
city: form.querySelector('#city').value || '',
phone: form.querySelector('#phone').value || '',
country: form.querySelector('#country').value || 'de',
vouchers: form.querySelector('#voucher').value.split(','),
participants: []
};
// Process participants
const participantSections = form.querySelectorAll('.participant-section');
participantSections.forEach((section, index) => {
const participant = {
name: section.querySelector(`[name="participants[${index}][name]"]`).value,
isMember: section.querySelector(`[name="participants[${index}][is_member]"]`).checked,
ticketCategoryId: parseInt(section.querySelector(`[name="participants[${index}][category]"]`).value, 10),
questionnaire: {},
addons: [],
};
// Process questionnaire answers
const questionnaireInputs = section.querySelectorAll('[name^="participants[' + index + '][questionnaire]"]');
questionnaireInputs.forEach(input => {
const nameMatch = input.name.match(/\[questionnaire\]\[([^\]]+)\]/);
if (nameMatch) {
const slug = nameMatch[1];
// Handle different input types
if (input.type === 'radio') {
if (input.checked) {
participant.questionnaire[slug] = input.value;
}
} else if (input.type === 'checkbox') {
if (input.checked) {
participant.questionnaire[slug] = 'true';
} else {
participant.questionnaire[slug] = 'false';
}
} else {
// Only include non-empty values
if (input.value.trim() !== '') {
participant.questionnaire[slug] = input.value;
}
}
}
});
const addons = section.querySelectorAll('input[data-addon-checkbox]');
for (const addon of addons) {
if (!addon.checked) {
continue;
}
const addonId = parseInt(addon.dataset.addonId, 10);
const payloadAddon = {
addonId: addonId,
questionnaire: {}
}
const questions = section.querySelectorAll(`[data-participant-index='${index}'][data-addon-id='${addonId}'][data-addon-question]`);
for (const question of questions) {
switch (question.dataset.addonQuestionType) {
case 'bool':
case 'string':
case 'uint':
case 'dropdown':
payloadAddon.questionnaire[question.dataset.addonQuestion] = question.value;
break;
case 'radio':
// Only add the selected radio button
if (question.checked) {
payloadAddon.questionnaire[question.dataset.addonQuestion] = question.value;
}
break;
}
}
participant.addons.push(payloadAddon);
}
bookingData.participants.push(participant);
});
// Debug logging
console.log('Built booking data:', bookingData);
localStorage.setItem('bookingData', JSON.stringify(bookingData));
return bookingData;
}
function showErrorMessage(message) {
// Remove existing error message
const existingError = document.getElementById('api-error-message');
if (existingError) {
existingError.remove();
}
// Create error message element with Bootstrap styling
const errorElement = document.createElement('div');
errorElement.id = 'api-error-message';
errorElement.className = 'alert alert-danger alert-dismissible fade show';
errorElement.innerHTML = `
Fehler: ${message}
`;
// Insert at the top of the main container
const container = document.querySelector('main');
const firstChild = container.querySelector('.row');
container.insertBefore(errorElement, firstChild);
// Scroll to error message
errorElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
}