Spaces:
Build error
Build error
| import { useState, useRef, useEffect } from 'react'; | |
| import { Send, Lock, MoreVertical, Phone, ArrowLeft, ShieldCheck } from 'lucide-react'; | |
| import { cryptoUtils } from './EncryptionHelper'; | |
| export default function ChatWindow({ chat, onBack, onSendMessage }) { | |
| const [messageText, setMessageText] = useState(''); | |
| const [isEncrypting, setIsEncrypting] = useState(false); | |
| const messagesEndRef = useRef(null); | |
| const [localMessages, setLocalMessages] = useState(chat ? chat.messages : []); | |
| // Scroll to bottom on new message | |
| useEffect(() => { | |
| messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); | |
| }, [localMessages]); | |
| useEffect(() => { | |
| if(chat) setLocalMessages(chat.messages); | |
| }, [chat]); | |
| if (!chat) { | |
| return ( | |
| <div className="hidden md:flex flex-1 flex-col items-center justify-center bg-telegram-bg text-telegram-secondary"> | |
| <div className="bg-telegram-sidebar p-6 rounded-full mb-4"> | |
| <ShieldCheck size={48} className="text-telegram-accent" /> | |
| </div> | |
| <h2 className="text-xl font-medium text-white mb-2">SecureChat</h2> | |
| <p className="text-sm max-w-md text-center"> | |
| Select a chat to start messaging. <br/> | |
| Messages are protected with end-to-end encryption. | |
| </p> | |
| </div> | |
| ); | |
| } | |
| const handleSend = async () => { | |
| if (!messageText.trim()) return; | |
| setIsEncrypting(true); | |
| // Simulate encryption delay | |
| setTimeout(async () => { | |
| // In a real app, we encrypt with the recipient's public key | |
| // Here we use a mock shared secret for the demo | |
| const encryptedContent = await cryptoUtils.encrypt(messageText, "secure-chat-demo-key"); | |
| const newMessage = { | |
| id: Date.now(), | |
| text: messageText, // Storing plain text locally for UI demo, but conceptually this is encrypted payload | |
| encryptedPayload: encryptedContent, | |
| sender: 'me', | |
| timestamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }), | |
| status: 'sent' | |
| }; | |
| setLocalMessages(prev => [...prev, newMessage]); | |
| onSendMessage(chat.id, newMessage); | |
| setMessageText(''); | |
| setIsEncrypting(false); | |
| }, 600); | |
| }; | |
| const handleKeyDown = (e) => { | |
| if (e.key === 'Enter' && !e.shiftKey) { | |
| e.preventDefault(); | |
| handleSend(); | |
| } | |
| }; | |
| return ( | |
| <div className="flex-1 flex flex-col bg-[#0e1621] relative h-full w-full"> | |
| {/* Chat Header */} | |
| <div className="h-16 bg-telegram-sidebar flex items-center justify-between px-4 border-b border-gray-800 shrink-0"> | |
| <div className="flex items-center gap-3"> | |
| <button onClick={onBack} className="md:hidden text-telegram-secondary hover:text-white"> | |
| <ArrowLeft size={24} /> | |
| </button> | |
| <div className={`w-10 h-10 rounded-full flex items-center justify-center text-white font-bold ${chat.isGroup ? 'bg-purple-600' : 'bg-gradient-to-br from-blue-500 to-cyan-400'}`}> | |
| {chat.isGroup ? <span className="text-sm">Grp</span> : chat.name.charAt(0)} | |
| </div> | |
| <div> | |
| <h3 className="font-bold text-white text-sm md:text-base">{chat.name}</h3> | |
| <div className="flex items-center gap-1 text-xs text-telegram-accent"> | |
| <Lock size={10} /> | |
| <span>Encrypted</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div className="flex items-center gap-4 text-telegram-secondary"> | |
| <Phone size={20} className="hover:text-white cursor-pointer hidden sm:block" /> | |
| <MoreVertical size={20} className="hover:text-white cursor-pointer" /> | |
| </div> | |
| </div> | |
| {/* Messages Area */} | |
| <div className="flex-1 overflow-y-auto p-4 space-y-2 bg-telegram-bg bg-opacity-95"> | |
| {/* Encryption Notice */} | |
| <div className="flex justify-center my-4"> | |
| <div className="bg-telegram-message/50 text-telegram-secondary text-xs px-3 py-1.5 rounded-lg text-center max-w-xs border border-white/5"> | |
| <Lock size={10} className="inline mr-1 mb-0.5" /> | |
| Messages are end-to-end encrypted. No one outside of this chat, not even SecureChat, can read or listen to them. | |
| </div> | |
| </div> | |
| {localMessages.map((msg) => ( | |
| <div | |
| key={msg.id} | |
| className={`flex ${msg.sender === 'me' ? 'justify-end' : 'justify-start'} animate-fade-in`} | |
| > | |
| <div | |
| className={`message-bubble p-3 rounded-xl text-sm shadow-sm relative ${ | |
| msg.sender === 'me' | |
| ? 'bg-telegram-outgoing text-white rounded-br-none' | |
| : 'bg-telegram-incoming text-white rounded-bl-none' | |
| }`} | |
| > | |
| <p className="leading-relaxed">{msg.text}</p> | |
| <div className={`flex items-center justify-end gap-1 mt-1 text-[10px] ${msg.sender === 'me' ? 'text-blue-200' : 'text-gray-400'}`}> | |
| <span>{msg.timestamp}</span> | |
| {msg.sender === 'me' && ( | |
| <span className={msg.status === 'read' ? 'text-blue-400' : 'text-gray-300'}> | |
| {msg.status === 'read' ? '✓✓' : '✓'} | |
| </span> | |
| )} | |
| </div> | |
| </div> | |
| </div> | |
| ))} | |
| <div ref={messagesEndRef} /> | |
| </div> | |
| {/* Input Area */} | |
| <div className="p-3 bg-telegram-sidebar border-t border-gray-800 shrink-0"> | |
| <div className="flex items-end gap-2 max-w-4xl mx-auto"> | |
| <button className="p-2 text-telegram-secondary hover:text-white transition-colors"> | |
| <MoreVertical size={24} className="rotate-90" /> | |
| </button> | |
| <div className="flex-1 bg-telegram-bg rounded-2xl flex items-center border border-transparent focus-within:border-telegram-accent/50 transition-colors"> | |
| <textarea | |
| value={messageText} | |
| onChange={(e) => setMessageText(e.target.value)} | |
| onKeyDown={handleKeyDown} | |
| placeholder="Message" | |
| className="w-full bg-transparent text-white px-4 py-3 min-h-[44px] max-h-32 focus:outline-none resize-none text-sm" | |
| rows={1} | |
| /> | |
| </div> | |
| <button | |
| onClick={handleSend} | |
| disabled={!messageText.trim() || isEncrypting} | |
| className={`p-3 rounded-full transition-all duration-200 flex items-center justify-center ${ | |
| messageText.trim() | |
| ? 'bg-telegram-accent text-white hover:bg-blue-600 shadow-lg shadow-blue-900/20' | |
| : 'bg-telegram-bg text-telegram-secondary' | |
| }`} | |
| > | |
| {isEncrypting ? ( | |
| <div className="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin" /> | |
| ) : ( | |
| <Send size={20} className={messageText.trim() ? 'ml-0.5' : ''} /> | |
| )} | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } |