class ChatMessaging {
constructor(socket) {
this.socket = socket;
this.currentPartner = null;
this.messages = [];
this.setupListeners();
}
setupListeners() {
// Chat started
this.socket.on('chatStart', ({ withVideo, partnerId }) => {
this.currentPartner = partnerId;
this.messages = [];
this.enableChat();
console.log(`Chat started with ${partnerId}`);
});
// Message received
this.socket.on('message', (messageData) => {
this.handleMessage(messageData);
});
// Partner left
this.socket.on('partnerLeft', ({ partnerId }) => {
this.handlePartnerLeft(partnerId);
});
// Waiting for partner
this.socket.on('waiting', () => {
this.disableChat();
this.showWaitingMessage();
});
}
handleMessage({ sender, text, senderEmail, timestamp }) {
const isOwn = sender === this.socket.id;
// Store message
this.messages.push({
sender,
text,
senderEmail,
timestamp,
isOwn
});
// Display message
this.displayMessage(text, isOwn, senderEmail, timestamp);
// Play notification sound for partner messages
if (!isOwn) {
this.playNotificationSound();
}
}
sendMessage(text) {
if (!this.currentPartner) {
console.error('No active chat');
return;
}
if (text.trim().length === 0) {
return;
}
// Limit message length
if (text.length > 1000) {
alert('Message too long (max 1000 characters)');
return;
}
this.socket.emit('sendMessage', text);
}
displayMessage(text, isOwn, email, timestamp) {
const container = document.getElementById('messages-container');
const messageEl = document.createElement('div');
messageEl.className = `message ${isOwn ? 'own' : 'partner'}`;
const time = new Date(timestamp).toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit'
});
messageEl.innerHTML = `
<div class="message-bubble">
<div class="message-header">
<span class="sender">${isOwn ? 'You' : email}</span>
<span class="timestamp">${time}</span>
</div>
<div class="message-content">${this.escapeHtml(text)}</div>
</div>
`;
container.appendChild(messageEl);
// Auto-scroll to bottom
container.scrollTop = container.scrollHeight;
}
handlePartnerLeft(partnerId) {
console.log(`Partner ${partnerId} left`);
this.currentPartner = null;
this.disableChat();
// Show system message
const container = document.getElementById('messages-container');
const systemMsg = document.createElement('div');
systemMsg.className = 'system-message';
systemMsg.textContent = 'Your chat partner has left';
container.appendChild(systemMsg);
// Show options
this.showPostChatOptions();
}
enableChat() {
const input = document.getElementById('message-input');
const sendBtn = document.getElementById('send-btn');
const nextBtn = document.getElementById('next-btn');
input.disabled = false;
sendBtn.disabled = false;
nextBtn.disabled = false;
input.focus();
}
disableChat() {
const input = document.getElementById('message-input');
const sendBtn = document.getElementById('send-btn');
input.disabled = true;
sendBtn.disabled = true;
input.value = '';
}
showWaitingMessage() {
const container = document.getElementById('messages-container');
container.innerHTML = '<div class="system-message">Looking for someone to chat with...</div>';
}
showPostChatOptions() {
const container = document.getElementById('chat-actions');
container.innerHTML = `
<button onclick="chatManager.findNewChat()">Find New Partner</button>
<button onclick="chatManager.exportChatHistory()">Save Chat</button>
`;
}
findNewChat() {
const withVideo = confirm('Start video chat?');
this.socket.emit('findChat', null, withVideo);
}
exportChatHistory() {
const text = this.messages.map(msg =>
`[${new Date(msg.timestamp).toLocaleString()}] ${msg.senderEmail}: ${msg.text}`
).join('\n');
const blob = new Blob([text], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `chat-${Date.now()}.txt`;
a.click();
URL.revokeObjectURL(url);
}
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
playNotificationSound() {
// Optional: Play sound for new messages
const audio = new Audio('/sounds/notification.mp3');
audio.play().catch(e => console.log('Could not play sound:', e));
}
}
// Initialize
const socket = io('http://localhost:3001', {
auth: { token: localStorage.getItem('authToken') }
});
const chatManager = new ChatMessaging(socket);
// UI Event Handlers
document.getElementById('message-input').addEventListener('keypress', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
const text = e.target.value;
chatManager.sendMessage(text);
e.target.value = '';
}
});
document.getElementById('send-btn').addEventListener('click', () => {
const input = document.getElementById('message-input');
chatManager.sendMessage(input.value);
input.value = '';
});
document.getElementById('next-btn').addEventListener('click', () => {
if (confirm('End this chat and find a new partner?')) {
socket.emit('next');
}
});