From 96412fb16c69d325ea086cf2a6eeb8508ffd8075 Mon Sep 17 00:00:00 2001 From: Emi <115059905+emylattuada@users.noreply.github.com> Date: Wed, 20 May 2026 00:36:10 -0300 Subject: [PATCH 1/4] Add files via upload --- src/components/Chatbot/Chatbot.css | 266 ++++++++++++++++++++++++++ src/components/Chatbot/Chatbot.tsx | 295 +++++++++++++++++++++++++++++ 2 files changed, 561 insertions(+) create mode 100644 src/components/Chatbot/Chatbot.css create mode 100644 src/components/Chatbot/Chatbot.tsx diff --git a/src/components/Chatbot/Chatbot.css b/src/components/Chatbot/Chatbot.css new file mode 100644 index 0000000..3586301 --- /dev/null +++ b/src/components/Chatbot/Chatbot.css @@ -0,0 +1,266 @@ +/* IssueBot — matches the dark zinc theme of IssueHub */ +/* Uses CSS variables from globals.css + Geist font from next/font */ + +.chatbot-bubble { + position: fixed; + bottom: 28px; + right: 28px; + width: 56px; + height: 56px; + background: #fafafa; + border: none; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + z-index: 1000; + transition: + transform 0.2s ease, + background 0.2s ease; + box-shadow: 0 4px 24px rgba(0, 0, 0, 0.5); +} + +.chatbot-bubble:hover { + transform: scale(1.08); + background: #e4e4e7; +} + +.chatbot-bubble .icon-chat path { + fill: #0a0a0b; +} + +.chatbot-bubble .icon-close line { + stroke: #0a0a0b; +} + +.icon-chat, +.icon-close { + position: absolute; + transition: + transform 0.25s ease, + opacity 0.2s ease; +} + +.icon-close { + opacity: 0; + transform: scale(0.6) rotate(-20deg); +} + +.chatbot-bubble.open .icon-chat { + opacity: 0; + transform: scale(0.6) rotate(20deg); +} + +.chatbot-bubble.open .icon-close { + opacity: 1; + transform: scale(1) rotate(0deg); +} + +/* ── Container ────────────────────────────────────────────────────────────── */ +.chatbot-container { + height: 420px; + width: 350px; + background: #18181b; /* --muted: zinc-900 */ + border: 1px solid #27272a; /* --border: zinc-800 */ + position: fixed; + bottom: 96px; + right: 28px; + box-shadow: 0 8px 40px rgba(0, 0, 0, 0.7); + border-radius: 12px; + overflow: hidden; + display: flex; + flex-direction: column; + z-index: 999; + font-family: var(--font-geist-sans, sans-serif); + color: #fafafa; + + transform-origin: bottom right; + transform: scale(0.85) translateY(16px); + opacity: 0; + pointer-events: none; + transition: + transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1), + opacity 0.2s ease; +} + +.chatbot-container.open { + transform: scale(1) translateY(0); + opacity: 1; + pointer-events: all; +} + +/* ── Header ───────────────────────────────────────────────────────────────── */ +.chatbot-header { + height: 56px; + display: flex; + align-items: center; + padding: 0 16px; + background: #0a0a0b; + border-bottom: 1px solid #27272a; + flex-shrink: 0; + gap: 10px; +} + +.chatbot-logo { + width: 32px; + height: 32px; + flex-shrink: 0; +} + +.chatbot-title { + font-size: 0.95rem; + font-weight: 600; + color: #fafafa; + letter-spacing: 0.01em; +} + +.chatbot-minimize-btn { + background: none; + border: none; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + margin-left: auto; + padding: 6px; + border-radius: 6px; + color: #a1a1aa; + transition: + color 0.15s ease, + background 0.15s ease; +} + +.chatbot-minimize-btn:hover { + color: #fafafa; + background: #27272a; +} + +/* ── Body ─────────────────────────────────────────────────────────────────── */ +.chatbot-body { + flex: 1; + display: flex; + flex-direction: column; + padding: 12px 10px; + align-items: flex-end; + overflow-y: auto; + gap: 2px; +} + +.chatbot-body::-webkit-scrollbar { + width: 4px; +} +.chatbot-body::-webkit-scrollbar-track { + background: transparent; +} +.chatbot-body::-webkit-scrollbar-thumb { + background: #27272a; + border-radius: 4px; +} + +/* ── Messages ─────────────────────────────────────────────────────────────── */ +.chatbot-bot-msg, +.chatbot-user-msg { + padding: 8px 12px; + margin: 3px 0; + max-width: 82%; + font-size: 0.875rem; + line-height: 1.45; + word-break: break-word; +} + +.chatbot-user-msg { + background: #27272a; + color: #fafafa; + align-self: flex-end; + border-radius: 12px 3px 12px 12px; +} + +.chatbot-bot-msg { + background: #3f3f46; + color: #fafafa; + align-self: flex-start; + border-radius: 3px 12px 12px 12px; +} + +/* ── Welcome ──────────────────────────────────────────────────────────────── */ +.chatbot-welcome { + display: flex; + flex-direction: column; + gap: 8px; +} + +.chatbot-recommended-label { + font-size: 0.68rem; + font-weight: 600; + color: #a1a1aa; + text-transform: uppercase; + letter-spacing: 0.06em; +} + +.chatbot-option-btn { + background: transparent; + color: #fafafa; + border: 1px solid #3f3f46; + border-radius: 20px; + padding: 5px 14px; + font-size: 0.8rem; + font-family: var(--font-geist-sans, sans-serif); + cursor: pointer; + align-self: flex-start; + transition: + background 0.2s, + border-color 0.2s; +} + +.chatbot-option-btn:hover { + background: #27272a; + border-color: #a1a1aa; +} + +/* ── Input row ────────────────────────────────────────────────────────────── */ +.chatbot-input-row { + height: 52px; + display: flex; + align-items: center; + border-top: 1px solid #27272a; + background: #0a0a0b; + flex-shrink: 0; + padding: 0 4px 0 0; +} + +.chatbot-input { + flex: 1; + background: transparent; + border: none; + outline: none; + color: #fafafa; + caret-color: #fafafa; + font-size: 0.9rem; + font-family: var(--font-geist-sans, sans-serif); + padding: 8px 12px; +} + +.chatbot-input::placeholder { + color: #52525b; +} + +.chatbot-send-btn { + background: none; + border: none; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + padding: 8px; + border-radius: 8px; + opacity: 0.6; + transition: + opacity 0.15s ease, + background 0.15s ease; +} + +.chatbot-send-btn:hover { + opacity: 1; + background: #27272a; +} diff --git a/src/components/Chatbot/Chatbot.tsx b/src/components/Chatbot/Chatbot.tsx new file mode 100644 index 0000000..1a2962d --- /dev/null +++ b/src/components/Chatbot/Chatbot.tsx @@ -0,0 +1,295 @@ +'use client'; + +import Image from 'next/image'; +import { useEffect, useRef, useState } from 'react'; +import { z } from 'zod'; +import './Chatbot.css'; + +// ── Response map ────────────────────────────────────────────────────────────── +// `today` and `time` are computed on call, not at module load +type ResponseValue = string | (() => string) | (() => void); + +const responseObj: Record = { + hello: 'Hey! How are you doing?', + hey: "Hey! What's up?", + today: () => new Date().toDateString(), + time: () => new Date().toLocaleTimeString(), + ping: 'Pong', + rn: () => '__EMAIL_FLOW__', + about: 'My role is to increase website traffic.', +}; + +// ── Email validation via zod ────────────────────────────────────────────────── +const emailSchema = z.string().email(); + +// ── Types ───────────────────────────────────────────────────────────────────── +interface Message { + id: number; + text: string; + type: 'bot' | 'user'; + isWelcome?: boolean; +} + +let msgId = 0; +const nextId = () => ++msgId; + +// ── Component ───────────────────────────────────────────────────────────────── +export default function Chatbot() { + const [isOpen, setIsOpen] = useState(false); + const [messages, setMessages] = useState([]); + const [inputValue, setInputValue] = useState(''); + const [placeholder, setPlaceholder] = useState('Type here'); + const [isEmailMode, setIsEmailMode] = useState(false); + const [welcomeRendered, setWelcomeRendered] = useState(false); + + const chatBodyRef = useRef(null); + const inputRef = useRef(null); + + // Scroll to bottom on new messages + useEffect(() => { + if (chatBodyRef.current) { + chatBodyRef.current.scrollTop = chatBodyRef.current.scrollHeight; + } + }, [messages]); + + // Focus input and render welcome on first open + useEffect(() => { + if (isOpen) { + setTimeout(() => inputRef.current?.focus(), 260); + if (!welcomeRendered) { + setMessages([{ id: nextId(), text: '', type: 'bot', isWelcome: true }]); + setWelcomeRendered(true); + } + } + }, [isOpen, welcomeRendered]); + + // ── Helpers ──────────────────────────────────────────────────────────────── + const addMessage = (text: string, type: 'bot' | 'user' = 'bot') => + setMessages(prev => [...prev, { id: nextId(), text, type }]); + + const removeLastMessage = () => setMessages(prev => prev.slice(0, -1)); + + // ── Email flow ───────────────────────────────────────────────────────────── + function startEmailFlow() { + setIsEmailMode(true); + addMessage('Please enter your email:'); + setPlaceholder('your@email.com'); + setTimeout(() => inputRef.current?.focus(), 50); + } + + const submitEmail = async (email: string) => { + const result = emailSchema.safeParse(email); + if (!result.success) { + addMessage('Invalid email. Please try again.'); + return; + } + + addMessage(email, 'user'); + setInputValue(''); + addMessage('Sending... ⏳'); + + try { + const emailjs = await import('@emailjs/browser'); + await emailjs.send( + 'service_2fc5v5k', + 'template_d3d70zp', + { user_email: email, user: 'IssueHub' }, + { publicKey: 'De3J97q5iJ8M72LB0' } + ); + removeLastMessage(); + addMessage('Email sent successfully! ✅'); + } catch (err) { + removeLastMessage(); + addMessage('Failed to send. Please try again. ❌'); + console.error(err); + } + + setIsEmailMode(false); + setPlaceholder('Type here'); + }; + + // ── Message handler ──────────────────────────────────────────────────────── + const handleSend = () => { + const text = inputValue.trim(); + if (!text) return; + + if (isEmailMode) { + submitEmail(text); + return; + } + + addMessage(text, 'user'); + setInputValue(''); + + setTimeout(() => { + const res = responseObj[text.toLowerCase()]; + + if (typeof res === 'function') { + const result = res(); + if (result === '__EMAIL_FLOW__') { + startEmailFlow(); + } else if (typeof result === 'string') { + addMessage(result); + } + } else if (typeof res === 'string') { + addMessage(res); + } else { + addMessage("Sorry, I didn't understand that. Try: hello, today, time, ping, rn."); + } + }, 500); + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter') handleSend(); + }; + + // ── Render ───────────────────────────────────────────────────────────────── + return ( + <> + {/* Chat window */} +
+ {/* Header */} +
+
+ IssueBot logo +
+ IssueBot + +
+ + {/* Body */} +
+ {messages.map(msg => + msg.isWelcome ? ( + + ) : ( +
+ {msg.text} +
+ ) + )} +
+ + {/* Input */} +
+ setInputValue(e.target.value)} + onKeyDown={handleKeyDown} + /> + +
+
+ + {/* Bubble toggle */} + + + ); +} + +// ── Welcome sub-component ───────────────────────────────────────────────────── +function WelcomeMessage({ onNotify }: { onNotify: () => void }) { + const [dismissed, setDismissed] = useState(false); + + const handleClick = () => { + setDismissed(true); + onNotify(); + }; + + return ( +
+ Hi! How can I help you today? + {!dismissed && ( + <> + Recommended + + + )} +
+ ); +} From 69ece39dfc7f9dd494a7fb2d4c713b18e7c51cd8 Mon Sep 17 00:00:00 2001 From: Emi <115059905+emylattuada@users.noreply.github.com> Date: Wed, 20 May 2026 00:36:56 -0300 Subject: [PATCH 2/4] Add files via upload --- public/images/logo.png | Bin 0 -> 13231 bytes public/images/send.png | Bin 0 -> 1441 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 public/images/logo.png create mode 100644 public/images/send.png diff --git a/public/images/logo.png b/public/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..25e77de6e18d4bf48d1e85a0ba2bf3362a6a67f8 GIT binary patch literal 13231 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 Date: Wed, 20 May 2026 00:39:03 -0300 Subject: [PATCH 3/4] Update layout.tsx --- src/app/layout.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 3c74ad8..a5697d4 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -3,6 +3,7 @@ import { Geist, Geist_Mono } from 'next/font/google'; import './globals.css'; import MuiProvider from '@/components/layout/MuiProvider'; import QueryProvider from '@/components/layout/QueryProvider'; +import Chatbot from '@/components/Chatbot/Chatbot'; const geistSans = Geist({ variable: '--font-geist-sans', @@ -31,6 +32,7 @@ export default function RootLayout({ {children} + ); From ec40e9e71bec4e4690c67ae2419116ea6ac542ad Mon Sep 17 00:00:00 2001 From: Emi <115059905+emylattuada@users.noreply.github.com> Date: Fri, 29 May 2026 15:17:41 -0300 Subject: [PATCH 4/4] Update EmailJS service and template identifiers --- src/components/Chatbot/Chatbot.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/Chatbot/Chatbot.tsx b/src/components/Chatbot/Chatbot.tsx index 1a2962d..87b7946 100644 --- a/src/components/Chatbot/Chatbot.tsx +++ b/src/components/Chatbot/Chatbot.tsx @@ -91,10 +91,10 @@ export default function Chatbot() { try { const emailjs = await import('@emailjs/browser'); await emailjs.send( - 'service_2fc5v5k', - 'template_d3d70zp', + 'YOUR_SERVICE', + 'YOUR_TEMPLATE', { user_email: email, user: 'IssueHub' }, - { publicKey: 'De3J97q5iJ8M72LB0' } + { publicKey: 'YOUR_APIKEY' } ); removeLastMessage(); addMessage('Email sent successfully! ✅');