+ {messages.map((message, index) => (
+
+
+ {index < messages.length - 1 && (
+
+ )}
+
+ ))}
+
+ )
+}
diff --git a/examples/online-store-customer-service/online-cs-chatbot/components/chat-message-actions.tsx b/examples/online-store-customer-service/online-cs-chatbot/components/chat-message-actions.tsx
new file mode 100755
index 00000000..37f68b2a
--- /dev/null
+++ b/examples/online-store-customer-service/online-cs-chatbot/components/chat-message-actions.tsx
@@ -0,0 +1,40 @@
+'use client'
+
+import { type Message } from 'ai'
+
+import { Button } from '@/components/ui/button'
+import { IconCheck, IconCopy } from '@/components/ui/icons'
+import { useCopyToClipboard } from '@/lib/hooks/use-copy-to-clipboard'
+import cn from 'mxcn'
+
+interface ChatMessageActionsProps extends React.ComponentProps<'div'> {
+ message: Message
+}
+
+export function ChatMessageActions({
+ message,
+ className,
+ ...props
+}: ChatMessageActionsProps) {
+ const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 2000 })
+
+ const onCopy = () => {
+ if (isCopied) return
+ copyToClipboard(message.content)
+ }
+
+ return (
+
+
+ {message.role === 'user' ? : }
+
+
+ {children}
+ },
+ code({ node, inline, className, children, ...props }) {
+ if (children.length) {
+ if (children[0] == 'β') {
+ return (
+ β
+ )
+ }
+
+ children[0] = (children[0] as string).replace('`β`', 'β')
+ }
+
+ const match = /language-(\w+)/.exec(className || '')
+
+ if (inline) {
+ return (
+
+ {children}
+
+ )
+ }
+
+ return (
+
+ )
+ }
+ }}
+ >
+ {message.content}
+
+
+
+
+ )
+}
diff --git a/examples/online-store-customer-service/online-cs-chatbot/components/chatbot-page.tsx b/examples/online-store-customer-service/online-cs-chatbot/components/chatbot-page.tsx
new file mode 100755
index 00000000..d79ee24e
--- /dev/null
+++ b/examples/online-store-customer-service/online-cs-chatbot/components/chatbot-page.tsx
@@ -0,0 +1,69 @@
+'use client'
+
+import { ChatList } from '@/components/chat-list'
+import { useChat, type Message } from 'ai/react'
+import cn from 'mxcn'
+import { useState } from 'react'
+import { toast } from 'sonner'
+import { ChatInput } from './chat-input'
+import { Opening } from './opening'
+import { Suggestions } from './suggestions'
+
+export interface ChatProps extends React.ComponentProps<'div'> {
+ id?: string // Optional: Thread ID if you want to persist the chat in a DB
+ initialMessages?: Message[] // Optional: Messages to pre-populate the chat from DB
+}
+
+export function Chatbot({ id, initialMessages, className }: ChatProps) {
+ const [threadId, setThreadId] = useState