Initial commit from remix

This commit is contained in:
gpt-engineer-app[bot]
2025-09-25 16:01:00 +00:00
commit 5ddc52658d
149 changed files with 32798 additions and 0 deletions

View File

@@ -0,0 +1,931 @@
import { useState, useEffect, useRef } from 'react';
import { useAuth } from '@/contexts/AuthContext';
import { useChat } from '@/hooks/useChat';
import { ScrollArea } from '@/components/ui/scroll-area';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';
import { Switch } from '@/components/ui/switch';
import { Label } from '@/components/ui/label';
import { toast } from 'sonner';
import {
MessageCircle,
Users,
UserCheck,
Bell,
Phone,
Video,
Paperclip,
Smile,
Send,
Search,
MoreVertical,
Plus,
X,
Settings,
UserPlus,
Circle,
Palette,
Edit3
} from 'lucide-react';
const Messages = () => {
const { user } = useAuth();
const [activeTab, setActiveTab] = useState('chats');
const [selectedChatId, setSelectedChatId] = useState<string | null>(null);
const [messageText, setMessageText] = useState('');
const [searchQuery, setSearchQuery] = useState('');
const [searchResults, setSearchResults] = useState<any[]>([]);
const [showUserSearch, setShowUserSearch] = useState(false);
const [showChatDetails, setShowChatDetails] = useState(true);
const [selectedColor, setSelectedColor] = useState('green');
const [isAutoBot, setIsAutoBot] = useState(true);
const [newNickname, setNewNickname] = useState('');
const messagesEndRef = useRef<HTMLDivElement>(null);
const {
chats,
messages,
onlineUsers,
loading,
error,
loadMessages,
sendMessage,
searchUsers,
createChat,
getChatById,
clearError
} = useChat();
const selectedChat = selectedChatId ? getChatById(selectedChatId) : chats[0];
// Auto-scroll to bottom of messages
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
};
useEffect(() => {
scrollToBottom();
}, [messages]);
// Load messages when chat is selected
useEffect(() => {
if (selectedChatId) {
loadMessages(selectedChatId);
}
}, [selectedChatId, loadMessages]);
// Auto-select first chat
useEffect(() => {
if (chats.length > 0 && !selectedChatId) {
setSelectedChatId(chats[0].id);
}
}, [chats, selectedChatId]);
// Handle search
const handleSearch = async (query: string) => {
setSearchQuery(query);
if (query.trim()) {
const results = await searchUsers(query);
setSearchResults(results);
} else {
setSearchResults([]);
}
};
// Handle send message
const handleSendMessage = async () => {
if (!messageText.trim() || !selectedChatId) return;
try {
await sendMessage(selectedChatId, messageText);
setMessageText('');
} catch (err) {
toast.error('Failed to send message');
}
};
// Handle create chat with user
const handleCreateChat = async (userId: string) => {
try {
const newChat = await createChat([userId]);
setSelectedChatId(newChat.id);
setShowUserSearch(false);
setSearchQuery('');
setSearchResults([]);
toast.success('Chat created successfully');
} catch (err) {
toast.error('Failed to create chat');
}
};
// Get notifications count
const getNotificationsCount = () => {
return chats.reduce((total, chat) => total + chat.unreadCount, 0);
};
// Format time
const formatTime = (timestamp: string) => {
const date = new Date(timestamp);
const now = new Date();
const diffInHours = (now.getTime() - date.getTime()) / (1000 * 60 * 60);
if (diffInHours < 24) {
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
} else if (diffInHours < 168) {
return date.toLocaleDateString([], { weekday: 'short' });
} else {
return date.toLocaleDateString();
}
};
return (
<div className="flex h-screen bg-background overflow-hidden">
{/* Chat Container */}
<div className="chat-container m-0 overflow-hidden relative rounded-lg flex w-full">
{/* Chat List Sidebar */}
<div className="chat-list__sidebar p-0 w-80 bg-background border-r border-border flex flex-col">
{/* Search Section */}
<div className="chat-list__search relative p-4 border-b border-border">
<form className="relative">
<Input
type="search"
className="pl-4 pr-16"
placeholder="People, Groups and Messages"
value={searchQuery}
onChange={(e) => handleSearch(e.target.value)}
/>
<button
type="button"
className="absolute right-12 top-1/2 transform -translate-y-1/2 p-1 hover:bg-accent rounded"
>
<Search className="h-5 w-5 text-muted-foreground" />
</button>
</form>
<button
className="absolute right-4 top-1/2 transform -translate-y-1/2 p-2 hover:bg-accent rounded"
onClick={() => setShowUserSearch(!showUserSearch)}
>
<Plus className="h-4 w-4" />
</button>
</div>
{/* Sidebar Tabs */}
<ul className="chat-list__sidebar-tabs flex border-b border-border bg-muted/30" role="tablist">
<li className="flex-1" role="presentation">
<button
className={`w-full p-3 text-center border-0 bg-transparent transition-colors ${
activeTab === 'chats'
? 'bg-background border-b-2 border-primary text-primary'
: 'text-muted-foreground hover:text-foreground'
}`}
onClick={() => setActiveTab('chats')}
role="tab"
aria-selected={activeTab === 'chats'}
>
<div className="relative inline-block">
<MessageCircle className="h-6 w-6 mx-auto mb-1" />
{chats.length > 0 && (
<div className="absolute -top-1 -right-1 bg-orange-500 text-white text-xs rounded-full h-5 w-5 flex items-center justify-center">
{chats.length}
</div>
)}
</div>
<span className="block text-xs font-semibold">Chats</span>
</button>
</li>
<li className="flex-1" role="presentation">
<button
className={`w-full p-3 text-center border-0 bg-transparent transition-colors ${
activeTab === 'online'
? 'bg-background border-b-2 border-primary text-primary'
: 'text-muted-foreground hover:text-foreground'
}`}
onClick={() => setActiveTab('online')}
role="tab"
aria-selected={activeTab === 'online'}
>
<Users className="h-6 w-6 mx-auto mb-1" />
<span className="block text-xs font-semibold">Online users</span>
</button>
</li>
<li className="flex-1" role="presentation">
<button
className={`w-full p-3 text-center border-0 bg-transparent transition-colors ${
activeTab === 'contacts'
? 'bg-background border-b-2 border-primary text-primary'
: 'text-muted-foreground hover:text-foreground'
}`}
onClick={() => setActiveTab('contacts')}
role="tab"
aria-selected={activeTab === 'contacts'}
>
<UserCheck className="h-6 w-6 mx-auto mb-1" />
<span className="block text-xs font-semibold">Contacts</span>
</button>
</li>
<li className="flex-1" role="presentation">
<button
className={`w-full p-3 text-center border-0 bg-transparent transition-colors ${
activeTab === 'notifications'
? 'bg-background border-b-2 border-primary text-primary'
: 'text-muted-foreground hover:text-foreground'
}`}
onClick={() => setActiveTab('notifications')}
role="tab"
aria-selected={activeTab === 'notifications'}
>
<div className="relative inline-block">
<Bell className="h-6 w-6 mx-auto mb-1" />
{getNotificationsCount() > 0 && (
<div className="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full h-5 w-5 flex items-center justify-center">
{getNotificationsCount()}
</div>
)}
</div>
<span className="block text-xs font-semibold">Notifications</span>
</button>
</li>
</ul>
{/* Tab Content */}
<div className="flex-1 overflow-hidden">
{/* Search Results */}
{showUserSearch && searchResults.length > 0 && (
<div className="p-3 border-b border-border">
<h3 className="text-sm font-medium mb-2">Search Results</h3>
{searchResults.map((user) => (
<div
key={user.id}
className="flex items-center p-2 hover:bg-accent rounded-lg cursor-pointer"
onClick={() => handleCreateChat(user.id)}
>
<Avatar className="h-8 w-8 mr-3">
<AvatarImage src={user.avatar} />
<AvatarFallback>{user.name?.charAt(0) || 'U'}</AvatarFallback>
</Avatar>
<div className="flex-1">
<p className="text-sm font-medium">{user.name}</p>
<p className="text-xs text-muted-foreground">{user.email}</p>
</div>
<Plus className="h-4 w-4 text-muted-foreground" />
</div>
))}
</div>
)}
{/* Chats Tab */}
{activeTab === 'chats' && (
<div className="chat-list__in relative">
<ScrollArea className="h-full">
<div className="p-4">
<h2 className="text-lg font-semibold mb-4">Recent Chat</h2>
<div className="nav chat-list space-y-1">
{chats.map((chat) => (
<div
key={chat.id}
className={`item-list item-list__chat flex items-start p-3 rounded-lg cursor-pointer transition-colors ${
selectedChatId === chat.id
? 'bg-primary/10 border-l-4 border-primary'
: 'hover:bg-accent unseen'
} ${chat.unreadCount > 0 ? 'unseen' : 'seen'}`}
onClick={() => setSelectedChatId(chat.id)}
>
<div className="avatar relative mr-3">
<Avatar className="h-12 w-12">
<AvatarImage src={chat.avatar} />
<AvatarFallback>{chat.name?.charAt(0) || 'C'}</AvatarFallback>
</Avatar>
{chat.online ? (
<div className="status online absolute bottom-0 right-0 h-3 w-3 bg-green-500 rounded-full border-2 border-background" />
) : (
<div className="status offline absolute bottom-0 right-0 h-3 w-3 bg-gray-400 rounded-full border-2 border-background" />
)}
{chat.unreadCount > 0 && (
<div className="new absolute -top-1 -left-1 h-6 w-6 bg-yellow-500 text-white text-xs rounded-full flex items-center justify-center">
{chat.unreadCount > 99 ? '99+' : chat.unreadCount}
</div>
)}
</div>
<div className="info-text flex-1 min-w-0">
<div className="flex items-center justify-between mb-1">
<h5 className="font-semibold text-sm truncate">{chat.name}</h5>
<span className="text-xs text-muted-foreground">
{chat.lastMessage ? formatTime(chat.lastMessage.timestamp) : ''}
</span>
</div>
<p className="text-xs text-muted-foreground truncate">
{chat.lastMessage?.content || 'No messages yet'}
</p>
</div>
</div>
))}
</div>
</div>
</ScrollArea>
</div>
)}
{/* Online Users Tab */}
{activeTab === 'online' && (
<div className="chat-list__in relative">
<ScrollArea className="h-full">
<div className="p-4">
<h2 className="text-lg font-semibold mb-4">Online Users</h2>
<div className="online-visitor space-y-2">
{onlineUsers.map((user) => (
<div
key={user.id}
className="visitor-history flex items-center p-3 hover:bg-accent rounded-lg cursor-pointer"
onClick={() => handleCreateChat(user.id)}
>
<div className="relative mr-3">
<Avatar className="h-10 w-10">
<AvatarImage src={user.avatar} />
<AvatarFallback>{user.name?.charAt(0) || 'U'}</AvatarFallback>
</Avatar>
<div className="absolute -bottom-1 -right-1 h-3 w-3 bg-green-500 rounded-full border-2 border-background" />
</div>
<div className="flex-1">
<div className="font-medium text-sm">{user.name}</div>
<div className="text-xs text-muted-foreground">{user.email}</div>
</div>
<MessageCircle className="h-4 w-4 text-muted-foreground" />
</div>
))}
</div>
</div>
</ScrollArea>
</div>
)}
{/* Contacts Tab */}
{activeTab === 'contacts' && (
<div className="chat-list__in relative">
<ScrollArea className="h-full">
<div className="p-4">
<h2 className="text-lg font-semibold mb-4">Contacts</h2>
<div className="nav contact-list space-y-1">
{chats.map((chat) => (
<div
key={chat.id}
className="item-list item-list__contact flex items-center p-3 hover:bg-accent rounded-lg cursor-pointer"
onClick={() => setSelectedChatId(chat.id)}
>
<div className="avatar relative mr-3">
<Avatar className="h-12 w-12">
<AvatarImage src={chat.avatar} />
<AvatarFallback>{chat.name?.charAt(0) || 'C'}</AvatarFallback>
</Avatar>
{chat.online ? (
<div className="status online absolute bottom-0 right-0 h-3 w-3 bg-green-500 rounded-full border-2 border-background" />
) : (
<div className="status offline absolute bottom-0 right-0 h-3 w-3 bg-gray-400 rounded-full border-2 border-background" />
)}
</div>
<div className="info-text flex-1">
<h5 className="font-semibold text-sm">{chat.name}</h5>
<p className="text-xs text-muted-foreground">
{chat.participants[0]?.email || 'No email'}
</p>
</div>
<div className="person-add">
<UserCheck className="h-5 w-5 text-green-500" />
</div>
</div>
))}
</div>
</div>
</ScrollArea>
</div>
)}
{/* Notifications Tab */}
{activeTab === 'notifications' && (
<div className="chat-list__in relative">
<ScrollArea className="h-full">
<div className="p-4">
<h2 className="text-lg font-semibold mb-4">Notifications</h2>
<div className="nav notification-list space-y-1">
{chats.filter(chat => chat.unreadCount > 0).map((chat) => (
<div
key={chat.id}
className="item-list item-list__contact flex items-center p-3 hover:bg-accent rounded-lg cursor-pointer"
onClick={() => setSelectedChatId(chat.id)}
>
<div className="avatar mr-3">
<Avatar className="h-12 w-12">
<AvatarImage src={chat.avatar} />
<AvatarFallback>{chat.name?.charAt(0) || 'C'}</AvatarFallback>
</Avatar>
</div>
<div className="info-text flex-1">
<h5 className="font-semibold text-sm">
{chat.name} sent you a message
</h5>
<p className="text-xs text-muted-foreground">
{chat.lastMessage ? formatTime(chat.lastMessage.timestamp) : ''}
</p>
</div>
</div>
))}
</div>
</div>
</ScrollArea>
</div>
)}
</div>
</div>
{/* Chat Area */}
<div className="flex-1 flex flex-col">
{selectedChat ? (
<>
{/* Chat Header */}
<div className="p-4 border-b border-border flex items-center justify-between">
<div className="flex items-center">
<Avatar className="h-10 w-10 mr-3">
<AvatarImage src={selectedChat.avatar} />
<AvatarFallback>{selectedChat.name?.charAt(0) || 'C'}</AvatarFallback>
</Avatar>
<div>
<h2 className="font-semibold">{selectedChat.name || 'Unknown'}</h2>
<div className="flex items-center text-sm text-muted-foreground">
<Circle className="h-2 w-2 fill-green-500 text-green-500 mr-1" />
{selectedChat.online ? 'Online' : 'Last seen 12 hour ago'}
</div>
</div>
</div>
<div className="flex items-center space-x-2">
<Button size="sm" variant="outline">
<Phone className="h-4 w-4" />
</Button>
<Button size="sm" variant="outline">
<Video className="h-4 w-4" />
</Button>
<Button size="sm" variant="outline">
<Settings className="h-4 w-4" />
</Button>
<Button size="sm" variant="outline">
<MoreVertical className="h-4 w-4" />
</Button>
</div>
</div>
{/* Messages */}
<ScrollArea className="flex-1">
<div className="message-content message-content-scroll bg-background">
<div className="relative">
{messages.length === 0 ? (
<div className="flex flex-col items-center justify-center h-full text-center p-8">
<div className="w-32 h-32 bg-orange-100 rounded-lg flex items-center justify-center mb-4">
<MessageCircle className="h-16 w-16 text-orange-500" />
</div>
<h3 className="text-lg font-medium mb-2">This chat is empty.</h3>
<p className="text-muted-foreground">Be the first one to start it.</p>
</div>
) : (
<>
{/* Date Divider */}
<div className="date flex items-center my-6">
<hr className="flex-1 border-border" />
<span className="px-4 text-sm text-muted-foreground bg-background">Yesterday</span>
<hr className="flex-1 border-border" />
</div>
{/* Sample Messages */}
<div className="message flex items-start mb-4 px-4">
<Avatar className="h-10 w-10 mr-3">
<AvatarImage src={selectedChat.avatar} />
<AvatarFallback>{selectedChat.name?.charAt(0) || 'U'}</AvatarFallback>
</Avatar>
<div className="text-main flex-1">
<span className="time-ago text-xs text-muted-foreground mb-2 block">09:46 AM</span>
<div className="text-group">
<div className="text bg-muted p-3 rounded-lg max-w-md">
<p className="text-sm">It is a long established fact that a reader will be.</p>
</div>
</div>
</div>
</div>
<div className="message me flex items-start mb-4 px-4 justify-end">
<div className="text-main flex-1 flex flex-col items-end">
<span className="time-ago text-xs text-muted-foreground mb-2 block">11:32 AM</span>
<div className="text-group me">
<div className="text me bg-primary text-primary-foreground p-3 rounded-lg max-w-md">
<p className="text-sm">By the readable content of a page when looking at its?</p>
</div>
</div>
</div>
</div>
<div className="message flex items-start mb-4 px-4">
<Avatar className="h-10 w-10 mr-3">
<AvatarImage src={selectedChat.avatar} />
<AvatarFallback>{selectedChat.name?.charAt(0) || 'U'}</AvatarFallback>
</Avatar>
<div className="text-main flex-1">
<span className="time-ago text-xs text-muted-foreground mb-2 block">02:56 PM</span>
<div className="text-group">
<div className="text bg-muted p-3 rounded-lg max-w-md">
<p className="text-sm">The point of using Lorem Ipsum is that it has a more-or-less normal distribution.</p>
</div>
</div>
</div>
</div>
<div className="message me flex items-start mb-4 px-4 justify-end">
<div className="text-main flex-1 flex flex-col items-end">
<span className="time-ago text-xs text-muted-foreground mb-2 block">10:21 PM</span>
<div className="text-group me space-y-2">
<div className="text me bg-primary text-primary-foreground p-3 rounded-lg max-w-md">
<p className="text-sm">Roger that boss!</p>
</div>
<div className="text me bg-primary text-primary-foreground p-3 rounded-lg max-w-md">
<p className="text-sm">Many desktop publishing packages and web page editors now use Lorem Ipsum as their!</p>
</div>
</div>
</div>
</div>
<div className="message flex items-start mb-4 px-4">
<Avatar className="h-10 w-10 mr-3">
<AvatarImage src={selectedChat.avatar} />
<AvatarFallback>{selectedChat.name?.charAt(0) || 'U'}</AvatarFallback>
</Avatar>
<div className="text-main flex-1">
<span className="time-ago text-xs text-muted-foreground mb-2 block">11:07 PM</span>
<div className="text-group">
<div className="text bg-muted p-3 rounded-lg max-w-md">
<p className="text-sm">Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like)!</p>
</div>
</div>
</div>
</div>
{/* Today Date Divider */}
<div className="date flex items-center my-6">
<hr className="flex-1 border-border" />
<span className="px-4 text-sm text-muted-foreground bg-background">Today</span>
<hr className="flex-1 border-border" />
</div>
{/* File Attachment Message */}
<div className="message flex items-start mb-4 px-4">
<Avatar className="h-10 w-10 mr-3">
<AvatarImage src={selectedChat.avatar} />
<AvatarFallback>{selectedChat.name?.charAt(0) || 'U'}</AvatarFallback>
</Avatar>
<div className="text-main flex-1">
<span className="time-ago text-xs text-muted-foreground mb-2 block">11:07 PM</span>
<div className="text-group">
<div className="text bg-muted p-3 rounded-lg max-w-md">
<div className="attachment flex items-center gap-3">
<Button size="sm" className="p-2 h-auto">
<Paperclip className="h-5 w-5" />
</Button>
<div className="file">
<h5 className="text-sm font-medium">
<a href="#" className="text-primary hover:underline">Documentations.pdf</a>
</h5>
<span className="text-xs text-muted-foreground">21kb Document</span>
</div>
</div>
</div>
</div>
</div>
</div>
{/* My Message with Read Receipt */}
<div className="message me flex items-start mb-4 px-4 justify-end">
<div className="text-main flex-1 flex flex-col items-end">
<span className="time-ago text-xs text-muted-foreground mb-2 flex items-center gap-1">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-check2-all" viewBox="0 0 16 16">
<path d="M12.354 4.354a.5.5 0 0 0-.708-.708L5 10.293 1.854 7.146a.5.5 0 1 0-.708.708l3.5 3.5a.5.5 0 0 0 .708 0l7-7zm-4.208 7-.896-.897.707-.707.543.543 6.646-6.647a.5.5 0 0 1 .708.708l-7 7a.5.5 0 0 1-.708 0z"></path>
<path d="m5.354 7.146.896.897-.707.707-.897-.896a.5.5 0 1 1 .708-.708"></path>
</svg>
10:21 PM
</span>
<div className="text-group me">
<div className="text me bg-primary text-primary-foreground p-3 rounded-lg max-w-md">
<p className="text-sm">If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing!</p>
</div>
</div>
</div>
</div>
{/* Typing Indicator */}
<div className="message flex items-start mb-4 px-4">
<Avatar className="h-10 w-10 mr-3">
<AvatarImage src={selectedChat.avatar} />
<AvatarFallback>{selectedChat.name?.charAt(0) || 'U'}</AvatarFallback>
</Avatar>
<div className="text-main flex-1">
<div className="text-group">
<div className="text typing bg-muted p-3 rounded-lg w-16">
<div className="wave flex items-center justify-center space-x-1">
<span className="dot w-2 h-2 bg-muted-foreground rounded-full animate-bounce [animation-delay:-0.3s]"></span>
<span className="dot w-2 h-2 bg-muted-foreground rounded-full animate-bounce [animation-delay:-0.15s]"></span>
<span className="dot w-2 h-2 bg-muted-foreground rounded-full animate-bounce"></span>
</div>
</div>
</div>
</div>
</div>
{/* Render dynamic messages */}
{messages.map((message) => (
<div
key={message.id}
className={`message flex items-start mb-4 px-4 ${message.isOwn ? 'me justify-end' : ''}`}
>
{!message.isOwn && (
<Avatar className="h-10 w-10 mr-3">
<AvatarImage src={message.senderAvatar} />
<AvatarFallback>{message.senderName?.charAt(0) || 'U'}</AvatarFallback>
</Avatar>
)}
<div className={`text-main flex-1 ${message.isOwn ? 'flex flex-col items-end' : ''}`}>
<span className="time-ago text-xs text-muted-foreground mb-2 block">{message.timestamp}</span>
<div className={`text-group ${message.isOwn ? 'me' : ''}`}>
<div className={`text p-3 rounded-lg max-w-md ${
message.isOwn
? 'me bg-primary text-primary-foreground'
: 'bg-muted'
}`}>
<p className="text-sm">{message.content}</p>
</div>
</div>
</div>
</div>
))}
<div ref={messagesEndRef} />
</>
)}
</div>
</div>
</ScrollArea>
{/* Message Input */}
<div className="p-4 border-t border-border">
<div className="flex items-center space-x-2">
<Button size="sm" variant="outline">
<Paperclip className="h-4 w-4" />
</Button>
<div className="flex-1">
<Input
placeholder="Type a message here..."
value={messageText}
onChange={(e) => setMessageText(e.target.value)}
onKeyPress={(e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
handleSendMessage();
}
}}
/>
</div>
<Button size="sm" variant="outline">
<Smile className="h-4 w-4" />
</Button>
<Button
size="sm"
onClick={handleSendMessage}
disabled={!messageText.trim()}
>
<Send className="h-4 w-4" />
</Button>
</div>
</div>
</>
) : (
<div className="flex-1 flex items-center justify-center">
<div className="text-center">
<MessageCircle className="h-16 w-16 text-muted-foreground mx-auto mb-4" />
<h3 className="text-lg font-medium mb-2">Select a conversation</h3>
<p className="text-muted-foreground">Choose from your existing conversations or start a new one</p>
</div>
</div>
)}
</div>
{/* Chat Details Sidebar - Right */}
{selectedChat && showChatDetails && (
<div className="chat-list__sidebar--right w-80 border-l border-border bg-background">
<ScrollArea className="h-full">
<div className="p-4">
{/* User Info */}
<div className="chat-user__info flex items-center mb-6">
<div className="avatar relative mr-3">
<Avatar className="h-12 w-12">
<AvatarImage src={selectedChat.avatar} />
<AvatarFallback>{selectedChat.name?.charAt(0) || 'C'}</AvatarFallback>
</Avatar>
<div className="status online absolute bottom-0 right-0 h-3 w-3 bg-green-500 rounded-full border-2 border-background" />
</div>
<div className="info-text flex-1">
<h5 className="text-lg font-semibold m-0">{selectedChat.name || 'Unknown'}</h5>
<p className="text-sm text-muted-foreground writing">{selectedChat.name} typing a message</p>
</div>
</div>
{/* Auto Bot/Manual Toggle */}
<div className="chatting_indicate bg-muted/50 p-4 rounded-lg mb-4">
<h5 className="text-base font-semibold mb-2">Conversation With Auto bot or manual</h5>
<p className="text-sm text-muted-foreground mb-4">Everyone in this conversation will see this.</p>
<div className="flex items-center justify-center space-x-4">
<Label
className={`cursor-pointer px-3 py-1 rounded ${isAutoBot ? 'bg-primary text-primary-foreground' : 'text-muted-foreground'}`}
htmlFor="autobot"
>
Auto bot
</Label>
<div className="toggle">
<Switch
id="switcher"
checked={!isAutoBot}
onCheckedChange={(checked) => setIsAutoBot(!checked)}
/>
</div>
<Label
className={`cursor-pointer px-3 py-1 rounded ${!isAutoBot ? 'bg-primary text-primary-foreground' : 'text-muted-foreground'}`}
htmlFor="manual"
>
Manual
</Label>
</div>
</div>
{/* Accordion */}
<Accordion type="single" collapsible defaultValue="change-color">
{/* User Details */}
<AccordionItem value="user-details">
<AccordionTrigger className="text-left">
<div className="flex items-center">
<UserCheck className="h-5 w-5 mr-2" />
User Details
</div>
</AccordionTrigger>
<AccordionContent>
<div className="user-info">
<div className="overflow-x-auto">
<table className="w-full border border-border rounded">
<tbody>
<tr className="border-b border-border">
<td className="user-info-first p-3 font-medium bg-muted/50">Name</td>
<td className="p-3">{selectedChat.name || 'Unknown'}</td>
</tr>
<tr className="border-b border-border">
<td className="user-info-first p-3 font-medium bg-muted/50">ID</td>
<td className="p-3">{selectedChat.id}</td>
</tr>
<tr className="border-b border-border">
<td className="user-info-first p-3 font-medium bg-muted/50">E-mail</td>
<td className="p-3">{selectedChat.participants[0]?.email || 'example@email.com'}</td>
</tr>
<tr className="border-b border-border">
<td className="user-info-first p-3 font-medium bg-muted/50">URL</td>
<td className="p-3">
<a href="#" className="text-primary hover:underline">https://easital.com/</a>
</td>
</tr>
<tr>
<td className="user-info-first p-3 font-medium bg-muted/50">Browser</td>
<td className="p-3">Chrome</td>
</tr>
</tbody>
</table>
</div>
</div>
</AccordionContent>
</AccordionItem>
{/* Edit Name */}
<AccordionItem value="edit-name">
<AccordionTrigger className="text-left">
<div className="flex items-center">
<Edit3 className="h-5 w-5 mr-2" />
Edit name
</div>
</AccordionTrigger>
<AccordionContent>
<div className="space-y-4">
<h5 className="font-semibold">Edit Nickname for {selectedChat.name}</h5>
<p className="text-sm text-muted-foreground">Everyone in this conversation will see this.</p>
<div className="space-y-3">
<Input
type="text"
placeholder={selectedChat.name || 'Enter nickname'}
value={newNickname}
onChange={(e) => setNewNickname(e.target.value)}
/>
<div className="flex justify-end">
<Button size="sm" variant="default">
Save
</Button>
</div>
</div>
</div>
</AccordionContent>
</AccordionItem>
{/* Change Color */}
<AccordionItem value="change-color">
<AccordionTrigger className="text-left">
<div className="flex items-center">
<Palette className="h-5 w-5 mr-2" />
Change color
</div>
</AccordionTrigger>
<AccordionContent>
<div className="space-y-4">
<h5 className="font-semibold">Pick a color for this conversation</h5>
<p className="text-sm text-muted-foreground">Everyone in this conversation will see this.</p>
<div className="radio-list change-bg-color grid grid-cols-5 gap-3">
{[
{ id: 'red', color: 'bg-red-500' },
{ id: 'green', color: 'bg-green-500' },
{ id: 'yellow', color: 'bg-yellow-500' },
{ id: 'orange', color: 'bg-orange-500' },
{ id: 'teal', color: 'bg-teal-500' },
{ id: 'blue', color: 'bg-blue-500' },
{ id: 'violet', color: 'bg-violet-500' },
{ id: 'purple', color: 'bg-purple-500' },
{ id: 'pink', color: 'bg-pink-500' },
{ id: 'gray', color: 'bg-gray-500' }
].map((colorOption) => (
<label
key={colorOption.id}
className="cursor-pointer"
htmlFor={colorOption.id}
>
<input
type="radio"
name="color"
id={colorOption.id}
value={colorOption.id}
checked={selectedColor === colorOption.id}
onChange={(e) => setSelectedColor(e.target.value)}
className="sr-only"
/>
<span
className={`block w-8 h-8 rounded-full ${colorOption.color} ${
selectedColor === colorOption.id ? 'ring-2 ring-offset-2 ring-primary' : ''
}`}
/>
</label>
))}
</div>
</div>
</AccordionContent>
</AccordionItem>
{/* Notifications */}
<AccordionItem value="notifications">
<AccordionTrigger className="text-left">
<div className="flex items-center">
<Bell className="h-5 w-5 mr-2" />
Notifications
</div>
</AccordionTrigger>
<AccordionContent>
<div className="space-y-4">
<h5 className="font-semibold">Conversation Notifications</h5>
<p className="text-sm text-muted-foreground">Everyone in this conversation will see this.</p>
<div className="space-y-4">
<div className="flex items-center space-x-2">
<Switch id="notifications1" />
<Label htmlFor="notifications1" className="text-sm">
Receive notifications for new messages
</Label>
</div>
<div className="flex items-center space-x-2">
<Switch id="notifications2" />
<Label htmlFor="notifications2" className="text-sm">
Receive notifications for reactions
</Label>
</div>
<div className="flex justify-end">
<Button size="sm" variant="default">
Done
</Button>
</div>
</div>
</div>
</AccordionContent>
</AccordionItem>
</Accordion>
</div>
</ScrollArea>
</div>
)}
</div>
</div>
);
};
export default Messages;