/** * js/main.js * Core application logic, event handling, and orchestrator. */ import api from './api.js'; import ui from './ui.js'; import {calculateRentalPrice, formatDate} from './utils.js'; document.addEventListener('DOMContentLoaded', async () => { // Accessibility: make skip link focus the main content const skipLink = document.querySelector('.skip-link'); const mainContent = document.getElementById('maincontent'); if (skipLink && mainContent) { skipLink.addEventListener('click', (e) => { e.preventDefault(); mainContent.setAttribute('tabindex', '-1'); mainContent.focus(); }); } // --- Initial setup --- // Set default dates for the search form (today to +3 days) const today = new Date(); const threeDaysLater = new Date(today); threeDaysLater.setDate(today.getDate() + 3); const pickupDateInput = document.getElementById('pickup-date'); const returnDateInput = document.getElementById('return-date'); if (pickupDateInput && returnDateInput) { pickupDateInput.value = today.toISOString().split('T')[0]; returnDateInput.value = threeDaysLater.toISOString().split('T')[0]; // Ensure return date is not before pickup date pickupDateInput.addEventListener('change', () => { if (returnDateInput.value < pickupDateInput.value) { returnDateInput.value = pickupDateInput.value; } }); returnDateInput.addEventListener('change', () => { if (returnDateInput.value < pickupDateInput.value) { pickupDateInput.value = returnDateInput.value; } }); } // Load initial list of cars on page load await loadCars(); // Update active nav link based on URL hash on load ui.updateActiveNavLink(window.location.hash || '#home'); // --- Event Listeners --- // Mobile menu toggle if (ui.mobileMenuButton) { ui.mobileMenuButton.addEventListener('click', () => ui.toggleMobileMenu()); } // Close mobile menu when a nav link is clicked document.querySelectorAll('.nav-link').forEach(link => { link.addEventListener('click', (e) => { ui.closeMobileMenu(); // Update active nav link ui.updateActiveNavLink(e.target.getAttribute('href')); }); }); // Handle hash change for navigation (for simple SPA-like behavior) window.addEventListener('hashchange', () => { ui.updateActiveNavLink(window.location.hash || '#home'); // If you had different "pages" (sections) that you wanted to show/hide // based on hash, you'd add that logic here. // For now, it just scrolls to the section. }); // Hero section search form submission const heroSearchForm = document.getElementById('hero-search-form'); if (heroSearchForm) { heroSearchForm.addEventListener('submit', async (e) => { e.preventDefault(); // Prevent default form submission const pickupLocation = document.getElementById('pickup-location').value; const pickupDate = document.getElementById('pickup-date').value; const returnDate = document.getElementById('return-date').value; if (!pickupLocation || !pickupDate || !returnDate) { ui.showNotification('กรุณากรอกข้อมูลการค้นหาให้ครบถ้วน', 'warning'); return; } ui.showNotification(`กำลังค้นหารถยนต์จาก ${pickupLocation} ระหว่างวันที่ ${formatDate(pickupDate)} ถึง ${formatDate(returnDate)}`, 'info'); // In a real scenario, these filters would be sent to the API await loadCars({ pickupLocation, pickupDate, returnDate }); // Scroll to the cars section after search ui.carsSection.scrollIntoView({behavior: 'smooth'}); }); } // Event delegation for "View Details" buttons in the car list if (ui.carListContainer) { ui.carListContainer.addEventListener('click', async (e) => { if (e.target.classList.contains('btn-primary') && e.target.dataset.carId) { const carId = e.target.dataset.carId; await fetchCarDetails(carId); } }); } // --- Core Functions --- /** * Fetches and renders the list of cars. * @param {object} filters - Optional filters for the car list. */ async function loadCars(filters = {}) { ui.showLoading(true); const result = await api.get('/cars', filters); // Call the mockup API or real API if (result.success) { ui.renderCarList(result.data); if (result.data.length > 0) { ui.showNotification('โหลดรายการรถยนต์สำเร็จ!', 'success'); } else if (Object.keys(filters).length > 0) { ui.showNotification('ไม่พบรถยนต์ที่ตรงกับเงื่อนไขการค้นหา', 'info'); } } else { ui.showNotification(`เกิดข้อผิดพลาดในการโหลดรถยนต์: ${result.message}`, 'error'); ui.renderCarList([]); // Render empty list or error state } ui.showLoading(false); } /** * Fetches details for a specific car and displays them (e.g., in a modal/popup). * For this simplified example, it just shows a notification. * In a real application, you'd render a dedicated detail view. * @param {string} carId - The ID of the car to fetch. */ async function fetchCarDetails(carId) { ui.showLoading(true); const result = await api.get(`/cars/${carId}`); if (result.success && result.data) { const car = result.data; const rentalPrice = calculateRentalPrice(car.pricePerDay, pickupDateInput.value, returnDateInput.value); // --- Simulate showing car details (e.g., in a modal/popup) --- // For now, we'll just log and show a notification console.log("รายละเอียดรถ:", car); ui.showNotification(`รถรุ่น ${car.brand} ${car.model}: ${car.description} ราคาเช่าประมาณ ฿${rentalPrice ? rentalPrice.toLocaleString() : car.pricePerDay.toLocaleString()} (สำหรับ ${rentalPrice ? 'วันที่เลือก' : '1 วัน'})`, 'info'); // Here you would typically open a modal with more details, a booking button, etc. // Example of how to add a modal dynamically (conceptual): /* const modalHtml = `
`; document.body.insertAdjacentHTML('beforeend', modalHtml); document.querySelector('.car-detail-modal-overlay').addEventListener('click', (e) => { if (e.target.classList.contains('car-detail-modal-overlay') || e.target.classList.contains('close-btn')) { document.querySelector('.car-detail-modal-overlay').remove(); } }); document.querySelector('.btn-book-now').addEventListener('click', () => handleBooking(car.id, pickupDateInput.value, returnDateInput.value)); */ } else { ui.showNotification(`ไม่พบข้อมูลรถยนต์ ID: ${carId}`, 'error'); } ui.showLoading(false); } /** * Simulates a booking process. * @param {string} carId * @param {string} pickupDate * @param {string} returnDate */ async function handleBooking(carId, pickupDate, returnDate) { ui.showLoading(true); const bookingData = { carId, pickupDate, returnDate, userId: 'guest_user_123', // In a real app, this would come from authenticated user bookingDate: new Date().toISOString().split('T')[0] }; const result = await api.post('/bookings', bookingData); if (result.success) { ui.showNotification(`จองรถสำเร็จ! Booking ID: ${result.data.bookingId}`, 'success'); console.log("Booking Confirmation:", result.data); // Optionally, redirect to a confirmation page or show confirmation modal } else { ui.showNotification(`การจองล้มเหลว: ${result.message}`, 'error'); } ui.showLoading(false); } // Initial scroll to top if hash is #home or empty if (window.location.hash === '#home' || !window.location.hash) { window.scrollTo(0, 0); } });