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};