diff --git a/webapp/src/App.js b/webapp/src/App.js
index d19d707..0b8f5a3 100644
--- a/webapp/src/App.js
+++ b/webapp/src/App.js
@@ -7,31 +7,38 @@ import Leaderboard from "./container/Leaderboard"
import Game from "./components/Game"
import About from "./components/About"
-import Polling from './reducer/polling';
-import { LeaderboardApi } from './api/leaderboard';
-// import { UserApi } from './api/user';
+import Polling from './flux/polling';
+import User from './flux/user';
+import useLeaderboardApi from './api/leaderboard';
+import useUserApi from './api/user';
function App() {
- const [polling, dispatchPolling] = useReducer(Polling.reducer, Polling.initialState)
-
- const leaderboard = LeaderboardApi(polling, dispatchPolling).get();
- // const user = UserApi(polling, dispatchPolling).get();
+ const pollingFlux = useReducer(Polling.reducer, Polling.restoreState);
+ const userFlux = useReducer(User.reducer, User.initialState);
+
+ const leaderboardApi = useLeaderboardApi(pollingFlux);
+ const userApi = useUserApi(userFlux);
+
+ const leaderboard = leaderboardApi.get();
+ const user = userApi.get();
- return
-
-
-
- {/* https://stackoverflow.com/questions/40541994/multiple-path-names-for-a-same-component-in-react-router */}
- } />
- } />
- } />
- } />
- } />
- } />
- } />
-
-
-
+ return (
+
+
+
+
+ {/* https://stackoverflow.com/questions/40541994/multiple-path-names-for-a-same-component-in-react-router */}
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+
+
+
+ )
}
export default App;
diff --git a/webapp/src/api/leaderboard.js b/webapp/src/api/leaderboard.js
index 993932c..5b2e565 100644
--- a/webapp/src/api/leaderboard.js
+++ b/webapp/src/api/leaderboard.js
@@ -2,7 +2,7 @@ import usePolling from "../util/Polling"
const uri = '/api/leaderboard';
-export function LeaderboardApi(polling, dispatchPolling) {
+export default function useLeaderboardApi([polling, dispatchPolling]) {
const useGet = () => {
const mode = (polling.enabled === true)
diff --git a/webapp/src/api/user.js b/webapp/src/api/user.js
new file mode 100644
index 0000000..7f8606a
--- /dev/null
+++ b/webapp/src/api/user.js
@@ -0,0 +1,20 @@
+import usePolling from "../util/Polling"
+
+const uri = '/api/user';
+
+export default function useUserApi([user, dispatchUser]) {
+
+ const useGet = () => {
+ const [nextUser] = usePolling(uri);
+
+ if (typeof nextUser?.username === 'string' && nextUser.username !== user.username) {
+ dispatchUser({ type: "next", username: nextUser.username });
+ }
+
+ return user;
+ }
+
+ return {
+ get: useGet
+ }
+}
\ No newline at end of file
diff --git a/webapp/src/container/Header.jsx b/webapp/src/container/Header.jsx
index b6a446a..72f52bf 100644
--- a/webapp/src/container/Header.jsx
+++ b/webapp/src/container/Header.jsx
@@ -4,7 +4,8 @@ import { NavLink } from "react-router-dom";
import OnlineToggle from '../components/OnlineToggle';
import Wobler from '../components/Wobler';
-export default function Header({ polling, dispatchPolling }) {
+export default function Header({ pollingFlux }) {
+ const [polling, dispatchPolling] = pollingFlux;
return (
diff --git a/webapp/src/container/Leaderboard.css b/webapp/src/container/Leaderboard.css
index 89964b1..4eeafb6 100644
--- a/webapp/src/container/Leaderboard.css
+++ b/webapp/src/container/Leaderboard.css
@@ -4,6 +4,6 @@
align-items: center;
}
-tr.username {
+tr.currentuser {
background-color:aliceblue;
}
diff --git a/webapp/src/container/Leaderboard.jsx b/webapp/src/container/Leaderboard.jsx
index 4194048..44e338b 100644
--- a/webapp/src/container/Leaderboard.jsx
+++ b/webapp/src/container/Leaderboard.jsx
@@ -2,25 +2,18 @@ import './Leaderboard.css';
import React from "react"
import Loading from '../components/Loading';
-export default function Leaderboard({ leaderboard }) {
+export default function Leaderboard({ leaderboard, user }) {
if (leaderboard == null)
return
- // var listItems = Object.keys(data).map(playerName => {
- // var rank = data[playerName];
- //
- // return
- // {playerName}: played {rank.gamesPlayed}, won {rank.gamesWon}, draw {rank.gamesDraw}
- //
- // });
- // return
;
+ const isCurrentUser = (playerName) =>
+ user.isCurrentUser(playerName) === true ? true : null;
const tableRows = Object.keys(leaderboard).map(playerName => {
var rank = leaderboard[playerName];
- // TODO tr: className={data.isCurrentUser(playerName) && 'username'}
- return
+ return
{playerName} |
{rank.gamesPlayed} |
{rank.gamesWon} |
@@ -43,4 +36,4 @@ export default function Leaderboard({ leaderboard }) {
-};
+};
\ No newline at end of file
diff --git a/webapp/src/reducer/polling.js b/webapp/src/flux/polling.js
similarity index 75%
rename from webapp/src/reducer/polling.js
rename to webapp/src/flux/polling.js
index 88573a3..2f8cbd8 100644
--- a/webapp/src/reducer/polling.js
+++ b/webapp/src/flux/polling.js
@@ -7,18 +7,16 @@ const Persistent = (() => {
getEnabled,
setEnabled
}
-})(); // <<--- execute
+})(); // <<--- Execute
-export const pollingGetInitialState = () => {
- return {
+const restoreState = {
enabled: Persistent.getEnabled() === 'true',
games: false,
leaderboard: false
- }
};
-export function pollingReducer(state, action) {
+function reducer(state, action) {
switch (action.type) {
case 'toggleOnOff': return {
@@ -41,9 +39,6 @@ export function pollingReducer(state, action) {
}
}
-const Polling = {
- initialState: pollingGetInitialState(), // <<--- execute
- reducer: pollingReducer
-}
+const Polling = { reducer, restoreState }
export default Polling
\ No newline at end of file
diff --git a/webapp/src/flux/user.js b/webapp/src/flux/user.js
new file mode 100644
index 0000000..0d286cd
--- /dev/null
+++ b/webapp/src/flux/user.js
@@ -0,0 +1,28 @@
+import { localeCompare } from '../util/Locale'
+import StateHelper from '../util/StateHelper';
+
+export const userInitialState = {
+ username: '',
+ isCurrentUser: function (otherUsername) {
+ return localeCompare(this.username, otherUsername)
+ },
+
+};
+
+export function userReducer(state, action) {
+ switch (action.type) {
+
+ case 'next':
+ return StateHelper.next(state, action);
+
+ default:
+ throw Error('Unknown action.type: ' + action.type);
+ }
+}
+
+const User = {
+ reducer: userReducer,
+ initialState: userInitialState
+};
+
+export default User;
\ No newline at end of file
diff --git a/webapp/src/util/Locale.js b/webapp/src/util/Locale.js
new file mode 100644
index 0000000..42e0b83
--- /dev/null
+++ b/webapp/src/util/Locale.js
@@ -0,0 +1,6 @@
+export function localeCompare(a, b) {
+ // console.log(localeCompare, a, b);
+ return typeof a === 'string' && typeof b === 'string'
+ ? a.localeCompare(b, undefined, { sensitivity: 'accent' }) === 0
+ : a === b;
+}
\ No newline at end of file
diff --git a/webapp/src/util/StateHelper.js b/webapp/src/util/StateHelper.js
new file mode 100644
index 0000000..1cda2df
--- /dev/null
+++ b/webapp/src/util/StateHelper.js
@@ -0,0 +1,22 @@
+export function nextState(state, action) {
+ const nextState = { ...state };
+
+ Object.keys(action)
+ .slice(1) // skip first property i.e. 'next'
+ .forEach(key => {
+ if (Object.hasOwn(nextState, key)) {
+ console.log("next [", key, "] = ", action[key]);
+ nextState[key] = action[key];
+ } else {
+ console.warn("nextState: bad action property\n", key + ":", action[key]);
+ }
+ })
+
+ return nextState;
+}
+
+const StateHelper = {
+ next: nextState
+};
+
+export default StateHelper;
\ No newline at end of file