leaderboard api polling
This commit is contained in:
		
							parent
							
								
									ba7f9ce7d1
								
							
						
					
					
						commit
						472f5de928
					
				| @ -8,10 +8,15 @@ 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';
 | ||||
| 
 | ||||
| function App() { | ||||
|   const [polling, dispatchPolling] = useReducer(Polling.reducer, Polling.initialState) | ||||
|   | ||||
|   const leaderboard = LeaderboardApi(polling, dispatchPolling).get(); | ||||
|   // const user = UserApi(polling, dispatchPolling).get();
 | ||||
| 
 | ||||
|   return <div className="App"> | ||||
|     <BrowserRouter> | ||||
|       <Header polling={polling} dispatchPolling={dispatchPolling} /> | ||||
| @ -22,7 +27,7 @@ function App() { | ||||
|         <Route path="/game/proposal" element={<Game />} /> | ||||
|         <Route path="/game/active" element={<Game />} /> | ||||
|         <Route path="/game/archive" element={<Game />} /> | ||||
|         <Route path="/leaderboard" element={<Leaderboard />} /> | ||||
|         <Route path="/leaderboard" element={<Leaderboard leaderboard={leaderboard} />} /> | ||||
|         <Route path="/about" element={<About />} /> | ||||
|       </Routes> | ||||
|     </BrowserRouter> | ||||
|  | ||||
							
								
								
									
										24
									
								
								webapp/src/api/leaderboard.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								webapp/src/api/leaderboard.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| import usePolling from "../util/Polling" | ||||
| 
 | ||||
| const uri = '/api/leaderboard'; | ||||
| 
 | ||||
| export function LeaderboardApi(polling, dispatchPolling) { | ||||
| 
 | ||||
|     const useGet = () => { | ||||
|         const mode = (polling.enabled === true) | ||||
|             ? { interval_sec: 300 }     // update leaderbord stats every 5 min
 | ||||
|             : { interval_stop: true }   // user has fliped OfflineToggel
 | ||||
| 
 | ||||
|         const [leaderboard, isFetching] = usePolling(uri, mode); | ||||
| 
 | ||||
|         if (polling.leaderboard !== isFetching) { | ||||
|             dispatchPolling({ type: 'setLeaderboard', value: isFetching }); | ||||
|         } | ||||
| 
 | ||||
|         return leaderboard; | ||||
|     } | ||||
| 
 | ||||
|     return { | ||||
|         get: useGet | ||||
|     } | ||||
| } | ||||
| @ -1,26 +1,25 @@ | ||||
| import React from "react" | ||||
| import './index.css'; | ||||
| import { AppData } from "../../context/data" | ||||
| 
 | ||||
| export default function Leaderboard() { | ||||
|   const [data] = React.useContext(AppData) | ||||
| export default function Leaderboard({ leaderboard }) { | ||||
| 
 | ||||
|   if (data.leaderboard == null)  | ||||
|   if (leaderboard == null) | ||||
|     return <p>Loading...</p> | ||||
| 
 | ||||
| //  var listItems = Object.keys(data).map(playerName => { | ||||
| //    var rank = data[playerName]; | ||||
| // | ||||
| //    return <li key={playerName}> | ||||
| //      {playerName}: played {rank.gamesPlayed}, won {rank.gamesWon}, draw {rank.gamesDraw} | ||||
| //      </li> | ||||
| //  }); | ||||
| //  return <ul>{listItems}</ul>; | ||||
|   //  var listItems = Object.keys(data).map(playerName => { | ||||
|   //    var rank = data[playerName]; | ||||
|   // | ||||
|   //    return <li key={playerName}> | ||||
|   //      {playerName}: played {rank.gamesPlayed}, won {rank.gamesWon}, draw {rank.gamesDraw} | ||||
|   //      </li> | ||||
|   //  }); | ||||
|   //  return <ul>{listItems}</ul>; | ||||
| 
 | ||||
|   const tableRows = Object.keys(data.leaderboard).map(playerName => { | ||||
|     var rank = data.leaderboard[playerName]; | ||||
|   const tableRows = Object.keys(leaderboard).map(playerName => { | ||||
|     var rank = leaderboard[playerName]; | ||||
| 
 | ||||
|     return <tr key={playerName} className={data.isCurrentUser(playerName) && 'username'}> | ||||
|     // TODO tr:  className={data.isCurrentUser(playerName) && 'username'} | ||||
|     return <tr key={playerName} > | ||||
|       <td>{playerName}</td> | ||||
|       <td>{rank.gamesPlayed}</td> | ||||
|       <td>{rank.gamesWon}</td> | ||||
| @ -39,7 +38,7 @@ export default function Leaderboard() { | ||||
|         </tr> | ||||
|       </thead> | ||||
|       <tbody> | ||||
|         { tableRows } | ||||
|         {tableRows} | ||||
|       </tbody> | ||||
|     </table> | ||||
|   </div> | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| import { useLocalStorage } from './util/PersistentStorage' | ||||
| import { useLocalStorage } from '../util/PersistentStorage' | ||||
| 
 | ||||
| const Persistent = (() => { | ||||
|   const [getEnabled, setEnabled] = useLocalStorage('polling.enabled', true); | ||||
| @ -26,18 +26,18 @@ export function pollingReducer(state, action) { | ||||
|       enabled: Persistent.setEnabled(!state.enabled) | ||||
|     }; | ||||
| 
 | ||||
|     case 'games': return { | ||||
|     case 'setGames': return { | ||||
|       ...state, | ||||
|       games: action.value | ||||
|     }; | ||||
| 
 | ||||
|     case 'leaderboard': return { | ||||
|     case 'setLeaderboard': return { | ||||
|       ...state, | ||||
|       leaderboard: action.value | ||||
|     }; | ||||
| 
 | ||||
|     default: | ||||
|       throw Error('Unknown action:' + action.type); | ||||
|       throw Error('Unknown action.type:' + action.type); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										53
									
								
								webapp/src/util/Polling.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								webapp/src/util/Polling.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| import { useState, useCallback, useEffect, } from "react" | ||||
| 
 | ||||
| /* | ||||
|   - uri: string | ||||
|   - mode: | ||||
|     - null  - default, return cashed value while polling fresh one from server) | ||||
|     - interval_sec | ||||
|     - interval_stop | ||||
| */ | ||||
| 
 | ||||
| export default function usePolling(url, mode) { | ||||
|     const [cache, setCache] = useState(null); | ||||
|     const [isFetching, setFetching] = useState(false); | ||||
|     const [delayID, setDelayID] = useState(null); | ||||
| 
 | ||||
|     const fetchData = useCallback(() => { | ||||
|         setDelayID(null); | ||||
|         setFetching(true); | ||||
| 
 | ||||
|         fetch(url) | ||||
|             .then((response) => response.json()) | ||||
|             .then((freshData) => { | ||||
|                 setCache(freshData); | ||||
|                 setFetching(false); | ||||
|             }) | ||||
|             .catch((err) => { | ||||
|                 console.warn(err.message); | ||||
|                 setFetching(false); | ||||
|             }) | ||||
|     }, [url]) | ||||
| 
 | ||||
|     useEffect(() => { | ||||
|         if (cache === null && isFetching === false) { | ||||
|             fetchData(); | ||||
|         } | ||||
| 
 | ||||
|         if (mode?.interval_sec && delayID === null) { | ||||
|             const timeoutID = setTimeout(fetchData, mode.interval_sec * 1000) | ||||
|             setDelayID(timeoutID) | ||||
|             console.log("Fetch '" + url + "' scheduled in " + mode.interval_sec + " sec") | ||||
|         } | ||||
|         else if (mode?.interval_stop) { | ||||
|             clearTimeout(delayID);  // cancel already scheduled fetch
 | ||||
|             setDelayID(null);        | ||||
|         } | ||||
| 
 | ||||
|     }, [url, mode, isFetching, cache, fetchData, delayID]); | ||||
| 
 | ||||
|     return [ | ||||
|         cache, // API response
 | ||||
|         isFetching  // true / false
 | ||||
|     ] | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user