api.push (#36)

Reviewed-on: http://192.168.8.55:3000/HQLAx/CordaCheckers/pulls/36
This commit is contained in:
djmil 2023-11-13 16:55:10 +01:00
parent 2482226e0e
commit 04f0b86527
6 changed files with 81 additions and 36 deletions

View File

@ -1,4 +1,4 @@
import usePolling from '../hook/Polling'; import { usePolling, doPushing } from '../hook/api';
export default function useGamesApi(gamesReducer, config) { export default function useGamesApi(gamesReducer, config) {
const [games, dispatchGames] = gamesReducer; const [games, dispatchGames] = gamesReducer;
@ -16,14 +16,13 @@ export default function useGamesApi(gamesReducer, config) {
return games; return games;
} }
const usePushNewGame = () => {
const onSuccess = (game) => {
dispatchGames({ type: 'next', game });
}
}
return { return {
pollGamesList: usePollingGamesList, pollGamesList: usePollingGamesList,
pushNewGame: usePushNewGame
pushNewGame: (reqParams) => doPushing('/api/gameproposal', 'POST', reqParams, {
onPushing: (isPushingNewGame) => dispatchGames({ type: 'next', isPushingNewGame }),
onSuccess: (game) => dispatchGames({ type: 'next', gamesList: [...games.gamesList, game] })
}),
} }
} }

View File

@ -1,4 +1,4 @@
import usePolling from "../hook/Polling"; import { usePolling } from "../hook/api";
export default function useLeaderboardApi(leaderboardReducer, config) { export default function useLeaderboardApi(leaderboardReducer, config) {
const [leaderboard, dispatchLeaderboard] = leaderboardReducer; const [leaderboard, dispatchLeaderboard] = leaderboardReducer;

View File

@ -1,4 +1,4 @@
import usePolling from "../hook/Polling"; import { usePolling } from "../hook/api";
export default function useUserApi(userReducer) { export default function useUserApi(userReducer) {
const [user, dispatchUser] = userReducer; const [user, dispatchUser] = userReducer;

View File

@ -30,7 +30,7 @@ export default function Games({ context: { gamesReducer, gamesApi }, players })
<ViewProvider players={players} dispatchGames={dispatchGames} /> <ViewProvider players={players} dispatchGames={dispatchGames} />
</div> </div>
<div className='right-side'> <div className='right-side'>
<ActionPanel players={players}/> <ActionPanel players={players} gamesApi={gamesApi} />
<GameBoard /> <GameBoard />
{/* {/*
<GameMessage /> <GameMessage />
@ -81,12 +81,13 @@ function ViewProvider({ players, dispatchGames }) {
) )
} }
function ActionPanel({ players }) { function ActionPanel({ players, gamesApi }) {
return ( return (
<div className='ActionPanel'> <div className='ActionPanel'>
<Routes> <Routes>
<Route path='new' element={ <Route path='new' element={
<Create isCurrentUser={players.isCurrentUser} <Create isCurrentUser={players.isCurrentUser}
pushNewGame={(reqParams) => gamesApi.pushNewGame(reqParams)}
/> />
} /> } />
<Route path='proposal' element={[<Accept key={1} />, <Reject key={2} />, <Cancel key={3} />]} /> <Route path='proposal' element={[<Accept key={1} />, <Reject key={2} />, <Cancel key={3} />]} />

View File

@ -1,36 +1,45 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { GamesContext } from '../../../context/games'; import { GamesContext } from '../../../context/games';
import Wobler from '../../../components/Wobler'; import Wobler from '../../../components/Wobler';
import { Color } from '../../../components/Checkers';
export default function Create({ isCurrentUser, pushNewGame }) {
const games = useContext(GamesContext);
export default function Create({ isCurrentUser, onClick }) { const hasPlayers = checkPlayers(games.newGame);
const newGameCtx = useContext(GamesContext).newGame; const hasCurrentUser = checkCurrentUser(games.newGame, isCurrentUser);
const hasPlayers = checkPlayers(newGameCtx); const prepareNewGameRequest = () => {
const hasCurrentUser = checkCurrentUser(newGameCtx, isCurrentUser);
const prepareRequest = () => {
if (!hasPlayers) if (!hasPlayers)
return alert("Black and White players must be selected for the game"); return alert("Black and White players must be selected for the game");
if (!hasCurrentUser) if (!hasCurrentUser)
return alert("You must be one of the selected players"); return alert("You must be one of the selected players");
if (newGameCtx.pushing) if (games.isPushingNewGame)
return; // current request is still being processed return; // current request is still being processed
//onClick /*
console.log("send request"); * Prepare & send NewGame request
*/
const [opponentName, opponentColor] = getOpponent(games.newGame, isCurrentUser);
const reqParams = {
opponentName,
opponentColor,
board: null, // default board configuration
message: 'default NewGame req message'
}
pushNewGame(reqParams);
} }
return ( return (
<button className={'Create' <button className={'Create' + (hasPlayers && hasCurrentUser ? ' ready' : '')}
+ (hasPlayers && hasCurrentUser ? ' ready' : '') onClick={prepareNewGameRequest}
}
onClick={prepareRequest}
> >
<Wobler text="Create" dance={newGameCtx.pushing} /> <Wobler text="Create" dance={games.isPushingNewGame} />
</button> </button>
) )
} }
@ -42,4 +51,16 @@ function checkPlayers({ whitePlayer, blackPlayer }) {
function checkCurrentUser({ whitePlayer, blackPlayer }, isCurrentUser) { function checkCurrentUser({ whitePlayer, blackPlayer }, isCurrentUser) {
return isCurrentUser(whitePlayer) || isCurrentUser(blackPlayer); return isCurrentUser(whitePlayer) || isCurrentUser(blackPlayer);
}
function getOpponent({whitePlayer, blackPlayer}, isCurrentUser) {
if (isCurrentUser(whitePlayer)) {
return [blackPlayer, Color.black];
}
if (isCurrentUser(blackPlayer)) {
return [whitePlayer, Color.white];
}
return ['', ''];
} }

View File

@ -8,22 +8,21 @@ import { useState, useRef, useCallback, useEffect, } from "react"
- interval_stop - interval_stop
*/ */
export default function usePolling(uri, onResponce, mode = null) { export function usePolling(uri, onSuccess, mode = null) {
const [isPolling, setPolling] = useState(false); const [isPolling, setPolling] = useState(false);
const initialPollRef = useRef(true); const initialPollRef = useRef(true);
const initialPoll = initialPollRef.current; const initialPoll = initialPollRef.current;
const intervalTimerIdRef = useRef(null); const intervalTimerIdRef = useRef(null);
const intervalTimerId = intervalTimerIdRef.current; const intervalTimerId = intervalTimerIdRef.current;
const pollData = useCallback(() => { const pollData = useCallback(() => {
setPolling(true); setPolling(true);
initialPollRef.current = false; initialPollRef.current = false;
fetch(uri) fetch(uri)
.then((responce) => { .then((response) => {
setPolling(false); setPolling(false);
if (typeof mode?.interval_sec === 'number') { if (typeof mode?.interval_sec === 'number') {
@ -31,15 +30,15 @@ export default function usePolling(uri, onResponce, mode = null) {
intervalTimerIdRef.current = setTimeout(pollData, mode.interval_sec * 1000); intervalTimerIdRef.current = setTimeout(pollData, mode.interval_sec * 1000);
} }
return responce.json(); return response.json();
}) })
.then((json) => { .then((json) => {
onResponce(json); onSuccess(json);
}) })
.catch((err) => { .catch((err) => {
console.warn(err.message); console.warn(err.message);
}) })
}, [uri, mode, onResponce, initialPollRef, intervalTimerIdRef]); }, [uri, mode, onSuccess, initialPollRef, intervalTimerIdRef]);
const stopPollInterval = useCallback(() => { const stopPollInterval = useCallback(() => {
console.log("Cancel scheduled fetch for", uri); console.log("Cancel scheduled fetch for", uri);
@ -51,11 +50,36 @@ export default function usePolling(uri, onResponce, mode = null) {
useEffect(() => { useEffect(() => {
if ((initialPoll || (typeof mode?.interval_sec === 'number' && intervalTimerId === null)) && !isPolling) { if ((initialPoll || (typeof mode?.interval_sec === 'number' && intervalTimerId === null)) && !isPolling) {
pollData(); pollData();
} else } else
if (mode?.interval_stop && intervalTimerId) { if (mode?.interval_stop && intervalTimerId) {
stopPollInterval(); stopPollInterval();
} }
}, [initialPoll, mode, intervalTimerId, isPolling, pollData, stopPollInterval]); }, [initialPoll, mode, intervalTimerId, isPolling, pollData, stopPollInterval]);
return isPolling; return isPolling;
}
export async function doPushing(uri, method, data, { onSuccess, onPushing }) {
if (onPushing)
onPushing(true);
try {
const response = await fetch(uri, {
method,
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data), // body data type must match "Content-Type" header
});
if (!response.ok)
throw new Error(`Error! status: ${response.status}`);
if (onSuccess)
onSuccess(await response.json());
// } catch (err) {
} finally {
if (onPushing)
onPushing(false);
}
} }