38cc93bc1c
Courses without scraped layouts can now be used in tours by entering a layout name and par manually. The layout is saved to the database for reuse. All courses are shown in the dropdown, not just those with existing layouts.
256 lines
7.6 KiB
JavaScript
256 lines
7.6 KiB
JavaScript
var coursesData = [];
|
|
|
|
async function loadCourses() {
|
|
try {
|
|
var res = await fetch('/api/tours/courses-with-layouts');
|
|
coursesData = await res.json();
|
|
updateCourseDropdowns();
|
|
} catch (err) {
|
|
console.error('Failed to load courses:', err);
|
|
}
|
|
}
|
|
|
|
function populateSelectWithCourses(select) {
|
|
select.textContent = '';
|
|
var defaultOpt = document.createElement('option');
|
|
defaultOpt.value = '';
|
|
defaultOpt.textContent = 'Select a course...';
|
|
select.appendChild(defaultOpt);
|
|
|
|
coursesData.forEach(function(course) {
|
|
var opt = document.createElement('option');
|
|
opt.value = course.id;
|
|
opt.textContent = course.name + ' (' + course.city + ')';
|
|
select.appendChild(opt);
|
|
});
|
|
}
|
|
|
|
function updateCourseDropdowns() {
|
|
document.querySelectorAll('.course-select').forEach(function(select) {
|
|
var currentValue = select.value;
|
|
populateSelectWithCourses(select);
|
|
select.value = currentValue;
|
|
});
|
|
}
|
|
|
|
function onCourseChange(courseSelect) {
|
|
var index = courseSelect.dataset.index;
|
|
var layoutSelect = courseSelect.parentElement.querySelector('.layout-select');
|
|
var manualFields = courseSelect.parentElement.querySelector('.manual-layout');
|
|
var courseId = parseInt(courseSelect.value);
|
|
|
|
layoutSelect.textContent = '';
|
|
layoutSelect.disabled = true;
|
|
|
|
if (manualFields) {
|
|
manualFields.style.display = 'none';
|
|
}
|
|
|
|
var defaultOpt = document.createElement('option');
|
|
defaultOpt.value = '';
|
|
defaultOpt.textContent = 'Select layout...';
|
|
layoutSelect.appendChild(defaultOpt);
|
|
|
|
if (!courseId) return;
|
|
|
|
var course = coursesData.find(function(c) { return c.id === courseId; });
|
|
if (!course) return;
|
|
|
|
if (course.layouts.length > 0) {
|
|
course.layouts.forEach(function(layout) {
|
|
var opt = document.createElement('option');
|
|
opt.value = layout.id;
|
|
opt.textContent = layout.name + ' (Par ' + layout.par + ')';
|
|
layoutSelect.appendChild(opt);
|
|
});
|
|
|
|
// Add "custom" option at the end
|
|
var customOpt = document.createElement('option');
|
|
customOpt.value = 'custom';
|
|
customOpt.textContent = '+ Add custom layout...';
|
|
layoutSelect.appendChild(customOpt);
|
|
} else {
|
|
// No layouts — show "custom" as the only real option
|
|
var customOpt = document.createElement('option');
|
|
customOpt.value = 'custom';
|
|
customOpt.textContent = '+ Add custom layout...';
|
|
layoutSelect.appendChild(customOpt);
|
|
}
|
|
|
|
layoutSelect.disabled = false;
|
|
}
|
|
|
|
function onLayoutChange(layoutSelect) {
|
|
var manualFields = layoutSelect.parentElement.querySelector('.manual-layout');
|
|
if (layoutSelect.value === 'custom') {
|
|
if (manualFields) manualFields.style.display = '';
|
|
} else {
|
|
if (manualFields) manualFields.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
function createManualLayoutFields() {
|
|
var div = document.createElement('div');
|
|
div.className = 'manual-layout';
|
|
div.style.display = 'none';
|
|
|
|
var nameInput = document.createElement('input');
|
|
nameInput.type = 'text';
|
|
nameInput.className = 'input layout-name-input';
|
|
nameInput.placeholder = 'Layout name';
|
|
|
|
var parInput = document.createElement('input');
|
|
parInput.type = 'number';
|
|
parInput.className = 'input layout-par-input';
|
|
parInput.placeholder = 'Par';
|
|
parInput.min = '1';
|
|
parInput.style.width = '80px';
|
|
|
|
div.appendChild(nameInput);
|
|
div.appendChild(parInput);
|
|
return div;
|
|
}
|
|
|
|
var courseIndex = 1;
|
|
|
|
function createCourseEntry(index) {
|
|
var entry = document.createElement('div');
|
|
entry.className = 'course-entry';
|
|
|
|
var courseSelect = document.createElement('select');
|
|
courseSelect.className = 'input course-select';
|
|
courseSelect.dataset.index = index;
|
|
populateSelectWithCourses(courseSelect);
|
|
courseSelect.addEventListener('change', function() { onCourseChange(courseSelect); });
|
|
|
|
var layoutSelect = document.createElement('select');
|
|
layoutSelect.className = 'input layout-select';
|
|
layoutSelect.dataset.index = index;
|
|
layoutSelect.disabled = true;
|
|
var defaultOpt = document.createElement('option');
|
|
defaultOpt.value = '';
|
|
defaultOpt.textContent = 'Select course first';
|
|
layoutSelect.appendChild(defaultOpt);
|
|
layoutSelect.addEventListener('change', function() { onLayoutChange(layoutSelect); });
|
|
|
|
var manualFields = createManualLayoutFields();
|
|
|
|
entry.appendChild(courseSelect);
|
|
entry.appendChild(layoutSelect);
|
|
entry.appendChild(manualFields);
|
|
|
|
return entry;
|
|
}
|
|
|
|
function addCourseEntry() {
|
|
var container = document.getElementById('course-selector');
|
|
var entry = createCourseEntry(courseIndex);
|
|
|
|
var removeBtn = document.createElement('button');
|
|
removeBtn.className = 'btn-remove';
|
|
removeBtn.type = 'button';
|
|
var icon = document.createElement('i');
|
|
icon.className = 'fas fa-times';
|
|
removeBtn.appendChild(icon);
|
|
removeBtn.addEventListener('click', function() { entry.remove(); });
|
|
|
|
entry.appendChild(removeBtn);
|
|
container.appendChild(entry);
|
|
|
|
courseIndex++;
|
|
}
|
|
|
|
async function createTour() {
|
|
var name = document.getElementById('tour-name').value.trim();
|
|
var startDate = document.getElementById('tour-start').value;
|
|
var endDate = document.getElementById('tour-end').value;
|
|
|
|
if (!name || !startDate || !endDate) {
|
|
alert('Please fill in name and dates');
|
|
return;
|
|
}
|
|
|
|
var courses = [];
|
|
var valid = true;
|
|
document.querySelectorAll('.course-entry').forEach(function(entry) {
|
|
var courseId = entry.querySelector('.course-select').value;
|
|
var layoutSelect = entry.querySelector('.layout-select');
|
|
var layoutValue = layoutSelect.value;
|
|
|
|
if (!courseId) return;
|
|
|
|
if (layoutValue === 'custom') {
|
|
var layoutName = entry.querySelector('.layout-name-input').value.trim();
|
|
var par = entry.querySelector('.layout-par-input').value;
|
|
if (!layoutName || !par) {
|
|
alert('Please fill in layout name and par for custom layouts');
|
|
valid = false;
|
|
return;
|
|
}
|
|
courses.push({ courseId: parseInt(courseId), layoutName: layoutName, par: parseInt(par) });
|
|
} else if (layoutValue) {
|
|
courses.push({ courseId: parseInt(courseId), layoutId: parseInt(layoutValue) });
|
|
}
|
|
});
|
|
|
|
if (!valid) return;
|
|
|
|
if (courses.length === 0) {
|
|
alert('Please select at least one course with a layout');
|
|
return;
|
|
}
|
|
|
|
var btn = document.getElementById('create-tour-btn');
|
|
btn.disabled = true;
|
|
|
|
try {
|
|
var res = await fetch('/api/tours', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ name: name, startDate: startDate, endDate: endDate, courses: courses })
|
|
});
|
|
|
|
var data = await res.json();
|
|
if (data.success) {
|
|
var link = document.getElementById('tour-link');
|
|
link.href = '/tours/' + data.code;
|
|
link.textContent = window.location.origin + '/tours/' + data.code;
|
|
document.getElementById('tour-created').style.display = '';
|
|
} else {
|
|
alert(data.error || 'Failed to create tour');
|
|
}
|
|
} catch (err) {
|
|
console.error('Error creating tour:', err);
|
|
alert('Failed to create tour');
|
|
} finally {
|
|
btn.disabled = false;
|
|
}
|
|
}
|
|
|
|
function goToTour() {
|
|
var code = document.getElementById('tour-code').value.trim().toUpperCase();
|
|
if (code) {
|
|
window.location.href = '/tours/' + code;
|
|
}
|
|
}
|
|
|
|
// Initialize
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
loadCourses();
|
|
|
|
// Replace the initial static course entry with a dynamic one
|
|
var container = document.getElementById('course-selector');
|
|
container.textContent = '';
|
|
container.appendChild(createCourseEntry(0));
|
|
|
|
// Delegate change events
|
|
container.addEventListener('change', function(e) {
|
|
if (e.target.classList.contains('course-select')) {
|
|
onCourseChange(e.target);
|
|
}
|
|
if (e.target.classList.contains('layout-select')) {
|
|
onLayoutChange(e.target);
|
|
}
|
|
});
|
|
});
|