Complete Your Booking

You're one step away from your appointment with Katie

+ depositAmt; document.getElementById('totalAmount').textContent = ' } // ============================================= // PAYMENT HANDLER // ============================================= async function handlePayment() { clearError(); var name = document.getElementById('cardholderName').value.trim(); if (!name) { showError('Please enter the name on your card.'); return; } if (!stripe || !cardNumber) { showError('Payment system not yet configured. Please contact us directly to complete your booking.'); return; } var btn = document.getElementById('payBtn'); btn.disabled = true; btn.textContent = 'Processing...'; try { var amountCents = (selectedOption === 'deposit' ? DEPOSIT_AMOUNT : serviceTotal) * 100; // ------------------------------------------------------- // STRIPE INTEGRATION POINT // On your server, create a PaymentIntent and return the // client_secret. Replace the fetch URL with your endpoint. // // Example server endpoint (Node/Express): // POST /create-payment-intent // Body: { amount, currency, metadata } // Returns: { clientSecret } // ------------------------------------------------------- var response = await fetch('/create-payment-intent', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ amount: amountCents, currency: 'usd', metadata: { service: bookingData.service, date: bookingData.date, time: bookingData.time, client_name: bookingData.name, client_email: bookingData.email, payment_type: selectedOption } }) }); if (!response.ok) throw new Error('Server error. Please try again.'); var data = await response.json(); var result = await stripe.confirmCardPayment(data.clientSecret, { payment_method: { card: cardNumber, billing_details: { name: name } } }); if (result.error) { showError(result.error.message); btn.disabled = false; btn.innerHTML = 'Pay ' + document.getElementById('payBtnAmount').textContent + ''; } else if (result.paymentIntent.status === 'succeeded') { // Save appointment to collection if (window.siteData) { await window.siteData.create('appointments', { client_name: bookingData.name, client_email: bookingData.email, client_phone: bookingData.phone, service_type: bookingData.service, date: bookingData.date, time: bookingData.time, notes: bookingData.notes, payment_type: selectedOption, amount_paid: selectedOption === 'deposit' ? DEPOSIT_AMOUNT : serviceTotal, payment_id: result.paymentIntent.id, status: 'confirmed' }); } showSuccess(); } } catch(err) { showError(err.message || 'Something went wrong. Please try again.'); btn.disabled = false; updatePayBtn(); } } function updatePayBtn() { var amtLabel = selectedOption === 'deposit' ? '— $' + DEPOSIT_AMOUNT + ' Deposit' : (serviceTotal ? '— $' + serviceTotal + ' in Full' : ''); document.getElementById('payBtn').innerHTML = 'Pay ' + amtLabel + ''; document.getElementById('payBtn').disabled = false; } // ============================================= // HELPERS // ============================================= function formatDate(dateStr) { if (!dateStr) return 'Date TBD'; var d = new Date(dateStr + 'T12:00:00'); return d.toLocaleDateString('en-US', { weekday:'long', month:'long', day:'numeric', year:'numeric' }); } function showError(msg) { var el = document.getElementById('checkoutError'); el.textContent = msg; el.style.display = 'block'; } function clearError() { var el = document.getElementById('checkoutError'); el.style.display = 'none'; el.textContent = ''; } function showSuccess() { document.getElementById('paymentForm').style.display = 'none'; document.getElementById('checkoutSuccess').style.display = 'block'; } function handleLogout() { window.siteAuth.logout(); window.location.href = 'index.html'; } + depositAmt; document.getElementById('totalLabel').textContent = 'Deposit Due Today'; document.getElementById('summaryNote').textContent = fullAmt ? 'Remaining balance of } // ============================================= // PAYMENT HANDLER // ============================================= async function handlePayment() { clearError(); var name = document.getElementById('cardholderName').value.trim(); if (!name) { showError('Please enter the name on your card.'); return; } if (!stripe || !cardNumber) { showError('Payment system not yet configured. Please contact us directly to complete your booking.'); return; } var btn = document.getElementById('payBtn'); btn.disabled = true; btn.textContent = 'Processing...'; try { var amountCents = (selectedOption === 'deposit' ? DEPOSIT_AMOUNT : serviceTotal) * 100; // ------------------------------------------------------- // STRIPE INTEGRATION POINT // On your server, create a PaymentIntent and return the // client_secret. Replace the fetch URL with your endpoint. // // Example server endpoint (Node/Express): // POST /create-payment-intent // Body: { amount, currency, metadata } // Returns: { clientSecret } // ------------------------------------------------------- var response = await fetch('/create-payment-intent', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ amount: amountCents, currency: 'usd', metadata: { service: bookingData.service, date: bookingData.date, time: bookingData.time, client_name: bookingData.name, client_email: bookingData.email, payment_type: selectedOption } }) }); if (!response.ok) throw new Error('Server error. Please try again.'); var data = await response.json(); var result = await stripe.confirmCardPayment(data.clientSecret, { payment_method: { card: cardNumber, billing_details: { name: name } } }); if (result.error) { showError(result.error.message); btn.disabled = false; btn.innerHTML = 'Pay ' + document.getElementById('payBtnAmount').textContent + ''; } else if (result.paymentIntent.status === 'succeeded') { // Save appointment to collection if (window.siteData) { await window.siteData.create('appointments', { client_name: bookingData.name, client_email: bookingData.email, client_phone: bookingData.phone, service_type: bookingData.service, date: bookingData.date, time: bookingData.time, notes: bookingData.notes, payment_type: selectedOption, amount_paid: selectedOption === 'deposit' ? DEPOSIT_AMOUNT : serviceTotal, payment_id: result.paymentIntent.id, status: 'confirmed' }); } showSuccess(); } } catch(err) { showError(err.message || 'Something went wrong. Please try again.'); btn.disabled = false; updatePayBtn(); } } function updatePayBtn() { var amtLabel = selectedOption === 'deposit' ? '— $' + DEPOSIT_AMOUNT + ' Deposit' : (serviceTotal ? '— $' + serviceTotal + ' in Full' : ''); document.getElementById('payBtn').innerHTML = 'Pay ' + amtLabel + ''; document.getElementById('payBtn').disabled = false; } // ============================================= // HELPERS // ============================================= function formatDate(dateStr) { if (!dateStr) return 'Date TBD'; var d = new Date(dateStr + 'T12:00:00'); return d.toLocaleDateString('en-US', { weekday:'long', month:'long', day:'numeric', year:'numeric' }); } function showError(msg) { var el = document.getElementById('checkoutError'); el.textContent = msg; el.style.display = 'block'; } function clearError() { var el = document.getElementById('checkoutError'); el.style.display = 'none'; el.textContent = ''; } function showSuccess() { document.getElementById('paymentForm').style.display = 'none'; document.getElementById('checkoutSuccess').style.display = 'block'; } function handleLogout() { window.siteAuth.logout(); window.location.href = 'index.html'; } + remaining + ' is due at your appointment.' : 'Remaining balance due at appointment.'; document.getElementById('payBtnAmount').textContent = '— } // ============================================= // PAYMENT HANDLER // ============================================= async function handlePayment() { clearError(); var name = document.getElementById('cardholderName').value.trim(); if (!name) { showError('Please enter the name on your card.'); return; } if (!stripe || !cardNumber) { showError('Payment system not yet configured. Please contact us directly to complete your booking.'); return; } var btn = document.getElementById('payBtn'); btn.disabled = true; btn.textContent = 'Processing...'; try { var amountCents = (selectedOption === 'deposit' ? DEPOSIT_AMOUNT : serviceTotal) * 100; // ------------------------------------------------------- // STRIPE INTEGRATION POINT // On your server, create a PaymentIntent and return the // client_secret. Replace the fetch URL with your endpoint. // // Example server endpoint (Node/Express): // POST /create-payment-intent // Body: { amount, currency, metadata } // Returns: { clientSecret } // ------------------------------------------------------- var response = await fetch('/create-payment-intent', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ amount: amountCents, currency: 'usd', metadata: { service: bookingData.service, date: bookingData.date, time: bookingData.time, client_name: bookingData.name, client_email: bookingData.email, payment_type: selectedOption } }) }); if (!response.ok) throw new Error('Server error. Please try again.'); var data = await response.json(); var result = await stripe.confirmCardPayment(data.clientSecret, { payment_method: { card: cardNumber, billing_details: { name: name } } }); if (result.error) { showError(result.error.message); btn.disabled = false; btn.innerHTML = 'Pay ' + document.getElementById('payBtnAmount').textContent + ''; } else if (result.paymentIntent.status === 'succeeded') { // Save appointment to collection if (window.siteData) { await window.siteData.create('appointments', { client_name: bookingData.name, client_email: bookingData.email, client_phone: bookingData.phone, service_type: bookingData.service, date: bookingData.date, time: bookingData.time, notes: bookingData.notes, payment_type: selectedOption, amount_paid: selectedOption === 'deposit' ? DEPOSIT_AMOUNT : serviceTotal, payment_id: result.paymentIntent.id, status: 'confirmed' }); } showSuccess(); } } catch(err) { showError(err.message || 'Something went wrong. Please try again.'); btn.disabled = false; updatePayBtn(); } } function updatePayBtn() { var amtLabel = selectedOption === 'deposit' ? '— $' + DEPOSIT_AMOUNT + ' Deposit' : (serviceTotal ? '— $' + serviceTotal + ' in Full' : ''); document.getElementById('payBtn').innerHTML = 'Pay ' + amtLabel + ''; document.getElementById('payBtn').disabled = false; } // ============================================= // HELPERS // ============================================= function formatDate(dateStr) { if (!dateStr) return 'Date TBD'; var d = new Date(dateStr + 'T12:00:00'); return d.toLocaleDateString('en-US', { weekday:'long', month:'long', day:'numeric', year:'numeric' }); } function showError(msg) { var el = document.getElementById('checkoutError'); el.textContent = msg; el.style.display = 'block'; } function clearError() { var el = document.getElementById('checkoutError'); el.style.display = 'none'; el.textContent = ''; } function showSuccess() { document.getElementById('paymentForm').style.display = 'none'; document.getElementById('checkoutSuccess').style.display = 'block'; } function handleLogout() { window.siteAuth.logout(); window.location.href = 'index.html'; } + depositAmt + ' Deposit'; } // ============================================= // PAYMENT HANDLER // ============================================= async function handlePayment() { clearError(); var name = document.getElementById('cardholderName').value.trim(); if (!name) { showError('Please enter the name on your card.'); return; } if (!stripe || !cardNumber) { showError('Payment system not yet configured. Please contact us directly to complete your booking.'); return; } var btn = document.getElementById('payBtn'); btn.disabled = true; btn.textContent = 'Processing...'; try { var amountCents = (selectedOption === 'deposit' ? DEPOSIT_AMOUNT : serviceTotal) * 100; // ------------------------------------------------------- // STRIPE INTEGRATION POINT // On your server, create a PaymentIntent and return the // client_secret. Replace the fetch URL with your endpoint. // // Example server endpoint (Node/Express): // POST /create-payment-intent // Body: { amount, currency, metadata } // Returns: { clientSecret } // ------------------------------------------------------- var response = await fetch('/create-payment-intent', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ amount: amountCents, currency: 'usd', metadata: { service: bookingData.service, date: bookingData.date, time: bookingData.time, client_name: bookingData.name, client_email: bookingData.email, payment_type: selectedOption } }) }); if (!response.ok) throw new Error('Server error. Please try again.'); var data = await response.json(); var result = await stripe.confirmCardPayment(data.clientSecret, { payment_method: { card: cardNumber, billing_details: { name: name } } }); if (result.error) { showError(result.error.message); btn.disabled = false; btn.innerHTML = 'Pay ' + document.getElementById('payBtnAmount').textContent + ''; } else if (result.paymentIntent.status === 'succeeded') { // Save appointment to collection if (window.siteData) { await window.siteData.create('appointments', { client_name: bookingData.name, client_email: bookingData.email, client_phone: bookingData.phone, service_type: bookingData.service, date: bookingData.date, time: bookingData.time, notes: bookingData.notes, payment_type: selectedOption, amount_paid: selectedOption === 'deposit' ? DEPOSIT_AMOUNT : serviceTotal, payment_id: result.paymentIntent.id, status: 'confirmed' }); } showSuccess(); } } catch(err) { showError(err.message || 'Something went wrong. Please try again.'); btn.disabled = false; updatePayBtn(); } } function updatePayBtn() { var amtLabel = selectedOption === 'deposit' ? '— $' + DEPOSIT_AMOUNT + ' Deposit' : (serviceTotal ? '— $' + serviceTotal + ' in Full' : ''); document.getElementById('payBtn').innerHTML = 'Pay ' + amtLabel + ''; document.getElementById('payBtn').disabled = false; } // ============================================= // HELPERS // ============================================= function formatDate(dateStr) { if (!dateStr) return 'Date TBD'; var d = new Date(dateStr + 'T12:00:00'); return d.toLocaleDateString('en-US', { weekday:'long', month:'long', day:'numeric', year:'numeric' }); } function showError(msg) { var el = document.getElementById('checkoutError'); el.textContent = msg; el.style.display = 'block'; } function clearError() { var el = document.getElementById('checkoutError'); el.style.display = 'none'; el.textContent = ''; } function showSuccess() { document.getElementById('paymentForm').style.display = 'none'; document.getElementById('checkoutSuccess').style.display = 'block'; } function handleLogout() { window.siteAuth.logout(); window.location.href = 'index.html'; } + DEPOSIT_AMOUNT + ' Deposit'; document.getElementById('payBtn').innerHTML = 'Pay ' + amtLabel + ''; document.getElementById('payBtn').disabled = false; } // ============================================= // HELPERS // ============================================= function formatDate(dateStr) { if (!dateStr) return 'Date TBD'; var d = new Date(dateStr + 'T12:00:00'); return d.toLocaleDateString('en-US', { weekday:'long', month:'long', day:'numeric', year:'numeric' }); } function showError(msg) { var el = document.getElementById('checkoutError'); el.textContent = msg; el.style.display = 'block'; } function clearError() { var el = document.getElementById('checkoutError'); el.style.display = 'none'; el.textContent = ''; } function showSuccess() { document.getElementById('paymentForm').style.display = 'none'; document.getElementById('checkoutSuccess').style.display = 'block'; } function handleLogout() { window.siteAuth.logout(); window.location.href = 'index.html'; } + depositAmt; document.getElementById('totalAmount').textContent = ' } // ============================================= // PAYMENT HANDLER // ============================================= async function handlePayment() { clearError(); var name = document.getElementById('cardholderName').value.trim(); if (!name) { showError('Please enter the name on your card.'); return; } if (!stripe || !cardNumber) { showError('Payment system not yet configured. Please contact us directly to complete your booking.'); return; } var btn = document.getElementById('payBtn'); btn.disabled = true; btn.textContent = 'Processing...'; try { var amountCents = (selectedOption === 'deposit' ? DEPOSIT_AMOUNT : serviceTotal) * 100; // ------------------------------------------------------- // STRIPE INTEGRATION POINT // On your server, create a PaymentIntent and return the // client_secret. Replace the fetch URL with your endpoint. // // Example server endpoint (Node/Express): // POST /create-payment-intent // Body: { amount, currency, metadata } // Returns: { clientSecret } // ------------------------------------------------------- var response = await fetch('/create-payment-intent', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ amount: amountCents, currency: 'usd', metadata: { service: bookingData.service, date: bookingData.date, time: bookingData.time, client_name: bookingData.name, client_email: bookingData.email, payment_type: selectedOption } }) }); if (!response.ok) throw new Error('Server error. Please try again.'); var data = await response.json(); var result = await stripe.confirmCardPayment(data.clientSecret, { payment_method: { card: cardNumber, billing_details: { name: name } } }); if (result.error) { showError(result.error.message); btn.disabled = false; btn.innerHTML = 'Pay ' + document.getElementById('payBtnAmount').textContent + ''; } else if (result.paymentIntent.status === 'succeeded') { // Save appointment to collection if (window.siteData) { await window.siteData.create('appointments', { client_name: bookingData.name, client_email: bookingData.email, client_phone: bookingData.phone, service_type: bookingData.service, date: bookingData.date, time: bookingData.time, notes: bookingData.notes, payment_type: selectedOption, amount_paid: selectedOption === 'deposit' ? DEPOSIT_AMOUNT : serviceTotal, payment_id: result.paymentIntent.id, status: 'confirmed' }); } showSuccess(); } } catch(err) { showError(err.message || 'Something went wrong. Please try again.'); btn.disabled = false; updatePayBtn(); } } function updatePayBtn() { var amtLabel = selectedOption === 'deposit' ? '— $' + DEPOSIT_AMOUNT + ' Deposit' : (serviceTotal ? '— $' + serviceTotal + ' in Full' : ''); document.getElementById('payBtn').innerHTML = 'Pay ' + amtLabel + ''; document.getElementById('payBtn').disabled = false; } // ============================================= // HELPERS // ============================================= function formatDate(dateStr) { if (!dateStr) return 'Date TBD'; var d = new Date(dateStr + 'T12:00:00'); return d.toLocaleDateString('en-US', { weekday:'long', month:'long', day:'numeric', year:'numeric' }); } function showError(msg) { var el = document.getElementById('checkoutError'); el.textContent = msg; el.style.display = 'block'; } function clearError() { var el = document.getElementById('checkoutError'); el.style.display = 'none'; el.textContent = ''; } function showSuccess() { document.getElementById('paymentForm').style.display = 'none'; document.getElementById('checkoutSuccess').style.display = 'block'; } function handleLogout() { window.siteAuth.logout(); window.location.href = 'index.html'; } + depositAmt; document.getElementById('totalLabel').textContent = 'Deposit Due Today'; document.getElementById('summaryNote').textContent = fullAmt ? 'Remaining balance of } // ============================================= // PAYMENT HANDLER // ============================================= async function handlePayment() { clearError(); var name = document.getElementById('cardholderName').value.trim(); if (!name) { showError('Please enter the name on your card.'); return; } if (!stripe || !cardNumber) { showError('Payment system not yet configured. Please contact us directly to complete your booking.'); return; } var btn = document.getElementById('payBtn'); btn.disabled = true; btn.textContent = 'Processing...'; try { var amountCents = (selectedOption === 'deposit' ? DEPOSIT_AMOUNT : serviceTotal) * 100; // ------------------------------------------------------- // STRIPE INTEGRATION POINT // On your server, create a PaymentIntent and return the // client_secret. Replace the fetch URL with your endpoint. // // Example server endpoint (Node/Express): // POST /create-payment-intent // Body: { amount, currency, metadata } // Returns: { clientSecret } // ------------------------------------------------------- var response = await fetch('/create-payment-intent', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ amount: amountCents, currency: 'usd', metadata: { service: bookingData.service, date: bookingData.date, time: bookingData.time, client_name: bookingData.name, client_email: bookingData.email, payment_type: selectedOption } }) }); if (!response.ok) throw new Error('Server error. Please try again.'); var data = await response.json(); var result = await stripe.confirmCardPayment(data.clientSecret, { payment_method: { card: cardNumber, billing_details: { name: name } } }); if (result.error) { showError(result.error.message); btn.disabled = false; btn.innerHTML = 'Pay ' + document.getElementById('payBtnAmount').textContent + ''; } else if (result.paymentIntent.status === 'succeeded') { // Save appointment to collection if (window.siteData) { await window.siteData.create('appointments', { client_name: bookingData.name, client_email: bookingData.email, client_phone: bookingData.phone, service_type: bookingData.service, date: bookingData.date, time: bookingData.time, notes: bookingData.notes, payment_type: selectedOption, amount_paid: selectedOption === 'deposit' ? DEPOSIT_AMOUNT : serviceTotal, payment_id: result.paymentIntent.id, status: 'confirmed' }); } showSuccess(); } } catch(err) { showError(err.message || 'Something went wrong. Please try again.'); btn.disabled = false; updatePayBtn(); } } function updatePayBtn() { var amtLabel = selectedOption === 'deposit' ? '— $' + DEPOSIT_AMOUNT + ' Deposit' : (serviceTotal ? '— $' + serviceTotal + ' in Full' : ''); document.getElementById('payBtn').innerHTML = 'Pay ' + amtLabel + ''; document.getElementById('payBtn').disabled = false; } // ============================================= // HELPERS // ============================================= function formatDate(dateStr) { if (!dateStr) return 'Date TBD'; var d = new Date(dateStr + 'T12:00:00'); return d.toLocaleDateString('en-US', { weekday:'long', month:'long', day:'numeric', year:'numeric' }); } function showError(msg) { var el = document.getElementById('checkoutError'); el.textContent = msg; el.style.display = 'block'; } function clearError() { var el = document.getElementById('checkoutError'); el.style.display = 'none'; el.textContent = ''; } function showSuccess() { document.getElementById('paymentForm').style.display = 'none'; document.getElementById('checkoutSuccess').style.display = 'block'; } function handleLogout() { window.siteAuth.logout(); window.location.href = 'index.html'; } + remaining + ' is due at your appointment.' : 'Remaining balance due at appointment.'; document.getElementById('payBtnAmount').textContent = '— } // ============================================= // PAYMENT HANDLER // ============================================= async function handlePayment() { clearError(); var name = document.getElementById('cardholderName').value.trim(); if (!name) { showError('Please enter the name on your card.'); return; } if (!stripe || !cardNumber) { showError('Payment system not yet configured. Please contact us directly to complete your booking.'); return; } var btn = document.getElementById('payBtn'); btn.disabled = true; btn.textContent = 'Processing...'; try { var amountCents = (selectedOption === 'deposit' ? DEPOSIT_AMOUNT : serviceTotal) * 100; // ------------------------------------------------------- // STRIPE INTEGRATION POINT // On your server, create a PaymentIntent and return the // client_secret. Replace the fetch URL with your endpoint. // // Example server endpoint (Node/Express): // POST /create-payment-intent // Body: { amount, currency, metadata } // Returns: { clientSecret } // ------------------------------------------------------- var response = await fetch('/create-payment-intent', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ amount: amountCents, currency: 'usd', metadata: { service: bookingData.service, date: bookingData.date, time: bookingData.time, client_name: bookingData.name, client_email: bookingData.email, payment_type: selectedOption } }) }); if (!response.ok) throw new Error('Server error. Please try again.'); var data = await response.json(); var result = await stripe.confirmCardPayment(data.clientSecret, { payment_method: { card: cardNumber, billing_details: { name: name } } }); if (result.error) { showError(result.error.message); btn.disabled = false; btn.innerHTML = 'Pay ' + document.getElementById('payBtnAmount').textContent + ''; } else if (result.paymentIntent.status === 'succeeded') { // Save appointment to collection if (window.siteData) { await window.siteData.create('appointments', { client_name: bookingData.name, client_email: bookingData.email, client_phone: bookingData.phone, service_type: bookingData.service, date: bookingData.date, time: bookingData.time, notes: bookingData.notes, payment_type: selectedOption, amount_paid: selectedOption === 'deposit' ? DEPOSIT_AMOUNT : serviceTotal, payment_id: result.paymentIntent.id, status: 'confirmed' }); } showSuccess(); } } catch(err) { showError(err.message || 'Something went wrong. Please try again.'); btn.disabled = false; updatePayBtn(); } } function updatePayBtn() { var amtLabel = selectedOption === 'deposit' ? '— $' + DEPOSIT_AMOUNT + ' Deposit' : (serviceTotal ? '— $' + serviceTotal + ' in Full' : ''); document.getElementById('payBtn').innerHTML = 'Pay ' + amtLabel + ''; document.getElementById('payBtn').disabled = false; } // ============================================= // HELPERS // ============================================= function formatDate(dateStr) { if (!dateStr) return 'Date TBD'; var d = new Date(dateStr + 'T12:00:00'); return d.toLocaleDateString('en-US', { weekday:'long', month:'long', day:'numeric', year:'numeric' }); } function showError(msg) { var el = document.getElementById('checkoutError'); el.textContent = msg; el.style.display = 'block'; } function clearError() { var el = document.getElementById('checkoutError'); el.style.display = 'none'; el.textContent = ''; } function showSuccess() { document.getElementById('paymentForm').style.display = 'none'; document.getElementById('checkoutSuccess').style.display = 'block'; } function handleLogout() { window.siteAuth.logout(); window.location.href = 'index.html'; } + depositAmt + ' Deposit'; } // ============================================= // PAYMENT HANDLER // ============================================= async function handlePayment() { clearError(); var name = document.getElementById('cardholderName').value.trim(); if (!name) { showError('Please enter the name on your card.'); return; } if (!stripe || !cardNumber) { showError('Payment system not yet configured. Please contact us directly to complete your booking.'); return; } var btn = document.getElementById('payBtn'); btn.disabled = true; btn.textContent = 'Processing...'; try { var amountCents = (selectedOption === 'deposit' ? DEPOSIT_AMOUNT : serviceTotal) * 100; // ------------------------------------------------------- // STRIPE INTEGRATION POINT // On your server, create a PaymentIntent and return the // client_secret. Replace the fetch URL with your endpoint. // // Example server endpoint (Node/Express): // POST /create-payment-intent // Body: { amount, currency, metadata } // Returns: { clientSecret } // ------------------------------------------------------- var response = await fetch('/create-payment-intent', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ amount: amountCents, currency: 'usd', metadata: { service: bookingData.service, date: bookingData.date, time: bookingData.time, client_name: bookingData.name, client_email: bookingData.email, payment_type: selectedOption } }) }); if (!response.ok) throw new Error('Server error. Please try again.'); var data = await response.json(); var result = await stripe.confirmCardPayment(data.clientSecret, { payment_method: { card: cardNumber, billing_details: { name: name } } }); if (result.error) { showError(result.error.message); btn.disabled = false; btn.innerHTML = 'Pay ' + document.getElementById('payBtnAmount').textContent + ''; } else if (result.paymentIntent.status === 'succeeded') { // Save appointment to collection if (window.siteData) { await window.siteData.create('appointments', { client_name: bookingData.name, client_email: bookingData.email, client_phone: bookingData.phone, service_type: bookingData.service, date: bookingData.date, time: bookingData.time, notes: bookingData.notes, payment_type: selectedOption, amount_paid: selectedOption === 'deposit' ? DEPOSIT_AMOUNT : serviceTotal, payment_id: result.paymentIntent.id, status: 'confirmed' }); } showSuccess(); } } catch(err) { showError(err.message || 'Something went wrong. Please try again.'); btn.disabled = false; updatePayBtn(); } } function updatePayBtn() { var amtLabel = selectedOption === 'deposit' ? '— $' + DEPOSIT_AMOUNT + ' Deposit' : (serviceTotal ? '— $' + serviceTotal + ' in Full' : ''); document.getElementById('payBtn').innerHTML = 'Pay ' + amtLabel + ''; document.getElementById('payBtn').disabled = false; } // ============================================= // HELPERS // ============================================= function formatDate(dateStr) { if (!dateStr) return 'Date TBD'; var d = new Date(dateStr + 'T12:00:00'); return d.toLocaleDateString('en-US', { weekday:'long', month:'long', day:'numeric', year:'numeric' }); } function showError(msg) { var el = document.getElementById('checkoutError'); el.textContent = msg; el.style.display = 'block'; } function clearError() { var el = document.getElementById('checkoutError'); el.style.display = 'none'; el.textContent = ''; } function showSuccess() { document.getElementById('paymentForm').style.display = 'none'; document.getElementById('checkoutSuccess').style.display = 'block'; } function handleLogout() { window.siteAuth.logout(); window.location.href = 'index.html'; }