1
0
Fork 0

fix(poker): keep the lobby list stable across background polls

Background polls no longer flip the lobby into its scanning state, so the empty window and table rows stop blinking every three seconds; the refresh spinner is reserved for manual refreshes and the error line only clears on a successful load.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
Jason Fraley 2026-09-11 17:07:37 -04:00
parent 16a44d3fc5
commit 71e9f3e9e0

View file

@ -49,8 +49,8 @@ function createdLabel(createdAt: string): string {
} }
export function PokerLobby({ refreshKey, onOpenTable, isSuperuser = false }: PokerLobbyProps) { export function PokerLobby({ refreshKey, onOpenTable, isSuperuser = false }: PokerLobbyProps) {
const [tables, setTables] = useState<readonly PokerTableSummary[]>([]); const [tables, setTables] = useState<readonly PokerTableSummary[] | null>(null);
const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false);
const [pendingTable, setPendingTable] = useState<string | null>(null); const [pendingTable, setPendingTable] = useState<string | null>(null);
const [forceEndingTable, setForceEndingTable] = useState<string | null>(null); const [forceEndingTable, setForceEndingTable] = useState<string | null>(null);
const [creating, setCreating] = useState(false); const [creating, setCreating] = useState(false);
@ -58,22 +58,28 @@ export function PokerLobby({ refreshKey, onOpenTable, isSuperuser = false }: Pok
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const loadTables = useCallback(async () => { const loadTables = useCallback(async () => {
setLoading(true);
setError(null);
try { try {
const result = await listPokerTables(); const result = await listPokerTables();
if (!result.success) { if (!result.success) {
setError(result.error ?? "Could not load poker tables."); setError(result.error ?? "Could not load poker tables.");
return; return;
} }
setError(null);
setTables(result.data ?? []); setTables(result.data ?? []);
} catch (caught) { } catch (caught) {
setError(caught instanceof Error ? caught.message : "Could not load poker tables."); setError(caught instanceof Error ? caught.message : "Could not load poker tables.");
} finally {
setLoading(false);
} }
}, []); }, []);
const manualRefresh = useCallback(async () => {
setRefreshing(true);
try {
await loadTables();
} finally {
setRefreshing(false);
}
}, [loadTables]);
useEffect(() => { useEffect(() => {
void loadTables(); void loadTables();
}, [loadTables, refreshKey]); }, [loadTables, refreshKey]);
@ -172,12 +178,12 @@ export function PokerLobby({ refreshKey, onOpenTable, isSuperuser = false }: Pok
type="button" type="button"
variant="outline" variant="outline"
size="icon" size="icon"
onClick={() => void loadTables()} onClick={() => void manualRefresh()}
disabled={loading} disabled={refreshing}
aria-label="Refresh poker tables" aria-label="Refresh poker tables"
title="Refresh tables" title="Refresh tables"
> >
<RefreshCw className={cn(loading && "animate-spin motion-reduce:animate-none")} /> <RefreshCw className={cn(refreshing && "animate-spin motion-reduce:animate-none")} />
</Button> </Button>
<Button type="button" onClick={() => void create()} disabled={creating}> <Button type="button" onClick={() => void create()} disabled={creating}>
{creating ? ( {creating ? (
@ -193,7 +199,7 @@ export function PokerLobby({ refreshKey, onOpenTable, isSuperuser = false }: Pok
{error && ( {error && (
<p className="border-b border-border px-4 py-3 text-sm text-destructive">{error}</p> <p className="border-b border-border px-4 py-3 text-sm text-destructive">{error}</p>
)} )}
{loading && tables.length === 0 ? ( {tables === null ? (
<p className="px-4 py-8 text-center text-sm text-muted-foreground"> <p className="px-4 py-8 text-center text-sm text-muted-foreground">
Scanning for open tables... Scanning for open tables...
</p> </p>