diff --git a/README.md b/README.md index 60f55e53..138ac2ac 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,17 @@ -# Project Name +# Joyce's ActivityBot -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. +This project uses JavaScript to create an interactive chatbot that prompts the user with a series of questions. Assuming the user is a child (or parent/guardian of a child) and the child is around 5 years old, the chatbot uses the information given by the user to help suggest an activity before signing off. ## 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? +My approach to the problem was to first make sure I understood how all the parts of the code were interconnected. Once I could get the initial code to start and call the first function, I started to get a work flow going. However, I felt like my code was a bit convoluted and I was getting confused quite easily. One of the first challenges was to figure out how to get information from the user, and then pass that information as an argument into the next function call. With some help from some of the course videos and ChatGPT, I was able to work out some code that I think was as concise as I could figure out for this stage of my learning. + +I had an idea that I wanted to ask the user to choose their favorite color from a series of buttons, and then use the user's choice to trigger a particular color scheme for the buttons. This led to a small problem because the buttons would only change color for the next function, but then they would revert to the same color. As I was working out a solution for this, it gave me the idea to change the entire color scheme. This ended up being another challenge, but again I used a healthy dose of course video content and ChatGPT to find a way to make the color scheme idea work. I specified the elements I wanted to change for each color scheme in CSS and referenced that in a new function that would set a particular color scheme based on the user's choice. + +The other challenge was to create all the activity options based on user input, collect that data into variables in the global scope so that they could be referenced in a function that would work through conditional statements and weigh all the variables, eventually pointing to a couple of activity options for the user to choose from. In the planning stages, I brainstormed on paper all the potential variables before settling on mood, weather, and amount of time as the variables I would use for my chatbot. Then I sketched a tree of possibilities for different moods leading to different combinations for indoor/outdoor and short/long activities. + +If I had more time, I would create more activity choices, and maybe use a loop to continuously prompt the user if they were not satisfied with the initial options. The chatbot could offer a few more choices, and if the user rejected those, more options could come up before finally the chatbot would exhaust all options. ## 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://joyceschatbot.netlify.app/ \ No newline at end of file diff --git a/code/assets/activity-bot.jpg b/code/assets/activity-bot.jpg new file mode 100644 index 00000000..4784c976 Binary files /dev/null and b/code/assets/activity-bot.jpg differ diff --git a/code/assets/activitybot-favicon.png b/code/assets/activitybot-favicon.png new file mode 100644 index 00000000..06c99884 Binary files /dev/null and b/code/assets/activitybot-favicon.png differ diff --git a/code/assets/botbubble.png b/code/assets/botbubble.png new file mode 100644 index 00000000..8558bdcd Binary files /dev/null and b/code/assets/botbubble.png differ diff --git a/code/assets/pizzabot.jpg b/code/assets/pizzabot.jpg new file mode 100644 index 00000000..c3e1e75d Binary files /dev/null and b/code/assets/pizzabot.jpg differ diff --git a/code/assets/userbubble.png b/code/assets/userbubble.png new file mode 100644 index 00000000..42fb1326 Binary files /dev/null and b/code/assets/userbubble.png differ diff --git a/code/index.html b/code/index.html index 316eb187..36cba16a 100644 --- a/code/index.html +++ b/code/index.html @@ -1,32 +1,47 @@ - - - - - - Chatbot - + + + + + + + ActivityBot + - -

Welcome to my chatbot!

+ +
+ + +
+
+

ActivityBot

+

Find Your Next Playtime Activity!

+
+
+ A robot standing in a room full of toys +
+
+ +
- - -
- - +
+ + - + \ No newline at end of file diff --git a/code/script.js b/code/script.js index 125d6904..6b1d481e 100644 --- a/code/script.js +++ b/code/script.js @@ -1,27 +1,26 @@ -// DOM selectors (variables that point to selected DOM elements) goes here ๐Ÿ‘‡ +// DOM selectors const chat = document.getElementById('chat') +const nameInput = document.getElementById('name-input') +const sendButton = document.getElementById('send-button') +const inputWrapper = document.getElementById('input-wrapper') -// Functions goes here ๐Ÿ‘‡ +let userName = "" // 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 += `

${message}

- User + 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 += `
- Bot + Bot

${message}

@@ -29,25 +28,284 @@ 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 } // 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 + showMessage("Hey there, little buddy! I am ActivityBot ๐Ÿค– I am here to help you find a fun activity. First, let's get to know each other. What's your name?", 'bot') } -// Eventlisteners goes here ๐Ÿ‘‡ +const clearButtons = () => { + inputWrapper.innerHTML = '' +} + +// Variables to be collected and used to determine activities +let currentMood = "" +let currentWeather = "" +let currentTime = "" + +//8. Sign off message +const sayGoodbye = () => { + showMessage(`Go on then and have a great time! ๐Ÿคฉ Bye for now!`, 'bot') + clearButtons() +} + +//7. Suggest activity based on user's answers to questions (variables for currentMood, currentWeather, and currentTime) +const getActivity = (mood, weather, time) => { + if (mood === "calm" && weather === "rainy" && time === "short") { + showMessage(`How about coloring or doing a simple puzzle?`, 'bot') + inputWrapper.innerHTML = ` + + + ` + document.getElementById('coloring').addEventListener("click", () => { + showMessage(`๐ŸŽจ Coloring sounds perfect!`, 'user') + setTimeout(sayGoodbye, 1000) + }) + document.getElementById('puzzle').addEventListener("click", () => { + showMessage(`๐Ÿงฉ Doing a puzzle would be fun!`, 'user') + setTimeout(sayGoodbye, 1000) + }) + } else if (mood === "calm" && weather === "rainy" && time === "long") { + showMessage(`How about painting or building something with LEGO?`, 'bot') + inputWrapper.innerHTML = ` + + + ` + document.getElementById('painting').addEventListener("click", () => { + showMessage(`๐ŸŽจ Painting sounds perfect!`, 'user') + setTimeout(sayGoodbye, 1000) + }) + document.getElementById('lego').addEventListener("click", () => { + showMessage(`๐Ÿงฉ Building with LEGO would be fun!`, 'user') + setTimeout(sayGoodbye, 1000) + }) + } else if (mood === "calm" && weather === "sunny" && time === "short") { + showMessage(`How about cloud watching or collecting leaves and flowers?`, 'bot') + inputWrapper.innerHTML = ` + + + ` + document.getElementById('cloud').addEventListener("click", () => { + showMessage(`โ˜๏ธ Cloud watching sounds perfect!`, 'user') + setTimeout(sayGoodbye, 1000) + }) + document.getElementById('collecting').addEventListener("click", () => { + showMessage(`โ˜˜๏ธ Collecting leaves and flowers would be fun!`, 'user') + setTimeout(sayGoodbye, 1000) + }) + } else if (mood === "calm" && weather === "sunny" && time === "long") { + showMessage(`How about taking a long nature walk or having a relaxing picnic outside?`, 'bot') + inputWrapper.innerHTML = ` + + + ` + document.getElementById('nature').addEventListener("click", () => { + showMessage(`๐ŸŒณ A nature walk sounds perfect!`, 'user') + setTimeout(sayGoodbye, 1000) + }) + document.getElementById('picnic').addEventListener("click", () => { + showMessage(`๐Ÿงบ A picnic outside would be fun!`, 'user') + setTimeout(sayGoodbye, 1000) + }) + } else if (mood === "active" && weather === "rainy" && time === "short") { + showMessage(`How about a mini dance party or a game of balloon volleyball?`, 'bot') + inputWrapper.innerHTML = ` + + + ` + document.getElementById('dance').addEventListener("click", () => { + showMessage(`๐Ÿชฉ A dance party sounds perfect!`, 'user') + setTimeout(sayGoodbye, 1000) + }) + document.getElementById('balloon').addEventListener("click", () => { + showMessage(`๐ŸŽˆ Balloon volleyball would be fun!`, 'user') + setTimeout(sayGoodbye, 1000) + }) + } else if (mood === "active" && weather === "rainy" && time === "long") { + showMessage(`How about building a fort or setting up an obstacle course?`, 'bot') + inputWrapper.innerHTML = ` + + + ` + document.getElementById('fort').addEventListener("click", () => { + showMessage(`๐Ÿฐ Building a fort sounds perfect!`, 'user') + setTimeout(sayGoodbye, 1000) + }) + document.getElementById('obstacle').addEventListener("click", () => { + showMessage(`๐Ÿชœ An obstacle course would be fun!`, 'user') + setTimeout(sayGoodbye, 1000) + }) + } else if (mood === "active" && weather === "sunny" && time === "short") { + showMessage(`How about outdoor jump rope or going for a bike ride?`, 'bot') + inputWrapper.innerHTML = ` + + + ` + document.getElementById('jump').addEventListener("click", () => { + showMessage(`๐Ÿชข Jump rope sounds perfect!`, 'user') + setTimeout(sayGoodbye, 1000) + }) + document.getElementById('bike').addEventListener("click", () => { + showMessage(`๐Ÿšฒ A bike ride would be fun!`, 'user') + setTimeout(sayGoodbye, 1000) + }) + } else if (mood === "active" && weather === "sunny" && time === "long") { + showMessage(`How about a trip to the playground or playing a ball game like soccer or basketball?`, 'bot') + inputWrapper.innerHTML = ` + + + ` + document.getElementById('playground').addEventListener("click", () => { + showMessage(`๐Ÿ› A trip to the playground sounds perfect!`, 'user') + setTimeout(sayGoodbye, 1000) + }) + document.getElementById('ball').addEventListener("click", () => { + showMessage(`โšฝ A ball game would be fun!`, 'user') + setTimeout(sayGoodbye, 1000) + }) + } else { + showMessage(`I am confused. Please refresh the page.`, 'bot') + clearButtons() + } +} + +//6. Comment on user's answer for weather and ask how much time they have for an activity +const getTime = () => { + showMessage(`Good to know. How much time do you have to spare?`, 'bot') + inputWrapper.innerHTML = ` + + + ` + document.getElementById('short').addEventListener("click", () => { + currentTime = "short" + showMessage(`Not much, less than 30 minutes.`, 'user') + setTimeout(() => getActivity(currentMood, currentWeather, currentTime), 1000) + }) + document.getElementById('long').addEventListener("click", () => { + currentTime = "long" + showMessage(`Quite a lot, at least 30 minutes.`, 'user') + setTimeout(() => getActivity(currentMood, currentWeather, currentTime), 1000) + }) +} + +//5. Comment on user's mood and ask about the weather +const getWeather = () => { + showMessage(`OK, we will think of something that best suits your mood. What is the weather like?`, 'bot') + inputWrapper.innerHTML = ` + + + ` + document.getElementById('sunny').addEventListener("click", () => { + currentWeather = "sunny" + showMessage(`โ˜€๏ธ Perfect weather to be outdoors!`, 'user') + setTimeout(getTime, 1000) + }) + document.getElementById('rainy').addEventListener("click", () => { + currentWeather = "rainy" + showMessage(`โ›ˆ๏ธ Not so nice outside, I'd rather be indoors.`, 'user') + setTimeout(getTime, 1000) + }) +} + +//4. Comment on user's favorite animal and ask about mood +const getMood = (userAnimal) => { + showMessage(`${userAnimal}`, 'user') + setTimeout(() => { + showMessage(`Wow, we really have a lot in common! ${userAnimal} is also my favorite animal. Now, what kind of activity are you in the mood for today?`, 'bot') + inputWrapper.innerHTML = ` + + + ` + document.getElementById('calm').addEventListener("click", () => { + currentMood = "calm" + showMessage(`๐Ÿง˜๐Ÿป I'm in the mood for something calm.`, 'user') + setTimeout(getWeather, 1000) + }) + document.getElementById('active').addEventListener("click", () => { + currentMood = "active" + showMessage(`โ›ฐ๏ธ I have a lot of energy to burn off!`, 'user') + setTimeout(getWeather, 1000) + }) + }, 1000) +} + +//3. Find out user's favorite animal using buttons +const getAnimal = (userColor, colorValue) => { + showMessage(`${userColor}`, 'user') + setTimeout(() => { + showMessage(`How cool! ${userColor} just so happens to be my favorite color too! What is your favorite animal?`, 'bot') + inputWrapper.innerHTML = ` + + + + + + + ` + document.getElementById('cat').addEventListener("click", () => getMood('Cat')) + document.getElementById('dog').addEventListener("click", () => getMood('Dog')) + document.getElementById('bear').addEventListener("click", () => getMood('Bear')) + document.getElementById('monkey').addEventListener("click", () => getMood('Monkey')) + document.getElementById('pig').addEventListener("click", () => getMood('Pig')) + document.getElementById('lion').addEventListener("click", () => getMood('Lion')) + }, 1000) +} + +// Change color scheme +const changeColorScheme = (scheme) => { + document.body.className = scheme +} + +//2. Find out user's favorite color and change color scheme based on selection. +const getColor = () => { + showMessage(`Nice to meet you, ${userName}! What is your favorite color?`, 'bot') + inputWrapper.innerHTML = ` + + + + + + + ` + document.getElementById('red').addEventListener("click", () => { + changeColorScheme('red-scheme') + getAnimal('Red') + }) + document.getElementById('blue').addEventListener("click", () => { + changeColorScheme('blue-scheme') + getAnimal('Blue') + }) + document.getElementById('yellow').addEventListener("click", () => { + changeColorScheme('yellow-scheme') + getAnimal('Yellow') + }) + document.getElementById('purple').addEventListener("click", () => { + changeColorScheme('purple-scheme') + getAnimal('Purple') + }) + document.getElementById('green').addEventListener("click", () => { + changeColorScheme('green-scheme') + getAnimal('Green') + }) + document.getElementById('pink').addEventListener("click", () => { + changeColorScheme('pink-scheme') + getAnimal('Pink') + }) +} + +//1. Get user's name and trigger color function +const getUserName = (event) => { + event.preventDefault() // Keeps chat history going + userName = nameInput.value + showMessage(`${userName}`, 'user') + nameInput.value = '' // Clear the input field + setTimeout(getColor, 1000) +} + +// Event listener for the form submission +sendButton.addEventListener("click", getUserName) -// 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) +// First function to greet the user +setTimeout(greetUser, 1000) \ No newline at end of file diff --git a/code/style.css b/code/style.css index a275402f..99c4e662 100644 --- a/code/style.css +++ b/code/style.css @@ -6,20 +6,56 @@ body { margin: 0; padding: 0; font-family: 'Montserrat', sans-serif; - background: #0026ff; + background: linear-gradient(to top right, pink, blue); + height: 100%; + overflow: hidden; +} + +.container { + margin: 3%; + display: flex; + flex-direction: column; + justify-content: space-between; + height: 97vh; +} + +.header-image-container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + margin: 5px; +} + +header h1 { + font-size: 3vh; + text-align: center; + margin: 5px; +} + +.image { + display: flex; + justify-content: center; + height: 100%; +} + +img { + height: auto; + max-width: 30%; + border-radius: 10px; + object-fit: cover; } h1 { font-weight: bold; - font-size: 28px; - line-height: 34px; + font-size: 8.8vh; color: #fff; text-align: center; } h2 { font-weight: bold; - font-size: 24px; + font-size: 20px; line-height: 34px; color: #fff; text-align: center; @@ -27,9 +63,9 @@ h2 { } p { - font-size: 18px; + font-size: 14px; font-weight: 600; - line-height: 28px; + line-height: 20px; margin: 0; } @@ -40,19 +76,19 @@ input { background: #e5e9ff; color: #0026ff; padding: 16px; - font-size: 16px; + font-size: 14px; font-family: 'Montserrat'; font-weight: 600; line-height: 26px; flex: 1; - width: 100%; + width: calc(100% - 40px); } main { margin: 0 auto; width: 100%; max-width: 700px; - height: 600px; + height: 77vh; border-radius: 30px; background: #fff; padding: 20px 24px; @@ -93,16 +129,17 @@ main { .bubble { background: #e5e9ff; font-weight: 600; - font-size: 16px; + font-size: 14px; line-height: 26px; padding: 16px 24px; color: #0026ff; - max-width: 40%; + max-width: 60%; } .bot-bubble { border-radius: 0px 26px 26px 26px; margin-left: 8px; + background-color: #cce5ff; } .user-bubble { @@ -111,8 +148,12 @@ main { } .input-wrapper { + flex-shrink: 0; display: flex; justify-content: center; + flex-wrap: wrap; + width: 100%; + gap: 5px; } .input-wrapper form { @@ -121,22 +162,24 @@ main { align-items: center; } -label { +.input-wrapper button { + flex: 1 1 45%; +} + +.name-input { font-size: 16px; - font-family: 'Montserrat'; - font-weight: 500; - color: #0026ff; - margin-right: 20px; + flex: 0 0 60%; } button { + width: auto; background-color: #0026ff; color: white; border: none; border-radius: 4px; padding: 16px 20px; margin-right: 4px; - font-size: 16px; + font-size: 12px; line-height: 26px; font-family: 'Montserrat'; font-weight: 500; @@ -147,4 +190,172 @@ button { button:hover { opacity: 0.9; transition: all 0.2s ease; +} + +/* =========================== + Color Schemes + =========================== */ + +/* Red color scheme */ +body.red-scheme { + background: linear-gradient(to bottom, red, white); + color: white; +} + +body.red-scheme button { + background-color: red; + color: white; +} + +body.red-scheme .bubble { + background: #ffe6e6; + color: red; +} + +body.red-scheme .bot-bubble { + background: #ffb3b3; +} + +/* Blue color scheme */ +body.blue-scheme { + background: linear-gradient(to bottom, blue, white); + color: white; +} + +body.blue-scheme button { + background-color: darkblue; + color: white; +} + +body.blue-scheme .bubble { + background: #cce5ff; + color: darkblue; +} + +body.blue-scheme .bot-bubble { + background: #99ccff; +} + +/* Yellow color scheme */ +body.yellow-scheme { + background: linear-gradient(to bottom, yellow, white); + color: black; +} + +body.yellow-scheme button { + background-color: gold; + color: black; +} + +body.yellow-scheme .bubble { + background: #fffacd; + color: goldenrod; +} + +body.yellow-scheme h1 { + color: black; +} + +body.yellow-scheme h2 { + color: darkgoldenrod; +} + +body.yellow-scheme .bot-bubble { + background: #ffff99; +} + +/* Purple color scheme */ +body.purple-scheme { + background: linear-gradient(to bottom, purple, white); + color: white; +} + +body.purple-scheme button { + background-color: indigo; + color: white; +} + +body.purple-scheme .bubble { + background: #e6e6fa; + color: indigo; +} + +body.purple-scheme .bot-bubble { + background: #d1b3ff; +} + +/* Green color scheme */ +body.green-scheme { + background: linear-gradient(to bottom, green, white); + color: white; +} + +body.green-scheme button { + background-color: darkgreen; + color: white; +} + +body.green-scheme .bubble { + background: #ccffcc; + color: darkgreen; +} + +body.green-scheme .bot-bubble { + background: #99ff99; +} + +/* Pink color scheme */ +body.pink-scheme { + background: linear-gradient(to bottom, deeppink, white); + color: white; +} + +body.pink-scheme button { + background-color: deeppink; + color: white; +} + +body.pink-scheme .bubble { + background: #ffccff; + color: deeppink; +} + +body.pink-scheme .bot-bubble { + background: #ffb3d9; +} + +/* For mobile */ +@media (max-width: 700px) { + header h2 { + display: none; + } +} + +/* For tablet and larger screens */ +@media (min-width: 701px) { + .container { + flex-direction: row; + min-height: 100%; + } + + .header-image-container { + max-height: 95vh; + } + + p { + line-height: 2vw; + } + + header h1 { + font-size: 5vw; + } + + img { + max-width: 90%; + } + + main { + min-height: 90%; + height: 95vh; + } } \ No newline at end of file diff --git a/pull_request_template.md b/pull_request_template.md index 70fa177f..f65265fa 100644 --- a/pull_request_template.md +++ b/pull_request_template.md @@ -1,3 +1,3 @@ ## Netlify link -Add your Netlify link here. -PS. Don't forget to add it in your readme as well. + +https://joyceschatbot.netlify.app/ \ No newline at end of file