Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cdc0695f4 | ||
|
|
10cf71527f | ||
|
|
678f4423b6 | ||
|
|
c5268b79de | ||
|
|
d9aadd1f81 | ||
|
|
4686f59d24 | ||
|
|
1219539585 | ||
|
|
87cc0b64fb |
28
CHANGELOG.md
28
CHANGELOG.md
@@ -1,3 +1,31 @@
|
||||
## [2.8.5](https://github.com/antialias/soroban-abacus-flashcards/compare/v2.8.4...v2.8.5) (2025-10-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove redirect loop by not redirecting from room page ([10cf715](https://github.com/antialias/soroban-abacus-flashcards/commit/10cf71527f7cede7fd93e502dbfc59df99b5a524))
|
||||
|
||||
## [2.8.4](https://github.com/antialias/soroban-abacus-flashcards/compare/v2.8.3...v2.8.4) (2025-10-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* prevent redirect loops by checking if already at target URL ([c5268b7](https://github.com/antialias/soroban-abacus-flashcards/commit/c5268b79dee66aa02e14e2024fe1c6242a172ed3))
|
||||
|
||||
## [2.8.3](https://github.com/antialias/soroban-abacus-flashcards/compare/v2.8.2...v2.8.3) (2025-10-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove ArcadeGuardedPage from room page to prevent redirect loop ([4686f59](https://github.com/antialias/soroban-abacus-flashcards/commit/4686f59d245b2b502dc0764c223a5ce84bf1af44))
|
||||
|
||||
## [2.8.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v2.8.1...v2.8.2) (2025-10-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* revert to showing only active players in room games ([87cc0b6](https://github.com/antialias/soroban-abacus-flashcards/commit/87cc0b64fb5f3debaf1d2f122aecfefc62922fed))
|
||||
|
||||
## [2.8.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v2.8.0...v2.8.1) (2025-10-08)
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
'use client'
|
||||
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useEffect } from 'react'
|
||||
import { ArcadeGuardedPage } from '@/components/ArcadeGuardedPage'
|
||||
import { useRoomData } from '@/hooks/useRoomData'
|
||||
import { MemoryPairsGame } from '../matching/components/MemoryPairsGame'
|
||||
import { ArcadeMemoryPairsProvider } from '../matching/context/ArcadeMemoryPairsContext'
|
||||
@@ -10,18 +7,14 @@ import { ArcadeMemoryPairsProvider } from '../matching/context/ArcadeMemoryPairs
|
||||
/**
|
||||
* /arcade/room - Renders the game for the user's current room
|
||||
* Since users can only be in one room at a time, this is a simple singular route
|
||||
*
|
||||
* Note: We don't redirect to /arcade if no room exists because:
|
||||
* - It would conflict with arcade session redirects and create loops
|
||||
* - useArcadeRedirect on /arcade page handles redirecting to active sessions
|
||||
*/
|
||||
export default function RoomPage() {
|
||||
const router = useRouter()
|
||||
const { roomData, isLoading } = useRoomData()
|
||||
|
||||
// Redirect to arcade if no room
|
||||
useEffect(() => {
|
||||
if (!isLoading && !roomData) {
|
||||
router.push('/arcade')
|
||||
}
|
||||
}, [isLoading, roomData, router])
|
||||
|
||||
// Show loading state
|
||||
if (isLoading) {
|
||||
return (
|
||||
@@ -40,20 +33,44 @@ export default function RoomPage() {
|
||||
)
|
||||
}
|
||||
|
||||
// Show nothing while redirecting
|
||||
// Show error if no room (instead of redirecting)
|
||||
if (!roomData) {
|
||||
return null
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: '100vh',
|
||||
fontSize: '18px',
|
||||
color: '#666',
|
||||
gap: '1rem',
|
||||
}}
|
||||
>
|
||||
<div>No active room found</div>
|
||||
<a
|
||||
href="/arcade"
|
||||
style={{
|
||||
color: '#3b82f6',
|
||||
textDecoration: 'underline',
|
||||
}}
|
||||
>
|
||||
Go to Champion Arena
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// Render the appropriate game based on room's gameName
|
||||
// Note: We don't use ArcadeGuardedPage here because room-based games
|
||||
// have their own navigation logic via useRoomData
|
||||
switch (roomData.gameName) {
|
||||
case 'matching':
|
||||
return (
|
||||
<ArcadeGuardedPage>
|
||||
<ArcadeMemoryPairsProvider>
|
||||
<MemoryPairsGame />
|
||||
</ArcadeMemoryPairsProvider>
|
||||
</ArcadeGuardedPage>
|
||||
<ArcadeMemoryPairsProvider>
|
||||
<MemoryPairsGame />
|
||||
</ArcadeMemoryPairsProvider>
|
||||
)
|
||||
|
||||
// TODO: Add other games (complement-race, memory-quiz, etc.)
|
||||
|
||||
@@ -74,10 +74,13 @@ export function useArcadeGuard(options: UseArcadeGuardOptions = {}): UseArcadeGu
|
||||
})
|
||||
|
||||
// Redirect if we're not already on the active game page (only if enabled)
|
||||
if (enabled && pathname !== data.gameUrl) {
|
||||
const isAlreadyAtTarget = pathname === data.gameUrl
|
||||
if (enabled && !isAlreadyAtTarget) {
|
||||
console.log('[ArcadeGuard] Redirecting to active session:', data.gameUrl)
|
||||
onRedirect?.(data.gameUrl)
|
||||
router.push(data.gameUrl)
|
||||
} else if (isAlreadyAtTarget) {
|
||||
console.log('[ArcadeGuard] Already at target URL, no redirect needed')
|
||||
}
|
||||
},
|
||||
|
||||
@@ -127,10 +130,13 @@ export function useArcadeGuard(options: UseArcadeGuardOptions = {}): UseArcadeGu
|
||||
})
|
||||
|
||||
// Redirect if we're not already on the active game page (only if enabled)
|
||||
if (enabled && pathname !== session.gameUrl) {
|
||||
const isAlreadyAtTarget = pathname === session.gameUrl
|
||||
if (enabled && !isAlreadyAtTarget) {
|
||||
console.log('[ArcadeGuard] Redirecting to active session:', session.gameUrl)
|
||||
onRedirect?.(session.gameUrl)
|
||||
router.push(session.gameUrl)
|
||||
} else if (isAlreadyAtTarget) {
|
||||
console.log('[ArcadeGuard] Already at target URL, no redirect needed')
|
||||
}
|
||||
} else if (response.status === 404) {
|
||||
// No active session
|
||||
|
||||
@@ -71,10 +71,13 @@ export function useArcadeRedirect(options: UseArcadeRedirectOptions = {}): UseAr
|
||||
// Determine if we need to redirect
|
||||
const isArcadeLobby = currentGame === null || currentGame === undefined
|
||||
const isWrongGame = currentGame && currentGame !== data.currentGame
|
||||
const isAlreadyAtTarget = _pathname === data.gameUrl
|
||||
|
||||
if (isArcadeLobby || isWrongGame) {
|
||||
if ((isArcadeLobby || isWrongGame) && !isAlreadyAtTarget) {
|
||||
console.log('[ArcadeRedirect] Redirecting to active game:', data.gameUrl)
|
||||
router.push(data.gameUrl)
|
||||
} else if (isAlreadyAtTarget) {
|
||||
console.log('[ArcadeRedirect] Already at target URL, no redirect needed')
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -51,8 +51,8 @@ export async function getActivePlayers(viewerId: string): Promise<Player[]> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all players for all members in a room
|
||||
* In room mode, ALL players from room members participate (isActive is ignored)
|
||||
* Get active players for all members in a room
|
||||
* Returns only players marked isActive=true from each room member
|
||||
* Returns a map of userId -> Player[]
|
||||
*/
|
||||
export async function getRoomActivePlayers(roomId: string): Promise<Map<string, Player[]>> {
|
||||
@@ -61,11 +61,10 @@ export async function getRoomActivePlayers(roomId: string): Promise<Map<string,
|
||||
where: eq(schema.roomMembers.roomId, roomId),
|
||||
})
|
||||
|
||||
// Fetch ALL players for each member (not just isActive ones)
|
||||
// In room mode, the concept is "all players from all members participate"
|
||||
// Fetch active players for each member (respects isActive flag)
|
||||
const playerMap = new Map<string, Player[]>()
|
||||
for (const member of members) {
|
||||
const players = await getAllPlayers(member.userId)
|
||||
const players = await getActivePlayers(member.userId)
|
||||
playerMap.set(member.userId, players)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "soroban-monorepo",
|
||||
"version": "2.8.1",
|
||||
"version": "2.8.5",
|
||||
"private": true,
|
||||
"description": "Beautiful Soroban Flashcard Generator - Monorepo",
|
||||
"workspaces": [
|
||||
|
||||
Reference in New Issue
Block a user