');
} catch (error) {
checklistModalContent.innerHTML = `
Sorry, we couldn't generate the checklist at this time. Please try again later.
`;
console.error("Gemini API Error:", error);
}
}
function closeChecklistModal() {
checklistModal.classList.add('hidden');
}
// --- Booking Modal Logic ---
const bookingModal = document.getElementById('bookingModal');
const bookingModalContent = document.getElementById('bookingModalContent');
const bookingForm = document.getElementById('bookingForm');
const serviceTypeInput = document.getElementById('serviceType');
const modalServiceDisplay = document.getElementById('modalServiceDisplay');
const deepCleanSelector = document.getElementById('deepCleanSelector');
const propertyTypeSelect = document.getElementById('propertyType');
const residentialInputs = document.getElementById('residentialInputs');
const commercialInputs = document.getElementById('commercialInputs');
const bedroomsInput = document.getElementById('bedrooms');
const bathroomsInput = document.getElementById('bathrooms');
const roomsInput = document.getElementById('rooms');
const areaInput = document.getElementById('area');
const specialInstructionsInput = document.getElementById('specialInstructions');
const addressInput = document.getElementById('address');
const datetimeInput = document.getElementById('datetime');
const estimatedTimeSpan = document.getElementById('estimatedTime');
const estimateReasoningP = document.getElementById('estimateReasoning');
const estimateLoader = document.getElementById('estimateLoader');
const estimateResult = document.getElementById('estimateResult');
const sendBookingBtn = document.getElementById('sendBookingBtn');
const formErrorP = document.getElementById('formError');
function setupModalForm(serviceName) {
deepCleanSelector.classList.add('hidden');
residentialInputs.classList.add('hidden');
commercialInputs.classList.add('hidden');
propertyTypeSelect.value = '';
if (serviceName === 'Deep Cleaning' || serviceName === 'Instan Cleaning') {
deepCleanSelector.classList.remove('hidden');
} else if (serviceName === 'Office & Commercial Cleaning') {
commercialInputs.classList.remove('hidden');
} else {
residentialInputs.classList.remove('hidden');
}
}
propertyTypeSelect.addEventListener('change', (e) => {
residentialInputs.classList.add('hidden');
commercialInputs.classList.add('hidden');
if(e.target.value === 'residential') {
residentialInputs.classList.remove('hidden');
} else if (e.target.value === 'commercial') {
commercialInputs.classList.remove('hidden');
}
});
function openBookingModal(serviceName) {
formErrorP.textContent = '';
bookingForm.reset();
serviceTypeInput.value = serviceName;
modalServiceDisplay.textContent = serviceName;
estimatedTimeSpan.textContent = '-';
estimateReasoningP.textContent = 'Click the button below for an accurate estimate.';
sendBookingBtn.disabled = true;
setupModalForm(serviceName);
bookingModal.classList.remove('hidden');
setTimeout(() => {
bookingModal.classList.add('opacity-100');
bookingModalContent.classList.remove('scale-95');
}, 10);
}
function closeBookingModal() {
bookingModal.classList.remove('opacity-100');
bookingModalContent.classList.add('scale-95');
setTimeout(() => {
bookingModal.classList.add('hidden');
}, 300);
}
async function getAIEstimate() {
estimateResult.classList.add('hidden');
estimateLoader.classList.remove('hidden');
sendBookingBtn.disabled = true;
formErrorP.textContent = '';
const systemPrompt = "You are an expert cleaning service estimator in Bali. Calculate cleaning time in hours. Base residential time is 1hr + 1hr/bedroom + 0.5hr/bathroom. Base commercial time is 1hr + 0.5hr/room + 1hr per 50m². Minimum 2 hours. Add time for special requests (e.g., 'clean oven' +0.5hr, 'organize cluttered room' +1.5hr). If service is 'Deep Cleaning', multiply the final time by 1.5. Output ONLY a JSON object: { \"estimated_hours\": number, \"reasoning\": \"string\" }. The reasoning must be a brief explanation for the estimate.";
let details = '';
let service = serviceTypeInput.value;
if (service === 'Deep Cleaning' || service === 'Instan Cleaning') {
if (propertyTypeSelect.value === 'residential') {
details = `Property Type: Residential, Bedrooms: ${bedroomsInput.value}, Bathrooms: ${bathroomsInput.value}.`;
} else if (propertyTypeSelect.value === 'commercial') {
details = `Property Type: Commercial, Rooms: ${roomsInput.value}, Area: ${areaInput.value || 0}m².`;
} else {
formErrorP.textContent = "Please select a property type for this service.";
estimateResult.classList.remove('hidden');
estimateLoader.classList.add('hidden');
return;
}
} else if (service === 'Office & Commercial Cleaning') {
details = `Property Type: Commercial, Rooms: ${roomsInput.value}, Area: ${areaInput.value || 0}m².`;
} else {
details = `Property Type: Residential, Bedrooms: ${bedroomsInput.value}, Bathrooms: ${bathroomsInput.value}.`;
}
const userPrompt = `Service: ${service}. ${details} Special Instructions: "${specialInstructionsInput.value || 'None'}"`;
try {
const response = await fetch(API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
systemInstruction: { parts: [{ text: systemPrompt }] },
contents: [{ parts: [{ text: userPrompt }] }],
generationConfig: { responseMimeType: "application/json" }
})
});
if (!response.ok) throw new Error(`API Error: ${response.statusText}`);
const result = await response.json();
const jsonResponse = JSON.parse(result.candidates[0].content.parts[0].text);
estimatedTimeSpan.textContent = jsonResponse.estimated_hours;
estimateReasoningP.textContent = jsonResponse.reasoning;
sendBookingBtn.disabled = false;
} catch (error) {
formErrorP.textContent = "Could not generate estimate. Please try again.";
console.error("Gemini Estimate Error:", error);
} finally {
estimateResult.classList.remove('hidden');
estimateLoader.classList.add('hidden');
}
}
bookingModal.addEventListener('click', (event) => {
if (event.target === bookingModal) closeBookingModal();
});
bookingForm.addEventListener('submit', (event) => {
event.preventDefault();
formErrorP.textContent = '';
const service = serviceTypeInput.value;
const address = addressInput.value;
const datetimeValue = datetimeInput.value;
const estimatedTime = estimatedTimeSpan.textContent;
if (!address || !datetimeValue) {
formErrorP.textContent = 'Please fill in both address and preferred time.';
return;
}
if (estimatedTime === '-') {
formErrorP.textContent = 'Please generate an AI estimate first.';
return;
}
const datetime = new Date(datetimeValue).toLocaleString('en-GB', { dateStyle: 'full', timeStyle: 'short'});
let propertyDetails = '';
if(service === 'Deep Cleaning' || service === 'Instan Cleaning') {
const type = propertyTypeSelect.options[propertyTypeSelect.selectedIndex].text;
propertyDetails = `*Property Type:* ${type}\n`;
}
const message = `Hello Bersinstant, I'd like to book a cleaning.\n\n` +
`*Service:* ${service}\n` +
propertyDetails +
`*Address:* ${address}\n` +
`*Preferred Time:* ${datetime}\n` +
`*AI-Estimated Duration:* ${estimatedTime} hours\n\n` +
`Please confirm availability and the deposit details. Thank you!`;
const whatsappUrl = `https://wa.me/62818404067?text=${encodeURIComponent(message)}`;
window.open(whatsappUrl, '_blank');
closeBookingModal();
});