Skip to content

Commit

Permalink
feat: chatbot (#489)
Browse files Browse the repository at this point in the history
  • Loading branch information
kabir0x23 authored Oct 9, 2023
1 parent 356a511 commit d0dce0a
Show file tree
Hide file tree
Showing 11 changed files with 620 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import SecurityRoutes from "./components/Other/Security/SecurityRoutes";
import ExploreRoutes from "./components/Explore/ExploreRoutes";
import Leaderboard from "./components/Other/CyberGames/Leaderboard/Leaderboard";
import SettingsRoute from "./components/Dashboard/Settings";
import TCHBot from "./components/Chatbot/TCHBot";

const App = () => {
const [isLoading, setIsLoading] = useState(true);
Expand Down Expand Up @@ -163,6 +164,7 @@ const App = () => {
<Route path={"*"} element={<NotFound />} />
</Routes>
</ScrollToTop>
<TCHBot />
{!hideHomeHeader() && <Footer />}
</Container>
<ToastContainer
Expand Down
44 changes: 44 additions & 0 deletions src/components/ChatBot/ActionProvider.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// ActionProvider code
class ActionProvider {
constructor(createChatBotMessage, setStateFunc, createClientMessage, stateRef, createCustomMessage, ...rest) {
this.createChatBotMessage = createChatBotMessage;
this.setState = setStateFunc;
this.createClientMessage = createClientMessage;
this.stateRef = stateRef;
this.createCustomMessage = createCustomMessage;
}

updateChatbotState(message) {
this.setState((prevState) => ({
...prevState,
messages: [...prevState.messages, message],
}));
}

welcome(name) {
const userName = name.charAt(0).toUpperCase() + name.slice(1);
const welcomeMessage = this.createChatBotMessage(`Hi, ${userName}! How can I best assist you today?`, {
widget: "assistOptions",
});
this.updateChatbotState(welcomeMessage);
}

warn() {
const warnMessage = this.createChatBotMessage("I didn't get that. Your First Name would do please.");
this.updateChatbotState(warnMessage);
}

suggestLinks = (name, reply) => {
const message = this.createChatBotMessage(`${reply[name]}`, {
widget: "assistLinks",
});

this.setState((prevState) => ({
...prevState,
optionName: name,
messages: [...prevState.messages, message],
}));
};
}

export default ActionProvider;
195 changes: 195 additions & 0 deletions src/components/ChatBot/ChatbotElements.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import styled from "styled-components";

export const ThecyberhubBot = styled.div`
background-color: #0b0b0b;
color: #cecac3;
outline: 1px solid rgb(42, 42, 42);
display: ${({ callBot }) => (callBot ? "block" : "none")};
height: 100vh;
width: 40vw;
transition: 260ms all;
padding: 2rem 2rem 0;
position: fixed;
right: 0;
top: 0;
z-index: 11;
@media screen and (max-width: 1024px) {
width: 50vw;
}
@media screen and (max-width: 768px) {
width: 70vw;
}
@media screen and (max-width: 640px) {
width: 100vw;
}
.react-chatbot-kit-chat-container {
border-radius: 0.5rem;
outline: 1px solid #2a2a2a;
transition: 260ms all;
width: 100%;
:hover {
outline-color: #545454;
outline-offset: 2px;
}
.react-chatbot-kit-chat-inner-container {
.react-chatbot-kit-chat-header {
background: rgba(32, 194, 14, 0.04);
background: linear-gradient(to right, #b1faa9, #f6dbaa);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
border-bottom: 1px solid #363636;
border-radius: 0.5rem 0.5rem 0 0;
font-weight: 500;
padding: 1rem;
}
.react-chatbot-kit-chat-message-container {
display: flex;
flex-direction: column;
justify-content: start;
row-gap: 1.3rem;
height: 60vh;
overflow: auto;
padding: 1.5rem;
.react-chatbot-kit-chat-bot-message-container {
display: flex;
column-gap: 0.5rem;
.react-chatbot-kit-chat-bot-avatar {
div {
width: 2.5rem;
}
img {
object-fit: fill;
width: 100%;
}
}
.react-chatbot-kit-chat-bot-message {
background: #1a1c1d;
border-radius: 0 0.5rem 0.5rem;
outline: 2px solid #2a2a2a;
overflow-wrap: break-word;
padding: 0.5rem;
/* width: fit-content; */
span {
font-weight: 400;
letter-spacing: 0.08rem;
}
}
}
.react-chatbot-kit-user-chat-message-container {
display: flex;
justify-content: end;
column-gap: 0.5rem;
.react-chatbot-kit-user-chat-message {
background: rgba(32, 194, 14, 0.2);
border-radius: 0.5rem 0 0.5rem 0.5rem;
font-weight: 300;
letter-spacing: 0.08rem;
outline: 2px solid #2a2a2a;
overflow-wrap: break-word;
padding: 0.5rem;
}
.react-chatbot-kit-user-avatar {
div {
height: 2rem;
width: 2rem;
background: linear-gradient(to right, #b1faa9, #f6dbaa);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
svg {
fill: rgb(32, 194, 14);
width: 50%;
}
}
}
}
.react-chatbot-kit-chat-input-container {
border-top: 1px solid #363636;
height: 3rem;
width: 100%;
form {
display: flex;
align-items: center;
justify-content: start;
height: 100%;
width: 100%;
}
input {
background: rgba(32, 194, 14, 0.04);
border: none;
border-radius: 0 0 0 0.5rem;
caret-color: white;
color: #cecac3;
height: 100%;
width: 100%;
text-indent: 1rem;
:focus {
outline: none;
}
::placeholder {
color: #cecac3;
font-weight: 100;
letter-spacing: 0.1rem;
}
}
button {
background: rgba(32, 194, 14, 0.04);
border: none;
border-radius: 0 0 0.5rem 0;
cursor: pointer;
height: 100%;
width: 3rem;
transition: 260ms all;
:hover {
background: rgba(32, 194, 14, 0.2);
}
}
svg {
fill: #cecac3;
width: 1rem;
}
}
}
}
`;

export const BotButtonCont = styled.div`
position: fixed;
right: 2rem;
bottom: 1rem;
z-index: 11;
button {
background: #0f0a06;
border-radius: 50%;
cursor: pointer;
outline: 2px solid #363636;
display: flex;
justify-content: center;
align-items: center;
width: 3.5rem;
height: 3.5rem;
transition: 260ms all;
:hover {
background: #23150e;
outline-color: #545454;
outline-offset: 1px;
}
}
`;
39 changes: 39 additions & 0 deletions src/components/ChatBot/MessageParser.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// MessageParser code
class MessageParser {
constructor(actionProvider, state) {
this.actionProvider = actionProvider;
this.state = state;
}

parse(message) {
const lowerCaseMessage = message.toLowerCase();
const lowerCaseMessageArr = lowerCaseMessage.split(" ");
const actions = this.actionProvider;

// Detect the User's name
if (lowerCaseMessage === "") {
actions.warn();
} else if (lowerCaseMessage.includes("is") || lowerCaseMessage.includes("am")) {
const userName = lowerCaseMessage.includes("is")
? lowerCaseMessageArr[lowerCaseMessageArr.indexOf("is") + 1]
: lowerCaseMessageArr[lowerCaseMessageArr.indexOf("am") + 1];
actions.welcome(userName);
} else if (lowerCaseMessageArr.length === 1) {
actions.welcome(lowerCaseMessage);
} else if (lowerCaseMessageArr.length === 2 && lowerCaseMessage.includes("i'm")) {
actions.welcome(lowerCaseMessageArr[1]);
} else if (lowerCaseMessageArr.length === 2) {
actions.welcome(lowerCaseMessageArr[0]);
} else if (
!lowerCaseMessage.includes("is") &&
lowerCaseMessageArr.length !== 1 &&
lowerCaseMessageArr.length !== 2
) {
actions.warn();
} else {
actions.warn();
}
}
}

export default MessageParser;
45 changes: 45 additions & 0 deletions src/components/ChatBot/TCHBot.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React, { useState, useCallback } from "react";

import Chatbot from "react-chatbot-kit";

import config from "./config";
import ActionProvider from "./ActionProvider";
import MessageParser from "./MessageParser";

import { ThecyberhubBot, BotButtonCont } from "./ChatbotElements";

// import { FaRobot } from "react-icons/fa";
import { CgClose } from "react-icons/cg";
import { getCdnAssets } from "../../features/apiUrl";
const logoThecyberworld = `${getCdnAssets}/images/ThecyberworldLogo/Thecyberworld_logo_outlined.png`;

export default function TCHBot() {
const [callBot, setCallBot] = useState(false);

const talkToBot = useCallback(() => {
setCallBot((prevCallBot) => !prevCallBot);
}, []);

return (
<>
<ThecyberhubBot callBot={callBot}>
<Chatbot config={config} messageParser={MessageParser} actionProvider={ActionProvider} />
</ThecyberhubBot>
<BotButtonCont>
<button onClick={talkToBot}>
{!callBot ? (
<img
style={{
padding: "5px",
}}
src={logoThecyberworld}
alt={""}
/>
) : (
<CgClose size={35} style={{ color: "white" }} />
)}
</button>
</BotButtonCont>
</>
);
}
56 changes: 56 additions & 0 deletions src/components/ChatBot/Widgets/Assists/AssistElements.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import styled from "styled-components";

export const OptionButton = styled.button`
background: transparent;
border-radius: 0.3rem;
color: #cecac3;
cursor: pointer;
font-weight: 700;
letter-spacing: 0.08rem;
outline: 1px solid rgba(32, 194, 14, 0.4);
padding: 0.5rem;
transition: 260ms all;
:hover {
background: rgba(32, 194, 14, 0.2);
color: white;
outline-color: #545454;
outline-offset: 1px;
}
`;

export const OptionCont = styled.div`
display: flex;
gap: 0.5rem;
align-items: flex-start;
flex-wrap: wrap;
`;

export const LinkList = styled.ul`
list-style: none;
display: flex;
flex-direction: column;
row-gap: 1.5rem;
li {
a {
text-decoration: none;
background: rgba(32, 194, 14, 0.2);
border-radius: 0.3rem;
color: white;
font-weight: 500;
font-style: italic;
letter-spacing: 0.08rem;
outline: 1px solid #545454;
padding: 0.5rem;
transition: 260ms all;
:hover {
background: transparent;
color: #cecac3;
outline-color: rgba(32, 194, 14, 0.4);
outline-offset: 1px;
}
}
}
`;
Loading

0 comments on commit d0dce0a

Please sign in to comment.