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

Movie Chatbot #296

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
25 changes: 19 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -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/

53 changes: 27 additions & 26 deletions code/index.html
Original file line number Diff line number Diff line change
@@ -1,32 +1,33 @@
<!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>
</head>
<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>Movie-chatbot</title>
</head>

<body>
<h1>Welcome to my chatbot!</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>
</form>
</div>
</main>
<body>
<h1>Welcome to the Movie-chatbot!🍿</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>
<!-- added required for input field -->
<input id="name-input" type="text" required />
<button class="send-btn" type="submit">
Send
</button>
</form>
</div>
</main>

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

</html>
</html>
258 changes: 235 additions & 23 deletions code/script.js
Original file line number Diff line number Diff line change
@@ -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 += `
<section class="user-msg">
Expand All @@ -16,8 +14,6 @@ const showMessage = (message, sender) => {
<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') {
chat.innerHTML += `
<section class="bot-msg">
Expand All @@ -28,26 +24,242 @@ const showMessage = (message, sender) => {
</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

}
//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 = `
<button class="genre-btn" type="button">
Action
</button>
<button class="genre-btn" type="button">
Drama
</button>
<button class="genre-btn" type="button">
Comedy
</button>
`
//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 = `
<button class="age-btn" type="button">
Child
</button>
<button class="age-btn" type="button">
Adult
</button>
`
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 = `
<option>Spy Kids</option>
<option>Harry Potter</option>
<option>The Incredibles</option>
`;

} else if (selectedAgeGroup === "Child" && selectedGenre === "Drama") {
options = `
<option>Swim Team</option>
<option>Charlotte's Web</option>
<option>Inside Out</option>
`;
} else if (selectedAgeGroup === "Child" && selectedGenre === "Comedy") {
options = `
<option>Freaky Friday</option>
<option>Home Alone</option>
<option>Shrek</option>
`;
} else if (selectedAgeGroup === "Adult" && selectedGenre === "Action") {
options = `
<option>Deadpool</option>
<option>Kill Bill</option>
<option>Aliens</option>
`;
} else if (selectedAgeGroup === "Adult" && selectedGenre === "Drama") {
options = `
<option>The Godfather</option>
<option>Schindler's List</option>
<option>Clockwork Orange</option>
`;
} else if (selectedAgeGroup === "Adult" && selectedGenre === "Comedy") {
options = `
<option>The Hangover</option>
<option>Bridesmaids</option>
<option>Juno</option>
`;
}
inputWrapper.innerHTML = `
<select id="movie-option" name="movie-genre">
<option value="">Select a movie here: 👇</option>
${options}
</select>
<button id="submit-movie" type="button">Submit</button>
`;

inputWrapper.style.display = 'flex';
inputWrapper.style.width = '100%';
inputWrapper.style.boxSizing = 'border-box';
inputWrapper.style.padding = '10px';
Comment on lines +183 to +186
Copy link
Contributor

Choose a reason for hiding this comment

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

This could maybe be refactored 👀

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 = `
<button class="yes-btn" type="button">
Yes!
</button>
<button class="no-btn" type="button">
No.
</button>
`;

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)
Loading