Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Holiday bot #290

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
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
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
# Project Name
# Project Chatbot

Replace this readme with your own information about your project.

Start by briefly describing the assignment in a sentence or two. Keep it short and to the point.
A simple chatbot that interacts with the user and guides them through a fun, personalized conversation.

## The problem

Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next?
The problem was approached by breaking down the interaction flow into distinct steps: greeting the user, capturing inputs, and generating responses based on the input. Vanilla JavaScript was used for DOM manipulation and event handling, such as form submission. The UI was dynamically updated. Given more time, additional conversation options and design improvements would be implemented to enhance user experience.

## View it live

Have you deployed your project somewhere? Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about.
https://holiday-bot.netlify.app/
Binary file modified code/assets/bot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added code/assets/holiday.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified code/assets/user.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 11 additions & 11 deletions code/index.html
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./style.css" />
<link
href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
rel="stylesheet" />
<title>Chatbot</title>
rel="stylesheet"
/>
<!-- h1 font -->
<link
href="https://fonts.googleapis.com/css2?family=Great+Vibes&display=swap"
rel="stylesheet"
/>
<title>Holiday bot</title>
</head>

<body>
<h1>Welcome to my chatbot!</h1>
<h1>Holiday bot</h1>

<main>
<section class="chat" id="chat"></section>
<div class="input-wrapper" id="input-wrapper">
<form id="name-form">
<label for="name-input">Name</label>
<input id="name-input" type="text" />
<button class="send-btn" type="submit">
Send
</button>
<button class="send-btn" id="send" type="submit">Send</button>
</form>
</div>
</main>

<script src="./script.js"></script>
</body>

</html>
278 changes: 246 additions & 32 deletions code/script.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,267 @@
// DOM selectors (variables that point to selected DOM elements) goes here 👇
const chat = document.getElementById('chat')
// DOM selectors (variables that point to selected DOM elements) goes here
const chat = document.getElementById("chat");
const nameInput = document.getElementById("name-input");
const form = document.getElementById("name-form");
const submit = document.getElementById("send");
const inputWrapper = document.getElementById("input-wrapper");

// Functions goes here 👇
// Variables
let questionNumber = 1;
Copy link
Contributor

Choose a reason for hiding this comment

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

Really good idea to keep track of the flow ⭐

let userName = "";

// Destinations mapped by mood
// Based on the mood selected by the user, the bot will suggest destinations
const destinationsByMood = {
Adventure: ["🏔️ Mount Everest", "🌳 Amazon Rainforest", "🏜️ Sahara Desert"],
Relax: ["🛳️ Maldives", "🌴 Bora Bora", "🏖️ Bali"],
Cultural: ["🍝 Italy", "🏺 Greece", "🍣 Japan"],
Romantic: ["🌹 Paris", "🌅 Venice", "🌺 Santorini"],
};

// Function for bot to reply with a message after a delay
// The delay is used to make the conversation feel more natural.
const botReply = (msg) => {
setTimeout(() => showMessage(msg, "bot"), 500);
};
const userReply = (msg) => {
showMessage(msg, "user");
};
Comment on lines +23 to +28
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice ⭐


// A function that will add a chat bubble in the correct place based on who the sender is
const showMessage = (message, sender) => {
// The if statement checks if the sender is the user and if that's the case it inserts
// an HTML section inside the chat with the posted message from the user
if (sender === 'user') {
if (sender === "user") {
chat.innerHTML += `
<section class="user-msg">
<div class="bubble user-bubble">
<p>${message}</p>
</div>
<img src="assets/user.png" alt="User" />
</section>
`
// The else if statement checks if the sender is the bot and if that's the case it inserts
// an HTML section inside the chat with the posted message from the bot
} else if (sender === 'bot') {
`;
} else if (sender === "bot") {
console.log("Bot message is being shown:", message); // This will log when the bot sends a message
chat.innerHTML += `
<section class="bot-msg">
<img src="assets/bot.png" alt="Bot" />
<div class="bubble bot-bubble">
<p>${message}</p>
</div>
</section>
`
`;
}

// This little thing makes the chat scroll to the last message when there are too many to
// be shown in the chat box
chat.scrollTop = chat.scrollHeight
}
chat.scrollTop = chat.scrollHeight;
};

// A function to start the conversation
const greetUser = () => {
// Here we call the function showMessage, that we declared earlier with the argument:
// "Hello there, what's your name?" for message, and the argument "bot" for sender
showMessage("Hello there, what's your name?", 'bot')
// Just to check it out, change 'bot' to 'user' here 👆 and see what happens
}

// Eventlisteners goes here 👇

// Here we invoke the first function to get the chatbot to ask the first question when
// the website is loaded. Normally we invoke functions like this: greeting()
// To add a little delay to it, we can wrap it in a setTimeout (a built in JavaScript function):
// and pass along two arguments:
// 1.) the function we want to delay, and 2.) the delay in milliseconds
// This means the greeting function will be called one second after the website is loaded.
setTimeout(greetUser, 1000)
const greeting = () => {
botReply(
`Hi there! I'm your travel assistant, ready to help you pick the perfect destination.`
);
botReply(`Before we start, can I get your name?`);

// Show the name input field
inputWrapper.innerHTML = `
<input id="name-input" type="text" placeholder="Enter your name..." />
<button id="submit-name">Submit</button>
`;

document
.getElementById("submit-name")
.addEventListener("click", () => handleNameInput());
};

// Handle name input
const handleNameInput = () => {
const nameInput = document.getElementById("name-input");
userName = nameInput.value.trim(); // Get the user's name

if (userName) {
userReply(userName);
botReply(
`Nice to meet you, ${userName}! Let's figure out what kind of trip you're in the mood for.`
);

showMoodOptions(); // Proceed to mood selection
} else {
botReply(`Oops, I didn't catch that! Please enter your name to continue.`);
}
};

const showMoodOptions = () => {
// Wait for the bot's message to be displayed first
setTimeout(() => {
inputWrapper.innerHTML = `
<select id="moodSelect">
<option value="" selected disabled>👇 Select a mood...</option>
<option value="Adventure">🌍 Adventure</option>
<option value="Relax">🌴 Relax</option>
<option value="Cultural">🏛️ Cultural</option>
<option value="Romantic">💖 Romantic</option>
</select>
`;

document
.getElementById("moodSelect")
.addEventListener("change", (event) => nextQuestion(event.target.value));
}, 600); // 500ms delay
};

// Proceed to the next question based on the selected mood
const nextQuestion = (mood) => {
botReply(`${mood}, exciting! Let's see which destinations match your mood.`);

showDestinationOptions(mood); // Pass the mood to showDestinationOptions
};

const showDestinationOptions = (mood) => {
const destinations = destinationsByMood[mood];

// Wait for the bot's message to be displayed first
setTimeout(() => {
inputWrapper.innerHTML = `
<select id="select">
<option value="" selected disabled>👇 Select a destination...</option>
${destinations
.map(
(destination) =>
`<option value="${destination}">${destination}</option>`
)
.join("")}
</select>
`;

const select = document.getElementById("select");
select.addEventListener("change", () => showMenu(select.value));
}, 600); // 500ms delay
};

// Ask about activities after selecting a destination
const showMenu = (destination) => {
questionNumber++;

botReply(
`Great choice! ${destination} sounds like an amazing place. Would you like to plan some activities while you're there?`
);

// Delay the appearance of the Yes/No buttons
setTimeout(() => {
inputWrapper.innerHTML = `
<button id="theEnd">NO</button>
<button id="confirm">YES</button>
`;

document.getElementById("theEnd").addEventListener("click", () => {
botReply("Alright, enjoy your trip!");
inputWrapper.innerHTML = ``;
showStartOverButton(); // Show the "Start Over" button
});

document.getElementById("confirm").addEventListener("click", () => {
showActivities();
});
}, 600); // Delay of 600ms
};

const showActivities = () => {
questionNumber++;

botReply(`Awesome! What activities would you like to do while you're there?`);

// Create a dropdown menu for activities
setTimeout(() => {
inputWrapper.innerHTML = `
<select id="activitySelect">
<option value="" selected disabled>👇 Select an activity...</option>
<option value="Hiking">🥾 Hiking</option>
<option value="Beach">🏖️ Beach</option>
<option value="Sightseeing">🗺️ Sightseeing</option>
</select>
`;

document
.getElementById("activitySelect")
.addEventListener("change", (event) => {
const selectedActivity = event.target.value;
if (selectedActivity) {
showChoice(selectedActivity);
}
});
}, 600); // 500ms delay
};

// Show the choice made by the user and prompt readiness
const showChoice = (choice) => {
questionNumber++;

botReply(`${choice} sounds fun! Are you ready to start planning your trip?`);

// Add suggestions based on the selected activity
let suggestions = "";

Choose a reason for hiding this comment

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

nice!!

if (choice === "Hiking") {
suggestions = `
Here are some hiking tips and guides:
<ul>
<li><a href="random url" target="_blank">AllTrails - Discover Hiking</a></li>
<li><a href="random url" target="_blank">Hiking for Beginners</a></li>
<li><a href="random url" target="_blank">Top Hiking Trails</a></li>
</ul>
`;
} else if (choice === "Beach") {
suggestions = `
Here are some beach travel ideas:
<ul>
<li><a href="random url" target="_blank">TripAdvisor - Must-Visit Beaches</a></li>
<li><a href="random url" target="_blank">Condé Nast Traveler - Top Beaches</a></li>
<li><a href="random url" target="_blank">Top 5 Beaches</a></li>
</ul>
`;
} else if (choice === "Sightseeing") {
suggestions = `
Here are some sightseeing guides:
<ul>
<li><a href="random url" target="_blank">Lonely Planet - Best Sightseeing Tours</a></li>
<li><a href="random url" target="_blank">BuzzFeed - Top Bucket List Sights</a></li>
<li><a href="random url" target="_blank">Rough Guides - Best in Travel 2024</a></li>
</ul>
`;
}

// Display the suggestions before asking if they're ready
botReply(suggestions);

// Delay the appearance of the "Ready" button
setTimeout(() => {
inputWrapper.innerHTML = `
<button id="ready">Ready</button>
`;

document.getElementById("ready").addEventListener("click", () => {
thankYou();
});
}, 600); // Delay of 500ms
};

// End of conversation
const thankYou = () => {
botReply(
`Wishing you an incredible trip ${userName}! Hope you have an amazing adventure.`
);
inputWrapper.innerHTML = ``; // Clear input, removes the "ready" btn
showStartOverButton(); // Show the "Start Over" button
};

// Show the "Start Over" button after the conversation ends
const showStartOverButton = () => {
setTimeout(() => {
inputWrapper.innerHTML = `
<button id="start-over">Start Over</button>
`;

Choose a reason for hiding this comment

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

Loved this!


document
.getElementById("start-over")
.addEventListener("click", () => location.reload());
}, 600); // 500ms delay
};

// Initiate the conversation
greeting();
Loading