Spa Day Planner Generator

Spa Day Planner

Design your perfect relaxation itinerary

Reservation Details

Preferences

Treatment Menu

Your Package

No treatments selected.

Total Duration: 0 min
Total Cost: $0.00

Proposed Itinerary

Includes 15-min transition buffer between services.

Summary

Arrival: --:--

Estimated Departure: --:--

Additional Notes & Requests

Ready to Relax?

Download your personalized itinerary PDF to take with you or send to the booking team.

Spa Itinerary

Plan prepared for:

Date:
Occasion:
Guests:

Selected Treatments

Service Duration Cost
Total:

Schedule

Notes:
Generated by Serenity Spa Planner

No treatments selected.

'; } else { basket.forEach((item, index) => { totalCost += item.cost; totalTime += item.duration; const div = document.createElement('div'); div.className = 'basket-item'; div.innerHTML = ` ${item.name} $${item.cost} × `; list.appendChild(div); }); } // Update Totals document.getElementById('spa-total-cost').innerText = '$' + totalCost.toFixed(2); document.getElementById('spa-total-time').innerText = totalTime + ' min'; // Check Budget const budget = parseFloat(document.getElementById('spa-budget').value) || 0; const warning = document.getElementById('spa-budget-warning'); if(budget > 0 && totalCost > budget) { warning.style.display = 'block'; } else { warning.style.display = 'none'; } } // --- Logic: Schedule Builder --- window.spaBuildItinerary = function() { const startInput = document.getElementById('spa-start-time').value; const lunchTime = parseInt(document.getElementById('spa-add-lunch').value); const buffer = 15; // min between services const timeline = document.getElementById('spa-timeline-container'); timeline.innerHTML = ''; if(basket.length === 0) { timeline.innerHTML = '

Please select treatments first.

'; return; } let [hrs, mins] = startInput.split(':').map(Number); let currentTime = new Date(); currentTime.setHours(hrs, mins, 0, 0); // Helper to fmt time const fmtTime = (date) => date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}); document.getElementById('summ-start').innerText = fmtTime(currentTime); // Build List including breaks let scheduleItems = [...basket]; // Insert Lunch if > 0, ideally in middle (simplified here: after 2nd service or halfway) if(lunchTime > 0 && scheduleItems.length > 1) { const insertIndex = Math.ceil(scheduleItems.length / 2); scheduleItems.splice(insertIndex, 0, { name: 'Break / Lunch', duration: lunchTime, isBreak: true }); } scheduleItems.forEach((item, index) => { const startStr = fmtTime(currentTime); // Calculate End currentTime.setMinutes(currentTime.getMinutes() + item.duration); const endStr = fmtTime(currentTime); // Add to Timeline const div = document.createElement('div'); div.className = 'timeline-item'; div.innerHTML = `
${startStr}
${item.name}
Until ${endStr} (${item.duration} min)
`; timeline.appendChild(div); // Add Buffer if not last item if(index < scheduleItems.length - 1 && !item.isBreak) { // buffer visual currentTime.setMinutes(currentTime.getMinutes() + buffer); } }); document.getElementById('summ-end').innerText = fmtTime(currentTime); }; // --- Navigation --- window.spaNextTab = function(tabId) { document.querySelectorAll('#spa-planner-tool .tab-content').forEach(t => t.classList.remove('active')); document.querySelectorAll('#spa-planner-tool .tab-btn').forEach(t => t.classList.remove('active')); document.getElementById(tabId).classList.add('active'); document.querySelector(`.tab-btn[data-tab="${tabId}"]`).classList.add('active'); document.getElementById('spa-planner-tool').scrollIntoView({ behavior: 'smooth' }); }; document.querySelectorAll('#spa-planner-tool .tab-btn').forEach(btn => { btn.addEventListener('click', function() { const id = this.getAttribute('data-tab'); spaNextTab(id); if(id === 'spa-tab-itinerary') spaBuildItinerary(); }); }); // --- PDF Generation --- document.getElementById('spa-download-btn').addEventListener('click', function() { // Populate PDF Data document.getElementById('pdf-guest-name').innerText = document.getElementById('spa-guest-name').value || 'Guest'; document.getElementById('pdf-date').innerText = document.getElementById('spa-date').value; document.getElementById('pdf-occasion').innerText = document.getElementById('spa-occasion').value; document.getElementById('pdf-guests').innerText = document.getElementById('spa-party-size').value; document.getElementById('pdf-notes').innerText = document.getElementById('spa-notes').value; // Treatments Table const tBody = document.getElementById('pdf-treatments-body'); tBody.innerHTML = ''; let costTotal = 0; let timeTotal = 0; basket.forEach(item => { costTotal += item.cost; timeTotal += item.duration; tBody.innerHTML += ` ${item.name} ${item.duration} min $${item.cost} `; }); document.getElementById('pdf-total-cost').innerText = '$' + costTotal.toFixed(2); document.getElementById('pdf-total-dur').innerText = timeTotal + ' min'; // Schedule List (Clone logic roughly) const schedList = document.getElementById('pdf-schedule-list'); schedList.innerHTML = ''; // Reuse timeline logic or simpler clone const timelineHTML = document.getElementById('spa-timeline-container').innerHTML; schedList.innerHTML = timelineHTML; // Clean up styles slightly for PDF if needed by stripping classes or adding inline styles via replace // For simplicity, html2pdf handles CSS well enough usually. const element = document.getElementById('spa-print-container'); const guestName = document.getElementById('spa-guest-name').value || 'My'; const opt = { margin: 0.5, filename: `${guestName}_Spa_Itinerary.pdf`, image: { type: 'jpeg', quality: 0.98 }, html2canvas: { scale: 2 }, jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' } }; html2pdf().set(opt).from(element).save(); }); });
Scroll to Top