const countInput = document.getElementById('child_count'); const template = document.getElementById('child-template'); const childrenContainer = document.getElementById('children-fields'); const hint = document.getElementById('capacity-hint'); const calendar = document.getElementById('booking-calendar'); const monthLabel = document.getElementById('calendar-month-label'); const selectedInputs = document.getElementById('selected-slot-inputs'); const selectedCount = document.getElementById('selected-count'); const selectedDatesList = document.getElementById('selected-dates-list'); let slots = []; let slotMap = new Map(); let selectedSlots = new Set(); let currentMonth = null; let calendarStart = null; let calendarEnd = null; const monthNames = ['styczeń','luty','marzec','kwiecień','maj','czerwiec','lipiec','sierpień','wrzesień','październik','listopad','grudzień']; const weekdayShort = ['Nd','Pon','Wt','Śr','Czw','Pt','Sob']; function parseLocalDate(iso){ const [y,m,d] = iso.split('-').map(Number); return new Date(y, m-1, d); } function isoDate(date){ return `${date.getFullYear()}-${String(date.getMonth()+1).padStart(2,'0')}-${String(date.getDate()).padStart(2,'0')}`; } function selectedPrefillModel(){ return new URLSearchParams(window.location.search).get('model'); } function maxCapacityAcrossSelected(){ if(selectedSlots.size === 0) return 8; return Math.min(...[...selectedSlots].map(id => Number(slotMap.get(id)?.free || 0))); } function renderChildren(){ if(!childrenContainer || !template || !countInput) return; const oldValues = [...childrenContainer.querySelectorAll('.child-card')].map(card => ({ name: card.querySelector('.child-name')?.value || '', age: card.querySelector('.child-age')?.value || '', model: card.querySelector('.child-model')?.value || 'undecided' })); const count = Number(countInput.value); childrenContainer.innerHTML = ''; for(let i=1;i<=count;i++){ const node = template.content.cloneNode(true); node.querySelector('.child-number').textContent = i; const nameInput = node.querySelector('.child-name'); const ageInput = node.querySelector('.child-age'); const modelSelect = node.querySelector('.child-model'); nameInput.name = `child_name_${i}`; ageInput.name = `child_age_${i}`; modelSelect.name = `child_model_${i}`; if(oldValues[i-1]){ nameInput.value = oldValues[i-1].name; ageInput.value = oldValues[i-1].age; modelSelect.value = oldValues[i-1].model; } else if(i === 1 && selectedPrefillModel()) { modelSelect.value = selectedPrefillModel(); } childrenContainer.appendChild(node); } } function updateHint(){ if(!hint || !countInput) return; const count = Number(countInput.value); if(selectedSlots.size === 0){ hint.textContent = `Zapisujesz ${count} ${count === 1 ? 'dziecko' : 'dzieci'}. Wybierz termin lub kilka terminów w kalendarzu.`; return; } const minFree = maxCapacityAcrossSelected(); if(count <= minFree){ hint.textContent = `Wybrane terminy mają co najmniej ${minFree} wolnych stanowisk. Rezerwujesz ${count} ${count === 1 ? 'stanowisko' : 'stanowiska'} w każdym terminie.`; } else { hint.textContent = `Co najmniej jeden termin ma tylko ${minFree} wolnych stanowisk. Zmniejsz liczbę dzieci albo usuń ten termin.`; } } function updateSelectedSummary(){ if(!selectedInputs || !selectedCount || !selectedDatesList) return; selectedInputs.innerHTML = ''; const selected = [...selectedSlots] .map(id => slotMap.get(id)) .filter(Boolean) .sort((a,b) => a.date.localeCompare(b.date)); selected.forEach(slot => { const input = document.createElement('input'); input.type = 'hidden'; input.name = 'slots'; input.value = slot.id; selectedInputs.appendChild(input); }); if(selected.length === 0){ selectedCount.textContent = 'Nie wybrano jeszcze terminu.'; selectedDatesList.innerHTML = ''; } else { selectedCount.textContent = `Wybrane terminy: ${selected.length}`; selectedDatesList.innerHTML = selected.map(slot => `${slot.label}` ).join(''); } updateHint(); } function toggleSlot(id){ const slot = slotMap.get(id); if(!slot || slot.free <= 0) return; const childCount = Number(countInput?.value || 1); if(!selectedSlots.has(id) && childCount > slot.free){ hint.textContent = `Tego dnia są tylko ${slot.free} wolne stanowiska. Zmniejsz liczbę dzieci albo wybierz inny termin.`; return; } if(selectedSlots.has(id)) selectedSlots.delete(id); else selectedSlots.add(id); renderCalendar(); updateSelectedSummary(); } function renderCalendar(){ if(!calendar || !currentMonth) return; const year = currentMonth.getFullYear(); const month = currentMonth.getMonth(); monthLabel.textContent = `${monthNames[month]} ${year}`; calendar.innerHTML = ''; const first = new Date(year, month, 1); const last = new Date(year, month + 1, 0); const mondayOffset = (first.getDay() + 6) % 7; for(let i=0;i${day}${weekdayShort[dateObj.getDay()]}${slot.free > 0 ? `${slot.free} wolnych` : 'brak miejsc'}${slot.free > 0 ? '16–19' : ''}`; } else { cell.classList.add('no-slot'); cell.innerHTML = `${day}`; } calendar.appendChild(cell); } const prev = document.getElementById('prev-month'); const next = document.getElementById('next-month'); const prevMonth = new Date(year, month-1, 1); const nextMonth = new Date(year, month+1, 1); if(prev) prev.disabled = prevMonth < new Date(calendarStart.getFullYear(), calendarStart.getMonth(), 1); if(next) next.disabled = nextMonth > new Date(calendarEnd.getFullYear(), calendarEnd.getMonth(), 1); } if(calendar){ const raw = document.getElementById('slots-data')?.textContent || '[]'; slots = JSON.parse(raw); slotMap = new Map(slots.map(slot => [slot.id, slot])); calendarStart = parseLocalDate(calendar.dataset.start); calendarEnd = parseLocalDate(calendar.dataset.end); const today = new Date(); const firstAllowed = new Date(calendarStart.getFullYear(), calendarStart.getMonth(), 1); const lastAllowed = new Date(calendarEnd.getFullYear(), calendarEnd.getMonth(), 1); let initial = new Date(today.getFullYear(), today.getMonth(), 1); if(initial < firstAllowed) initial = firstAllowed; if(initial > lastAllowed) initial = firstAllowed; currentMonth = initial; calendar.addEventListener('click', e => { const button = e.target.closest('[data-slot-id]'); if(button) toggleSlot(button.dataset.slotId); }); document.getElementById('prev-month')?.addEventListener('click', () => { currentMonth = new Date(currentMonth.getFullYear(), currentMonth.getMonth()-1, 1); renderCalendar(); }); document.getElementById('next-month')?.addEventListener('click', () => { currentMonth = new Date(currentMonth.getFullYear(), currentMonth.getMonth()+1, 1); renderCalendar(); }); selectedDatesList?.addEventListener('click', e => { const button = e.target.closest('[data-remove-slot]'); if(button) toggleSlot(button.dataset.removeSlot); }); renderCalendar(); updateSelectedSummary(); } if(countInput){ document.getElementById('plus')?.addEventListener('click',()=>{ const max = selectedSlots.size ? maxCapacityAcrossSelected() : 8; countInput.value = Math.min(Number(countInput.value)+1, max || 1); renderChildren(); updateHint(); }); document.getElementById('minus')?.addEventListener('click',()=>{ countInput.value = Math.max(Number(countInput.value)-1, 1); renderChildren(); updateHint(); }); renderChildren(); updateHint(); } const signupForm = document.getElementById('signup-form'); signupForm?.addEventListener('submit', e => { if(selectedSlots.size === 0){ e.preventDefault(); hint.textContent = 'Przed wysłaniem formularza wybierz co najmniej jeden termin w kalendarzu.'; document.querySelector('.calendar-fieldset')?.scrollIntoView({behavior:'smooth', block:'start'}); } });