Separate concerns - move Socket.IO and form logic from components to reusable hooks New Hooks: - useForm: Generic form state management with handleChange/handleSubmit/reset - useEventChat: Extract Socket.IO logic from EventChatPage (156 lines) * Manages messages, active users, connection state * Handles send message, load older messages with scroll preservation * Real-time updates via Socket.IO event listeners - useMatchChat: Extract Socket.IO logic from MatchChatPage (115 lines) * Manages 1:1 chat messages and connection * Loads message history from API * Real-time message sync via Socket.IO Pages Refactored: - EventChatPage: 661 → 564 lines (-97 lines, -15%) - MatchChatPage: 517 → 446 lines (-71 lines, -14%) Benefits: - Cleaner component code - UI separated from business logic - Reusable hooks can be used in other components - Easier to test - hooks can be unit tested independently - Better code organization - single responsibility principle - 168 lines eliminated from pages, moved to 271 lines of reusable hooks Phase 2 Total: -168 lines Grand Total (Phase 1+2): -389 lines (-12%)
123 lines
2.9 KiB
JavaScript
123 lines
2.9 KiB
JavaScript
import { useState, useEffect } from 'react';
|
|
import { connectSocket, getSocket } from '../services/socket';
|
|
import { matchesAPI } from '../services/api';
|
|
|
|
/**
|
|
* Custom hook for Match Chat functionality (1:1 private chat)
|
|
* Extracts Socket.IO logic and chat state management from MatchChatPage
|
|
*
|
|
* @param {object} match - Match object with id and partner info
|
|
* @param {number} userId - Current user ID
|
|
* @param {string} slug - Match slug for API calls
|
|
* @returns {object} Chat state and handlers
|
|
*
|
|
* @example
|
|
* const {
|
|
* messages,
|
|
* isConnected,
|
|
* sendMessage,
|
|
* newMessage,
|
|
* setNewMessage
|
|
* } = useMatchChat(match, user.id, slug);
|
|
*/
|
|
const useMatchChat = (match, userId, slug) => {
|
|
// Chat state
|
|
const [messages, setMessages] = useState([]);
|
|
const [newMessage, setNewMessage] = useState('');
|
|
const [isConnected, setIsConnected] = useState(false);
|
|
|
|
// Load message history from API
|
|
useEffect(() => {
|
|
const loadMessages = async () => {
|
|
if (!match || !slug) return;
|
|
|
|
try {
|
|
const result = await matchesAPI.getMatchMessages(slug);
|
|
setMessages(result.data || []);
|
|
} catch (error) {
|
|
console.error('Failed to load messages:', error);
|
|
}
|
|
};
|
|
loadMessages();
|
|
}, [match, slug]);
|
|
|
|
// Socket.IO connection and event listeners
|
|
useEffect(() => {
|
|
// Wait for match to be loaded
|
|
if (!match) return;
|
|
|
|
// Connect to Socket.IO
|
|
const socket = connectSocket();
|
|
|
|
if (!socket) {
|
|
console.error('Failed to connect to socket');
|
|
return;
|
|
}
|
|
|
|
// Helper to join match room
|
|
const joinMatchRoom = () => {
|
|
setIsConnected(true);
|
|
socket.emit('join_match_room', { matchId: match.id });
|
|
console.log(`Joined match room ${match.id}`);
|
|
};
|
|
|
|
// Socket event listeners
|
|
socket.on('connect', joinMatchRoom);
|
|
|
|
socket.on('disconnect', () => {
|
|
setIsConnected(false);
|
|
});
|
|
|
|
// Receive messages
|
|
socket.on('match_message', (message) => {
|
|
setMessages((prev) => [...prev, message]);
|
|
});
|
|
|
|
// Join immediately if already connected
|
|
if (socket.connected) {
|
|
joinMatchRoom();
|
|
}
|
|
|
|
// Cleanup
|
|
return () => {
|
|
socket.off('connect', joinMatchRoom);
|
|
socket.off('disconnect');
|
|
socket.off('match_message');
|
|
};
|
|
}, [match, userId]);
|
|
|
|
/**
|
|
* Send a message to the match chat
|
|
*/
|
|
const sendMessage = (e) => {
|
|
e.preventDefault();
|
|
if (!newMessage.trim() || !match) return;
|
|
|
|
const socket = getSocket();
|
|
if (!socket || !socket.connected) {
|
|
alert('Not connected to chat server');
|
|
return;
|
|
}
|
|
|
|
// Send message via Socket.IO using numeric match ID
|
|
socket.emit('send_match_message', {
|
|
matchId: match.id,
|
|
content: newMessage,
|
|
});
|
|
|
|
setNewMessage('');
|
|
};
|
|
|
|
return {
|
|
// State
|
|
messages,
|
|
newMessage,
|
|
setNewMessage,
|
|
isConnected,
|
|
// Actions
|
|
sendMessage
|
|
};
|
|
};
|
|
|
|
export default useMatchChat;
|