Skip to content

Commit 30f482f

Browse files
committed
Cleaned up Olliebot layout. Added a dropdown for FAQs to increase message space.
1 parent c768fea commit 30f482f

File tree

2 files changed

+159
-0
lines changed

2 files changed

+159
-0
lines changed
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import React, { useState } from 'react';
2+
import { MessageCircle, X, ChevronDown, ChevronUp, CircleQuestionMark } from 'lucide-react';
3+
4+
const Olliebot = () => {
5+
const [isOpen, setIsOpen] = useState(false);
6+
const [showFaqs, setShowFaqs] = useState(true);
7+
8+
const toggleChat = () => {
9+
setIsOpen(!isOpen);
10+
};
11+
12+
const toggleFaqs = () => {
13+
setShowFaqs(!showFaqs);
14+
};
15+
16+
interface Message {
17+
id: string;
18+
text: string;
19+
isUser: boolean;
20+
}
21+
22+
interface FaqItem {
23+
id: string;
24+
question: string;
25+
answer: string;
26+
}
27+
28+
// All new messages are added here
29+
const [messages, setMessages] = useState<Message[]>([
30+
{ id: '1', text: "Hi! What can I help you with today?", isUser: false }
31+
]);
32+
33+
// Mapping? Similar to how freerooms was done for search
34+
const FaqItems: FaqItem[] = [
35+
{
36+
id: "1",
37+
question: "What is CSESoc?",
38+
answer: "We're one of the largest computing societies in the southern hemisphere! Whether you're looking to improve your tech skills, network with like-minded peers, or explore career opportunities, CSESoc offers valuable resources and experiences for computer science and engineering students.",
39+
},
40+
{
41+
id: "2",
42+
question: "How can I join CSESoc?",
43+
answer: "Check our discord and website for updates! Spots open up every year :)",
44+
},
45+
{
46+
id: "3",
47+
question: "What events do CSESoc run?",
48+
answer: "We run events that range from fun social meetups to hackathons and training workshops. You can check out our full event listing at our facebook page and on discord announcements!",
49+
},
50+
{
51+
id: "4",
52+
question: "Who's Ollie?",
53+
answer: "That would be me! Wait, I'm actually a bot. Anyways, Ollie is CSESoc's ottersome little mascot!",
54+
},
55+
];
56+
57+
const addMessage = (text: string, isUser: boolean) => {
58+
const newMessage: Message = {
59+
id: Date.now().toString(),
60+
text,
61+
isUser,
62+
};
63+
{/*Update array, append new message atop previous*/}
64+
setMessages(prevMessages => [...prevMessages, newMessage]);
65+
};
66+
67+
const handleFaqSelect = (faq: FaqItem) => {
68+
addMessage(faq.question, true);
69+
setTimeout(() => {
70+
addMessage(faq.answer, false);
71+
}, 500);
72+
};
73+
74+
return (
75+
<div className="fixed bottom-6 right-6 z-50">
76+
<div
77+
className={`transition-all duration-300 ease-in-out flex flex-col shadow-2xl ${
78+
!isOpen
79+
? 'w-16 h-16 rounded-lg cursor-pointer bg-[#3977F8] hover:bg-blue-700'
80+
: 'w-[420px] h-[520px] bg-white rounded-lg'
81+
}`}
82+
onClick={!isOpen ? toggleChat : undefined}
83+
>
84+
{!isOpen ? (
85+
<div className="flex items-center justify-center w-full h-full text-white">
86+
<MessageCircle size={24} />
87+
</div>
88+
) : (
89+
<>
90+
<div className="bg-[#3977F8] text-white p-4 rounded-t-lg flex items-center justify-between">
91+
<div className="flex items-center gap-2">
92+
<MessageCircle size={20} />
93+
<span className="font-semibold">Olliebot</span>
94+
</div>
95+
<button className="text-white hover:text-gray-200"
96+
onClick={toggleChat}
97+
>
98+
<X size={20} />
99+
</button>
100+
</div>
101+
102+
{/* Messages */}
103+
<div className="flex-1 p-4 overflow-y-auto space-y-3">
104+
{messages.map((message) => (
105+
<div
106+
key={message.id}
107+
className={`flex ${message.isUser ? 'justify-end' : 'justify-start'}`}
108+
>
109+
<div
110+
className={`max-w-xs px-3 py-2 rounded-lg text-sm ${
111+
message.isUser
112+
? 'bg-[#3977F8] text-white rounded-br-none'
113+
: 'bg-gray-100 text-gray-800 rounded-bl-none'
114+
}`}
115+
>
116+
{message.text}
117+
</div>
118+
</div>
119+
))}
120+
</div>
121+
122+
{/* FAQs */}
123+
<div className="border-t border-gray-200">
124+
<button
125+
className="w-full p-3 flex items-center justify-between text-left bg-gray-50 hover:bg-gray-100 transition-colors"
126+
onClick={toggleFaqs}
127+
>
128+
<div className="flex items-center gap-2">
129+
<CircleQuestionMark size={16} className="text-[#3977F8]" />
130+
<span className="font-medium text-gray-700 text-sm">FAQs</span>
131+
</div>
132+
{showFaqs ? <ChevronUp size={16} className='text-gray-700'/> : <ChevronDown size={16} className='text-gray-700'/>}
133+
</button>
134+
135+
{showFaqs && (
136+
<div className="p-3 space-y-2 max-h-[160px] overflow-y-auto bg-gray-50">
137+
{FaqItems.map((faq) => (
138+
<button
139+
key={faq.id}
140+
className="w-full text-left p-2 bg-white hover:bg-blue-50 hover:border-blue-200 rounded border border-gray-200 transition-colors"
141+
onClick={() => handleFaqSelect(faq)}
142+
>
143+
<span className="text-sm text-gray-800">{faq.question}</span>
144+
</button>
145+
))}
146+
</div>
147+
)}
148+
</div>
149+
</>
150+
)}
151+
</div>
152+
</div>
153+
);
154+
};
155+
156+
export default Olliebot;

frontend/src/pages/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Sponsors from '@/components/Sponsors/index';
44
import AboutHomePage from '@/components/About/AboutHomepage';
55
import EventsBrief from '@/components/Event/EventsBrief';
66
import TabTitle from 'next/head';
7+
import Olliebot from '@/components/Olliebot';
78

89
export default function HomePage() {
910
return (
@@ -25,6 +26,8 @@ export default function HomePage() {
2526
<EventsBrief />
2627
<Sponsors />
2728
</section>
29+
30+
<Olliebot/>
2831
</>
2932

3033
);

0 commit comments

Comments
 (0)