const API_URL = window.location.origin; let currentUser = null; let currentTheme = 'dark'; async function apiRequest(endpoint, options = {}) { const response = await fetch(`${API_URL}${endpoint}`, { ...options, credentials: 'include', headers: { 'Content-Type': 'application/json', ...options.headers } }); if (!response.ok) { const error = await response.json(); throw new Error(error.error || 'Request failed'); } return response.json(); } function toggleTheme() { currentTheme = currentTheme === 'dark' ? 'light' : 'dark'; document.documentElement.setAttribute('data-theme', currentTheme); localStorage.setItem('theme', currentTheme); if (currentUser) { apiRequest('/api/settings/theme', { method: 'POST', body: JSON.stringify({ theme: currentTheme }) }); } } async function login(username, password) { try { const data = await apiRequest('/api/auth/login', { method: 'POST', body: JSON.stringify({ username, password }) }); currentUser = data.user; currentTheme = data.user.theme; document.documentElement.setAttribute('data-theme', currentTheme); if (data.user.first_login) { showChangePasswordModal(); } else { window.location.href = '/dashboard'; } } catch (error) { alert(error.message); } } async function register(username, email, password) { try { await apiRequest('/api/auth/register', { method: 'POST', body: JSON.stringify({ username, email, password }) }); alert('Registration successful! Please login.'); window.location.href = '/login'; } catch (error) { alert(error.message); } } async function logout() { try { await apiRequest('/api/auth/logout', { method: 'POST' }); window.location.href = '/login'; } catch (error) { alert(error.message); } } async function loadVehicles() { try { const vehicles = await apiRequest('/api/vehicles'); displayVehicles(vehicles); } catch (error) { console.error('Failed to load vehicles:', error); } } function displayVehicles(vehicles) { const container = document.getElementById('vehicles-container'); container.innerHTML = vehicles.map(v => `
${v.photo ? `${v.make} ${v.model}` : ''}

${v.year} ${v.make} ${v.model}

${v.vin || 'No VIN'}

Odometer: ${v.odometer.toLocaleString()} miles

`).join(''); } async function addVehicle(vehicleData) { try { await apiRequest('/api/vehicles', { method: 'POST', body: JSON.stringify(vehicleData) }); loadVehicles(); closeModal('vehicle-modal'); } catch (error) { alert(error.message); } } async function loadServiceRecords(vehicleId) { try { const records = await apiRequest(`/api/vehicles/${vehicleId}/service-records`); displayServiceRecords(records); } catch (error) { console.error('Failed to load service records:', error); } } function displayServiceRecords(records) { const tbody = document.getElementById('service-records-tbody'); tbody.innerHTML = records.map(r => ` ${new Date(r.date).toLocaleDateString()} ${r.odometer.toLocaleString()} ${r.description} $${r.cost.toFixed(2)} ${r.category || 'N/A'} ${r.notes || ''} `).join(''); } async function loadFuelRecords(vehicleId) { try { const records = await apiRequest(`/api/vehicles/${vehicleId}/fuel-records`); displayFuelRecords(records); calculateFuelStats(records); } catch (error) { console.error('Failed to load fuel records:', error); } } function displayFuelRecords(records) { const tbody = document.getElementById('fuel-records-tbody'); tbody.innerHTML = records.map(r => ` ${new Date(r.date).toLocaleDateString()} ${r.odometer.toLocaleString()} ${r.fuel_amount.toFixed(2)} $${r.cost.toFixed(2)} ${r.distance || 'N/A'} ${r.fuel_economy ? r.fuel_economy.toFixed(2) : 'N/A'} ${r.unit} `).join(''); } function calculateFuelStats(records) { const totalCost = records.reduce((sum, r) => sum + r.cost, 0); const avgEconomy = records.filter(r => r.fuel_economy).reduce((sum, r, _, arr) => sum + r.fuel_economy / arr.length, 0); document.getElementById('total-fuel-cost').textContent = `$${totalCost.toFixed(2)}`; document.getElementById('avg-fuel-economy').textContent = avgEconomy.toFixed(2); } async function loadReminders(vehicleId) { try { const reminders = await apiRequest(`/api/vehicles/${vehicleId}/reminders`); displayReminders(reminders); } catch (error) { console.error('Failed to load reminders:', error); } } function displayReminders(reminders) { const container = document.getElementById('reminders-container'); container.innerHTML = reminders.map(r => `

${r.description}

${r.due_date ? `Due: ${new Date(r.due_date).toLocaleDateString()}` : ''}

${r.due_odometer ? `At: ${r.due_odometer.toLocaleString()} miles` : ''}

${r.notes || ''}

`).join(''); } async function loadTodos(vehicleId) { try { const todos = await apiRequest(`/api/vehicles/${vehicleId}/todos`); displayTodos(todos); } catch (error) { console.error('Failed to load todos:', error); } } function displayTodos(todos) { const statuses = ['planned', 'doing', 'testing', 'done']; statuses.forEach(status => { const column = document.getElementById(`todos-${status}`); const filtered = todos.filter(t => t.status === status); column.innerHTML = filtered.map(t => `

${t.description}

Cost: $${t.cost.toFixed(2)}

${t.type || ''}

${t.notes || ''}
`).join(''); }); } function showContextMenu(event, type, id) { event.preventDefault(); const menu = document.getElementById('context-menu'); menu.style.left = `${event.pageX}px`; menu.style.top = `${event.pageY}px`; menu.classList.add('active'); menu.dataset.type = type; menu.dataset.id = id; } document.addEventListener('click', () => { document.getElementById('context-menu')?.classList.remove('active'); }); function showModal(modalId) { document.getElementById(modalId).classList.add('active'); } function closeModal(modalId) { document.getElementById(modalId).classList.remove('active'); } async function exportData(type, vehicleId) { window.location.href = `${API_URL}/api/export/${type}?vehicle_id=${vehicleId}`; } document.addEventListener('DOMContentLoaded', () => { const theme = localStorage.getItem('theme') || 'dark'; currentTheme = theme; document.documentElement.setAttribute('data-theme', theme); });