Fix broken routing by unifying game state via Context API

This commit is contained in:
10x Developer 2026-05-08 21:35:14 +02:00
parent 6fc0820831
commit 82cae002f8
8 changed files with 53 additions and 20 deletions

View file

@ -21,10 +21,13 @@ Mobile-first React web app for tracking Schaffhauser (Jass) card game rounds usi
6. History Screen - Game storage and export functionality
### Development Commands
- `npm run dev` - Start development server
- `npm run build` - Build production version
- `npm run preview` - Preview production build
### Development Server
- A development server is always guaranteed to be running on localhost:5173
- **Do not start the development server manually under any circumstances**
### Camera & Detection
- Uses HTML5 Camera API with environment-facing camera preference
- Card detection implemented with custom image processing techniques

View file

@ -2,14 +2,15 @@
"name": "tschausepp",
"version": "1.0.0",
"scripts": {
"dev": "vite",
"dev": "vite --host 0.0.0.0",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@tensorflow/tfjs": "^4.19.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"@tensorflow/tfjs": "^4.19.0"
"react-router-dom": "^7.15.0"
},
"devDependencies": {
"@types/react": "^18.3.5",

View file

@ -1,12 +1,20 @@
import React from 'react';
import { GameStateProvider, useGameStateContext } from './context/GameStateContext';
import SetupScreen from './components/Setup/SetupScreen';
import CameraScreen from './components/Camera/CameraScreen';
import ResultsScreen from './components/Results/ResultsScreen';
import HistoryScreen from './components/History/HistoryScreen';
import useGameState from './hooks/useGameState';
const App = () => {
const { gameState } = useGameState();
return (
<GameStateProvider>
<AppContent />
</GameStateProvider>
);
};
const AppContent = () => {
const { gameState } = useGameStateContext();
const renderScreen = () => {
switch (gameState.currentScreen) {

View file

@ -1,16 +1,16 @@
import React, { useRef, useEffect } from 'react';
import { GameState } from '../../types';
import useGameState from '../../hooks/useGameState';
import { useGameStateContext } from '../../context/GameStateContext';
import Detection from '../Detection/Detection';
import Assignment from '../Assignment/Assignment';
const CameraScreen: React.FC = () => {
const {
gameState,
setCurrentScreen,
setCameraStream,
scanTable,
showResults
} = useGameState();
scanTable
} = useGameStateContext();
const videoRef = useRef<HTMLVideoElement>(null);
const canvasRef = useRef<HTMLCanvasElement>(null);
@ -99,7 +99,7 @@ const CameraScreen: React.FC = () => {
<div className="screen camera-screen">
<div className="camera-header">
<h2>🎥 Round <span>{gameState.currentRound}</span></h2>
<button onClick={() => window.location.hash = '#setup'} className="secondary">
<button onClick={() => gameState.setCurrentScreen('setup')} className="secondary">
End Round
</button>
</div>

View file

@ -1,9 +1,9 @@
import React from 'react';
import { Game } from '../../types';
import useGameState from '../../hooks/useGameState';
import { useGameStateContext } from '../../context/GameStateContext';
const HistoryScreen: React.FC = () => {
const { gameState, setCurrentScreen } = useGameState();
const { gameState, setCurrentScreen } = useGameStateContext();
const renderHistory = () => {
if (!gameState.gameHistory || gameState.gameHistory.length === 0) {

View file

@ -1,13 +1,13 @@
import React from 'react';
import { GameState } from '../../types';
import useGameState from '../../hooks/useGameState';
import { useGameStateContext } from '../../context/GameStateContext';
const ResultsScreen: React.FC = () => {
const {
gameState,
setCurrentScreen,
saveGame
} = useGameState();
saveGame,
setCurrentScreen
} = useGameStateContext();
const calculateScores = () => {
// Scoring logic based on card values

View file

@ -1,6 +1,6 @@
import React, { useState } from 'react';
import { Player, GameState } from '../../types';
import useGameState from '../../hooks/useGameState';
import { useGameStateContext } from '../../context/GameStateContext';
const SetupScreen: React.FC = () => {
const {
@ -9,7 +9,7 @@ const SetupScreen: React.FC = () => {
updateCardValues,
addPlayer,
startNewGame
} = useGameState();
} = useGameStateContext();
const [newPlayerName, setNewPlayerName] = useState('');
@ -147,7 +147,7 @@ const SetupScreen: React.FC = () => {
<button onClick={startGame} disabled={gameState.players.length < 2}>
Start Game
</button>
<button onClick={() => window.location.hash = '#history'} className="secondary">
<button onClick={() => gameState.setCurrentScreen('history')} className="secondary">
View History
</button>
</div>

View file

@ -0,0 +1,21 @@
import React, { createContext, useContext } from 'react';
import useGameState from '../hooks/useGameState';
const GameStateContext = createContext<any>(null);
export const GameStateProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const value = useGameState();
return (
<GameStateContext.Provider value={value}>
{children}
</GameStateContext.Provider>
);
};
export const useGameStateContext = () => {
const context = useContext(GameStateContext);
if (!context) {
throw new Error('useGameStateContext must be used within a GameStateProvider');
}
return context;
};