import { useCallback, useEffect } from "react"; import { webrtcService } from "@/lib/webrtcService"; import { useFileTransferStore } from "@/stores/fileTransferStore"; import { fetchRoom, createRoom, checkRoom, leaveRoom } from "@/app/config/api"; import { debounce } from "lodash"; import type { Messages } from "@/types/messages"; function format_peopleMsg(template: string, peerCount: number) { return template.replace("{peerCount}", peerCount.toString()); } // Remove all WebRTC related props dependencies interface UseRoomManagerProps { messages: Messages | null; putMessageInMs: ( message: string, isShareEnd?: boolean, displayTimeMs?: number ) => void; } export function useRoomManager({ messages, putMessageInMs, }: UseRoomManagerProps) { // Get state from store const { shareRoomId, initShareRoomId, shareLink, shareRoomStatusText, retrieveRoomStatusText, activeTab, sharePeerCount, retrievePeerCount, senderDisconnected, isSenderInRoom, isReceiverInRoom, isAnyFileTransferring, setShareRoomId, setInitShareRoomId, setShareLink, setShareRoomStatusText, setRetrieveRoomStatusText, resetReceiverState, resetSenderApp, } = useFileTransferStore(); // Join room method - directly use webrtcService const joinRoom = useCallback( async (isSenderSide: boolean, roomId: string) => { if (!messages) return; try { // If it's the sender side and the room ID is not the initial ID, need to create the room first if ( isSenderSide && activeTab === "send" && roomId !== initShareRoomId ) { try { const success = await createRoom(roomId); if (!success) { putMessageInMs( messages.text.ClipboardApp.joinRoom.DuplicateMsg, isSenderSide ); return; } setShareRoomId(roomId); } catch (error) { putMessageInMs( messages.text.ClipboardApp.joinRoom.failMsg + ` (Create room error)`, isSenderSide ); return; } } // Determine the actual room ID to join const actualRoomId = isSenderSide && roomId !== initShareRoomId ? roomId : isSenderSide ? shareRoomId : roomId; // Directly call the service method without dependency injection await webrtcService.joinRoom(actualRoomId, isSenderSide); putMessageInMs( messages.text.ClipboardApp.joinRoom.successMsg, isSenderSide, 6000 ); // Update share link if (isSenderSide) { const link = `${window.location.origin}${window.location.pathname}?roomId=${actualRoomId}`; setShareLink(link); if (actualRoomId !== shareRoomId) { setShareRoomId(actualRoomId); } } } catch (error) { console.error("[RoomManager] Failed to join room:", error); let errorMsg = messages.text.ClipboardApp.joinRoom.failMsg; if (error instanceof Error) { errorMsg = error.message === "Room does not exist" ? messages.text.ClipboardApp.joinRoom.notExist : `${messages.text.ClipboardApp.joinRoom.failMsg} ${error.message}`; } putMessageInMs(errorMsg, isSenderSide); } }, [ messages, putMessageInMs, activeTab, initShareRoomId, shareRoomId, setShareRoomId, setShareLink, ] ); // Generate share link and broadcast const generateShareLinkAndBroadcast = useCallback(async () => { if (!messages || !shareRoomId) return; try { if (sharePeerCount === 0) { putMessageInMs(messages.text.ClipboardApp.waitting_tips, true); } else { // Directly call the service's broadcast method await webrtcService.broadcastDataToAllPeers(); } // Update share link const link = `${window.location.origin}${window.location.pathname}?roomId=${shareRoomId}`; setShareLink(link); } catch (error) { console.error("[RoomManager] Failed to generate share link:", error); putMessageInMs("Failed to generate share link", true); } }, [messages, putMessageInMs, shareRoomId, sharePeerCount, setShareLink]); // Receiver leave room const handleLeaveReceiverRoom = useCallback(async () => { if (!messages) return; // Check if files are transferring and show confirmation if (isAnyFileTransferring) { const confirmed = window.confirm(messages.text.ClipboardApp.confirmLeaveWhileTransferring); if (!confirmed) return; } try { // Call backend API to leave room if (webrtcService.receiver.roomId && webrtcService.receiver.peerId) { await leaveRoom( webrtcService.receiver.roomId, webrtcService.receiver.peerId ); } const message = isAnyFileTransferring ? messages.text.ClipboardApp.leaveWhileTransferringSuccess : messages.text.ClipboardApp.roomStatus.leftRoomMsg; putMessageInMs(message, false); // Reset receiver state (clears all as per requirement) resetReceiverState(); // Clean up WebRTC connection await webrtcService.leaveRoom(false); } catch (error) { console.error("[RoomManager] Receiver failed to leave room:", error); putMessageInMs("Failed to leave room", true); } }, [messages, putMessageInMs, resetReceiverState, isAnyFileTransferring]); // Sender reset app state const resetSenderAppState = useCallback(async () => { try { // 1. Clean up WebRTC connection await webrtcService.leaveRoom(true); // 2. Clear share link and progress resetSenderApp(); // 3. Fetch new room ID from backend const newRoomId = await fetchRoom(); setShareRoomId(newRoomId || ""); setInitShareRoomId(newRoomId || ""); } catch (error) { console.error("[RoomManager] Failed to reset sender state:", error); putMessageInMs("Failed to reset sender state", true); } }, [putMessageInMs, resetSenderApp, setShareRoomId, setInitShareRoomId]); // Sender leave room const handleLeaveSenderRoom = useCallback(async () => { if (!messages) return; // Check if files are transferring and show confirmation if (isAnyFileTransferring) { const confirmed = window.confirm(messages.text.ClipboardApp.confirmLeaveWhileTransferring); if (!confirmed) return; } try { // Call backend API to leave room if (webrtcService.sender.roomId && webrtcService.sender.peerId) { await leaveRoom( webrtcService.sender.roomId, webrtcService.sender.peerId ); } const message = isAnyFileTransferring ? messages.text.ClipboardApp.leaveWhileTransferringSuccess : messages.text.ClipboardApp.roomStatus.leftRoomMsg; putMessageInMs(message, true); // Reset sender state and get new room ID (keeps files as per requirement) await resetSenderAppState(); } catch (error) { console.error("[RoomManager] Sender failed to leave room:", error); putMessageInMs("Failed to leave room", true); } }, [messages, putMessageInMs, resetSenderAppState, isAnyFileTransferring]); // Room ID input processing const processRoomIdInput = useCallback( debounce(async (input: string) => { if (!input.trim() || !messages) return; try { const isValid = await checkRoom(input); if (isValid) { setShareRoomId(input); putMessageInMs( messages.text.ClipboardApp.roomCheck.available_msg, true ); } else { putMessageInMs( messages.text.ClipboardApp.roomCheck.notAvailable_msg, true ); } } catch (error) { console.error("[RoomManager] Failed to validate room:", error); putMessageInMs("Failed to validate room", true); } }, 750), [messages, putMessageInMs, setShareRoomId] ); // Initialize sender room ID useEffect(() => { if ( messages && putMessageInMs && !initShareRoomId && activeTab === "send" ) { const initNewRoom = async () => { try { const newRoomId = await fetchRoom(); setShareRoomId(newRoomId || ""); setInitShareRoomId(newRoomId || ""); } catch (err) { console.error("[RoomManager] Failed to fetch initial room:", err); const errorMsg = messages.text?.ClipboardApp?.fetchRoom_err || "Failed to fetch room ID"; putMessageInMs(errorMsg, true); } }; initNewRoom(); } }, [ messages, putMessageInMs, initShareRoomId, activeTab, setShareRoomId, setInitShareRoomId, ]); // Room status text update useEffect(() => { if (!messages) { if (activeTab === "send") setShareRoomStatusText(""); else setRetrieveRoomStatusText(""); return; } const isInRoom = activeTab === "send" ? isSenderInRoom : isReceiverInRoom; const currentPeerCount = activeTab === "send" ? sharePeerCount : retrievePeerCount; let statusText = ""; if (!isInRoom) { statusText = activeTab === "retrieve" ? messages.text.ClipboardApp.roomStatus.receiverEmptyMsg : messages.text.ClipboardApp.roomStatus.senderEmptyMsg; } else if (currentPeerCount === 0) { statusText = messages.text.ClipboardApp.roomStatus.onlyOneMsg; } else { statusText = activeTab === "send" ? format_peopleMsg( messages.text.ClipboardApp.roomStatus.peopleMsg_template, currentPeerCount + 1 ) : messages.text.ClipboardApp.roomStatus.connected_dis; } if (activeTab === "send") setShareRoomStatusText(statusText); else setRetrieveRoomStatusText(statusText); }, [ activeTab, sharePeerCount, retrievePeerCount, messages, senderDisconnected, isSenderInRoom, isReceiverInRoom, setShareRoomStatusText, setRetrieveRoomStatusText, ]); return { // State shareRoomId, initShareRoomId, shareLink, shareRoomStatusText, retrieveRoomStatusText, sharePeerCount, retrievePeerCount, senderDisconnected, isSenderInRoom, isReceiverInRoom, // Methods processRoomIdInput, joinRoom, generateShareLinkAndBroadcast, handleLeaveReceiverRoom, handleLeaveSenderRoom, }; }