diff --git a/README.md b/README.md index 60f55e53..3057f14f 100644 --- a/README.md +++ b/README.md @@ -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/ diff --git a/code/assets/bot.png b/code/assets/bot.png index 2c894b15..24cb9055 100644 Binary files a/code/assets/bot.png and b/code/assets/bot.png differ diff --git a/code/assets/holiday.jpg b/code/assets/holiday.jpg new file mode 100644 index 00000000..156a3813 Binary files /dev/null and b/code/assets/holiday.jpg differ diff --git a/code/assets/user.png b/code/assets/user.png index 6d95f08f..13cbeb44 100644 Binary files a/code/assets/user.png and b/code/assets/user.png differ diff --git a/code/index.html b/code/index.html index 316eb187..5ebffb44 100644 --- a/code/index.html +++ b/code/index.html @@ -1,32 +1,32 @@ - - Chatbot + rel="stylesheet" + /> + + + Holiday bot - -

Welcome to my chatbot!

+

Holiday bot

+
- - +
- - diff --git a/code/script.js b/code/script.js index 125d6904..695ac073 100644 --- a/code/script.js +++ b/code/script.js @@ -1,13 +1,35 @@ -// 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; +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"); +}; // 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 += `
@@ -15,10 +37,9 @@ const showMessage = (message, sender) => {
User
- ` - // 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 += `
Bot @@ -26,28 +47,221 @@ const showMessage = (message, sender) => {

${message}

- ` + `; } - - // 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 = ` + + + `; + + 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 = ` + + `; + + 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 = ` + + `; + + 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 = ` + + + `; + + 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 = ` + + `; + + 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 = ""; + if (choice === "Hiking") { + suggestions = ` + Here are some hiking tips and guides: + + `; + } else if (choice === "Beach") { + suggestions = ` + Here are some beach travel ideas: + + `; + } else if (choice === "Sightseeing") { + suggestions = ` + Here are some sightseeing guides: + + `; + } + + // Display the suggestions before asking if they're ready + botReply(suggestions); + + // Delay the appearance of the "Ready" button + setTimeout(() => { + inputWrapper.innerHTML = ` + + `; + + 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 = ` + + `; + + document + .getElementById("start-over") + .addEventListener("click", () => location.reload()); + }, 600); // 500ms delay +}; + +// Initiate the conversation +greeting(); diff --git a/code/style.css b/code/style.css index a275402f..617495d9 100644 --- a/code/style.css +++ b/code/style.css @@ -1,29 +1,37 @@ +/*{ + outline: 1px solid red; +} */ + * { + margin: 0; + padding: 0; box-sizing: border-box; } body { margin: 0; padding: 0; - font-family: 'Montserrat', sans-serif; - background: #0026ff; -} + font-family: "Montserrat", sans-serif; /* Default font */ -h1 { - font-weight: bold; - font-size: 28px; - line-height: 34px; - color: #fff; - text-align: center; + background-image: url(assets/holiday.jpg); + background-size: cover; + background-repeat: no-repeat; + background-attachment: fixed; + background-position: center; + max-height: 100%; + overflow-x: hidden; } -h2 { - font-weight: bold; - font-size: 24px; +h1 { + font-family: "Great Vibes", cursive; + font-weight: 595; + font-size: 90px; line-height: 34px; color: #fff; text-align: center; - margin-bottom: 36px; + margin-top: 50px; + margin-bottom: 25px; + line-height: 65px; } p { @@ -37,39 +45,68 @@ input { box-sizing: border-box; border: none; border-radius: 4px 0 0 4px; - background: #e5e9ff; - color: #0026ff; + background: #e7e8e6; + color: #232222; padding: 16px; font-size: 16px; - font-family: 'Montserrat'; - font-weight: 600; - line-height: 26px; + font-weight: 550; + line-height: 26px; /*make it airy*/ flex: 1; width: 100%; } -main { - margin: 0 auto; +input::placeholder { + font-size: 16px; /* Default size for larger screens */ +} + +input:focus, +select:focus { + outline: none; +} + +select { + border: none; + border-radius: 4px; + /* color: #e43838; */ + font-size: 20px; + font-weight: 600; + height: 60px; + background: #e7e8e6; width: 100%; - max-width: 700px; + padding: 0 20px; + cursor: pointer; + + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} +main { + margin: 0 auto; /* vertical 0, horizontal auto, equally centered*/ + width: 100%; /*responsive*/ + max-width: 700px; /*responsive*/ height: 600px; border-radius: 30px; background: #fff; padding: 20px 24px; padding-top: 0; - box-sizing: border-box; + box-sizing: border-box; /* everything fits in the box */ display: flex; flex-direction: column; + opacity: 90%; } .chat { flex: 1; display: flex; justify-content: flex-start; - overflow: scroll; + overflow: scroll; /* essential */ flex-direction: column; padding-bottom: 16px; } +#chat { + padding-bottom: 65px; /* makes bottom space so that the last message appears fully */ + overflow-y: auto; +} .bot-msg { display: flex; @@ -79,7 +116,7 @@ main { .user-msg { display: flex; - justify-content: flex-end; + justify-content: flex-end; /*moves the msg to the right side*/ margin: 16px 0 0 8px; flex-shrink: 0; } @@ -91,13 +128,15 @@ main { } .bubble { - background: #e5e9ff; + background: #e7e8e6; + font-family: "Montserrat"; font-weight: 600; font-size: 16px; line-height: 26px; padding: 16px 24px; - color: #0026ff; - max-width: 40%; + color: 232222; + max-width: 40%; /*put a media for 320*/ + word-wrap: break-word; /* Ensure long text breaks within the bubble */ } .bot-bubble { @@ -121,16 +160,8 @@ main { align-items: center; } -label { - font-size: 16px; - font-family: 'Montserrat'; - font-weight: 500; - color: #0026ff; - margin-right: 20px; -} - button { - background-color: #0026ff; + background-color: #2791e3; color: white; border: none; border-radius: 4px; @@ -138,13 +169,63 @@ button { margin-right: 4px; font-size: 16px; line-height: 26px; - font-family: 'Montserrat'; - font-weight: 500; + font-family: "Montserrat"; + font-weight: 600; cursor: pointer; transition: all 0.3s ease; } button:hover { - opacity: 0.9; + opacity: 0.8; transition: all 0.2s ease; -} \ No newline at end of file +} + +/* Media Query for Small Screens */ + +@media (max-width: 600px) { + .bubble { + max-width: 70%; /* Increase the width of bubbles on smaller screens */ + } + + .bot-msg img, + .user-msg img { + width: 50px; /* Reduce the size of user/bot images */ + height: 50px; + } + + p { + font-size: 15px; /* Smaller font size for paragraphs */ + line-height: 20px; + } + + button { + font-size: 14px; /* Smaller font size for buttons */ + padding: 12px 16px; /* Adjust padding for buttons */ + } + + main { + width: calc( + 100% - 40px + ); /* Reduce width on smaller screens for more background visibility */ + margin: 0 20px; /* Adjust margins to create space on the sides */ + } + + input::placeholder { + font-size: 14px; /* Smaller font size for smaller screens */ + } + + h1 { + font-size: 70px; /* Smaller font size for headings on smaller screens */ + line-height: 40px; /* Adjust line height for readability */ + } + + select { + font-size: 15px; /* Smaller font size for smaller screens */ + } + + body { + background-attachment: scroll; /* Allow the background to scroll normally */ + background-size: cover; /* Make sure the image covers the full screen */ + min-height: 100vh; /* Ensure the image takes the full height */ + } +} diff --git a/pull_request_template.md b/pull_request_template.md deleted file mode 100644 index 70fa177f..00000000 --- a/pull_request_template.md +++ /dev/null @@ -1,3 +0,0 @@ -## Netlify link -Add your Netlify link here. -PS. Don't forget to add it in your readme as well.