Merge branch 'devel'

This commit is contained in:
HF 2022-09-24 17:20:43 +02:00
commit a143e3737e
7 changed files with 190 additions and 61 deletions

View File

@ -5,18 +5,23 @@
/* eslint-disable max-len */ /* eslint-disable max-len */
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useSelector } from 'react-redux'; import { shallowEqual, useSelector } from 'react-redux';
import { t } from 'ttag'; import { t } from 'ttag';
import { selectStats } from '../store/selectors/ranks';
const Rankings = () => { const Rankings = () => {
const [orderDaily, setOrderDaily] = useState(false); const [area, setArea] = useState('total');
const totalRanking = useSelector( const [
(state) => state.ranks.totalRanking, totalRanking,
); totalDailyRanking,
const totalDailyRanking = useSelector( dailyCRanking,
(state) => state.ranks.totalDailyRanking, prevTop,
); onlineStats,
cHistStats,
histStats,
] = useSelector(selectStats, shallowEqual);
return ( return (
<> <>
@ -25,65 +30,124 @@ const Rankings = () => {
role="button" role="button"
tabIndex={-1} tabIndex={-1}
className={ className={
(!orderDaily) ? 'modallink selected' : 'modallink' (area === 'total') ? 'modallink selected' : 'modallink'
} }
onClick={() => setOrderDaily(false)} onClick={() => setArea('total')}
>{t`Total`}</span> >{t`Total`}</span>
<span className="hdivider" /> <span className="hdivider" />
<span <span
role="button" role="button"
tabIndex={-1} tabIndex={-1}
className={ className={
(orderDaily) ? 'modallink selected' : 'modallink' (area === 'today') ? 'modallink selected' : 'modallink'
} }
onClick={() => setOrderDaily(true)} onClick={() => setArea('today')}
>{t`Daily`}</span> >{t`Today`}</span>
<span className="hdivider" />
<span
role="button"
tabIndex={-1}
className={
(area === 'yesterday') ? 'modallink selected' : 'modallink'
}
onClick={() => setArea('yesterday')}
>{t`Yesterday`}</span>
<span className="hdivider" />
<span
role="button"
tabIndex={-1}
className={
(area === 'countries') ? 'modallink selected' : 'modallink'
}
onClick={() => setArea('countries')}
>{t`Countries Today`}</span>
</div> </div>
<table style={{ {(['total', 'today', 'yesterday', 'countries'].includes(area)) && (
display: 'inline', <table style={{
}} display: 'inline',
> }}
<thead> >
{(orderDaily) ? ( <thead>
<tr> {{
<th>#</th> total: (
<th>user</th> <tr>
<th>Pixels</th> <th>#</th>
<th># Total</th> <th>{t`User`}</th>
<th>Total Pixels</th> <th>Pixels</th>
</tr> <th># Today</th>
) : ( <th>Pixels Today</th>
<tr> </tr>
<th>#</th> ),
<th>user</th> today: (
<th>Pixels</th> <tr>
<th># Today</th> <th>#</th>
<th>Pixels Today</th> <th>{t`User`}</th>
</tr> <th>Pixels</th>
)} <th># Total</th>
</thead> <th>Total Pixels</th>
<tbody> </tr>
{(orderDaily) ),
? totalDailyRanking.map((rank) => ( yesterday: (
<tr key={rank.name}> <tr>
<td>{rank.dr}</td> <th>#</th>
<td><span>{rank.name}</span></td> <th>{t`User`}</th>
<td>{rank.dt}</td> <th>Pixels</th>
<td>{rank.r}</td> </tr>
<td>{rank.t}</td> ),
</tr> countries: (
)) <tr>
: totalRanking.map((rank) => ( <th>#</th>
<tr key={rank.name}> <th>{t`Country`}</th>
<td>{rank.r}</td> <th>Pixels</th>
<td><span>{rank.name}</span></td> </tr>
<td>{rank.t}</td> ),
<td>{rank.dr}</td> }[area]}
<td>{rank.dt}</td> </thead>
</tr> <tbody>
))} {{
</tbody> total: totalRanking.map((rank) => (
</table> <tr key={rank.name}>
<td>{rank.r}</td>
<td><span>{rank.name}</span></td>
<td>{rank.t}</td>
<td>{rank.dr}</td>
<td>{rank.dt}</td>
</tr>
)),
today: totalDailyRanking.map((rank) => (
<tr key={rank.name}>
<td>{rank.dr}</td>
<td><span>{rank.name}</span></td>
<td>{rank.dt}</td>
<td>{rank.r}</td>
<td>{rank.t}</td>
</tr>
)),
yesterday: prevTop.map((rank, ind) => (
<tr key={rank.name}>
<td>{ind + 1}</td>
<td><span>{rank.name}</span></td>
<td>{rank.px}</td>
</tr>
)),
countries: prevTop.map((rank, ind) => (
<tr key={rank.name}>
<td>{ind + 1}</td>
<td title={rank.cc}><img
style={{
height: '1em',
imageRendering: 'crisp-edges',
}}
alt={rank.cc}
src={`/cf/${rank.cc}.gif`}
/></td>
<td>{rank.px}</td>
</tr>
)),
}[area]}
</tbody>
</table>
)}
<p> <p>
{t`Ranking updates every 5 min. Daily rankings get reset at midnight UTC.`} {t`Ranking updates every 5 min. Daily rankings get reset at midnight UTC.`}
</p> </p>

View File

@ -10,6 +10,7 @@ import {
getOnlineUserStats, getOnlineUserStats,
storeOnlinUserAmount, storeOnlinUserAmount,
getCountryDailyHistory, getCountryDailyHistory,
getCountryRanks,
getTopDailyHistory, getTopDailyHistory,
} from '../data/redis/ranks'; } from '../data/redis/ranks';
import socketEvents from '../socket/socketEvents'; import socketEvents from '../socket/socketEvents';
@ -23,6 +24,7 @@ class Ranks {
this.ranks = { this.ranks = {
dailyRanking: [], dailyRanking: [],
ranking: [], ranking: [],
dailyCRanking: [],
prevTop: [], prevTop: [],
onlineStats: [], onlineStats: [],
cHistStats: [], cHistStats: [],
@ -78,9 +80,11 @@ class Ranks {
1, 1,
100, 100,
)); ));
const dailyCRanking = await getCountryRanks(1, 100);
const ret = { const ret = {
ranking, ranking,
dailyRanking, dailyRanking,
dailyCRanking,
}; };
socketEvents.rankingListUpdate(ret); socketEvents.rankingListUpdate(ret);
return ret; return ret;

View File

@ -80,6 +80,21 @@ export async function getRanks(daily, start, amount) {
return ret; return ret;
} }
/*
* get daily country ranking
*/
export async function getCountryRanks(start, amount) {
let ranks = await client.zRangeWithScores(
DAILY_CRANKED_KEY, start, start + amount, {
REV: true,
});
ranks = ranks.map((r) => ({
cc: r.value,
px: Number(r.score),
}));
return ranks;
}
/* /*
* get top 10 from previous day * get top 10 from previous day
*/ */

View File

@ -271,11 +271,24 @@ export function receiveMe(
export function receiveStats( export function receiveStats(
rankings, rankings,
) { ) {
const { ranking: totalRanking, dailyRanking: totalDailyRanking } = rankings; const {
ranking: totalRanking,
dailyRanking: totalDailyRanking,
dailyCRanking,
prevTop,
onlineStats,
cHistStats,
histStats,
} = rankings;
return { return {
type: 'REC_STATS', type: 'REC_STATS',
totalRanking, totalRanking,
totalDailyRanking, totalDailyRanking,
dailyCRanking,
prevTop,
onlineStats,
cHistStats,
histStats,
}; };
} }

View File

@ -17,6 +17,11 @@ const initialState = {
}, },
totalRanking: [], totalRanking: [],
totalDailyRanking: [], totalDailyRanking: [],
dailyCRanking: [],
prevTop: [],
onlineStats: [],
cHistStats: [],
histStats: [],
}; };
export default function ranks( export default function ranks(
@ -70,13 +75,26 @@ export default function ranks(
} }
case 'REC_STATS': { case 'REC_STATS': {
const { totalRanking, totalDailyRanking } = action; const {
totalRanking,
totalDailyRanking,
dailyCRanking,
prevTop,
onlineStats,
cHistStats,
histStats,
} = action;
const lastFetch = Date.now(); const lastFetch = Date.now();
return { return {
...state, ...state,
lastFetch, lastFetch,
totalRanking, totalRanking,
totalDailyRanking, totalDailyRanking,
dailyCRanking,
prevTop,
onlineStats,
cHistStats,
histStats,
}; };
} }

View File

@ -0,0 +1,15 @@
/*
* selectors for ranks
*/
/* eslint-disable import/prefer-default-export */
export const selectStats = (state) => [
state.ranks.totalRanking,
state.ranks.totalDailyRanking,
state.ranks.dailyCRanking,
state.ranks.prevTop,
state.ranks.onlineStats,
state.ranks.cHistStats,
state.ranks.histStats,
];

View File

@ -15,7 +15,7 @@ import canvas from './reducers/canvas';
import chat from './reducers/chat'; import chat from './reducers/chat';
import fetching from './reducers/fetching'; import fetching from './reducers/fetching';
export const CURRENT_VERSION = 11; export const CURRENT_VERSION = 12;
export const migrate = (state, version) => { export const migrate = (state, version) => {
// eslint-disable-next-line no-underscore-dangle // eslint-disable-next-line no-underscore-dangle