Spaces:
Build error
Build error
File size: 7,018 Bytes
f4ce85b 41cae12 f4ce85b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | 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>
);
} |