import { useState, useEffect, useCallback } from 'react'; import PartySocket from 'partysocket'; import { GameState } from '../types'; import { useAuth, useUser } from '@clerk/clerk-react'; const PARTY_HOST = import.meta.env.DEV ? 'localhost:1999' : 'bozo-clicker.your-username.partykit.dev'; export function usePartyKit() { const { getToken, isLoaded, isSignedIn } = useAuth(); const { user } = useUser(); const [gameState, setGameState] = useState(null); const [socket, setSocket] = useState(null); // Generate a persistent guest ID if the user is not signed in const [guestId] = useState(() => { let storedGuestId = localStorage.getItem('bozo_guest_id'); if (!storedGuestId) { storedGuestId = `guest_${Math.random().toString(36).substring(2, 15)}`; localStorage.setItem('bozo_guest_id', storedGuestId); } return storedGuestId; }); const [guestName] = useState(() => { let storedGuestName = localStorage.getItem('bozo_guest_name'); if (!storedGuestName) { storedGuestName = `Guest${Math.floor(Math.random() * 10000)}`; localStorage.setItem('bozo_guest_name', storedGuestName); } return storedGuestName; }); useEffect(() => { // Always attempt to connect the socket const ws = new PartySocket({ host: PARTY_HOST, room: 'bozo-clicker' }); ws.onopen = async () => { if (isLoaded && isSignedIn && user) { const token = await getToken(); ws.send(JSON.stringify({ type: 'user-join', userId: user.id, userName: user.username || user.fullName || user.emailAddresses[0].emailAddress, token })); } else { // If not signed in, send a generic user-join message for guest ws.send(JSON.stringify({ type: 'user-join', userId: guestId, userName: guestName })); } }; ws.onmessage = (event) => { const data = JSON.parse(event.data); if (data.type === 'game-state') { setGameState(data.state); } }; setSocket(ws); return () => { ws.close(); }; }, [isLoaded, guestId, guestName]); // Removed isSignedIn, user, getToken from dependencies const sendClick = useCallback(async () => { if (socket && isSignedIn && user) { const token = await getToken(); socket.send(JSON.stringify({ type: 'click', userId: user.id, userName: user.username || user.fullName || user.emailAddresses[0].emailAddress, token })); } }, [socket, isSignedIn, user, getToken]); const purchaseUpgrade = useCallback(async (upgradeId: string) => { if (socket && isSignedIn && user) { const token = await getToken(); socket.send(JSON.stringify({ type: 'purchase-upgrade', userId: user.id, upgradeId, token })); } }, [socket, isSignedIn, user, getToken]); const sendMascotClickBonus = useCallback(async (multiplierBonus: number) => { if (socket && isSignedIn && user) { const token = await getToken(); socket.send(JSON.stringify({ type: 'apply-multiplier-bonus', userId: user.id, userName: user.username || user.fullName || user.emailAddresses[0].emailAddress, token, multiplierBonus })); } }, [socket, isSignedIn, user, getToken]); // Determine the userId and userName to expose based on sign-in status // Only expose Clerk user ID/name if signed in, otherwise undefined const currentUserId = isSignedIn && user ? user.id : undefined; const currentUserName = isSignedIn && user ? (user.username || user.fullName || user.emailAddresses[0].emailAddress) : undefined; return { gameState, sendClick, purchaseUpgrade, sendMascotClickBonus, userId: currentUserId, userName: currentUserName }; }