Skip to content
Merged
22 changes: 22 additions & 0 deletions chatbot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# 🤖 ExpenseFlow Chatbot

A modular, rule-based chatbot to help users with:

- Expense tracking tips
- Budget explanations
- Analytics guidance
- App navigation

## Features

- Frontend-only
- No backend dependency
- Easily extendable to AI later

## Enable Chatbot

Include this script in your HTML:

```html
<script type="module" src="chatbot/chatbot.js"></script>
```
4 changes: 4 additions & 0 deletions chatbot/chatbot.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const CHATBOT_CONFIG = {
enabled: true,
welcomeMessage: true,
};
73 changes: 73 additions & 0 deletions chatbot/chatbot.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#expenseflow-chatbot {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 9999;
font-family: system-ui, sans-serif;
}

#chatbot-toggle {
background: #4f46e5;
color: #fff;
border: none;
border-radius: 50%;
width: 56px;
height: 56px;
font-size: 24px;
cursor: pointer;
}

#chatbot-window {
position: absolute;
bottom: 70px;
right: 0;
width: 320px;
height: 420px;
background: #111827;
color: #fff;
border-radius: 12px;
display: flex;
flex-direction: column;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
}

.hidden {
display: none;
}

.chatbot-header {
padding: 12px;
background: #1f2933;
display: flex;
justify-content: space-between;
align-items: center;
}

#chatbot-messages {
flex: 1;
padding: 10px;
overflow-y: auto;
font-size: 14px;
}

.chatbot-input {
display: flex;
padding: 8px;
gap: 6px;
}

.chatbot-input input {
flex: 1;
padding: 6px;
border-radius: 6px;
border: none;
}

.chatbot-input button {
background: #4f46e5;
color: white;
border: none;
border-radius: 6px;
padding: 6px 10px;
cursor: pointer;
}
25 changes: 25 additions & 0 deletions chatbot/chatbot.data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export const chatbotKnowledge = {
greetings: [
"Hi! I’m your ExpenseFlow assistant 👋",
"Hello! Need help with expenses or budgets?",
],

tips: [
"Track expenses daily to avoid month-end surprises.",
"Use budget goals to control overspending.",
"Review analytics weekly to spot patterns.",
],

budget: {
setup:
"You can set a budget from the dashboard. This helps track monthly limits.",
analytics:
"Analytics shows where your money goes using charts and summaries.",
},

navigation: {
dashboard: "Dashboard gives you a quick overview of expenses and budgets.",
export: "Use the export feature to download your expense data.",
notifications: "Notifications alert you when you cross budget limits.",
},
};
21 changes: 21 additions & 0 deletions chatbot/chatbot.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<div id="expenseflow-chatbot">
<button id="chatbot-toggle" aria-label="Open chatbot">💬</button>

<div id="chatbot-window" class="hidden" style="display: none">
<div class="chatbot-header">
<span>ExpenseFlow Assistant</span>
<button id="chatbot-close">✕</button>
</div>

<div id="chatbot-messages"></div>

<div class="chatbot-input">
<input
type="text"
id="chatbot-input"
placeholder="Ask about expenses, budgets, tips..."
/>
<button id="chatbot-send">Send</button>
</div>
</div>
</div>
76 changes: 76 additions & 0 deletions chatbot/chatbot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = "./chatbot/chatbot.css";
document.head.appendChild(link);

import { chatbotKnowledge } from "./chatbot.data.js";
import { CHATBOT_CONFIG } from "./chatbot.config.js";

fetch("./chatbot/chatbot.html")
.then((res) => res.text())
.then((html) => {
document.body.insertAdjacentHTML("beforeend", html);

const toggleBtn = document.getElementById("chatbot-toggle");
const closeBtn = document.getElementById("chatbot-close");
const windowEl = document.getElementById("chatbot-window");
const messagesEl = document.getElementById("chatbot-messages");
const inputEl = document.getElementById("chatbot-input");
const sendBtn = document.getElementById("chatbot-send");

toggleBtn.onclick = () => {
windowEl.style.display =
windowEl.style.display === "none" ? "flex" : "none";
};

closeBtn.onclick = () => {
windowEl.style.display = "none";
};

const addMessage = (text, type = "bot") => {
const msg = document.createElement("div");
msg.textContent = text;
msg.style.marginBottom = "8px";
msg.style.textAlign = type === "user" ? "right" : "left";
messagesEl.appendChild(msg);
messagesEl.scrollTop = messagesEl.scrollHeight;
};

if (CHATBOT_CONFIG.welcomeMessage) {
addMessage(
chatbotKnowledge.greetings[
Math.floor(Math.random() * chatbotKnowledge.greetings.length)
],
);
}

const getResponse = (message) => {
const msg = message.toLowerCase();

if (msg.includes("tip"))
return chatbotKnowledge.tips[
Math.floor(Math.random() * chatbotKnowledge.tips.length)
];
if (msg.includes("budget")) return chatbotKnowledge.budget.setup;
if (msg.includes("analytics")) return chatbotKnowledge.budget.analytics;
if (msg.includes("export")) return chatbotKnowledge.navigation.export;
if (msg.includes("notification"))
return chatbotKnowledge.navigation.notifications;
if (msg.includes("dashboard"))
return chatbotKnowledge.navigation.dashboard;

return "I can help with tips, budgets, analytics, exports, and navigation 🙂";
};

sendBtn.onclick = () => {
const text = inputEl.value.trim();
if (!text) return;

addMessage(text, "user");
inputEl.value = "";

setTimeout(() => {
addMessage(getResponse(text));
}, 400);
};
});
Loading