Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# [Project Name] 🎯
# DestINo 🎯


## Basic Details
Expand Down
47 changes: 47 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Travel Itinerary Planner</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.4.0/jspdf.umd.min.js"></script>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header>
<h1>AI Travel Itinerary Planner</h1>
</header>

<div class="form-container">
<h2>Select Your Destination</h2>
<select id="destination">
<option value="" disabled selected>Select a destination</option>
<option value="Paris">Paris</option>
<option value="New York">New York</option>
<option value="Tokyo">Tokyo</option>
<option value="London">London</option>
<option value="Rome">Rome</option>
<option value="Sydney">Sydney</option>
<option value="Dubai">Dubai</option>
</select>

<h2>Enter Your Budget</h2>
<input type="number" id="budget" placeholder="Enter Budget">

<h2>Select Your Trip Dates</h2>
<input type="date" id="start-date">
<input type="date" id="end-date">

<button onclick="generateItinerary()">Generate Itinerary</button>
</div>
Comment on lines +15 to +36
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve form validation and accessibility.

The form lacks proper validation attributes and accessibility features:

  1. Add form validation attributes
  2. Add ARIA labels for screen readers
  3. Add an error message container
  4. Add a loading indicator for feedback during generation

Here's a suggested improvement:

-    <div class="form-container">
+    <form class="form-container" onsubmit="event.preventDefault(); generateItinerary();">
         <h2>Select Your Destination</h2>
-        <select id="destination">
+        <select id="destination" required aria-label="Travel destination">
             <option value="" disabled selected>Select a destination</option>
             <option value="Paris">Paris</option>
             <option value="New York">New York</option>
             <option value="Tokyo">Tokyo</option>
-            <option value="London">London</option>
-            <option value="Rome">Rome</option>
-            <option value="Sydney">Sydney</option>
-            <option value="Dubai">Dubai</option>
         </select>

         <h2>Enter Your Budget</h2>
-        <input type="number" id="budget" placeholder="Enter Budget">
+        <input type="number" id="budget" placeholder="Enter Budget" required min="0" aria-label="Travel budget">

         <h2>Select Your Trip Dates</h2>
-        <input type="date" id="start-date">
-        <input type="date" id="end-date">
+        <input type="date" id="start-date" required aria-label="Trip start date">
+        <input type="date" id="end-date" required aria-label="Trip end date">

-        <button onclick="generateItinerary()">Generate Itinerary</button>
+        <button type="submit">Generate Itinerary</button>
+        <div id="loading" class="hidden">Generating your itinerary...</div>
+        <div id="error-message" class="hidden"></div>
-    </div>
+    </form>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div class="form-container">
<h2>Select Your Destination</h2>
<select id="destination">
<option value="" disabled selected>Select a destination</option>
<option value="Paris">Paris</option>
<option value="New York">New York</option>
<option value="Tokyo">Tokyo</option>
<option value="London">London</option>
<option value="Rome">Rome</option>
<option value="Sydney">Sydney</option>
<option value="Dubai">Dubai</option>
</select>
<h2>Enter Your Budget</h2>
<input type="number" id="budget" placeholder="Enter Budget">
<h2>Select Your Trip Dates</h2>
<input type="date" id="start-date">
<input type="date" id="end-date">
<button onclick="generateItinerary()">Generate Itinerary</button>
</div>
<form class="form-container" onsubmit="event.preventDefault(); generateItinerary();">
<h2>Select Your Destination</h2>
<select id="destination" required aria-label="Travel destination">
<option value="" disabled selected>Select a destination</option>
<option value="Paris">Paris</option>
<option value="New York">New York</option>
<option value="Tokyo">Tokyo</option>
</select>
<h2>Enter Your Budget</h2>
<input type="number" id="budget" placeholder="Enter Budget" required min="0" aria-label="Travel budget">
<h2>Select Your Trip Dates</h2>
<input type="date" id="start-date" required aria-label="Trip start date">
<input type="date" id="end-date" required aria-label="Trip end date">
<button type="submit">Generate Itinerary</button>
<div id="loading" class="hidden">Generating your itinerary...</div>
<div id="error-message" class="hidden"></div>
</form>


<div id="itinerary-view">
<h2>Your AI-Generated Itinerary</h2>
<div id="itinerary-summary"></div>
</div>

<button onclick="exportItinerary()">Export as PDF</button>

<script src="script.js"></script>
</body>
</html>
91 changes: 91 additions & 0 deletions script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
const destinationData = {
"Paris": {
activities: [
{ name: "Eiffel Tower Visit", cost: 30 },
{ name: "Louvre Museum", cost: 20 },
{ name: "Seine River Cruise", cost: 50 }
],
accommodations: [
{ name: "Budget Hotel", costPerNight: 100 },
{ name: "Mid-range Hotel", costPerNight: 200 },
{ name: "Luxury Hotel", costPerNight: 400 }
]
},
"New York": {
activities: [
{ name: "Statue of Liberty", cost: 25 },
{ name: "Central Park", cost: 0 },
{ name: "Broadway Show", cost: 100 }
],
accommodations: [
{ name: "Budget Hostel", costPerNight: 50 },
{ name: "Mid-range Hotel", costPerNight: 150 },
{ name: "Luxury Hotel", costPerNight: 350 }
]
},
"Tokyo": {
activities: [
{ name: "Shibuya Crossing", cost: 0 },
{ name: "Tokyo Tower", cost: 15 },
{ name: "Senso-ji Temple", cost: 0 }
],
accommodations: [
{ name: "Capsule Hotel", costPerNight: 40 },
{ name: "Business Hotel", costPerNight: 100 },
{ name: "Luxury Hotel", costPerNight: 300 }
]
}
};
Comment on lines +1 to +38
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add missing destination data to match UI options.

The destinationData object is missing data for London, Rome, Sydney, and Dubai, which are available as options in the UI. This mismatch will result in "Sorry, we don't have data for this destination" errors when users select these destinations.

Consider internationalizing costs.

The costs are hardcoded without currency specification. Consider:

  1. Adding currency information to support international destinations
  2. Implementing currency conversion based on user preferences


// Function to generate the AI-driven itinerary
function generateItinerary() {
const destination = document.getElementById('destination').value;
const budget = parseFloat(document.getElementById('budget').value);

if (!destination || isNaN(budget) || budget <= 0) {
alert("Please enter a valid destination and budget.");
return;
}

// Check if the destination is in the predefined data
const data = destinationData[destination];
if (!data) {
alert("Sorry, we don't have data for this destination.");
return;
}

// Suggest activities based on the budget
let activities = data.activities.filter(activity => activity.cost <= budget);
let accommodations = data.accommodations.filter(acc => acc.costPerNight <= budget / 3); // Assume a 3-night stay

// Generate itinerary summary
let itinerarySummary = `
<h3>Destination: ${destination}</h3>
<h4>Activities (within your budget):</h4>
<ul>
${activities.map(activity => `<li>${activity.name} - $${activity.cost}</li>`).join('')}
</ul>
<h4>Accommodation Options (within your budget):</h4>
<ul>
${accommodations.map(acc => `<li>${acc.name} - $${acc.costPerNight} per night</li>`).join('')}
</ul>
<h4>Suggested Itinerary:</h4>
<ul>
<li>Day 1: Arrive and check into your accommodation</li>
${activities.slice(0, 2).map((activity, index) => `<li>Day ${index + 2}: ${activity.name}</li>`).join('')}
</ul>
`;

// Display the generated itinerary
document.getElementById('itinerary-summary').innerHTML = itinerarySummary;
}
Comment on lines +40 to +81
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Several improvements needed for the itinerary generation logic.

  1. Trip dates from the UI are not used in the itinerary generation
  2. The 3-night stay assumption for accommodation budget is hardcoded
  3. Missing error handling for cases where no activities/accommodations fit within budget
  4. HTML content is not sanitized against XSS attacks
  5. No consideration for seasonal availability or operating hours of activities

Here's a suggested improvement:

 function generateItinerary() {
     const destination = document.getElementById('destination').value;
     const budget = parseFloat(document.getElementById('budget').value);
+    const startDate = new Date(document.getElementById('start-date').value);
+    const endDate = new Date(document.getElementById('end-date').value);
+
+    // Validate dates
+    if (isNaN(startDate.getTime()) || isNaN(endDate.getTime()) || startDate >= endDate) {
+        alert("Please enter valid trip dates.");
+        return;
+    }
+
+    // Calculate number of nights
+    const nights = Math.ceil((endDate - startDate) / (1000 * 60 * 60 * 24));

     if (!destination || isNaN(budget) || budget <= 0) {
         alert("Please enter a valid destination and budget.");
         return;
     }

     // Check if the destination is in the predefined data
     const data = destinationData[destination];
     if (!data) {
         alert("Sorry, we don't have data for this destination.");
         return;
     }

     // Suggest activities based on the budget
     let activities = data.activities.filter(activity => activity.cost <= budget);
-    let accommodations = data.accommodations.filter(acc => acc.costPerNight <= budget / 3); // Assume a 3-night stay
+    let accommodations = data.accommodations.filter(acc => acc.costPerNight <= budget / nights);
+
+    // Check if we found any suitable options
+    if (activities.length === 0 || accommodations.length === 0) {
+        alert("Sorry, we couldn't find any suitable activities or accommodations within your budget.");
+        return;
+    }

     // Generate itinerary summary
     let itinerarySummary = `
         <h3>Destination: ${destination}</h3>
+        <h4>Trip Duration: ${nights} nights (${startDate.toLocaleDateString()} - ${endDate.toLocaleDateString()})</h4>
         <h4>Activities (within your budget):</h4>
         <ul>
-            ${activities.map(activity => `<li>${activity.name} - $${activity.cost}</li>`).join('')}
+            ${activities.map(activity => `<li>${escapeHtml(activity.name)} - $${activity.cost}</li>`).join('')}
         </ul>
         <h4>Accommodation Options (within your budget):</h4>
         <ul>
-            ${accommodations.map(acc => `<li>${acc.name} - $${acc.costPerNight} per night</li>`).join('')}
+            ${accommodations.map(acc => `<li>${escapeHtml(acc.name)} - $${acc.costPerNight} per night</li>`).join('')}
         </ul>
         <h4>Suggested Itinerary:</h4>
         <ul>
             <li>Day 1: Arrive and check into your accommodation</li>
-            ${activities.slice(0, 2).map((activity, index) => `<li>Day ${index + 2}: ${activity.name}</li>`).join('')}
+            ${activities.slice(0, nights).map((activity, index) => 
+                `<li>Day ${index + 2}: ${escapeHtml(activity.name)}</li>`
+            ).join('')}
         </ul>
     `;

     // Display the generated itinerary
     document.getElementById('itinerary-summary').innerHTML = itinerarySummary;
 }

+// Helper function to escape HTML and prevent XSS
+function escapeHtml(unsafe) {
+    return unsafe
+        .replace(/&/g, "&amp;")
+        .replace(/</g, "&lt;")
+        .replace(/>/g, "&gt;")
+        .replace(/"/g, "&quot;")
+        .replace(/'/g, "&#039;");
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Function to generate the AI-driven itinerary
function generateItinerary() {
const destination = document.getElementById('destination').value;
const budget = parseFloat(document.getElementById('budget').value);
if (!destination || isNaN(budget) || budget <= 0) {
alert("Please enter a valid destination and budget.");
return;
}
// Check if the destination is in the predefined data
const data = destinationData[destination];
if (!data) {
alert("Sorry, we don't have data for this destination.");
return;
}
// Suggest activities based on the budget
let activities = data.activities.filter(activity => activity.cost <= budget);
let accommodations = data.accommodations.filter(acc => acc.costPerNight <= budget / 3); // Assume a 3-night stay
// Generate itinerary summary
let itinerarySummary = `
<h3>Destination: ${destination}</h3>
<h4>Activities (within your budget):</h4>
<ul>
${activities.map(activity => `<li>${activity.name} - $${activity.cost}</li>`).join('')}
</ul>
<h4>Accommodation Options (within your budget):</h4>
<ul>
${accommodations.map(acc => `<li>${acc.name} - $${acc.costPerNight} per night</li>`).join('')}
</ul>
<h4>Suggested Itinerary:</h4>
<ul>
<li>Day 1: Arrive and check into your accommodation</li>
${activities.slice(0, 2).map((activity, index) => `<li>Day ${index + 2}: ${activity.name}</li>`).join('')}
</ul>
`;
// Display the generated itinerary
document.getElementById('itinerary-summary').innerHTML = itinerarySummary;
}
// Function to generate the AI-driven itinerary
function generateItinerary() {
const destination = document.getElementById('destination').value;
const budget = parseFloat(document.getElementById('budget').value);
const startDate = new Date(document.getElementById('start-date').value);
const endDate = new Date(document.getElementById('end-date').value);
// Validate dates
if (isNaN(startDate.getTime()) || isNaN(endDate.getTime()) || startDate >= endDate) {
alert("Please enter valid trip dates.");
return;
}
// Calculate number of nights
const nights = Math.ceil((endDate - startDate) / (1000 * 60 * 60 * 24));
if (!destination || isNaN(budget) || budget <= 0) {
alert("Please enter a valid destination and budget.");
return;
}
// Check if the destination is in the predefined data
const data = destinationData[destination];
if (!data) {
alert("Sorry, we don't have data for this destination.");
return;
}
// Suggest activities based on the budget
let activities = data.activities.filter(activity => activity.cost <= budget);
let accommodations = data.accommodations.filter(acc => acc.costPerNight <= budget / nights);
// Check if we found any suitable options
if (activities.length === 0 || accommodations.length === 0) {
alert("Sorry, we couldn't find any suitable activities or accommodations within your budget.");
return;
}
// Generate itinerary summary
let itinerarySummary = `
<h3>Destination: ${destination}</h3>
<h4>Trip Duration: ${nights} nights (${startDate.toLocaleDateString()} - ${endDate.toLocaleDateString()})</h4>
<h4>Activities (within your budget):</h4>
<ul>
${activities.map(activity => `<li>${escapeHtml(activity.name)} - $${activity.cost}</li>`).join('')}
</ul>
<h4>Accommodation Options (within your budget):</h4>
<ul>
${accommodations.map(acc => `<li>${escapeHtml(acc.name)} - $${acc.costPerNight} per night</li>`).join('')}
</ul>
<h4>Suggested Itinerary:</h4>
<ul>
<li>Day 1: Arrive and check into your accommodation</li>
${activities.slice(0, nights).map((activity, index) =>
`<li>Day ${index + 2}: ${escapeHtml(activity.name)}</li>`
).join('')}
</ul>
`;
// Display the generated itinerary
document.getElementById('itinerary-summary').innerHTML = itinerarySummary;
}
// Helper function to escape HTML and prevent XSS
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}


// Export function to PDF
function exportItinerary() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();

const itineraryContent = document.getElementById('itinerary-summary').innerText;
doc.text(itineraryContent, 10, 10);
doc.save('itinerary.pdf');
}
Comment on lines +83 to +91
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve PDF export functionality.

The current implementation has several limitations:

  1. No error handling if itinerary is not generated
  2. Basic PDF formatting with all text at position (10,10)
  3. No handling of content overflow or page breaks

Here's a suggested improvement:

 function exportItinerary() {
+    const itineraryElement = document.getElementById('itinerary-summary');
+    if (!itineraryElement || !itineraryElement.innerText.trim()) {
+        alert("Please generate an itinerary first.");
+        return;
+    }
+
     const { jsPDF } = window.jspdf;
     const doc = new jsPDF();
 
-    const itineraryContent = document.getElementById('itinerary-summary').innerText;
-    doc.text(itineraryContent, 10, 10);
+    // Set font size and line height
+    doc.setFontSize(12);
+    const lineHeight = 8;
+
+    // Split text into lines that fit the page width
+    const lines = doc.splitTextToSize(itineraryElement.innerText, 190);
+
+    // Add lines to PDF with proper spacing
+    let y = 20;
+    lines.forEach(line => {
+        if (y > 280) { // Check if we need a new page
+            doc.addPage();
+            y = 20;
+        }
+        doc.text(line, 10, y);
+        y += lineHeight;
+    });
+
     doc.save('itinerary.pdf');
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Export function to PDF
function exportItinerary() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
const itineraryContent = document.getElementById('itinerary-summary').innerText;
doc.text(itineraryContent, 10, 10);
doc.save('itinerary.pdf');
}
// Export function to PDF
function exportItinerary() {
const itineraryElement = document.getElementById('itinerary-summary');
if (!itineraryElement || !itineraryElement.innerText.trim()) {
alert("Please generate an itinerary first.");
return;
}
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
// Set font size and line height
doc.setFontSize(12);
const lineHeight = 8;
// Split text into lines that fit the page width
const lines = doc.splitTextToSize(itineraryElement.innerText, 190);
// Add lines to PDF with proper spacing
let y = 20;
lines.forEach(line => {
if (y > 280) { // Check if we need a new page
doc.addPage();
y = 20;
}
doc.text(line, 10, y);
y += lineHeight;
});
doc.save('itinerary.pdf');
}

49 changes: 49 additions & 0 deletions styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
text-align: center;
background-color: #f4f4f4;
}

header {
background-color: #3498db;
color: white;
padding: 15px;
}

.form-container {
background: white;
padding: 20px;
width: 50%;
margin: 20px auto;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

input, select, button {
margin: 10px;
padding: 10px;
width: 80%;
font-size: 16px;
}

button {
background-color: #3498db;
color: white;
border: none;
cursor: pointer;
}

button:hover {
background-color: #2980b9;
}

#itinerary-summary {
background: white;
padding: 20px;
margin: 20px auto;
width: 50%;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}