1import React from 'react';
2import {ChatProvider, Frame, Launcher, useChat} from '@booper/react';
3
4const Chat = () => {
5 const scrollRef = React.useRef<HTMLDivElement | null>(null);
6 const [content, setMessageContent] = React.useState('');
7 const {messages, open, toggle, send, refresh} = useChat();
8
9 React.useEffect(() => {
10 scrollRef.current?.scrollIntoView();
11 }, [messages.length]);
12
13 const handleSendMessage = async (e: React.FormEvent<HTMLFormElement>) => {
14 e.preventDefault();
15 setMessageContent('');
16 await send({content});
17 await refresh();
18 };
19
20 return (
21 <>
22 <Frame open={open}>
23 <div className="flex h-[70vh] w-96 flex-col overflow-hidden rounded-lg border bg-white text-gray-900 shadow-lg">
24 <div className="bg-gradient-to-r from-gray-900 via-gray-800 to-gray-700 px-4 py-4 text-gray-100 dark:border-gray-700">
25 <h1 className="mt-1 text-xl font-bold text-white">Hi there ๐</h1>
26 <p className="text-sm text-gray-200">
27 Let us know if you have any questions!
28 </p>
29 </div>
30 <ul className="flex-1 overflow-scroll border-b p-4">
31 {messages.map((message, index) => {
32 const isMe = message.source === 'chat';
33 const next = messages[index + 1];
34 const isNextSame = next && next.source === message.source;
35
36 return (
37 <li
38 key={index}
39 className={`flex ${
40 isMe ? 'justify-end pl-8' : 'justify-start pr-8'
41 } ${isNextSame ? 'mb-1' : 'mb-3'}`}
42 >
43 <div
44 className={`rounded-md border px-3 py-2 text-sm ${
45 isMe ? 'bg-gray-800 text-white' : 'bg-gray-200'
46 }`}
47 >
48 {message.content}
49 </div>
50 </li>
51 );
52 })}
53 <div ref={scrollRef} />
54 </ul>
55 <form onSubmit={handleSendMessage}>
56 <input
57 className="w-full border-none bg-white p-4 text-sm outline-none"
58 placeholder="Type your message..."
59 value={content}
60 onChange={(e) => setMessageContent(e.target.value)}
61 />
62 </form>
63 </div>
64 </Frame>
65 <Launcher open={open}>
66 <button
67 className="inline-flex h-10 w-10 items-center justify-center rounded-full bg-gray-800 text-sm font-medium text-gray-50 transition-colors hover:bg-gray-800/90 disabled:pointer-events-none disabled:opacity-70"
68 onClick={toggle}
69 >
70 {open ? (
71 <XIcon className="h-5 w-5 animate-in fade-in-0 duration-200" />
72 ) : (
73 <ChatIcon className="h-5 w-5 animate-in fade-in-0 duration-200" />
74 )}
75 </button>
76 </Launcher>
77 </>
78 );
79};
80
81export default function App() {
82 return (
83 <ChatProvider appId={YOUR_APP_ID}>
84 <Chat />
85 </ChatProvider>
86 );
87};