diff --git a/webapp/src/App.js b/webapp/src/App.js
index 379665f..9730e57 100644
--- a/webapp/src/App.js
+++ b/webapp/src/App.js
@@ -9,7 +9,9 @@ import About from "./components/About"
import Games from './container/Games';
import Leaderboard from './container/Leaderboard';
-import usePollingReducer from './reducer/polling';
+import useConfigReducer from './reducer/config';
+import useUserReducer from './reducer/user';
+import useLeaderboardReducer from './reducer/leaderboard';
import useGamesReducer from './reducer/games';
import useUserApi from './api/user';
@@ -17,35 +19,40 @@ import useLeaderboardApi from './api/leaderboard';
import useGamesApi from './api/games';
export default function App() {
- const pollingReducer = usePollingReducer();
+ const [config, dispatcConfig] = useConfigReducer();
- const leaderboard = useLeaderboardApi().poll(pollingReducer);
- const user = useUserApi().get();
-
- const [games, dispatchGames] = useGamesReducer();
- const gamesApi = useGamesApi(dispatchGames);
- gamesApi.list(pollingReducer);
+ const user = useUserApi(useUserReducer()).getUser();
+ const leaderboard = useLeaderboardApi(useLeaderboardReducer(), config).pollTable();
const players = {
leaderboard,
isCurrentUser: (playerName) => user?.isCurrentUser(playerName) === true ? true : null
};
+ const gamesReducer = useGamesReducer();
+ const gamesApi = useGamesApi(gamesReducer, config);
+ const games = gamesApi.pollGamesList();
+
+ const isPolling = {
+ games: games.isPollingGamesList,
+ leaderboard: leaderboard.isPollingTable
+ }
+
return (
-
+
} />
} />
- } />
+ } />
} />
)
}
-function Header({ pollingReducer }) {
- const [polling, dispatchPolling] = pollingReducer;
+function Header({ configReducer, isPolling }) {
+ const [config, dispatcConfig] = configReducer;
return (
@@ -54,8 +61,8 @@ function Header({ pollingReducer }) {
dispatchPolling({ type: 'toggleOnOff' })}
+ isOnline={config.online}
+ onClick={() => dispatcConfig({ type: 'toggleOnline' })}
/>
diff --git a/webapp/src/api/games.js b/webapp/src/api/games.js
index 01d4501..8a4f3ed 100644
--- a/webapp/src/api/games.js
+++ b/webapp/src/api/games.js
@@ -1,26 +1,29 @@
import usePolling from '../hook/Polling';
-export default function useGamesApi(dispatchGames) {
+export default function useGamesApi(gamesReducer, config) {
+ const [games, dispatchGames] = gamesReducer;
- const useList = (pollingReducer) => {
- const [polling, dispatchPolling] = pollingReducer;
-
- const onResponce = (json) => {
- dispatchGames({ type: 'next', list: json });
+ const usePollingGamesList = () => {
+ const onSuccess = (gamesList) => {
+ dispatchGames({ type: 'next', gamesList });
}
- const mode = (polling.enabled === true)
- ? { interval_sec: 30 } // fetch gamesList every half a minue
- : { interval_stop: true } // user has fliped OfflineToggel
+ const isPollingGamesList = usePolling('/api/games', onSuccess, config.intervalMode(30));
+ if (games.isPollingGamesList !== isPollingGamesList) {
+ dispatchGames({ type: 'next', isPollingGamesList });
+ }
- const isPolling = usePolling('/api/games', onResponce, mode);
+ return games;
+ }
- if (isPolling !== polling.games) {
- dispatchPolling({ type: 'next', games: isPolling });
+ const usePushNewGame = () => {
+ const onSuccess = (game) => {
+ dispatchGames({ type: 'next', game });
}
}
return {
- list: useList
+ pollGamesList: usePollingGamesList,
+ pushNewGame: usePushNewGame
}
}
\ No newline at end of file
diff --git a/webapp/src/api/leaderboard.js b/webapp/src/api/leaderboard.js
index c4901b8..fe279a3 100644
--- a/webapp/src/api/leaderboard.js
+++ b/webapp/src/api/leaderboard.js
@@ -1,26 +1,22 @@
-import { useState } from "react";
import usePolling from "../hook/Polling";
-export default function useLeaderboardApi() {
- const [leaderboard, setLeaderboard] = useState(null);
+export default function useLeaderboardApi(leaderboardReducer, config) {
+ const [leaderboard, dispatchLeaderboard] = leaderboardReducer;
- const usePoll = (pollingReducer) => {
- const [polling, dispatchPolling] = pollingReducer;
+ const usePollingTable = () => {
+ const onSuccess = (table) => {
+ dispatchLeaderboard({ type: 'next', table });
+ }
- const mode = (polling.enabled === true)
- ? { interval_sec: 300 } // update leaderbord stats every 5 min
- : { interval_stop: true } // user has fliped OfflineToggel
-
- const isPolling = usePolling('/api/leaderboard', setLeaderboard, mode);
-
- if (isPolling !== polling.leaderboard) {
- dispatchPolling({ type: 'next', leaderboard: isPolling });
+ const isPollingTable = usePolling('/api/leaderboard', onSuccess, config.intervalMode(300));
+ if (leaderboard.isPollingTable !== isPollingTable) {
+ dispatchLeaderboard({ type: 'next', isPollingTable });
}
return leaderboard;
}
return {
- poll: usePoll
+ pollTable: usePollingTable
}
}
\ No newline at end of file
diff --git a/webapp/src/api/user.js b/webapp/src/api/user.js
index 18f199c..39c3a68 100644
--- a/webapp/src/api/user.js
+++ b/webapp/src/api/user.js
@@ -1,20 +1,19 @@
import usePolling from "../hook/Polling";
-import useUserReducer from "../reducer/user";
-export default function useUserApi() {
- const [user, dispatchUser] = useUserReducer();
+export default function useUserApi(userReducer) {
+ const [user, dispatchUser] = userReducer;
- const useGet = () => {
- const onResponce = (json) => {
- dispatchUser({ type: "parse", json });
+ const useGetUser = () => {
+ const onSuccess = (userJson) => {
+ dispatchUser({ type: "parse", userJson });
}
- usePolling('/api/user', onResponce); // <<-- fetch once
+ usePolling('/api/user', onSuccess); // <<-- fetch once
return user;
}
return {
- get: useGet
+ getUser: useGetUser
}
}
\ No newline at end of file
diff --git a/webapp/src/container/Games.jsx b/webapp/src/container/Games.jsx
index 595c98b..3ac2c34 100644
--- a/webapp/src/container/Games.jsx
+++ b/webapp/src/container/Games.jsx
@@ -19,7 +19,8 @@ import GameBoard from './games/GameBoard';
import './Games.css';
-export default function Games({ context: { games, dispatchGames, gamesApi }, players }) {
+export default function Games({ context: { gamesReducer, gamesApi }, players }) {
+ const [games, dispatchGames] = gamesReducer;
return (
diff --git a/webapp/src/container/Leaderboard.jsx b/webapp/src/container/Leaderboard.jsx
index ca92490..9493dd7 100644
--- a/webapp/src/container/Leaderboard.jsx
+++ b/webapp/src/container/Leaderboard.jsx
@@ -4,13 +4,12 @@ import Loading from '../components/Loading';
export default function Leaderboard({ players }) {
- const leaderboard = players.leaderboard;
-
- if (leaderboard == null)
+ const table = players.leaderboard.table;
+ if (table == null)
return
- const tableRows = Object.keys(leaderboard).map(playerName => {
- var rank = leaderboard[playerName];
+ const tableRows = Object.keys(table).map(playerName => {
+ var rank = table[playerName];
return
{playerName} |
diff --git a/webapp/src/container/games/action/Create.jsx b/webapp/src/container/games/action/Create.jsx
index 893258f..9fd59ca 100644
--- a/webapp/src/container/games/action/Create.jsx
+++ b/webapp/src/container/games/action/Create.jsx
@@ -4,13 +4,13 @@ import Wobler from '../../../components/Wobler';
-export default function Create({ isCurrentUser }) {
+export default function Create({ isCurrentUser, onClick }) {
const newGameCtx = useContext(GamesContext).newGame;
const hasPlayers = checkPlayers(newGameCtx);
const hasCurrentUser = checkCurrentUser(newGameCtx, isCurrentUser);
- const pushNewGame = () => {
+ const prepareRequest = () => {
if (!hasPlayers)
return alert("Black and White players must be selected for the game");
@@ -20,6 +20,7 @@ export default function Create({ isCurrentUser }) {
if (newGameCtx.pushing)
return; // current request is still being processed
+ //onClick
console.log("send request");
}
@@ -27,7 +28,7 @@ export default function Create({ isCurrentUser }) {
diff --git a/webapp/src/container/games/view/GameSelector.jsx b/webapp/src/container/games/view/GameSelector.jsx
index 5578e7c..23c6d34 100644
--- a/webapp/src/container/games/view/GameSelector.jsx
+++ b/webapp/src/container/games/view/GameSelector.jsx
@@ -7,14 +7,14 @@ import Loading from '../../../components/Loading';
export default function GameSelector({ yours, opponents, onClick }) {
- const games = useContext(GamesContext);
- if (games.list === null)
+ const gamesList = useContext(GamesContext).gamesList;
+ if (gamesList === null)
return
- const yoursList = games.list.filter(game => game.status === yours)
+ const yoursList = gamesList.filter(game => game.status === yours)
.map(game => )
- const opponentsList = games.list.filter(game => game.status === opponents)
+ const opponentsList = gamesList.filter(game => game.status === opponents)
.map(game => )
return (
diff --git a/webapp/src/container/games/view/NewGame.jsx b/webapp/src/container/games/view/NewGame.jsx
index 0ce7d3e..a729a70 100644
--- a/webapp/src/container/games/view/NewGame.jsx
+++ b/webapp/src/container/games/view/NewGame.jsx
@@ -11,9 +11,9 @@ export default function NewGame({ players, onSelectPlayer }) {
/*
* Name options
*/
- const nameOptions = !players.leaderboard
+ const nameOptions = !players.leaderboard.table
? []
- : Object.keys(players.leaderboard).map(playerName =>
+ : Object.keys(players.leaderboard.table).map(playerName =>
)
diff --git a/webapp/src/reducer/config.js b/webapp/src/reducer/config.js
new file mode 100644
index 0000000..1d2f3a4
--- /dev/null
+++ b/webapp/src/reducer/config.js
@@ -0,0 +1,44 @@
+import { useReducer } from 'react';
+import { namedLocalStorage } from '../util/PersistentStorage';
+import { nextState } from '../util/StateHelper';
+
+const Persistent = (() => {
+ const [getOnline, setOnline] = namedLocalStorage('config.online', true);
+
+ return {
+ getOnline,
+ setOnline
+ }
+})(); // <<--- Execute
+
+const initialState = {
+ online: Persistent.getOnline() === 'true',
+
+ intervalMode
+};
+
+function dispatch(state, action) {
+ switch (action.type) {
+
+ case 'toggleOnline': return {
+ ...state,
+ online: Persistent.setOnline(!state.online)
+ };
+
+ case 'next':
+ return nextState(state, action);
+
+ default:
+ throw Error('ConfigReducer: unknown action.type', action.type);
+ }
+}
+
+export default function useConfigReducer() {
+ return useReducer(dispatch, initialState);
+}
+
+function intervalMode(interval_sec) {
+ return (this.online === true)
+ ? { interval_sec } // fetch from API every interval_sec
+ : { interval_stop: true } // user has fliped OfflineToggel
+}
\ No newline at end of file
diff --git a/webapp/src/reducer/games.js b/webapp/src/reducer/games.js
index 854ef37..073bd6a 100644
--- a/webapp/src/reducer/games.js
+++ b/webapp/src/reducer/games.js
@@ -1,16 +1,20 @@
import { useReducer } from 'react';
import { nextState } from '../util/StateHelper';
-export const gamesInitialState = {
- list: null,
+const initialState = {
+ gamesList: null,
newGame: {
whitePlayer: '',
blackPlayer: ''
- }
+ },
+
+ // Network
+ isPollingGamesList: false,
+ isPushingNewGame: false,
};
-export function gamesReducer(state, action) {
+function reducer(state, action) {
switch (action.type) {
case 'next':
@@ -22,5 +26,5 @@ export function gamesReducer(state, action) {
}
export default function useGamesReducer() {
- return useReducer(gamesReducer, gamesInitialState);
+ return useReducer(reducer, initialState);
}
\ No newline at end of file
diff --git a/webapp/src/reducer/leaderboard.js b/webapp/src/reducer/leaderboard.js
new file mode 100644
index 0000000..f2b0141
--- /dev/null
+++ b/webapp/src/reducer/leaderboard.js
@@ -0,0 +1,24 @@
+import { useReducer } from 'react';
+import { nextState } from '../util/StateHelper';
+
+const initialState = {
+ table: null,
+
+ // Network
+ isPollingTable: false
+};
+
+function reducer(state, action) {
+ switch (action.type) {
+
+ case 'next':
+ return nextState(state, action);
+
+ default:
+ throw Error('LeaderboardReducer: unknown action.type', action.type);
+ }
+}
+
+export default function useLeaderboardReducer() {
+ return useReducer(reducer, initialState);
+}
\ No newline at end of file
diff --git a/webapp/src/reducer/polling.js b/webapp/src/reducer/polling.js
deleted file mode 100644
index 750f2ca..0000000
--- a/webapp/src/reducer/polling.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import { useReducer } from 'react';
-import { namedLocalStorage } from '../util/PersistentStorage';
-import { nextState } from '../util/StateHelper';
-
-const Persistent = (() => {
- const [getEnabled, setEnabled] = namedLocalStorage('polling.enabled', true);
-
- return {
- getEnabled,
- setEnabled
- }
-})(); // <<--- Execute
-
-export const pollingInitialState = {
- enabled: Persistent.getEnabled() === 'true',
-
- games: false,
- leaderboard: false
-};
-
-export function pollingReducer(curntState, action) {
- switch (action.type) {
-
- case 'toggleOnOff': return {
- ...curntState,
- enabled: Persistent.setEnabled(!curntState.enabled)
- };
-
- case 'next':
- return nextState(curntState, action);
-
- default:
- throw Error('Unknown action.type:' + action.type);
- }
-}
-
-export default function usePollingReducer() {
- return useReducer(pollingReducer, pollingInitialState);
-}
\ No newline at end of file
diff --git a/webapp/src/reducer/user.js b/webapp/src/reducer/user.js
index 0351553..1cf1265 100644
--- a/webapp/src/reducer/user.js
+++ b/webapp/src/reducer/user.js
@@ -1,7 +1,7 @@
import { useReducer } from 'react';
import { localeCompare } from '../util/Locale';
-export const userInitialState = {
+const initialState = {
username: '',
isCurrentUser: function (otherUsername) {
@@ -9,13 +9,13 @@ export const userInitialState = {
}
};
-export function userReducer(state, action) {
+function reducer(state, action) {
switch (action.type) {
case 'parse':
return {
...state,
- username: action.json.username
+ username: action.userJson.username
};
default:
@@ -24,5 +24,5 @@ export function userReducer(state, action) {
}
export default function useUserReducer() {
- return useReducer(userReducer, userInitialState);
+ return useReducer(reducer, initialState);
}
\ No newline at end of file