39-message2opponent #40
@ -22,7 +22,13 @@ export default function useGamesApi(gamesReducer, config) {
|
||||
|
||||
pushNewGame: (reqParams) => doPushing('/api/gameproposal', 'POST', reqParams, {
|
||||
onPushing: (isPushingNewGame) => dispatchGames({ type: 'next', isPushingNewGame }),
|
||||
onSuccess: (game) => dispatchGames({ type: 'next', gamesList: [...games.gamesList, game] })
|
||||
onSuccess: (game) => dispatchGames({ type: 'next', gamesList: [...games.gamesList, game], newGame: emptyNewGame })
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
const emptyNewGame = {
|
||||
whitePlayer: '',
|
||||
blackPlayer: '',
|
||||
message2opponent: ''
|
||||
}
|
@ -16,6 +16,7 @@ import Backward from './games/action/Backward';
|
||||
import Forward from './games/action/Forward';
|
||||
|
||||
import GameBoard from './games/GameBoard';
|
||||
import Message2Opponent from './games/Message2Opponent';
|
||||
|
||||
import './Games.css';
|
||||
|
||||
@ -27,14 +28,15 @@ export default function Games({ context: { gamesReducer, gamesApi }, players })
|
||||
<div className='Games'>
|
||||
<div className='left-side'>
|
||||
<ViewSelector />
|
||||
<ViewProvider players={players} dispatchGames={dispatchGames} />
|
||||
<ViewProvider gamesReducer={gamesReducer} players={players} />
|
||||
</div>
|
||||
<div className='right-side'>
|
||||
<ActionPanel players={players} gamesApi={gamesApi} />
|
||||
<ActionPanel gamesApi={gamesApi} players={players} />
|
||||
<GameBoard />
|
||||
<Message2Opponent dispatchGames={dispatchGames} />
|
||||
{/*
|
||||
<GameMessage />
|
||||
<Message2Opponent /> */}
|
||||
*/}
|
||||
</div>
|
||||
</div >
|
||||
</GamesContext.Provider>
|
||||
@ -54,15 +56,19 @@ function ViewSelector() {
|
||||
)
|
||||
}
|
||||
|
||||
function ViewProvider({ players, dispatchGames }) {
|
||||
function ViewProvider({ gamesReducer, players }) {
|
||||
const [/*games*/, dispatchGames] = gamesReducer;
|
||||
|
||||
return (
|
||||
<div className='ViewProvider'>
|
||||
<Routes>
|
||||
|
||||
<Route path='new' element={
|
||||
<NewGame
|
||||
onSelectPlayer={(whitePlayer, blackPlayer) => {
|
||||
dispatchGames({ type: 'nextNewGame', whitePlayer, blackPlayer })
|
||||
}}
|
||||
players={players}
|
||||
onSelectPlayer={(whitePlayer, blackPlayer) => dispatchGames({ type: "next", newGame: { whitePlayer, blackPlayer } })}
|
||||
/>
|
||||
} />
|
||||
|
||||
|
62
webapp/src/container/games/Message2Opponent.jsx
Normal file
62
webapp/src/container/games/Message2Opponent.jsx
Normal file
@ -0,0 +1,62 @@
|
||||
import React, { useContext, /* useEffect,*/ useRef, useState } from 'react';
|
||||
import { useLocation, matchPath } from 'react-router-dom';
|
||||
import { GamesContext } from '../../context/games';
|
||||
//import { useLocationChange } from '../../hook/Location';
|
||||
|
||||
export default function Message2Opponent({ dispatchGames }) {
|
||||
const games = useContext(GamesContext);
|
||||
const [message2opponent, setMessage2opponent] = useState('');
|
||||
const { pathname } = useLocation();
|
||||
const timeoutIdRef = useRef(null);
|
||||
|
||||
if (timeoutIdRef.current === null) {
|
||||
// sync: internal <- external
|
||||
// Sync external and internsl states only in abnsence of a delay timer
|
||||
console.log("check message", message2opponent);
|
||||
if (matchPath('/games/new', pathname)) {
|
||||
if (message2opponent !== games.newGame.message2opponent)
|
||||
setMessage2opponent(games.newGame.message2opponent);
|
||||
}
|
||||
else
|
||||
if (message2opponent !== '') {
|
||||
setMessage2opponent('');
|
||||
}
|
||||
}
|
||||
|
||||
console.log('timeout.current', timeoutIdRef.current)
|
||||
/* --- */
|
||||
|
||||
|
||||
const delayedSync = (message2opponent) => {
|
||||
timeoutIdRef.current = null;
|
||||
|
||||
// sync: internl -> external
|
||||
if (matchPath('/games/new', pathname))
|
||||
return dispatchGames({ type: 'nextNewGame', message2opponent });
|
||||
|
||||
console.warn('unknown path');
|
||||
}
|
||||
|
||||
const onChange = (value) => {
|
||||
setMessage2opponent(value);
|
||||
|
||||
if (timeoutIdRef.current)
|
||||
clearTimeout(timeoutIdRef.current); // cancel previous sync
|
||||
|
||||
timeoutIdRef.current = setTimeout(() => delayedSync(value), 500);
|
||||
}
|
||||
|
||||
|
||||
//var gpathname;
|
||||
//useLocationChange(({ pathname }) => {
|
||||
|
||||
|
||||
return (
|
||||
<input className='Message2Opponent'
|
||||
placeholder='Message to opponent'
|
||||
value={message2opponent}
|
||||
maxLength={150}
|
||||
onChange={e => onChange(e.target.value)}
|
||||
/>
|
||||
)
|
||||
}
|
@ -29,7 +29,7 @@ export default function Create({ isCurrentUser, pushNewGame }) {
|
||||
opponentName,
|
||||
opponentColor,
|
||||
board: null, // default board configuration
|
||||
message: 'default NewGame req message'
|
||||
message: games.newGame.message2opponent
|
||||
}
|
||||
|
||||
pushNewGame(reqParams);
|
||||
|
46
webapp/src/hook/Location.js
Normal file
46
webapp/src/hook/Location.js
Normal file
@ -0,0 +1,46 @@
|
||||
import { useRef, useEffect } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
export default function usePrevious(value) {
|
||||
const ref = useRef();
|
||||
|
||||
useEffect(() => {
|
||||
ref.current = value;
|
||||
});
|
||||
|
||||
return ref.current;
|
||||
}
|
||||
|
||||
/* Usage example
|
||||
|
||||
const useLocationChange = (action) => {
|
||||
const location = useLocation();
|
||||
const prevLocation = usePrevious(location);
|
||||
|
||||
useEffect(() => {
|
||||
action(location, prevLocation);
|
||||
}, [location]);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
// runs action(location) on location, i.e. route, change
|
||||
export const useLocationChange = (action) => {
|
||||
const location = useLocation();
|
||||
const prevLocation = usePrevious(location);
|
||||
|
||||
useEffect(() => {
|
||||
if (location !== prevLocation)
|
||||
action(location, prevLocation);
|
||||
}, [action, location, prevLocation]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Usage example
|
||||
*/
|
||||
// const MyComponent1 = () => {
|
||||
// useLocationChange((location) => {
|
||||
// console.log('handle route change here', location)
|
||||
// });
|
||||
// // other code
|
||||
// }
|
@ -1,24 +0,0 @@
|
||||
import { useRef, useEffect } from 'react';
|
||||
|
||||
export default function usePrevious(value) {
|
||||
const ref = useRef();
|
||||
|
||||
useEffect(() => {
|
||||
ref.current = value;
|
||||
});
|
||||
|
||||
return ref.current;
|
||||
}
|
||||
|
||||
/* Usage example
|
||||
|
||||
const useLocationChange = (action) => {
|
||||
const location = useLocation();
|
||||
const prevLocation = usePrevious(location);
|
||||
|
||||
useEffect(() => {
|
||||
action(location, prevLocation);
|
||||
}, [location]);
|
||||
}
|
||||
|
||||
*/
|
@ -6,7 +6,8 @@ const initialState = {
|
||||
|
||||
newGame: {
|
||||
whitePlayer: '',
|
||||
blackPlayer: ''
|
||||
blackPlayer: '',
|
||||
message2opponent: '',
|
||||
},
|
||||
|
||||
// Network
|
||||
@ -20,6 +21,12 @@ function reducer(state, action) {
|
||||
case 'next':
|
||||
return nextState(state, action);
|
||||
|
||||
case 'nextNewGame':
|
||||
return {
|
||||
...state,
|
||||
newGame: nextState(state.newGame, action)
|
||||
};
|
||||
|
||||
default:
|
||||
throw Error('GamesReducer: unknown action.type', action.type);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user