πŸ”§Oil Change Tracker

Track oil changes, service history, and maintenance schedules for all your vehicles. Smart reminders based on mileage and time intervals. Works with synthetic, conventional, and blend oils for optimal engine protection.

πŸ€” What Is an Oil Change Tracker?

Think of a personal assistant for your car's health - that's our oil change tracker! This smart tool monitors service history and maintenance schedules for all your vehicles with automatic reminders based on mileage and time intervals. Never miss an oil change again, whether you use synthetic or conventional oil!

πŸš— Add Your Vehicle

🎯 Try Sample Vehicles

πŸš— 2024 Honda Civic
Synthetic Oil β€’ Normal Driving β€’ 15,000 miles
πŸš™ 2023 Toyota RAV4
Full Synthetic β€’ Highway Driving β€’ 25,000 miles
πŸ›» 2022 Ford F-150
Conventional Oil β€’ Severe Conditions β€’ 45,000 miles
🏎️ 2024 BMW M3
High Performance Synthetic β€’ Track Use β€’ 8,000 miles
`).join(''); } // Update mileage function updateMileage(vehicleId) { const vehicle = vehicles.find(v => v.id === vehicleId); if (!vehicle) return; const newMileage = prompt(`Update mileage for ${vehicle.name}:`, vehicle.currentMileage); if (newMileage && !isNaN(newMileage) && parseInt(newMileage) >= vehicle.currentMileage) { vehicle.currentMileage = parseInt(newMileage); // Recalculate status vehicle.milesRemaining = vehicle.nextServiceMileage - vehicle.currentMileage; vehicle.milesDriven = vehicle.currentMileage - vehicle.lastOilChangeMileage; const nextServiceDate = new Date(vehicle.nextServiceDate); vehicle.daysUntilDue = Math.floor((nextServiceDate - new Date()) / (1000 * 60 * 60 * 24)); if (vehicle.milesRemaining <= 500 || vehicle.daysUntilDue <= 30) { vehicle.status = 'due'; } else if (vehicle.milesRemaining <= 0 || vehicle.daysUntilDue <= 0) { vehicle.status = 'overdue'; } else { vehicle.status = 'ok'; } saveVehicles(); renderVehicles(); showNotification('Mileage updated successfully!', 'success'); } else if (newMileage) { showNotification('Invalid mileage. Must be greater than current mileage.', 'error'); } } // Record oil change function recordOilChange(vehicleId) { const vehicle = vehicles.find(v => v.id === vehicleId); if (!vehicle) return; const changeDate = prompt('Oil change date (YYYY-MM-DD):', new Date().toISOString().split('T')[0]); if (!changeDate) return; const changeMileage = prompt(`Mileage at oil change for ${vehicle.name}:`, vehicle.currentMileage); if (!changeMileage || isNaN(changeMileage)) return; // Add to history vehicle.history.push({ date: changeDate, mileage: parseInt(changeMileage), oilType: vehicle.oilType, notes: '' }); // Update vehicle data vehicle.lastOilChange = changeDate; vehicle.lastOilChangeMileage = parseInt(changeMileage); // Recalculate next service const interval = OIL_INTERVALS[vehicle.oilType][vehicle.drivingConditions]; vehicle.nextServiceMileage = vehicle.lastOilChangeMileage + interval.miles; const lastDate = new Date(changeDate); const nextServiceDate = new Date(lastDate); nextServiceDate.setMonth(nextServiceDate.getMonth() + interval.months); vehicle.nextServiceDate = nextServiceDate.toISOString().split('T')[0]; // Update status vehicle.milesRemaining = vehicle.nextServiceMileage - vehicle.currentMileage; vehicle.milesDriven = vehicle.currentMileage - vehicle.lastOilChangeMileage; vehicle.daysSinceChange = Math.floor((new Date() - lastDate) / (1000 * 60 * 60 * 24)); vehicle.daysUntilDue = Math.floor((nextServiceDate - new Date()) / (1000 * 60 * 60 * 24)); vehicle.status = 'ok'; saveVehicles(); renderVehicles(); showNotification('Oil change recorded successfully!', 'success'); trackEvent('oil_change_recorded', { vehicle_id: vehicleId }); } // View history function viewHistory(vehicleId) { const vehicle = vehicles.find(v => v.id === vehicleId); if (!vehicle) return; if (vehicle.history.length === 0) { showNotification('No maintenance history for this vehicle yet.', 'warning'); return; } const historyHtml = vehicle.history .sort((a, b) => new Date(b.date) - new Date(a.date)) .map(record => `
${new Date(record.date).toLocaleDateString()}
${record.mileage.toLocaleString()} miles - ${record.oilType} oil
`).join(''); const modal = document.createElement('div'); modal.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 10000; display: flex; align-items: center; justify-content: center; `; modal.innerHTML = `

${vehicle.name} - Maintenance History

${historyHtml}
`; modal.className = 'modal'; document.body.appendChild(modal); modal.addEventListener('click', (e) => { if (e.target === modal) modal.remove(); }); } // Delete vehicle function deleteVehicle(vehicleId) { if (confirm('Are you sure you want to delete this vehicle?')) { vehicles = vehicles.filter(v => v.id !== vehicleId); saveVehicles(); renderVehicles(); showNotification('Vehicle deleted successfully', 'success'); } } // Sample usage function function useSample(sampleId) { const samples = { 'honda': { name: '2024 Honda Civic', mileage: 15000, oilType: 'synthetic', conditions: 'normal', lastChange: '2024-08-01', lastMileage: 10000 }, 'toyota': { name: '2023 Toyota RAV4', mileage: 25000, oilType: 'synthetic', conditions: 'highway', lastChange: '2024-06-15', lastMileage: 20000 }, 'ford': { name: '2022 Ford F-150', mileage: 45000, oilType: 'conventional', conditions: 'severe', lastChange: '2024-11-01', lastMileage: 42000 }, 'bmw': { name: '2024 BMW M3', mileage: 8000, oilType: 'synthetic', conditions: 'performance', lastChange: '2024-10-15', lastMileage: 5000 } }; const sample = samples[sampleId]; document.getElementById('vehicleName').value = sample.name; document.getElementById('currentMileage').value = sample.mileage; document.getElementById('oilType').value = sample.oilType; document.getElementById('drivingConditions').value = sample.conditions; document.getElementById('lastOilChange').value = sample.lastChange; document.getElementById('lastOilChangeMileage').value = sample.lastMileage; document.getElementById('addVehicleForm').scrollIntoView({ behavior: 'smooth' }); } // ========== UTILITY FUNCTIONS ========== // Copy to clipboard function copyToClipboard(text) { navigator.clipboard.writeText(text).then(() => { showNotification('Copied to clipboard!', 'success'); }).catch(() => { const textArea = document.createElement('textarea'); textArea.value = text; document.body.appendChild(textArea); textArea.select(); document.execCommand('copy'); document.body.removeChild(textArea); showNotification('Copied to clipboard!', 'success'); }); } // Show notification toast function showNotification(message, type = 'success') { const toast = document.createElement('div'); toast.className = `toast ${type}`; toast.textContent = message; document.body.appendChild(toast); setTimeout(() => { toast.remove(); }, 3000); } // Show OTA section function showOTA() { const otaContainer = document.getElementById('otaContainer'); if (otaContainer && (otaContainer.style.display === 'none' || !otaContainer.style.display)) { otaContainer.style.display = 'block'; setTimeout(() => { const otaHeader = document.querySelector('.ota-header h3'); if (otaHeader) { otaHeader.style.animation = 'pulse 1s ease-in-out'; } }, 100); } } // Analytics tracking function trackEvent(eventName, data = {}) { if (typeof gtag !== 'undefined') { gtag('event', eventName, { 'event_category': TOOL_CONFIG.category, 'event_label': TOOL_CONFIG.name, ...data }); } } // ========== AI ASSISTANT FUNCTIONS ========== // AI λͺ¨λ‹¬ μ—΄κΈ° function openAIModal() { const modal = document.getElementById('aiModal'); if(modal) modal.classList.add('show'); if (aiModalState.apiKey && aiModalState.currentView === 'gemini') { showGeminiChat(); } else { showAISelector(); } updateAPIKeyStatus(); } // AI λͺ¨λ‹¬ λ‹«κΈ° function closeAIModal() { const modal = document.getElementById('aiModal'); if(modal) modal.classList.remove('show'); setTimeout(() => { aiModalState.currentView = 'selector'; showAISelector(); }, 300); } // AI 선택 ν™”λ©΄ ν‘œμ‹œ function showAISelector() { document.getElementById('aiModalTitle').textContent = 'Choose Your AI Assistant'; document.getElementById('aiSelector').style.display = 'flex'; document.getElementById('geminiChat').style.display = 'none'; document.getElementById('apiKeySetup').style.display = 'none'; aiModalState.currentView = 'selector'; } // Gemini μ±„νŒ… ν™”λ©΄ ν‘œμ‹œ function showGeminiChat() { document.getElementById('aiModalTitle').innerHTML = '✨ Gemini AI Assistant'; document.getElementById('aiSelector').style.display = 'none'; document.getElementById('geminiChat').style.display = 'flex'; document.getElementById('apiKeySetup').style.display = 'none'; aiModalState.currentView = 'gemini'; const chatMessages = document.getElementById('chatMessages'); if (!chatMessages.innerHTML.trim()) { addMessage('assistant', `Hello! I can help you with: β€’ Oil change intervals and schedules β€’ Best oil types for your vehicle β€’ Maintenance tracking tips β€’ Understanding severe vs normal driving β€’ Vehicle-specific recommendations What would you like to know about oil changes?`); } } // API ν‚€ μ„€μ • ν™”λ©΄ ν‘œμ‹œ function showAPIKeySetup() { document.getElementById('aiModalTitle').textContent = 'Setup Gemini API'; document.getElementById('aiSelector').style.display = 'none'; document.getElementById('geminiChat').style.display = 'none'; document.getElementById('apiKeySetup').style.display = 'block'; aiModalState.currentView = 'setup'; } // AI 선택 처리 function selectAI(aiType) { switch(aiType) { case 'chatgpt': const toolContext = `I need help with oil change tracking and vehicle maintenance schedules. This is an automotive maintenance tool.`; const chatUrl = `https://chat.openai.com/?q=${encodeURIComponent(toolContext)}`; window.open(chatUrl, '_blank'); closeAIModal(); trackEvent('ai_selection', { ai_type: 'chatgpt' }); break; case 'claude': const claudeContext = `I need help with oil change tracking and vehicle maintenance schedules. This is an automotive maintenance tool.`; const claudeUrl = `https://claude.ai/chat?q=${encodeURIComponent(claudeContext)}`; window.open(claudeUrl, '_blank'); closeAIModal(); trackEvent('ai_selection', { ai_type: 'claude' }); break; case 'gemini': if (!aiModalState.apiKey) { showAPIKeySetup(); } else { showGeminiChat(); } trackEvent('ai_selection', { ai_type: 'gemini' }); break; } } // API ν‚€ μ €μž₯ function saveGeminiApiKey() { const apiKey = document.getElementById('geminiApiKeyInput').value.trim(); if (apiKey) { localStorage.setItem('geminiApiKey', apiKey); aiModalState.apiKey = apiKey; showGeminiChat(); updateAPIKeyStatus(); } else { alert('Please enter a valid API key'); } } // API ν‚€ μƒνƒœ μ—…λ°μ΄νŠΈ function updateAPIKeyStatus() { const statusEl = document.getElementById('apiKeyStatus'); if (aiModalState.apiKey) { statusEl.innerHTML = 'Change API Key'; } else { statusEl.textContent = 'No API key set'; } } // μ±„νŒ… λ©”μ‹œμ§€ μΆ”κ°€ function addMessage(type, content) { const chatMessages = document.getElementById('chatMessages'); const messageDiv = document.createElement('div'); messageDiv.className = `message ${type}`; if (type === 'user') { messageDiv.innerHTML = `You: ${content}`; } else { messageDiv.innerHTML = `✨ Gemini:
${content.replace(/\n/g, '
')}`; } chatMessages.appendChild(messageDiv); chatMessages.scrollTop = chatMessages.scrollHeight; } // Gemini에 λ©”μ‹œμ§€ 전솑 async function sendToGemini() { const input = document.getElementById('geminiInput'); const message = input.value.trim(); if (!message) return; addMessage('user', message); input.value = ''; const loadingMsg = document.createElement('div'); loadingMsg.className = 'message assistant'; loadingMsg.innerHTML = '✨ Gemini:
Thinking...'; loadingMsg.id = 'loading-message'; document.getElementById('chatMessages').appendChild(loadingMsg); try { const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=${aiModalState.apiKey}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ contents: [{ parts: [{ text: `Context: User is using an Oil Change Tracker tool for vehicle maintenance. Current oil change intervals by type: - Synthetic: 7,500-15,000 miles (normal), 5,000-7,500 (severe) - Blend: 5,000-8,000 miles (normal), 3,000-5,000 (severe) - Conventional: 3,000-5,000 miles (normal), 3,000 (severe) Severe conditions include: city driving, short trips, extreme temperatures, towing, dusty conditions. User question: ${message}` }] }], generationConfig: { temperature: 0.7, maxOutputTokens: 1000 } }) }); const data = await response.json(); document.getElementById('loading-message').remove(); if (data.candidates && data.candidates[0] && data.candidates[0].content) { const reply = data.candidates[0].content.parts[0].text; addMessage('assistant', reply); } else { addMessage('assistant', 'Sorry, I could not generate a response. Please try again.'); } } catch (error) { document.getElementById('loading-message')?.remove(); if (error.message.includes('API key')) { addMessage('error', 'Invalid API key. Please check your API key and try again.'); showAPIKeySetup(); } else { addMessage('error', 'Failed to connect to Gemini. Please check your internet connection and try again.'); } } } // ========== EVENT LISTENERS ========== document.addEventListener('DOMContentLoaded', function() { // Initialize vehicles display renderVehicles(); // AI λ²„νŠΌ 이벀트 document.getElementById('aiBtn').addEventListener('click', openAIModal); // λͺ¨λ‹¬ μ™ΈλΆ€ ν΄λ¦­μ‹œ λ‹«κΈ° document.getElementById('aiModal').addEventListener('click', function(e) { if (e.target === this) { closeAIModal(); } }); // μ—”ν„° ν‚€ 지원 document.addEventListener('keydown', function(e) { if (e.key === 'Enter') { const geminiInput = document.getElementById('geminiInput'); if (document.activeElement === geminiInput) { sendToGemini(); } } if (e.key === 'Escape') { closeAIModal(); } }); // 초기 API ν‚€ μƒνƒœ μ—…λ°μ΄νŠΈ updateAPIKeyStatus(); updateCurrentYear(); updateToolCount(); }); // ========== DYNAMIC TOOL COUNT ========== async function updateToolCount() { try { const response = await fetch('/api/tool-count.php'); const data = await response.json(); document.querySelectorAll('.dynamic-tools-count').forEach(el => { el.textContent = `${data.count}+ free online tools in 211 languages. No signup, no fees, just tools that work.`; }); document.querySelectorAll('.dynamic-count').forEach(el => { const prefix = el.getAttribute('data-text') || ''; const suffix = el.getAttribute('data-suffix') || ''; const icon = el.textContent.split(' ')[0] || ''; el.textContent = `${icon} ${prefix} ${data.count}+ ${suffix}`; }); } catch (error) { const fallbackCount = 333; document.querySelectorAll('.dynamic-tools-count').forEach(el => { el.textContent = `${fallbackCount}+ free online tools in 211 languages. No signup, no fees, just tools that work.`; }); document.querySelectorAll('.dynamic-count').forEach(el => { const prefix = el.getAttribute('data-text') || ''; const suffix = el.getAttribute('data-suffix') || ''; const icon = el.textContent.split(' ')[0] || ''; el.textContent = `${icon} ${prefix} ${fallbackCount}+ ${suffix}`; }); } } function updateCurrentYear() { const currentYear = new Date().getFullYear(); document.querySelectorAll('.current-year').forEach(el => { el.textContent = currentYear; }); } // ========== ANALYTICS ========== window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-XXXXXXXXX'); trackEvent('page_view', { tool: TOOL_CONFIG.name, category: TOOL_CONFIG.category });