Skip to content

Commit 4f45db2

Browse files
committed
feat(html): Added new chat with us option in docs
1 parent 23e3637 commit 4f45db2

File tree

4 files changed

+240
-0
lines changed

4 files changed

+240
-0
lines changed

components/chat/chat-window.tsx

+173
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
'use client'
2+
import React, { useState } from 'react'
3+
import Image from 'next/image'
4+
// import MarkdownRenderer from '../content-hub/mark-down-render'
5+
interface ChatWindowProps {
6+
onClose: () => void
7+
}
8+
9+
const ChatWindow: React.FC<ChatWindowProps> = ({ onClose }) => {
10+
const [messages, setMessages] = useState<
11+
{ type: 'user' | 'ai'; text: string }[]
12+
>([
13+
{ type: 'ai', text: 'Hi there! 👋 Welcome to our chat.' },
14+
{ type: 'ai', text: 'How can I assist you today?' },
15+
])
16+
const [input, setInput] = useState('')
17+
const [isTyping, setIsTyping] = useState(false)
18+
19+
const handleSendMessage = async () => {
20+
if (!input.trim()) return
21+
22+
// Add user's message
23+
setMessages((prev) => [...prev, { type: 'user', text: input }])
24+
25+
// Clear input
26+
setInput('')
27+
28+
// Show typing indicator
29+
setIsTyping(true)
30+
31+
// Simulate a delay for AI response
32+
try {
33+
const response = await fetch('/docs/api/chat', {
34+
method: 'POST',
35+
headers: { 'Content-Type': 'application/json' },
36+
body: JSON.stringify({ message: input }),
37+
})
38+
const data = await response.json()
39+
40+
// Add AI's response
41+
setTimeout(() => {
42+
setMessages((prev) => [
43+
...prev,
44+
{ type: 'ai', text: data.reply },
45+
])
46+
setIsTyping(false)
47+
}, 1500) // Adjust delay as needed
48+
} catch (error) {
49+
console.log('error', error)
50+
setTimeout(() => {
51+
setMessages((prev) => [
52+
...prev,
53+
{
54+
type: 'ai',
55+
text: 'Sorry, something went wrong. Please try again.',
56+
},
57+
])
58+
setIsTyping(false)
59+
}, 1500)
60+
}
61+
}
62+
63+
return (
64+
<div className="nx-fixed nx-bottom-0 md:nx-bottom-3 nx-right-0 md:nx-right-3 nx-w-full nx-max-w-md nx-bg-[#F3F5F8] nx-shadow-xl nx-rounded-xl nx-z-[51] nx-pb-6">
65+
{/* Header */}
66+
<div className="nx-flex nx-justify-between nx-items-center nx-bg-gradient-to-b nx-from-[rgba(95,56,251,0.1)] nx-to-[rgba(208,234,255,0.1)] nx-rounded-xl nx-px-6">
67+
<h3 className="nx-text-lg nx-font-semibold"></h3>
68+
<button onClick={onClose} className="nx-text-[#000D3D] nx-mt-6">
69+
&#x2715;
70+
</button>
71+
</div>
72+
<div className="nx-px-6">
73+
{/* Messages */}
74+
<div className="nx-p-4 nx-space-y-2 nx-h-[calc(100vh-128px)] nx-md:!h-[464px] nx-overflow-y-auto">
75+
{messages.map((msg, idx) => (
76+
<div
77+
key={idx}
78+
className={`nx-flex ${
79+
msg.type === 'user'
80+
? 'nx-justify-end'
81+
: 'nx-justify-start'
82+
}`}
83+
>
84+
{msg.type === 'ai' ? (
85+
<div className="nx-w-6 nx-h-6 nx-rounded-full nx-bg-white nx-mt-2 nx-mr-2 nx-flex nx-justify-center nx-items-center">
86+
<div className="nx-w-4 nx-h-4 nx-rounded-full nx-bg-[#0B1742] nx-flex nx-justify-center nx-items-center">
87+
<Image
88+
src="/Images/logo/fetch_logo_only_white.svg"
89+
alt="agentverse-img"
90+
width={6}
91+
height={6}
92+
className="nx-w-[6px] nx-h-[6px]"
93+
/>
94+
</div>
95+
</div>
96+
) : undefined}
97+
98+
{msg.type === 'user' ? (
99+
<p
100+
className={`nx-px-4 nx-py-3 nx-rounded-lg nx-text-[#000D3D] nx-bg-[#FCFCFD]`}
101+
>
102+
{msg.text}
103+
</p>
104+
) : (
105+
<p
106+
className={`nx-px-4 nx-py-3 nx-rounded-lg nx-text-[#000D3D] nx-bg-white`}
107+
>
108+
{/* <MarkdownRenderer
109+
markdownContent={msg.text}
110+
/> */}
111+
{msg.text}
112+
</p>
113+
)}
114+
</div>
115+
))}
116+
{isTyping && (
117+
<div className="nx-flex nx-justify-start">
118+
<div className="nx-w-6 nx-h-6 nx-rounded-full nx-bg-white nx-mt-2 nx-mr-2 nx-flex nx-justify-center nx-items-center">
119+
<div className="nx-w-4 nx-h-4 nx-rounded-full nx-bg-[#0B1742] nx-flex nx-justify-center nx-items-center">
120+
<Image
121+
src="/Images/logo/fetch_logo_only_white.svg"
122+
alt="agentverse-img"
123+
width={6}
124+
height={6}
125+
className="nx-w-[6px] nx-h-[6px]"
126+
/>
127+
</div>
128+
</div>
129+
<div className="nx-bg-white nx-text-[#000D3D] nx-px-4 nx-py-3 nx-rounded-lg nx-flex nx-items-center nx-space-x-1">
130+
<span className="nx-dot-animation"></span>
131+
<span className="nx-dot-animation"></span>
132+
<span className="nx-dot-animation"></span>
133+
</div>
134+
</div>
135+
)}
136+
</div>
137+
138+
{/* Input */}
139+
<div className="nx-p-4 nx-h-[56px] nx-w-full nx-bg-white nx-rounded-lg">
140+
<div className="nx-flex nx-justify-between nx-space-x-2 nx-w-full">
141+
<input
142+
type="text"
143+
value={input}
144+
onChange={(e) => setInput(e.target.value)}
145+
placeholder="Type your message..."
146+
className="focus:nx-outline-none nx-w-11/12"
147+
onKeyDown={(e) => {
148+
if (e.key === 'Enter') {
149+
e.preventDefault()
150+
handleSendMessage()
151+
}
152+
}}
153+
/>
154+
<div
155+
onClick={handleSendMessage}
156+
className="nx-cursor-pointer nx-w-[14px] nx-h-[14px] nx-ml-3 nx-my-auto"
157+
>
158+
<Image
159+
src="/Images/icons/send-icon.svg"
160+
alt="agentverse-img"
161+
width={14}
162+
height={14}
163+
/>
164+
</div>
165+
</div>
166+
</div>
167+
</div>
168+
</div>
169+
170+
)
171+
}
172+
173+
export default ChatWindow

components/chat/chat-with-us.tsx

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use client'
2+
import React, { useState } from 'react'
3+
import ChatWindow from './chat-window'
4+
// import Button from '../button/new-button'
5+
import Image from 'next/image'
6+
7+
const ChatWithUs = () => {
8+
const [isChatOpen, setIsChatOpen] = useState(false)
9+
10+
return (
11+
<>
12+
{/* Floating Button */}
13+
<button
14+
onClick={() => setIsChatOpen(!isChatOpen)}
15+
className="nx-fixed nx-bottom-12 nx-right-12 !nx-px-6 !nx-py-4 nx-z-40 nx-flex"
16+
>
17+
<Image
18+
src="/Images/icons/agent-icon.svg"
19+
alt="agentverse-img"
20+
width={23}
21+
height={24}
22+
className="nx-w-6 nx-h-6 nx-my-auto"
23+
/>
24+
Chat with us
25+
</button>
26+
27+
{/* Chat Window */}
28+
{isChatOpen && <ChatWindow onClose={() => setIsChatOpen(false)} />}
29+
</>
30+
)
31+
}
32+
33+
export default ChatWithUs

components/landing-page.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
} from "src/icons/shared-icons";
3131
import { useTheme } from "next-themes";
3232
import { ThemeMode } from "theme/fetch-ai-docs/helpers";
33+
import ChatWithUs from "./chat/chat-with-us";
3334

3435
const startingGuides = (theme) => [
3536
{
@@ -314,6 +315,7 @@ function LandingPage() {
314315
</p>
315316
<Products />
316317
</section>
318+
<ChatWithUs />
317319
</section>
318320
);
319321
}

pages/api/chat.ts

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// src/pages/api/chat.ts
2+
import type { NextApiRequest, NextApiResponse } from 'next'
3+
4+
export default async function handler(
5+
req: NextApiRequest,
6+
res: NextApiResponse
7+
) {
8+
if (req.method === 'POST') {
9+
const { message } = req.body
10+
11+
try {
12+
const response = await fetch(
13+
'https://chat-with-docs-rzql.onrender.com/echo',
14+
{
15+
method: 'POST',
16+
headers: { 'Content-Type': 'application/json' },
17+
body: JSON.stringify({ message: message }),
18+
}
19+
)
20+
const data = await response.json()
21+
return res.status(200).json({ reply: data.message })
22+
} catch (error) {
23+
console.log('error', error)
24+
return res
25+
.status(500)
26+
.json({ reply: 'Something went wrong. Please try again.' })
27+
}
28+
} else {
29+
res.setHeader('Allow', ['POST'])
30+
res.status(405).end(`Method ${req.method} Not Allowed`)
31+
}
32+
}

0 commit comments

Comments
 (0)