Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c851462de | ||
|
|
85b2cf9816 | ||
|
|
4c6eb01f1e | ||
|
|
7d08fdd906 | ||
|
|
0d4f400dca |
19
CHANGELOG.md
19
CHANGELOG.md
@@ -1,3 +1,22 @@
|
||||
## [3.6.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v3.6.1...v3.6.2) (2025-10-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* allow join with pending invitation for restricted rooms ([85b2cf9](https://github.com/antialias/soroban-abacus-flashcards/commit/85b2cf98167ccf632ab634a94eb436e1eb584614))
|
||||
|
||||
## [3.6.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v3.6.0...v3.6.1) (2025-10-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* join user socket channel to receive approval notifications ([7d08fdd](https://github.com/antialias/soroban-abacus-flashcards/commit/7d08fdd90643920857eda09998ac01afbae74154))
|
||||
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* remove redundant polling from approval notifications ([0d4f400](https://github.com/antialias/soroban-abacus-flashcards/commit/0d4f400dca02ad9497522c24fded8b6d07d85fd2))
|
||||
|
||||
## [3.6.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v3.5.0...v3.6.0) (2025-10-14)
|
||||
|
||||
|
||||
|
||||
@@ -277,21 +277,17 @@ export default function JoinRoomPage({ params }: { params: { code: string } }) {
|
||||
return
|
||||
}
|
||||
|
||||
if (room.accessMode === 'restricted') {
|
||||
setError('This room is invitation-only')
|
||||
return
|
||||
}
|
||||
|
||||
if (room.accessMode === 'approval-only') {
|
||||
setShowApprovalPrompt(true)
|
||||
return
|
||||
}
|
||||
|
||||
// For restricted rooms, try to join - the API will check for invitation
|
||||
// If user is in a different room, show confirmation
|
||||
if (roomData) {
|
||||
setShowConfirmation(true)
|
||||
} else {
|
||||
// Otherwise, auto-join (for open rooms)
|
||||
// Otherwise, auto-join (for open rooms and restricted rooms with invitation)
|
||||
handleJoin(room.id)
|
||||
}
|
||||
})
|
||||
@@ -352,58 +348,57 @@ export default function JoinRoomPage({ params }: { params: { code: string } }) {
|
||||
}
|
||||
}
|
||||
|
||||
// Socket listener and polling for approval notifications
|
||||
// Socket listener for approval notifications
|
||||
useEffect(() => {
|
||||
if (!approvalRequested || !targetRoomData) return
|
||||
|
||||
console.log('[Join Page] Setting up approval listeners for room:', targetRoomData.id)
|
||||
console.log('[Join Page] Setting up approval listener for room:', targetRoomData.id)
|
||||
|
||||
// Socket listener for real-time approval notification
|
||||
const socket = io({ path: '/api/socket' })
|
||||
let socket: ReturnType<typeof io> | null = null
|
||||
|
||||
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 () => {
|
||||
// Fetch viewer ID and set up socket
|
||||
const setupSocket = 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()
|
||||
// Get current user's viewer ID
|
||||
const res = await fetch('/api/viewer')
|
||||
if (!res.ok) {
|
||||
console.error('[Join Page] Failed to get viewer ID')
|
||||
return
|
||||
}
|
||||
|
||||
const { viewerId } = await res.json()
|
||||
console.log('[Join Page] Got viewer ID:', viewerId)
|
||||
|
||||
// Connect socket
|
||||
socket = io({ path: '/api/socket' })
|
||||
|
||||
socket.on('connect', () => {
|
||||
console.log('[Join Page] Socket connected, joining user channel')
|
||||
// Join user-specific channel to receive moderation events
|
||||
socket?.emit('join-user-channel', { userId: viewerId })
|
||||
})
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[Join Page] Failed to poll join requests:', err)
|
||||
})
|
||||
|
||||
socket.on('connect_error', (error) => {
|
||||
console.error('[Join Page] Socket connection error:', error)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('[Join Page] Error setting up socket:', error)
|
||||
}
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
setupSocket()
|
||||
|
||||
return () => {
|
||||
console.log('[Join Page] Cleaning up approval listeners')
|
||||
socket.disconnect()
|
||||
clearInterval(pollInterval)
|
||||
console.log('[Join Page] Cleaning up approval listener')
|
||||
socket?.disconnect()
|
||||
}
|
||||
}, [approvalRequested, targetRoomData, handleJoin])
|
||||
|
||||
|
||||
@@ -77,18 +77,14 @@ export function JoinRoomModal({ isOpen, onClose, onSuccess }: JoinRoomModalProps
|
||||
return
|
||||
}
|
||||
|
||||
if (room.accessMode === 'restricted') {
|
||||
setError('This room is invitation-only. Please ask the host for an invitation.')
|
||||
setIsLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
if (room.accessMode === 'approval-only') {
|
||||
setNeedsApproval(true)
|
||||
setIsLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
// For restricted rooms, try to join - the API will check for invitation
|
||||
|
||||
if (room.accessMode === 'password') {
|
||||
// Check if password is provided
|
||||
if (!needsPassword) {
|
||||
@@ -143,53 +139,40 @@ export function JoinRoomModal({ isOpen, onClose, onSuccess }: JoinRoomModalProps
|
||||
}
|
||||
}
|
||||
|
||||
// Socket listener and polling for approval notifications
|
||||
// Socket listener for approval notifications
|
||||
useEffect(() => {
|
||||
if (!approvalRequested || !roomInfo) return
|
||||
|
||||
console.log('[JoinRoomModal] Setting up approval listeners for room:', roomInfo.id)
|
||||
console.log('[JoinRoomModal] Setting up approval listener for room:', roomInfo.id)
|
||||
|
||||
// Socket listener for real-time approval notification
|
||||
const socket = io({ path: '/api/socket' })
|
||||
let socket: ReturnType<typeof io> | null = null
|
||||
|
||||
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 () => {
|
||||
// Fetch viewer ID and set up socket
|
||||
const setupSocket = 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()
|
||||
// Get current user's viewer ID
|
||||
const res = await fetch('/api/viewer')
|
||||
if (!res.ok) {
|
||||
console.error('[JoinRoomModal] Failed to get viewer ID')
|
||||
return
|
||||
}
|
||||
|
||||
const { viewerId } = await res.json()
|
||||
console.log('[JoinRoomModal] Got viewer ID:', viewerId)
|
||||
|
||||
// Connect socket
|
||||
socket = io({ path: '/api/socket' })
|
||||
|
||||
socket.on('connect', () => {
|
||||
console.log('[JoinRoomModal] Socket connected, joining user channel')
|
||||
// Join user-specific channel to receive moderation events
|
||||
socket?.emit('join-user-channel', { userId: viewerId })
|
||||
})
|
||||
|
||||
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()
|
||||
@@ -199,16 +182,21 @@ export function JoinRoomModal({ isOpen, onClose, onSuccess }: JoinRoomModalProps
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[JoinRoomModal] Failed to poll join requests:', err)
|
||||
})
|
||||
|
||||
socket.on('connect_error', (error) => {
|
||||
console.error('[JoinRoomModal] Socket connection error:', error)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('[JoinRoomModal] Error setting up socket:', error)
|
||||
}
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
setupSocket()
|
||||
|
||||
return () => {
|
||||
console.log('[JoinRoomModal] Cleaning up approval listeners')
|
||||
socket.disconnect()
|
||||
clearInterval(pollInterval)
|
||||
console.log('[JoinRoomModal] Cleaning up approval listener')
|
||||
socket?.disconnect()
|
||||
}
|
||||
}, [approvalRequested, roomInfo, joinRoom, handleClose, onSuccess])
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "soroban-monorepo",
|
||||
"version": "3.6.0",
|
||||
"version": "3.6.2",
|
||||
"private": true,
|
||||
"description": "Beautiful Soroban Flashcard Generator - Monorepo",
|
||||
"workspaces": [
|
||||
|
||||
Reference in New Issue
Block a user