e2ee-chat
Version:
A simple realtime chat SDK for web and mobile apps using socket.io with support for end-to-end encryption and multi-tenant backend integration.
234 lines (216 loc) • 6.82 kB
JavaScript
// Example React component showing proper useChat integration
// This addresses the encryption issue between Flutter and React
import React, { useState, useEffect } from "react";
import { useChat } from "e2ee-chat";
const ChatComponent = () => {
const [messageInput, setMessageInput] = useState("");
const [debugInfo, setDebugInfo] = useState([]);
// Chat configuration - ensure these match your Flutter app
const chatConfig = {
serverUrl: "https://datahex-chat-server.azurewebsites.net",
roomId: "your-room-id", // Replace with actual room ID
userId: "649c0fee27d113dddba5491c", // Replace with actual user ID
userType: "admin",
secretKey: "shared-secret-123", // Must match Flutter
apiKey: "abc123-secret",
receiverId: "other-user-id", // Replace with actual receiver ID
};
// Enhanced message handler for debugging
const handleMessage = (message) => {
console.log("📥 New message received:", message);
// Add debug info
setDebugInfo((prev) => [
...prev,
{
type: "received",
timestamp: new Date().toLocaleTimeString(),
senderId: message.senderId,
encrypted: message.encryptedText,
decrypted: message.decryptedText,
hasError: !!message.decryptionError,
},
]);
};
// Use the updated chat hook
const {
messages,
sendMessage,
joined,
unreadCount,
markMessagesAsRead,
fetchUnreadCounts,
} = useChat({
...chatConfig,
onMessage: handleMessage,
});
// Handle sending messages
const handleSendMessage = (e) => {
e.preventDefault();
if (!messageInput.trim() || !joined) return;
console.log("📤 Sending message:", messageInput);
// Add debug info for sent message
setDebugInfo((prev) => [
...prev,
{
type: "sent",
timestamp: new Date().toLocaleTimeString(),
senderId: chatConfig.userId,
message: messageInput,
},
]);
sendMessage(messageInput, chatConfig.receiverId);
setMessageInput("");
};
// Debug effect to log encryption issues
useEffect(() => {
const errorMessages = messages.filter((msg) => msg.decryptionError);
if (errorMessages.length > 0) {
console.error("🚨 Found messages with decryption errors:", errorMessages);
}
}, [messages]);
return (
<div
className="chat-container"
style={{ maxWidth: "600px", margin: "0 auto", padding: "20px" }}
>
<div className="chat-header">
<h2>Chat Component</h2>
<div className="status-info">
<span>Status: {joined ? "🟢 Connected" : "🔴 Disconnected"}</span>
{unreadCount > 0 && <span> | Unread: {unreadCount}</span>}
</div>
</div>
{/* Debug Panel */}
<div
className="debug-panel"
style={{
background: "#f5f5f5",
padding: "10px",
marginBottom: "20px",
borderRadius: "5px",
fontSize: "12px",
}}
>
<h4>Debug Info:</h4>
<p>Room ID: {chatConfig.roomId}</p>
<p>User ID: {chatConfig.userId}</p>
<p>Secret Key: {chatConfig.secretKey}</p>
<p>Messages: {messages.length}</p>
<p>
Decryption Errors: {messages.filter((m) => m.decryptionError).length}
</p>
</div>
{/* Messages Display */}
<div
className="messages"
style={{
height: "400px",
overflowY: "auto",
border: "1px solid #ddd",
padding: "10px",
marginBottom: "20px",
}}
>
{messages.length === 0 ? (
<div style={{ textAlign: "center", color: "#888" }}>
No messages yet.{" "}
{joined ? "Start the conversation!" : "Connecting..."}
</div>
) : (
messages.map((msg, idx) => {
const isFromMe = msg.senderId === chatConfig.userId;
return (
<div
key={idx}
style={{
marginBottom: "10px",
textAlign: isFromMe ? "right" : "left",
}}
>
<div
style={{
display: "inline-block",
maxWidth: "70%",
padding: "8px 12px",
borderRadius: "18px",
backgroundColor: isFromMe ? "#007bff" : "#e9ecef",
color: isFromMe ? "white" : "black",
border: msg.decryptionError ? "2px solid red" : "none",
}}
>
<div>{msg.decryptedText}</div>
<div
style={{ fontSize: "10px", opacity: 0.7, marginTop: "4px" }}
>
{new Date(msg.timestamp).toLocaleTimeString()}
{msg.decryptionError && " ⚠️ Decryption Error"}
</div>
</div>
</div>
);
})
)}
</div>
{/* Message Input */}
<form
onSubmit={handleSendMessage}
style={{ display: "flex", gap: "10px" }}
>
<input
type="text"
value={messageInput}
onChange={(e) => setMessageInput(e.target.value)}
placeholder="Type your message..."
disabled={!joined}
style={{
flex: 1,
padding: "10px",
border: "1px solid #ddd",
borderRadius: "5px",
}}
/>
<button
type="submit"
disabled={!joined || !messageInput.trim()}
style={{
padding: "10px 20px",
backgroundColor: "#007bff",
color: "white",
border: "none",
borderRadius: "5px",
cursor: joined ? "pointer" : "not-allowed",
}}
>
Send
</button>
</form>
{/* Recent Debug Info */}
<div
className="recent-debug"
style={{
marginTop: "20px",
maxHeight: "200px",
overflowY: "auto",
fontSize: "11px",
backgroundColor: "#f8f9fa",
padding: "10px",
borderRadius: "5px",
}}
>
<h4>Recent Activity:</h4>
{debugInfo.slice(-10).map((info, idx) => (
<div key={idx} style={{ marginBottom: "5px" }}>
<strong>{info.timestamp}</strong> -{" "}
{info.type === "sent" ? "📤" : "📥"}
{info.type === "sent"
? ` Sent: "${info.message}"`
: ` From ${info.senderId}: "${info.decrypted}" ${
info.hasError ? "⚠️" : "✅"
}`}
</div>
))}
</div>
</div>
);
};
export default ChatComponent;