diff --git a/README.md b/README.md index 60f55e53..d3f824f7 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,26 @@ -# Project Name +Project Name: Movie 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. +The purpose of this project was to create an interactive chatbot that engages users in a conversational flow. The chatbot greets the user, allows them to pick a movie genre, select their age group, and then suggests appropriate movies based on their choices. ## 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? +Functionality & Hierarchy: +One of the primary challenges was creating functions that worked correctly while maintaining the proper structure of the website. Organizing the site hierarchically to ensure the right values and variables were filled out, and functions were called properly, was difficult. + +Variable Scope: +Another challenge was understanding where to place variables and values to ensure they were accessible at the right times. I struggled with ensuring that variables were in the correct scope so they could be used within functions. I solved this by restructuring my code and moving variables to the global scope when necessary, ensuring they were introduced before being called in functions. + +Event Listeners: +Setting up event listeners properly was tricky. Ensuring that they triggered the correct actions at the right time required careful structuring. I tested different ways of implementing event listeners, it took some time to learn how to ensure they correctly triggered the right functions. + +I used console.log extensively throughout the project to trace the flow of my code and see where issues were occurring. This helped me a lot with identifying bugs. + +If I had more time: +I would focus on cleaning up the structure of the code to make it shorter and more efficient. Right now, there is a lot of repeated code that I think could be simplified. For example, I believe there are opportunities to combine similar functions so that one function could handle multiple tasks instead of writing the same type of logic repeatedly. + +Fixing the Final Error: I encountered a TypeError: Cannot read properties of null (reading 'value') error when the user clicks "Yes" or "No" at the end of the flow. I couldn't solve this issue in the given time, but with more time, I would focus on fixing this error, possibly by ensuring that the selected movie value is properly stored and accessible when the confirmation step is triggered. ## 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://moviechatbot.netlify.app/ + diff --git a/code/index.html b/code/index.html index 316eb187..00dcf1df 100644 --- a/code/index.html +++ b/code/index.html @@ -1,32 +1,33 @@ - - - - - - Chatbot - + + + + + + Movie-chatbot + - -

Welcome to my chatbot!

-
-
-
-
- - - -
-
-
+ +

Welcome to the Movie-chatbot!🍿

+
+
+
+
+ + + + +
+
+
- - + + - + \ No newline at end of file diff --git a/code/script.js b/code/script.js index 125d6904..77fc6a97 100644 --- a/code/script.js +++ b/code/script.js @@ -1,12 +1,10 @@ -// DOM selectors (variables that point to selected DOM elements) goes here 👇 -const chat = document.getElementById('chat') -// Functions goes here 👇 +const chat = document.getElementById('chat') +const nameInput = document.getElementById('name-input') +const form = document.getElementById('name-form'); +const inputWrapper = document.getElementById('input-wrapper'); -// 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') { chat.innerHTML += `
@@ -16,8 +14,6 @@ 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') { chat.innerHTML += `
@@ -28,26 +24,242 @@ const showMessage = (message, sender) => {
` } - - // 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 + } +//the name is stored for the entire session with the value "name" +const handleNameInput = (event) => { + // Prevents the form from reloading the page when submitted + event.preventDefault(); + //This collects the input value for "name" + const name = nameInput.value; + showMessage(name, "user"); + //This clears the input field + nameInput.value = ""; + setTimeout(() => movieOptions(name), 1000) +}; + +//eventlisteners - handlenameinput is called when btn "submit" is pressed +form.addEventListener("submit", handleNameInput); + +//PART 2 +// calles the function movieOptions +const movieOptions = (name) => { + showMessage(`Hello there ${name}, what's do you want to watch today?`, 'bot') + //removing the eventlistener about name + form.removeEventListener("submit", handleNameInput); + // Hides the text-inputform and adds some more buttons, changed class to "genre-btn" and changed type to "button" to connect with event handleGenreClick + form.innerHTML = ` + + + + ` + //styles the buttons so that they are in the center + form.style.display = 'flex'; + form.style.justifyContent = 'center'; + form.style.alignItems = 'center'; + + const handleGenreClick = (event) => { + event.preventDefault(); + if (event.target.classList.contains('genre-btn')) { + const selectedGenre = event.target.textContent.trim(); + form.innerHTML = ""; + + showMessage(`${selectedGenre}`, 'user'); + // Delay the display of the message from the bot and the options + setTimeout(() => { + chat.scrollTop = chat.scrollHeight + showMessage(`You chose ${selectedGenre}. Excellent choice! Before we start selecting movies, are you a grownup or a child?`, 'bot'); + ageOption(selectedGenre); + }, 1000); + } + } + + form.addEventListener("click", handleGenreClick); +}; + +//PARTT 3: AGE +let selectedAgeGroup = ""; + +const ageOption = (genre) => { + form.innerHTML = ` + + + ` + form.style.display = 'flex'; + form.style.justifyContent = 'center'; + form.style.alignItems = 'center'; + form.style.gap = '30px'; + + const handleAgeClick = (event) => { + event.preventDefault(); + if (event.target.classList.contains('age-btn')) { + const selectedAgeGroup = event.target.textContent.trim(); + form.innerHTML = ""; + showMessage(`${selectedAgeGroup}`, 'user'); + // Delay the display of the message from the bot and the options + setTimeout(() => { + chat.scrollTop = chat.scrollHeight + showMessage(`Alrighty then! Here are some ${selectedAgeGroup} friendly options for you:`, 'bot'); + SelectMovieOption(selectedAgeGroup, genre); + }, 1000); + + } + chat.scrollTop = chat.scrollHeight + + } + form.addEventListener("click", handleAgeClick); + +} + +// PART 4 +// Function to display movie options based on age and genre option + +const SelectMovieOption = (selectedAgeGroup, selectedGenre) => { + + let options = ""; + + if (selectedAgeGroup === "Child" && selectedGenre === "Action") { + options = ` + + + + `; + + } else if (selectedAgeGroup === "Child" && selectedGenre === "Drama") { + options = ` + + + + `; + } else if (selectedAgeGroup === "Child" && selectedGenre === "Comedy") { + options = ` + + + + `; + } else if (selectedAgeGroup === "Adult" && selectedGenre === "Action") { + options = ` + + + + `; + } else if (selectedAgeGroup === "Adult" && selectedGenre === "Drama") { + options = ` + + + + `; + } else if (selectedAgeGroup === "Adult" && selectedGenre === "Comedy") { + options = ` + + + + `; + } + inputWrapper.innerHTML = ` + + + `; + + inputWrapper.style.display = 'flex'; + inputWrapper.style.width = '100%'; + inputWrapper.style.boxSizing = 'border-box'; + inputWrapper.style.padding = '10px'; + document.getElementById('movie-option').style.width = '400px'; + document.getElementById('movie-option').style.fontSize = '16px'; + + inputWrapper.addEventListener('click', handleSelectMovieOption); +} + +const handleSelectMovieOption = (event) => { + //targets the specific movie and not all three options that are stored in the value "options" + const selectedMovie = document.getElementById('movie-option').value; + + if (selectedMovie) { + event.preventDefault(); + inputWrapper.innerHTML = ""; + + showMessage(`${selectedMovie}`, 'user'); + // Delay the display of the message from the bot + setTimeout(() => { + chat.scrollTop = chat.scrollHeight; + showMessage(`You selected ${selectedMovie}. Excellent choice! That will be: $4. Would you like to rent this movie?`, 'bot'); + confirmation(selectedMovie) + }, 1000); + } +} + +// Handle confirmation click + +const handleConfirmationClick = (event, selectedMovie) => { + event.preventDefault(); + const button = event.target; + + if (button.classList.contains("yes-btn")) { + const selectedConfirmation = button.textContent.trim(); + inputWrapper.innerHTML = ""; + showMessage(`${selectedConfirmation}`, "user"); + + setTimeout(() => { + chat.scrollTop = chat.scrollHeight; + showMessage( + `Grab your popcorn, ${selectedMovie} is on the way!🍿 Thank you for using the movie chatbot.`, + "bot" + ); + }, 1000); + } else { + const selectedConfirmation = button.textContent.trim(); + inputWrapper.innerHTML = ""; + + setTimeout(() => { + chat.scrollTop = chat.scrollHeight; + showMessage(`${selectedConfirmation}`, "user"); + showMessage( + `Got it! Your order has been canceled. Have a great day!`, + "bot" + ); + }, 1000); + } +}; + +const confirmation = (selectedMovie) => { + inputWrapper.innerHTML = ` + + + `; + + inputWrapper.style.display = "flex"; + inputWrapper.style.justifyContent = "center"; + inputWrapper.style.alignItems = "center"; + inputWrapper.style.gap = "30px"; + + inputWrapper.addEventListener("click", (event) => + handleConfirmationClick(event, selectedMovie) + ); +}; -// 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) +setTimeout(greetUser, 1000) diff --git a/code/style.css b/code/style.css index a275402f..6a11b476 100644 --- a/code/style.css +++ b/code/style.css @@ -6,15 +6,18 @@ body { margin: 0; padding: 0; font-family: 'Montserrat', sans-serif; - background: #0026ff; + background: linear-gradient(to right, #04030b, #20040b); + + } h1 { font-weight: bold; - font-size: 28px; + font-size: 35px; line-height: 34px; - color: #fff; + color: #be131d; text-align: center; + padding: 10px; } h2 { @@ -38,7 +41,7 @@ input { border: none; border-radius: 4px 0 0 4px; background: #e5e9ff; - color: #0026ff; + color: black; padding: 16px; font-size: 16px; font-family: 'Montserrat'; @@ -50,7 +53,7 @@ input { main { margin: 0 auto; - width: 100%; + width: 90%; max-width: 700px; height: 600px; border-radius: 30px; @@ -91,12 +94,12 @@ main { } .bubble { - background: #e5e9ff; + background: #ffefea; font-weight: 600; font-size: 16px; line-height: 26px; padding: 16px 24px; - color: #0026ff; + color: #be131d; max-width: 40%; } @@ -125,12 +128,12 @@ label { font-size: 16px; font-family: 'Montserrat'; font-weight: 500; - color: #0026ff; + color: #720f0f; margin-right: 20px; } button { - background-color: #0026ff; + background-color: #720f0f; color: white; border: none; border-radius: 4px; @@ -147,4 +150,63 @@ button { button:hover { opacity: 0.9; transition: all 0.2s ease; +} + +/* Responsiveness */ +@media (max-width: 480px) { + h1 { + font-size: 25px; + } + + main { + padding: 10px; + height: 400px; + + } + + .bubble { + max-width: 80%; + /* Allow even more space for chat bubbles */ + } + + input { + padding: 10px; + font-size: 12px; + } + + button { + padding: 10px 16px; + font-size: 12px; + } + + .bot-msg img, + .user-msg img { + width: 40px; + height: 40px; + } + + label { + font-size: 14px; + margin-right: 10px; + } +} + +@media (min-width: 480px) and (max-width: 768px) { + h1 { + font-size: 30px; + } + + .bubble { + max-width: 60%; + } + + input { + padding: 12px; + font-size: 14px; + } + + button { + padding: 12px 18px; + font-size: 14px; + } } \ No newline at end of file