| | 'use client'; |
| |
|
| | import React, { useState, useEffect } from 'react'; |
| | import { |
| | ResizableHandle, |
| | ResizablePanel, |
| | ResizablePanelGroup, |
| | } from '@/components/ui/resizable'; |
| | import { cn } from '@/lib/utils'; |
| | import { Chat } from '@/lib/types'; |
| | import { ChatList } from './chat-list'; |
| | import { Message, UserData } from '@/lib/types'; |
| | import { MessageList } from './message-list'; |
| | import { MessageInput } from '../message-input'; |
| | import { ChatTopbar } from './chat-topbar'; |
| | import { Sidebar } from './sidebar'; |
| |
|
| | interface ChatLayoutProps { |
| | defaultLayout: number[] | undefined; |
| | navCollapsedSize: number; |
| | chats: Chat[]; |
| | loggedInUser: UserData; |
| | } |
| |
|
| | export function ChatLayout({ |
| | defaultLayout = [320, 1080], |
| | navCollapsedSize, |
| | chats: initialChats, |
| | loggedInUser, |
| | }: ChatLayoutProps) { |
| | const [isCollapsed, setIsCollapsed] = React.useState(false); |
| | const [selectedChat, setSelectedChat] = React.useState<Chat | null>(initialChats[0]); |
| | const [isMobile, setIsMobile] = useState(false); |
| | const [chats, setChats] = useState(initialChats); |
| | const [isTyping, setIsTyping] = useState(false); |
| |
|
| | useEffect(() => { |
| | const checkScreenWidth = () => { |
| | setIsMobile(window.innerWidth <= 768); |
| | }; |
| |
|
| | checkScreenWidth(); |
| | window.addEventListener('resize', checkScreenWidth); |
| |
|
| | return () => { |
| | window.removeEventListener('resize', checkScreenWidth); |
| | }; |
| | }, []); |
| |
|
| | const handleSendMessage = async (newMessageText: string) => { |
| | if (!selectedChat) return; |
| |
|
| | setIsTyping(true); |
| |
|
| | const themedResponse = { theme: undefined }; |
| |
|
| |
|
| | const newMessage: Message = { |
| | id: `msg-${Date.now()}`, |
| | sender: loggedInUser, |
| | text: newMessageText, |
| | timestamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }), |
| | theme: themedResponse.theme, |
| | }; |
| | |
| | |
| | setTimeout(() => { |
| | const otherUser = selectedChat.users.find(u => u.id !== loggedInUser.id); |
| | if (otherUser) { |
| | const responseMessage: Message = { |
| | id: `msg-${Date.now() + 1}`, |
| | sender: otherUser, |
| | text: `This is an automatic reply to: "${newMessageText}"`, |
| | timestamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }), |
| | }; |
| | setChats(prevChats => |
| | prevChats.map(chat => |
| | chat.id === selectedChat.id |
| | ? { ...chat, messages: [...chat.messages, newMessage, responseMessage] } |
| | : chat |
| | ) |
| | ); |
| | } |
| | setIsTyping(false); |
| | }, 1500); |
| |
|
| | setChats(prevChats => |
| | prevChats.map(chat => |
| | chat.id === selectedChat.id |
| | ? { ...chat, messages: [...chat.messages, newMessage] } |
| | : chat |
| | ) |
| | ); |
| | }; |
| | |
| | const currentChat = chats.find(c => c.id === selectedChat?.id); |
| |
|
| | return ( |
| | <div className="flex h-screen w-full"> |
| | <Sidebar isCollapsed={isCollapsed || isMobile} loggedInUser={loggedInUser} /> |
| | <div className="flex-1"> |
| | {isMobile ? ( |
| | <div className="flex h-full w-full"> |
| | {!selectedChat ? ( |
| | <ChatList |
| | chats={chats} |
| | selectedChat={selectedChat} |
| | onSelectChat={setSelectedChat} |
| | isMobile={isMobile} |
| | loggedInUser={loggedInUser} |
| | /> |
| | ) : ( |
| | <div className="flex flex-col w-full h-full"> |
| | <ChatTopbar selectedChat={selectedChat} onBack={() => setSelectedChat(null)} /> |
| | <MessageList |
| | messages={currentChat?.messages ?? []} |
| | loggedInUser={loggedInUser} |
| | isTyping={isTyping} |
| | /> |
| | {/* @ts-ignore */} |
| | <MessageInput onSendMessage={handleSendMessage} /> |
| | </div> |
| | )} |
| | </div> |
| | ) : ( |
| | <ResizablePanelGroup |
| | direction="horizontal" |
| | onLayout={(sizes: number[]) => { |
| | document.cookie = `react-resizable-panels:layout=${JSON.stringify( |
| | sizes |
| | )}`; |
| | }} |
| | className="h-full items-stretch" |
| | > |
| | <ResizablePanel |
| | defaultSize={defaultLayout[0]} |
| | collapsedSize={navCollapsedSize} |
| | collapsible={true} |
| | minSize={15} |
| | maxSize={25} |
| | onCollapse={() => { |
| | setIsCollapsed(true); |
| | document.cookie = `react-resizable-panels:collapsed=${JSON.stringify( |
| | true |
| | )}`; |
| | }} |
| | onExpand={() => { |
| | setIsCollapsed(false); |
| | document.cookie = `react-resizable-panels:collapsed=${JSON.stringify( |
| | false |
| | )}`; |
| | }} |
| | className={cn( |
| | isCollapsed && |
| | 'min-w-[50px] transition-all duration-300 ease-in-out' |
| | )} |
| | > |
| | <ChatList |
| | isCollapsed={isCollapsed} |
| | chats={chats} |
| | selectedChat={selectedChat} |
| | onSelectChat={setSelectedChat} |
| | loggedInUser={loggedInUser} |
| | /> |
| | </ResizablePanel> |
| | <ResizableHandle withHandle /> |
| | <ResizablePanel defaultSize={defaultLayout[1]} minSize={30}> |
| | {selectedChat ? ( |
| | <div className="flex flex-col h-full"> |
| | <ChatTopbar selectedChat={selectedChat} /> |
| | <MessageList |
| | messages={currentChat?.messages ?? []} |
| | loggedInUser={loggedInUser} |
| | isTyping={isTyping} |
| | /> |
| | {/* @ts-ignore */} |
| | <MessageInput onSendMessage={handleSendMessage} /> |
| | </div> |
| | ) : ( |
| | <div className="flex h-full items-center justify-center bg-muted/50"> |
| | <div className="text-center"> |
| | <h2 className="text-2xl font-bold">Select a chat to start messaging</h2> |
| | <p className="text-muted-foreground">Your conversations will appear here.</p> |
| | </div> |
| | </div> |
| | )} |
| | </ResizablePanel> |
| | </ResizablePanelGroup> |
| | )} |
| | </div> |
| | </div> |
| | ); |
| | } |
| |
|