stock / src /pages /Messages.tsx
Zelyanoth's picture
Upload 101 files
24d40b9 verified
import { useState } from "react";
import { Send, Search } from "lucide-react";
import AppLayout from "@/components/layout/AppLayout";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Avatar } from "@/components/ui/avatar";
import { ScrollArea } from "@/components/ui/scroll-area";
import { cn } from "@/lib/utils";
import { motion } from "framer-motion";
import { ThemeToggle } from "@/components/theme/ThemeToggle";
// Sample data for messages
const initialContacts = [
{ id: 1, name: "AI Assistant", avatar: "A", lastMessage: "How can I help with your finances?", time: "10:30 AM", unread: 2 },
{ id: 2, name: "Budget Bot", avatar: "B", lastMessage: "Your weekly spending report is ready", time: "Yesterday", unread: 0 },
{ id: 3, name: "Investment Advisor", avatar: "I", lastMessage: "Consider these stocks for your portfolio", time: "Yesterday", unread: 1 },
{ id: 4, name: "Expense Tracker", avatar: "E", lastMessage: "You've exceeded your dining budget", time: "Monday", unread: 0 },
{ id: 5, name: "Financial Coach", avatar: "F", lastMessage: "Let's review your saving goals", time: "08/12/23", unread: 0 },
];
const initialMessages = [
{ id: 1, sender: "client", text: "Hello! I need some help understanding my recent transactions.", time: "10:30 AM" },
{ id: 2, sender: "me", text: "Hi there! I'd be happy to help you analyze your spending patterns. What specifically would you like to know?", time: "10:32 AM" },
{ id: 3, sender: "client", text: "I noticed some unusual activity in my account", time: "10:33 AM" },
{ id: 4, sender: "me", text: "I can check that for you. Could you tell me which transactions look suspicious?", time: "10:35 AM" },
{ id: 5, sender: "me", text: "Based on your spending history, the transaction at 'Tech Store' for $349.99 is unusual for you.", time: "10:36 AM" },
{ id: 6, sender: "client", text: "Yes, that's the one I was concerned about. I don't remember making that purchase.", time: "10:38 AM" },
];
const Messages = () => {
const [contacts, setContacts] = useState(initialContacts);
const [selectedContact, setSelectedContact] = useState(initialContacts[0]);
const [messages, setMessages] = useState(initialMessages);
const [newMessage, setNewMessage] = useState("");
const [searchTerm, setSearchTerm] = useState("");
const handleSendMessage = () => {
if (newMessage.trim() === "") return;
const message = {
id: messages.length + 1,
sender: "me",
text: newMessage,
time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
};
setMessages([...messages, message]);
setNewMessage("");
};
const filteredContacts = contacts.filter(contact =>
contact.name.toLowerCase().includes(searchTerm.toLowerCase())
);
return (
<AppLayout>
<div className="max-w-6xl mx-auto h-full p-4">
<div className="flex justify-between items-center mb-4">
<h1 className="text-xl font-bold text-slate-800 dark:text-white">Messages</h1>
<ThemeToggle />
</div>
<div className="flex h-[calc(100vh-180px)] rounded-2xl overflow-hidden bg-white/80 dark:bg-violet-darker/90 backdrop-blur-lg border border-slate-200 dark:border-violet-muted/20 shadow-lg">
{/* Contacts sidebar */}
<div className="w-full max-w-xs border-r border-slate-200 dark:border-violet-muted/20 hidden md:flex flex-col">
<div className="p-3 border-b border-slate-200 dark:border-violet-muted/20">
<div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-slate-400 dark:text-violet-light/50 h-4 w-4" />
<Input
placeholder="Search contacts..."
className="pl-10 bg-slate-50 dark:bg-violet-darker border-slate-200 dark:border-violet-muted/30 text-slate-800 dark:text-white"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
</div>
</div>
<ScrollArea className="flex-1">
{filteredContacts.map(contact => (
<div
key={contact.id}
className={cn(
"p-3 flex items-center gap-3 cursor-pointer hover:bg-slate-50 dark:hover:bg-violet-muted/10 transition-colors",
selectedContact.id === contact.id ? "bg-slate-50 dark:bg-violet-muted/10" : ""
)}
onClick={() => setSelectedContact(contact)}
>
<Avatar className={cn(
"h-10 w-10 text-white",
selectedContact.id === contact.id
? "bg-primary dark:bg-violet"
: "bg-blue-600 dark:bg-violet-muted"
)}>
<div>{contact.avatar}</div>
</Avatar>
<div className="flex-1 min-w-0">
<div className="flex justify-between items-center">
<span className="font-medium truncate text-slate-800 dark:text-white">{contact.name}</span>
<span className="text-xs text-slate-500 dark:text-violet-light/70">{contact.time}</span>
</div>
<p className="text-sm text-slate-500 dark:text-violet-light/50 truncate">{contact.lastMessage}</p>
</div>
{contact.unread > 0 && (
<div className="bg-blue-600 dark:bg-violet text-white text-xs rounded-full h-5 w-5 flex items-center justify-center">
{contact.unread}
</div>
)}
</div>
))}
</ScrollArea>
</div>
{/* Chat area */}
<div className="flex-1 flex flex-col">
<div className="p-3 border-b border-slate-200 dark:border-violet-muted/20 flex items-center gap-3">
<Avatar className="h-8 w-8 bg-blue-600 dark:bg-violet text-white md:hidden">
<div>{selectedContact.avatar}</div>
</Avatar>
<div>
<h3 className="font-medium text-slate-800 dark:text-white">{selectedContact.name}</h3>
</div>
</div>
<ScrollArea className="flex-1 p-4">
<div className="space-y-4">
{messages.map((message, index) => (
<motion.div
key={message.id}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, delay: index * 0.1 }}
className={cn(
"flex",
message.sender === "me" ? "justify-end" : "justify-start"
)}
>
<div
className={cn(
"max-w-[80%] p-3 rounded-2xl shadow-sm",
message.sender === "me"
? "bg-blue-600 dark:bg-violet text-white rounded-tr-none"
: "bg-slate-100 dark:bg-violet-muted/30 text-slate-800 dark:text-white rounded-tl-none"
)}
>
<p>{message.text}</p>
<span className={cn(
"text-xs block mt-1",
message.sender === "me"
? "text-white/70"
: "text-slate-500 dark:text-violet-light/70"
)}>
{message.time}
</span>
</div>
</motion.div>
))}
</div>
</ScrollArea>
<div className="p-3 border-t border-slate-200 dark:border-violet-muted/20 flex items-center gap-2">
<Input
placeholder="Type a message..."
value={newMessage}
onChange={(e) => setNewMessage(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter") {
handleSendMessage();
}
}}
className="flex-1 bg-slate-50 dark:bg-violet-darker border-slate-200 dark:border-violet-muted/30 text-slate-800 dark:text-white"
/>
<Button size="icon" className="bg-blue-600 hover:bg-blue-700 dark:bg-violet dark:hover:bg-violet-dark" onClick={handleSendMessage}>
<Send size={18} />
</Button>
</div>
</div>
</div>
</div>
</AppLayout>
);
};
export default Messages;