Long-Term Travel Budget Planner

Long-Term Travel Budget Planner

Trip Basics & Savings Goal

Estimated Trip Expenses

No expense items added yet.

Total Estimated Trip Cost: $0.00

Budget Analysis & Summary

Analysis will appear here once trip details and expenses are entered.

Full Plan & Report

A summary of your travel budget plan will appear here.

No expense items added yet.

'; return; } let tableHTML = ``; lttb_expenseItems.forEach(item => { tableHTML += ``; }); tableHTML += '
DescriptionCategoryCost ($)Action
${item.description}${item.category} ${item.cost.toFixed(2)}
'; container.innerHTML = tableHTML; } function lttb_updateTotalEstimatedCost() { const totalCost = lttb_expenseItems.reduce((sum, item) => sum + item.cost, 0); const displayDiv = document.getElementById('lttbTotalEstimatedTripCostDisplay'); displayDiv.innerHTML = `Total Estimated Trip Cost: $${totalCost.toFixed(2)}`; return totalCost; } // --- Budget Analysis (Tab 3) --- function lttb_calculateMonthsUntilDeparture() { const targetMonth = lttb_getIntValue('lttbDepartureMonth'); const targetYear = lttb_getIntValue('lttbDepartureYear'); const today = new Date(); const currentMonth = today.getMonth() + 1; // JS months are 0-indexed const currentYear = today.getFullYear(); if (targetYear < currentYear || (targetYear === currentYear && targetMonth <= currentMonth)) { return 0; // Departure date is in the past or current month } let months = (targetYear - currentYear) * 12; months -= currentMonth; months += targetMonth; return months <= 0 ? 0 : months; } function lttb_calculateAndDisplayAnalysis() { const resultsDiv = document.getElementById('lttbAnalysisResults'); const tripName = document.getElementById('lttbTripName').value || "My Long-Term Trip"; const alreadySaved = lttb_getFloatValue('lttbAlreadySaved'); const targetMonthlySaving = lttb_getFloatValue('lttbTargetMonthlySaving'); const totalEstimatedTripCost = lttb_expenseItems.reduce((sum, item) => sum + item.cost, 0); const monthsUntilDeparture = lttb_calculateMonthsUntilDeparture(); const remainingToSave = Math.max(0, totalEstimatedTripCost - alreadySaved); const projectedSavingsByDeparture = (targetMonthlySaving * monthsUntilDeparture) + alreadySaved; let analysisHTML = `

${tripName} - Budget Analysis

Total Estimated Trip Cost: $${totalEstimatedTripCost.toFixed(2)}

Amount Already Saved: $${alreadySaved.toFixed(2)}

Remaining Amount to Save: $${remainingToSave.toFixed(2)}


Months Until Target Departure: ${monthsUntilDeparture} months

Your Target Monthly Savings: $${targetMonthlySaving.toFixed(2)}

Projected Total Savings by Departure: $${projectedSavingsByDeparture.toFixed(2)}


`; if (monthsUntilDeparture <= 0) { analysisHTML += `

Your target departure date is in the past or too soon to save. Please adjust.

`; } else { const requiredMonthlyToMeetGoal = remainingToSave > 0 ? remainingToSave / monthsUntilDeparture : 0; analysisHTML += `

Required Monthly Savings to Meet Goal by Departure: $${requiredMonthlyToMeetGoal.toFixed(2)}

`; if (projectedSavingsByDeparture >= totalEstimatedTripCost) { const surplus = projectedSavingsByDeparture - totalEstimatedTripCost; analysisHTML += `

You are ON TRACK! You're projected to have a surplus of $${surplus.toFixed(2)} by your departure date.

`; } else { const shortfall = totalEstimatedTripCost - projectedSavingsByDeparture; analysisHTML += `

POTENTIAL SHORTFALL: You are projected to be short $${shortfall.toFixed(2)}.

`; if (targetMonthlySaving < requiredMonthlyToMeetGoal) { analysisHTML += `

Consider increasing your monthly savings by at least $${(requiredMonthlyToMeetGoal - targetMonthlySaving).toFixed(2)}, adjusting trip costs, or extending your timeline.

`; } } } resultsDiv.innerHTML = analysisHTML; return {tripName, totalEstimatedTripCost, alreadySaved, remainingToSave, monthsUntilDeparture, targetMonthlySaving, projectedSavingsByDeparture }; // For PDF and report preview } // --- Report & PDF (Tab 4) --- function lttb_generateReportPreview() { const previewDiv = document.getElementById('lttbReportPreview'); const analysisData = lttb_calculateAndDisplayAnalysis(); // Recalculate for fresh data if (!analysisData) { // If analysis failed due to bad dates etc. previewDiv.innerHTML = "

Please ensure all inputs in previous tabs are correct to generate a report.

"; return; } let html = `

${analysisData.tripName} - Plan Summary

Total Estimated Trip Cost: $${analysisData.totalEstimatedTripCost.toFixed(2)}

Amount Already Saved: $${analysisData.alreadySaved.toFixed(2)}

Remaining to Save: $${analysisData.remainingToSave.toFixed(2)}

Months to Departure: ${analysisData.monthsUntilDeparture}

Target Monthly Saving: $${analysisData.targetMonthlySaving.toFixed(2)}

Projected Savings by Departure: $${analysisData.projectedSavingsByDeparture.toFixed(2)}

`; if (analysisData.monthsUntilDeparture > 0) { const requiredMonthly = analysisData.remainingToSave > 0 ? analysisData.remainingToSave / analysisData.monthsUntilDeparture : 0; html += `

Required Monthly Saving for Goal: $${requiredMonthly.toFixed(2)}

`; if (analysisData.projectedSavingsByDeparture >= analysisData.totalEstimatedTripCost) { html += `

Status: ON TRACK

`; } else { html += `

Status: SHORTFALL of $${(analysisData.totalEstimatedTripCost - analysisData.projectedSavingsByDeparture).toFixed(2)}

`; } } else { html += `

Status: Departure date issue.

`; } html += `

The full PDF will contain the detailed expense list.

`; previewDiv.innerHTML = html; } function lttb_generatePdf() { const analysisData = lttb_calculateAndDisplayAnalysis(); // Ensure data is current if (!analysisData) { alert("Please ensure all trip details and expenses are correctly entered before generating PDF."); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF(); let yPos = 20; const primaryColor = getComputedStyle(document.documentElement).getPropertyValue('--primary-color').trim(); const accentColor = getComputedStyle(document.documentElement).getPropertyValue('--accent-color').trim(); const dangerColor = getComputedStyle(document.documentElement).getPropertyValue('--danger-color').trim(); const textColor = getComputedStyle(document.documentElement).getPropertyValue('--text-color').trim(); const toCurrency = (num) => `$${num.toFixed(2)}`; doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text(`Travel Budget Plan: ${analysisData.tripName}`, doc.internal.pageSize.getWidth() / 2, yPos, { align: 'center' }); yPos += 10; doc.setFontSize(10); doc.setTextColor(textColor); doc.text(`Target Departure: ${document.getElementById('lttbDepartureMonth').selectedOptions[0].text} ${document.getElementById('lttbDepartureYear').value} (${analysisData.monthsUntilDeparture} months from now)`, doc.internal.pageSize.getWidth() / 2, yPos, { align: 'center' }); yPos += 10; // Savings Summary doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Savings Summary", 14, yPos); yPos += 7; doc.setFontSize(10); doc.setTextColor(textColor); doc.text(`Total Estimated Trip Cost: ${toCurrency(analysisData.totalEstimatedTripCost)}`, 14, yPos); yPos += 6; doc.text(`Amount Already Saved: ${toCurrency(analysisData.alreadySaved)}`, 14, yPos); yPos += 6; doc.text(`Remaining Amount to Save: ${toCurrency(analysisData.remainingToSave)}`, 14, yPos); yPos += 6; doc.text(`Target Monthly Savings: ${toCurrency(analysisData.targetMonthlySaving)}`, 14, yPos); yPos += 6; doc.text(`Projected Total Savings by Departure: ${toCurrency(analysisData.projectedSavingsByDeparture)}`, 14, yPos); yPos += 8; // Budget Analysis doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Budget Analysis", 14, yPos); yPos += 7; doc.setFontSize(10); doc.setTextColor(textColor); if (analysisData.monthsUntilDeparture <= 0) { doc.setTextColor(dangerColor); doc.text("Status: Departure date is in the past or too soon to effectively plan savings.", 14, yPos); yPos +=6; } else { const requiredMonthly = analysisData.remainingToSave > 0 ? analysisData.remainingToSave / analysisData.monthsUntilDeparture : 0; doc.text(`Required Monthly Savings to Meet Goal: ${toCurrency(requiredMonthly)}`, 14, yPos); yPos += 6; if (analysisData.projectedSavingsByDeparture >= analysisData.totalEstimatedTripCost) { doc.setTextColor(accentColor); doc.text(`Status: ON TRACK. Projected Surplus: ${toCurrency(analysisData.projectedSavingsByDeparture - analysisData.totalEstimatedTripCost)}`, 14, yPos); } else { doc.setTextColor(dangerColor); doc.text(`Status: SHORTFALL. Projected Shortfall: ${toCurrency(analysisData.totalEstimatedTripCost - analysisData.projectedSavingsByDeparture)}`, 14, yPos); } } doc.setTextColor(textColor); yPos += 10; // Detailed Expenses if (lttb_expenseItems.length > 0) { if (yPos > 250) { doc.addPage(); yPos = 20; } doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Detailed Estimated Expenses", 14, yPos); yPos += 7; const tableBody = lttb_expenseItems.map(item => [item.category, item.description, toCurrency(item.cost)]); doc.autoTable({ startY: yPos, head: [['Category', 'Description', 'Estimated Cost ($)']], body: tableBody, theme: 'grid', headStyles: { fillColor: primaryColor, textColor: '#ffffff' }, styles: { fontSize: 9, cellPadding: 2 }, columnStyles: { 1: { cellWidth: 'auto'} }, // Description can wrap didDrawPage: (d) => { yPos = d.cursor.y; } }); } else { doc.setFontSize(10); doc.text("No detailed expenses listed.", 14, yPos); } doc.save(`${analysisData.tripName.replace(/[^a-z0-9]/gi, '_').toLowerCase()}_travel_budget.pdf`); } // Initialize document.addEventListener('DOMContentLoaded', () => { lttb_populateDateSelects(); lttb_showTab(0); lttb_renderExpenseItemsList(); // For empty state lttb_updateTotalEstimatedCost(); // Demo Data lttb_expenseItems.push({id:'exp_001', category:'Flights', description:'Round-trip to Europe', cost:1200}); lttb_expenseItems.push({id:'exp_002', category:'Accommodation', description:'Hostels & Guesthouses (60 nights avg $40)', cost:2400}); lttb_expenseItems.push({id:'exp_003', category:'Food & Drinks', description:'Average $50/day for 60 days', cost:3000}); lttb_renderExpenseItemsList(); lttb_updateTotalEstimatedCost(); });
Scroll to Top