pretty much ready to 'ship'.3

This commit is contained in:
cottongin
2025-10-30 17:52:44 -04:00
parent 1a74b4d777
commit 47db3890e2
4 changed files with 119 additions and 94 deletions

View File

@@ -2,7 +2,7 @@ export const branding = {
app: { app: {
name: 'HSO Jackbox Game Picker', name: 'HSO Jackbox Game Picker',
shortName: 'HSO JGP', shortName: 'HSO JGP',
version: '0.3.1', version: '0.3.2 - Safari Walkabout Edition',
description: 'Spicing up Hyper Spaceout game nights!', description: 'Spicing up Hyper Spaceout game nights!',
}, },
meta: { meta: {

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect, useCallback } from 'react';
import { useAuth } from '../context/AuthContext'; import { useAuth } from '../context/AuthContext';
import { useToast } from '../components/Toast'; import { useToast } from '../components/Toast';
import api from '../api/axios'; import api from '../api/axios';
@@ -17,9 +17,32 @@ function History() {
const [showAllSessions, setShowAllSessions] = useState(false); const [showAllSessions, setShowAllSessions] = useState(false);
const [deletingSession, setDeletingSession] = useState(null); const [deletingSession, setDeletingSession] = useState(null);
const loadSessions = useCallback(async () => {
try {
const response = await api.get('/sessions');
setSessions(response.data);
} catch (err) {
console.error('Failed to load sessions', err);
} finally {
setLoading(false);
}
}, []);
const refreshSessionGames = useCallback(async (sessionId, silent = false) => {
try {
const response = await api.get(`/sessions/${sessionId}/games`);
// Reverse chronological order (most recent first)
setSessionGames(response.data.reverse());
} catch (err) {
if (!silent) {
console.error('Failed to load session games', err);
}
}
}, []);
useEffect(() => { useEffect(() => {
loadSessions(); loadSessions();
}, []); }, [loadSessions]);
// Auto-select active session if navigating from picker // Auto-select active session if navigating from picker
useEffect(() => { useEffect(() => {
@@ -29,7 +52,7 @@ function History() {
loadSessionGames(activeSession.id); loadSessionGames(activeSession.id);
} }
} }
}, [sessions]); }, [sessions, selectedSession]);
// Poll for session list updates (to detect when sessions end/start) // Poll for session list updates (to detect when sessions end/start)
useEffect(() => { useEffect(() => {
@@ -38,7 +61,7 @@ function History() {
}, 3000); }, 3000);
return () => clearInterval(interval); return () => clearInterval(interval);
}, []); }, [loadSessions]);
// Poll for updates on active session games // Poll for updates on active session games
useEffect(() => { useEffect(() => {
@@ -49,22 +72,11 @@ function History() {
// Refresh games every 3 seconds for active session // Refresh games every 3 seconds for active session
const interval = setInterval(() => { const interval = setInterval(() => {
loadSessionGames(selectedSession, true); // silent refresh refreshSessionGames(selectedSession, true); // silent refresh
}, 3000); }, 3000);
return () => clearInterval(interval); return () => clearInterval(interval);
}, [selectedSession, sessions]); }, [selectedSession, sessions, refreshSessionGames]);
const loadSessions = async () => {
try {
const response = await api.get('/sessions');
setSessions(response.data);
} catch (err) {
console.error('Failed to load sessions', err);
} finally {
setLoading(false);
}
};
const handleExport = async (sessionId, format) => { const handleExport = async (sessionId, format) => {
try { try {

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState, useCallback } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { useAuth } from '../context/AuthContext'; import { useAuth } from '../context/AuthContext';
import api from '../api/axios'; import api from '../api/axios';
@@ -11,21 +11,19 @@ function Home() {
const [sessionGames, setSessionGames] = useState([]); const [sessionGames, setSessionGames] = useState([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
useEffect(() => { const loadSessionGames = useCallback(async (sessionId, silent = false) => {
loadActiveSession(); try {
const gamesResponse = await api.get(`/sessions/${sessionId}/games`);
// Reverse chronological order (most recent first)
setSessionGames(gamesResponse.data.reverse());
} catch (error) {
if (!silent) {
console.error('Failed to load session games', error);
}
}
}, []); }, []);
// Auto-refresh for active session status and games const loadActiveSession = useCallback(async () => {
useEffect(() => {
// Poll for session status changes every 3 seconds
const interval = setInterval(() => {
loadActiveSession();
}, 3000);
return () => clearInterval(interval);
}, []);
const loadActiveSession = async () => {
try { try {
const response = await api.get('/sessions/active'); const response = await api.get('/sessions/active');
@@ -42,19 +40,21 @@ function Home() {
} finally { } finally {
setLoading(false); setLoading(false);
} }
}; }, [loadSessionGames]);
const loadSessionGames = async (sessionId, silent = false) => { useEffect(() => {
try { loadActiveSession();
const gamesResponse = await api.get(`/sessions/${sessionId}/games`); }, [loadActiveSession]);
// Reverse chronological order (most recent first)
setSessionGames(gamesResponse.data.reverse()); // Auto-refresh for active session status and games
} catch (error) { useEffect(() => {
if (!silent) { // Poll for session status changes every 3 seconds
console.error('Failed to load session games', error); const interval = setInterval(() => {
} loadActiveSession();
} }, 3000);
};
return () => clearInterval(interval);
}, [loadActiveSession]);
if (loading) { if (loading) {
return ( return (

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect, useCallback } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { useAuth } from '../context/AuthContext'; import { useAuth } from '../context/AuthContext';
import api from '../api/axios'; import api from '../api/axios';
@@ -42,29 +42,31 @@ function Picker() {
// Exclude previously played games // Exclude previously played games
const [excludePlayedGames, setExcludePlayedGames] = useState(false); const [excludePlayedGames, setExcludePlayedGames] = useState(false);
useEffect(() => { const checkActiveSession = useCallback(async () => {
// Wait for auth to finish loading before checking authentication try {
if (authLoading) return; const sessionResponse = await api.get('/sessions/active');
const session = sessionResponse.data?.session !== undefined
if (!isAuthenticated) { ? sessionResponse.data.session
navigate('/login'); : sessionResponse.data;
return;
// Check if session status changed
setActiveSession(prevSession => {
// If we had a session but now don't, mark it as ended
if (prevSession && (!session || !session.id)) {
setSessionEnded(true);
return null;
} else if (session && session.id) {
setSessionEnded(false);
return session;
}
return prevSession;
});
} catch (err) {
console.error('Failed to check session status', err);
} }
loadData(); }, []);
}, [isAuthenticated, authLoading, navigate]);
// Poll for active session status changes const loadData = useCallback(async () => {
useEffect(() => {
if (!isAuthenticated || authLoading) return;
const interval = setInterval(() => {
checkActiveSession();
}, 3000);
return () => clearInterval(interval);
}, [isAuthenticated, authLoading]);
const loadData = async () => {
try { try {
// Load active session // Load active session
const sessionResponse = await api.get('/sessions/active'); const sessionResponse = await api.get('/sessions/active');
@@ -85,27 +87,29 @@ function Picker() {
} finally { } finally {
setLoading(false); setLoading(false);
} }
}; }, []);
const checkActiveSession = async () => { useEffect(() => {
try { // Wait for auth to finish loading before checking authentication
const sessionResponse = await api.get('/sessions/active'); if (authLoading) return;
const session = sessionResponse.data?.session !== undefined
? sessionResponse.data.session if (!isAuthenticated) {
: sessionResponse.data; navigate('/login');
return;
// If we had a session but now don't, mark it as ended
if (activeSession && (!session || !session.id)) {
setSessionEnded(true);
setActiveSession(null);
} else if (session && session.id) {
setActiveSession(session);
setSessionEnded(false);
}
} catch (err) {
console.error('Failed to check session status', err);
} }
}; loadData();
}, [isAuthenticated, authLoading, navigate, loadData]);
// Poll for active session status changes
useEffect(() => {
if (!isAuthenticated || authLoading) return;
const interval = setInterval(() => {
checkActiveSession();
}, 3000);
return () => clearInterval(interval);
}, [isAuthenticated, authLoading, checkActiveSession]);
const handleCreateSession = async () => { const handleCreateSession = async () => {
try { try {
@@ -727,11 +731,7 @@ function SessionInfo({ sessionId, onGamesUpdate }) {
const [confirmingRemove, setConfirmingRemove] = useState(null); const [confirmingRemove, setConfirmingRemove] = useState(null);
const [showPopularity, setShowPopularity] = useState(true); const [showPopularity, setShowPopularity] = useState(true);
useEffect(() => { const loadGames = useCallback(async () => {
loadGames();
}, [sessionId, onGamesUpdate]);
const loadGames = async () => {
try { try {
const response = await api.get(`/sessions/${sessionId}/games`); const response = await api.get(`/sessions/${sessionId}/games`);
// Reverse chronological order (most recent first) // Reverse chronological order (most recent first)
@@ -741,7 +741,20 @@ function SessionInfo({ sessionId, onGamesUpdate }) {
} finally { } finally {
setLoading(false); setLoading(false);
} }
}; }, [sessionId]);
useEffect(() => {
loadGames();
}, [sessionId, onGamesUpdate, loadGames]);
// Auto-refresh games list every 3 seconds
useEffect(() => {
const interval = setInterval(() => {
loadGames();
}, 3000);
return () => clearInterval(interval);
}, [loadGames]);
const handleUpdateStatus = async (gameId, newStatus) => { const handleUpdateStatus = async (gameId, newStatus) => {
try { try {
@@ -815,8 +828,8 @@ function SessionInfo({ sessionId, onGamesUpdate }) {
<p className="text-gray-500 dark:text-gray-400">No games played yet. Pick a game to get started!</p> <p className="text-gray-500 dark:text-gray-400">No games played yet. Pick a game to get started!</p>
) : ( ) : (
<div className="space-y-2 max-h-96 overflow-y-auto"> <div className="space-y-2 max-h-96 overflow-y-auto">
{games.map((game) => { {games.map((game, index) => {
const index = games.length - games.indexOf(game); const displayNumber = games.length - index;
return ( return (
<div <div
key={game.id} key={game.id}
@@ -836,7 +849,7 @@ function SessionInfo({ sessionId, onGamesUpdate }) {
? 'text-gray-500 dark:text-gray-500 line-through' ? 'text-gray-500 dark:text-gray-500 line-through'
: 'text-gray-700 dark:text-gray-200' : 'text-gray-700 dark:text-gray-200'
}`}> }`}>
{index + 1}. {game.title} {displayNumber}. {game.title}
</span> </span>
{getStatusBadge(game.status)} {getStatusBadge(game.status)}
{game.manually_added === 1 && ( {game.manually_added === 1 && (