Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
396b6c07c7 | ||
|
|
35b4a72c8b |
@@ -1,3 +1,10 @@
|
||||
## [3.6.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v3.5.0...v3.6.0) (2025-10-14)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add socket listener and polling for approval notifications ([35b4a72](https://github.com/antialias/soroban-abacus-flashcards/commit/35b4a72c8b2f80a74b5d2fe02b048d4ec4d1d6f2))
|
||||
|
||||
## [3.5.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v3.4.0...v3.5.0) (2025-10-14)
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { io } from 'socket.io-client'
|
||||
import { useGetRoomByCode, useJoinRoom, useRoomData } from '@/hooks/useRoomData'
|
||||
import { getRoomDisplayWithEmoji } from '@/utils/room-display'
|
||||
|
||||
@@ -351,6 +352,61 @@ export default function JoinRoomPage({ params }: { params: { code: string } }) {
|
||||
}
|
||||
}
|
||||
|
||||
// Socket listener and polling for approval notifications
|
||||
useEffect(() => {
|
||||
if (!approvalRequested || !targetRoomData) return
|
||||
|
||||
console.log('[Join Page] Setting up approval listeners for room:', targetRoomData.id)
|
||||
|
||||
// Socket listener for real-time approval notification
|
||||
const socket = io({ path: '/api/socket' })
|
||||
|
||||
socket.on('connect', () => {
|
||||
console.log('[Join Page] Socket connected')
|
||||
})
|
||||
|
||||
socket.on('join-request-approved', (data: { roomId: string; requestId: string }) => {
|
||||
console.log('[Join Page] Request approved via socket!', data)
|
||||
if (data.roomId === targetRoomData.id) {
|
||||
console.log('[Join Page] Joining room automatically...')
|
||||
handleJoin(targetRoomData.id)
|
||||
}
|
||||
})
|
||||
|
||||
socket.on('connect_error', (error) => {
|
||||
console.error('[Join Page] Socket connection error:', error)
|
||||
})
|
||||
|
||||
// Polling fallback - check every 5 seconds
|
||||
const pollInterval = setInterval(async () => {
|
||||
try {
|
||||
console.log('[Join Page] Polling for approval status...')
|
||||
const res = await fetch(`/api/arcade/rooms/${targetRoomData.id}/join-requests`)
|
||||
if (res.ok) {
|
||||
const data = await res.json()
|
||||
// Check if any request for this user was approved
|
||||
const approvedRequest = data.requests?.find(
|
||||
(r: { status: string }) => r.status === 'approved'
|
||||
)
|
||||
if (approvedRequest) {
|
||||
console.log('[Join Page] Request approved via polling! Joining room...')
|
||||
clearInterval(pollInterval)
|
||||
socket.disconnect()
|
||||
handleJoin(targetRoomData.id)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[Join Page] Failed to poll join requests:', err)
|
||||
}
|
||||
}, 5000)
|
||||
|
||||
return () => {
|
||||
console.log('[Join Page] Cleaning up approval listeners')
|
||||
socket.disconnect()
|
||||
clearInterval(pollInterval)
|
||||
}
|
||||
}, [approvalRequested, targetRoomData, handleJoin])
|
||||
|
||||
// Only show error page for non-password and non-approval errors
|
||||
if (error && !showPasswordPrompt && !showApprovalPrompt) {
|
||||
return (
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useState } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { io } from 'socket.io-client'
|
||||
import { Modal } from '@/components/common/Modal'
|
||||
import type { schema } from '@/db'
|
||||
import { useRoomData } from '@/hooks/useRoomData'
|
||||
@@ -142,6 +143,75 @@ export function JoinRoomModal({ isOpen, onClose, onSuccess }: JoinRoomModalProps
|
||||
}
|
||||
}
|
||||
|
||||
// Socket listener and polling for approval notifications
|
||||
useEffect(() => {
|
||||
if (!approvalRequested || !roomInfo) return
|
||||
|
||||
console.log('[JoinRoomModal] Setting up approval listeners for room:', roomInfo.id)
|
||||
|
||||
// Socket listener for real-time approval notification
|
||||
const socket = io({ path: '/api/socket' })
|
||||
|
||||
socket.on('connect', () => {
|
||||
console.log('[JoinRoomModal] Socket connected')
|
||||
})
|
||||
|
||||
socket.on('join-request-approved', async (data: { roomId: string; requestId: string }) => {
|
||||
console.log('[JoinRoomModal] Request approved via socket!', data)
|
||||
if (data.roomId === roomInfo.id) {
|
||||
console.log('[JoinRoomModal] Joining room automatically...')
|
||||
try {
|
||||
await joinRoom(roomInfo.id)
|
||||
handleClose()
|
||||
onSuccess?.()
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Failed to join room')
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
socket.on('connect_error', (error) => {
|
||||
console.error('[JoinRoomModal] Socket connection error:', error)
|
||||
})
|
||||
|
||||
// Polling fallback - check every 5 seconds
|
||||
const pollInterval = setInterval(async () => {
|
||||
try {
|
||||
console.log('[JoinRoomModal] Polling for approval status...')
|
||||
const res = await fetch(`/api/arcade/rooms/${roomInfo.id}/join-requests`)
|
||||
if (res.ok) {
|
||||
const data = await res.json()
|
||||
// Check if any request for this user was approved
|
||||
const approvedRequest = data.requests?.find(
|
||||
(r: { status: string }) => r.status === 'approved'
|
||||
)
|
||||
if (approvedRequest) {
|
||||
console.log('[JoinRoomModal] Request approved via polling! Joining room...')
|
||||
clearInterval(pollInterval)
|
||||
socket.disconnect()
|
||||
try {
|
||||
await joinRoom(roomInfo.id)
|
||||
handleClose()
|
||||
onSuccess?.()
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Failed to join room')
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[JoinRoomModal] Failed to poll join requests:', err)
|
||||
}
|
||||
}, 5000)
|
||||
|
||||
return () => {
|
||||
console.log('[JoinRoomModal] Cleaning up approval listeners')
|
||||
socket.disconnect()
|
||||
clearInterval(pollInterval)
|
||||
}
|
||||
}, [approvalRequested, roomInfo, joinRoom, handleClose, onSuccess])
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={handleClose}>
|
||||
<div
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "soroban-monorepo",
|
||||
"version": "3.5.0",
|
||||
"version": "3.6.0",
|
||||
"private": true,
|
||||
"description": "Beautiful Soroban Flashcard Generator - Monorepo",
|
||||
"workspaces": [
|
||||
|
||||
Reference in New Issue
Block a user