From 1375dcfcf56ec8178792be957250922d9c6b9f96 Mon Sep 17 00:00:00 2001 From: Shaswat Mishra Date: Wed, 6 Aug 2025 08:14:05 +0530 Subject: [PATCH 1/2] ChatBot Implemeneted --- src/components/FAQbot/Chatbot.jsx | 427 ++++++++++++++++++++++++++++++ src/pages/Body.jsx | 2 + 2 files changed, 429 insertions(+) create mode 100644 src/components/FAQbot/Chatbot.jsx diff --git a/src/components/FAQbot/Chatbot.jsx b/src/components/FAQbot/Chatbot.jsx new file mode 100644 index 0000000..d8692bf --- /dev/null +++ b/src/components/FAQbot/Chatbot.jsx @@ -0,0 +1,427 @@ +import { useState, useEffect, useRef } from "react"; + +const QUESTIONS = { + "What is DevTinder?": { + text: + "DevTinder is a modern web app that connects developers based on their skills, interests, and project goals — like 'Tinder for Developers'.", + followUps: [ + { + question: "Is DevTinder free?", + text: "Yes, DevTinder is 100% free for all developers.", + }, + { + question: "Who is DevTinder for?", + text: + "Whether you're a student, freelancer, or pro — if you're building something, DevTinder is for you.", + }, + ], + }, + "How does team matching work?": { + text: + "You can find and join dev teams for hackathons and projects. It's currently in development (75%).", + followUps: [ + { + question: "When will it be available?", + text: + "Team Matching is in development and should roll out in the next major update.", + }, + ], + }, + "What is the Blogs section about?": { + text: + "In the Blogs section, users will be able to read & share technical blogs and tutorials — currently 50% done.", + followUps: [ + { + question: "Can I contribute a blog?", + text: "Yes, contribution will be open when the feature goes live.", + }, + ], + }, + "What’s in the Full Profile Preview?": { + text: + "It allows users to view developer profiles with detailed info like skills, GitHub links, and project history. Planning phase is at 50%.", + followUps: [ + { + question: "Will profiles be public?", + text: + "Only basic details will be public; full preview will require permission.", + }, + ], + }, + "Is there real-time code collaboration?": { + text: + "Real-time collaborative coding is being designed. It will let developers code together instantly — currently in design (45%).", + followUps: [ + { + question: "Will it support multiple languages?", + text: + "Yes, the plan includes support for popular languages and live preview.", + }, + ], + }, + "What’s Project Ideas Hub?": { + text: + "It’s a feature to explore and share innovative project ideas with others — planning phase (25%).", + followUps: [ + { + question: "Can I submit ideas anonymously?", + text: "Yes, anonymous submission will be supported.", + }, + ], + }, + "How does Skill Assessment work?": { + text: + "We're researching AI-powered skill testing and recommendations to help you find your best matches — early research phase.", + followUps: [ + { + question: "Will there be quizzes or coding rounds?", + text: "Yes, assessments may include coding tasks, quizzes, and GitHub metrics.", + }, + ], + }, +}; + +const questionOptions = Object.keys(QUESTIONS); + +export default function ChatBot() { + const [isOpen, setIsOpen] = useState(false); + const [chat, setChat] = useState([]); + const [isTyping, setIsTyping] = useState(false); + const [isLoadingOptions, setIsLoadingOptions] = useState(false); + const [isFirstLoad, setIsFirstLoad] = useState(true); // New state to track initial load + const chatRef = useRef(null); + + const scrollToBottom = () => { + chatRef.current?.scrollIntoView({ behavior: "smooth" }); + }; + + useEffect(() => { + scrollToBottom(); + }, [chat, isOpen]); + + // Handler for when the user clicks a main question button + const handleQuestionClick = (q) => { + const selected = QUESTIONS[q]; + if (!selected) return; + + // Clear loader when a question is clicked + setIsLoadingOptions(false); + + // Add the user's question to the chat + setChat((prev) => [...prev, { from: "user", text: q }]); + + // Show the typing indicator + setIsTyping(true); + + // After a delay, add the bot's main answer + setTimeout(() => { + setChat((prev) => [...prev, { from: "bot", text: selected.text }]); + setIsTyping(false); + + // After another delay, add the follow-up buttons AND the Main Menu button + setTimeout(() => { + setChat((prev) => [ + ...prev, + { from: "bot", followUps: selected.followUps, parentQuestion: q, showMainMenuButton: true }, + ]); + }, 1000); + }, 1000); + }; + + // Handler for when the user clicks a follow-up question + const handleFollowUpClick = (parentQuestion, followUp) => { + // Add the user's follow-up question to the chat + setChat((prev) => [...prev, { from: "user", text: followUp.question }]); + + // Show the typing indicator + setIsTyping(true); + + // After a delay, add the bot's response + setTimeout(() => { + setIsTyping(false); + setChat((prev) => [...prev, { from: "bot", text: followUp.text }]); + + // Always add the "You can navigate to the main menu" prompt and button after any follow-up answer + setTimeout(() => { + setChat((prev) => [ + ...prev, + { from: "bot", text: "You can navigate to the main menu for more options.", isMainMenuPrompt: true }, + ]); + }, 500); // Small delay for the prompt message + }, 1000); // Delay for bot's answer + }; + + // Renders the initial set of questions with conditional delay + const renderInitialQuestions = () => { + // Clear loader whenever initial questions are rendered + setIsLoadingOptions(false); + + // Step 1: Display the welcome message immediately if it's the first load + if (isFirstLoad) { + setChat([]); // Clear chat only on first load + setChat([ + { + from: "bot", + text: "✨ Welcome to DevTinder! I'm Nova, your assistant. I'm here to help you get started. What would you like to know? ❤️", + isWelcome: true, + }, + ]); + + // Step 2: After a short delay, show the loader + setTimeout(() => { + setIsLoadingOptions(true); + }, 500); + + // Step 3: After 3 seconds of loading, hide the loader and start showing questions one by one + setTimeout(() => { + setIsLoadingOptions(false); + // Add a new message to chat that will render the initial questions with staggered effect + setChat((prevChat) => [ + ...prevChat, + { from: "bot", initialOptions: questionOptions, isStaggered: true } + ]); + setIsFirstLoad(false); // Mark first load as complete + }, 3500); // 500ms initial delay + 3000ms loader duration + } else { + // If it's not the first load (i.e., coming from Main Menu button), append questions instantly + setChat((prevChat) => [ + ...prevChat, + { from: "bot", initialOptions: questionOptions, isStaggered: false } // No staggered effect for subsequent loads + ]); + } + }; + + // Function to reset all states when closing the chatbot + const resetChatbot = () => { + setIsOpen(false); + setChat([]); + setIsTyping(false); + setIsLoadingOptions(false); + setIsFirstLoad(true); // Reset to true so next open is a fresh start + }; + + return ( +
+ {/* Chatbot toggle button with neon effect and robot icon */} + {!isOpen && ( + + )} + + {/* Chatbot window */} + {isOpen && ( +
+ {/* Header */} +
+ Nova - DevTinder Assistant + +
+ + {/* Chat messages container */} +
+ {chat.map((msg, idx) => ( +
+ {/* Regular text messages (user, bot answer, welcome, main menu prompt) */} + {!msg.followUps && !msg.initialOptions && !msg.isMainMenuPrompt && ( +
+ {msg.text} +
+ )} + + {/* Conditional rendering for follow-up questions and Main Menu button */} + {msg.followUps && ( +
+ {msg.followUps.map((fup, i) => ( + + ))} + {/* Main Menu button always appears with follow-up options */} + +
+ )} + {/* Conditionally render the "Main Menu" prompt and button */} + {msg.isMainMenuPrompt && ( +
+
+ {msg.text} {/* Use msg.text for the prompt message */} +
+ +
+ )} + + {/* Conditional rendering for initial questions / main menu questions */} + {msg.initialOptions && ( +
+ {msg.initialOptions.map((opt, index) => ( + + ))} +
+ )} +
+ ))} + + {/* Conditional loader */} + {isLoadingOptions && ( +
+
+ Looking for questions... +
+ )} + + {isTyping && ( +
Nova is typing...
+ )} + +
+
+
+ )} + +
+ ); +} diff --git a/src/pages/Body.jsx b/src/pages/Body.jsx index 8ccf5c8..f4ef675 100644 --- a/src/pages/Body.jsx +++ b/src/pages/Body.jsx @@ -7,6 +7,7 @@ import { setUser } from "../utils/userSlicer.js"; import { useNavigate } from "react-router"; import { useEffect, useCallback } from "react"; import { createApiUrl, API_ENDPOINTS } from "../utils/apiConfig"; +import Chatbot from "../components/FAQbot/Chatbot.jsx"; const Body = () => { @@ -52,6 +53,7 @@ const Body = () => {
+
) From 022765eeca2b8c8016c22602f2c54f286adedbb3 Mon Sep 17 00:00:00 2001 From: Shaswat Mishra Date: Sat, 9 Aug 2025 10:40:46 +0530 Subject: [PATCH 2/2] ChatBOT added --- src/components/FAQbot/Chatbot.jsx | 138 +++++++----------------------- 1 file changed, 29 insertions(+), 109 deletions(-) diff --git a/src/components/FAQbot/Chatbot.jsx b/src/components/FAQbot/Chatbot.jsx index d8692bf..647d949 100644 --- a/src/components/FAQbot/Chatbot.jsx +++ b/src/components/FAQbot/Chatbot.jsx @@ -88,7 +88,7 @@ export default function ChatBot() { const [chat, setChat] = useState([]); const [isTyping, setIsTyping] = useState(false); const [isLoadingOptions, setIsLoadingOptions] = useState(false); - const [isFirstLoad, setIsFirstLoad] = useState(true); // New state to track initial load + const [isFirstLoad, setIsFirstLoad] = useState(true); const chatRef = useRef(null); const scrollToBottom = () => { @@ -99,133 +99,87 @@ export default function ChatBot() { scrollToBottom(); }, [chat, isOpen]); - // Handler for when the user clicks a main question button const handleQuestionClick = (q) => { const selected = QUESTIONS[q]; if (!selected) return; - // Clear loader when a question is clicked setIsLoadingOptions(false); - - // Add the user's question to the chat setChat((prev) => [...prev, { from: "user", text: q }]); - - // Show the typing indicator setIsTyping(true); - - // After a delay, add the bot's main answer setTimeout(() => { setChat((prev) => [...prev, { from: "bot", text: selected.text }]); setIsTyping(false); - // After another delay, add the follow-up buttons AND the Main Menu button setTimeout(() => { setChat((prev) => [ ...prev, - { from: "bot", followUps: selected.followUps, parentQuestion: q, showMainMenuButton: true }, - ]); - }, 1000); - }, 1000); + { from: "bot", followUps: selected.followUps, parentQuestion: q, showMainMenuButton: true },]); + }, 1100); + }, 1100); }; - // Handler for when the user clicks a follow-up question const handleFollowUpClick = (parentQuestion, followUp) => { - // Add the user's follow-up question to the chat setChat((prev) => [...prev, { from: "user", text: followUp.question }]); - // Show the typing indicator setIsTyping(true); - - // After a delay, add the bot's response setTimeout(() => { setIsTyping(false); setChat((prev) => [...prev, { from: "bot", text: followUp.text }]); - - // Always add the "You can navigate to the main menu" prompt and button after any follow-up answer setTimeout(() => { setChat((prev) => [ ...prev, { from: "bot", text: "You can navigate to the main menu for more options.", isMainMenuPrompt: true }, ]); - }, 500); // Small delay for the prompt message - }, 1000); // Delay for bot's answer + }, 500); + }, 1000); }; - // Renders the initial set of questions with conditional delay const renderInitialQuestions = () => { - // Clear loader whenever initial questions are rendered setIsLoadingOptions(false); - // Step 1: Display the welcome message immediately if it's the first load if (isFirstLoad) { - setChat([]); // Clear chat only on first load + setChat([]); setChat([ { from: "bot", - text: "✨ Welcome to DevTinder! I'm Nova, your assistant. I'm here to help you get started. What would you like to know? ❤️", + text: "✨ Welcome to DevTinder ❤️❤️! I'm Nova, your assistant. I'm here to help you get started. What would you like to know?", isWelcome: true, }, ]); - // Step 2: After a short delay, show the loader setTimeout(() => { setIsLoadingOptions(true); }, 500); - // Step 3: After 3 seconds of loading, hide the loader and start showing questions one by one setTimeout(() => { setIsLoadingOptions(false); - // Add a new message to chat that will render the initial questions with staggered effect setChat((prevChat) => [ ...prevChat, { from: "bot", initialOptions: questionOptions, isStaggered: true } ]); - setIsFirstLoad(false); // Mark first load as complete - }, 3500); // 500ms initial delay + 3000ms loader duration + setIsFirstLoad(false); + }, 3500); } else { - // If it's not the first load (i.e., coming from Main Menu button), append questions instantly setChat((prevChat) => [ ...prevChat, - { from: "bot", initialOptions: questionOptions, isStaggered: false } // No staggered effect for subsequent loads + { from: "bot", initialOptions: questionOptions, isStaggered: false } ]); } }; - // Function to reset all states when closing the chatbot const resetChatbot = () => { setIsOpen(false); setChat([]); setIsTyping(false); setIsLoadingOptions(false); - setIsFirstLoad(true); // Reset to true so next open is a fresh start + setIsFirstLoad(true); }; return (
- {/* Chatbot toggle button with neon effect and robot icon */} {!isOpen && ( - +
- {/* Chat messages container */}
{chat.map((msg, idx) => (
- {/* Regular text messages (user, bot answer, welcome, main menu prompt) */} {!msg.followUps && !msg.initialOptions && !msg.isMainMenuPrompt && (
@@ -274,54 +220,35 @@ export default function ChatBot() {
)} - {/* Conditional rendering for follow-up questions and Main Menu button */} {msg.followUps && (
{msg.followUps.map((fup, i) => ( - ))} - {/* Main Menu button always appears with follow-up options */} -
)} - {/* Conditionally render the "Main Menu" prompt and button */} {msg.isMainMenuPrompt && (
-
- {msg.text} {/* Use msg.text for the prompt message */} +
+ {msg.text}
-
)} - {/* Conditional rendering for initial questions / main menu questions */} {msg.initialOptions && (
{msg.initialOptions.map((opt, index) => ( - ))} @@ -330,7 +257,6 @@ export default function ChatBot() {
))} - {/* Conditional loader */} {isLoadingOptions && (
@@ -338,16 +264,13 @@ export default function ChatBot() {
)} - {isTyping && ( -
Nova is typing...
- )} + {isTyping && (
Nova is typing.....
)}
)}