diff --git a/src/components/ChatMessage.jsx b/src/components/ChatMessage.jsx
index 31786fd..d842453 100644
--- a/src/components/ChatMessage.jsx
+++ b/src/components/ChatMessage.jsx
@@ -7,10 +7,10 @@ import {
setBrightness,
getDateTimeString,
} from '../core/utils';
+import { selectIsDarkMode } from '../store/selectors/gui';
import { parseParagraph } from '../core/MarkdownParser';
-const selectStyle = (state) => state.gui.style.indexOf('dark') !== -1;
function ChatMessage({
name,
@@ -20,9 +20,7 @@ function ChatMessage({
ts,
openCm,
}) {
- const isDarkMode = useSelector(
- selectStyle,
- );
+ const isDarkMode = useSelector(selectIsDarkMode);
const refEmbed = useRef();
const isInfo = (name === 'info');
diff --git a/src/components/Rankings.jsx b/src/components/Rankings.jsx
index e114985..74cbd5d 100644
--- a/src/components/Rankings.jsx
+++ b/src/components/Rankings.jsx
@@ -17,11 +17,24 @@ import {
Tooltip,
Legend,
LineController,
+ ArcElement,
} from 'chart.js';
-import { Line } from 'react-chartjs-2';
+import { Line, Pie } from 'react-chartjs-2';
+import { selectIsDarkMode } from '../store/selectors/gui';
import { selectStats } from '../store/selectors/ranks';
-import { colorFromText } from '../core/utils';
+import {
+ getCHistChartOpts,
+ getCHistChartData,
+ getOnlineStatsOpts,
+ getOnlineStatsData,
+ getHistChartOpts,
+ getHistChartData,
+ getCPieOpts,
+ getCPieData,
+ getPDailyStatsOpts,
+ getPDailyStatsData,
+} from '../core/chartSettings';
ChartJS.register(
CategoryScale,
@@ -32,88 +45,10 @@ ChartJS.register(
Tooltip,
Legend,
LineController,
+ // for pie chart
+ ArcElement,
);
-const options = {
- responsive: true,
- aspectRatio: 1.2,
- color: '#e6e6e6',
- scales: {
- x: {
- grid: {
- drawBorder: false,
- color: '#656565',
- },
- ticks: {
- color: '#e6e6e6',
- },
- },
- y: {
- grid: {
- drawBorder: false,
- color: '#656565',
- },
- ticks: {
- color: '#e6e6e6',
- },
- },
- },
- interaction: {
- mode: 'index',
- intersect: false,
- },
- plugins: {
- legend: {
- position: 'top',
- },
- title: {
- display: true,
- color: '#e6e6e6',
- text: 'Top 10 Countries [pxls / day]',
- },
- },
-};
-
-const onlineStatsOptions = {
- responsive: true,
- color: '#e6e6e6',
- scales: {
- x: {
- grid: {
- drawBorder: false,
- color: '#656565',
- },
- ticks: {
- color: '#e6e6e6',
- },
- },
- y: {
- grid: {
- drawBorder: false,
- color: '#656565',
- },
- ticks: {
- color: '#e6e6e6',
- },
- },
- },
- interaction: {
- mode: 'index',
- intersect: false,
- },
- plugins: {
- legend: {
- display: false,
- },
- title: {
- display: true,
- color: '#e6e6e6',
- text: 'Players Online per full hour',
- },
- },
-};
-
-
const Rankings = () => {
const [area, setArea] = useState('total');
const [
@@ -124,82 +59,80 @@ const Rankings = () => {
onlineStats,
cHistStats,
histStats,
+ pDailyStats,
] = useSelector(selectStats, shallowEqual);
+ const isDarkMode = useSelector(selectIsDarkMode);
const cHistData = useMemo(() => {
if (area !== 'charts') {
return null;
}
- const dataPerCountry = {};
- const labels = [];
- let ts = Date.now();
- let c = cHistStats.length;
- while (c) {
- const dAmount = cHistStats.length - c;
- c -= 1;
- // x label
- const date = new Date(ts);
- labels.unshift(`${date.getUTCMonth() + 1} / ${date.getUTCDate()}`);
- ts -= 1000 * 3600 * 24;
- // y data per country
- const dailyRanks = cHistStats[c];
- for (let i = 0; i < dailyRanks.length; i += 1) {
- const { cc, px } = dailyRanks[i];
- if (!dataPerCountry[cc]) {
- dataPerCountry[cc] = [];
- }
- const countryDat = dataPerCountry[cc];
- while (countryDat.length < dAmount) {
- countryDat.push(null);
- }
- countryDat.push(px);
- }
- }
- console.log(dataPerCountry);
- const countries = Object.keys(dataPerCountry);
- const datasets = countries.map((cc) => {
- const color = colorFromText(`${cc}${cc}${cc}${cc}${cc}`);
- return {
- label: cc,
- data: dataPerCountry[cc],
- borderColor: color,
- backgroundColor: color,
- };
- });
- return {
- labels,
- datasets,
- };
+ return getCHistChartData(cHistStats);
}, [area, cHistStats]);
+ const cHistOpts = useMemo(() => {
+ if (area !== 'charts') {
+ return null;
+ }
+ return getCHistChartOpts(isDarkMode);
+ }, [area, isDarkMode]);
+
const onlineData = useMemo(() => {
if (area !== 'charts') {
return null;
}
- const labels = [];
- const data = [];
- let ts = Date.now();
- let c = onlineStats.length;
- while (c) {
- c -= 1;
- const date = new Date(ts);
- const hours = date.getHours();
- const key = hours || `${date.getMonth() + 1} / ${date.getDate()}`;
- labels.unshift(String(key));
- ts -= 1000 * 3600;
- data.push(onlineStats[c]);
- }
- return {
- labels,
- datasets: [{
- label: 'Players',
- data,
- borderColor: '#3fadda',
- backgroundColor: '#3fadda',
- }],
- };
+ return getOnlineStatsData(onlineStats);
}, [area, onlineStats]);
+ const onlineOpts = useMemo(() => {
+ if (area !== 'charts') {
+ return null;
+ }
+ return getOnlineStatsOpts(isDarkMode);
+ }, [area, isDarkMode]);
+
+ const histData = useMemo(() => {
+ if (area !== 'charts') {
+ return null;
+ }
+ return getHistChartData(histStats);
+ }, [area, histStats]);
+
+ const histOpts = useMemo(() => {
+ if (area !== 'charts') {
+ return null;
+ }
+ return getHistChartOpts(isDarkMode);
+ }, [area, isDarkMode]);
+
+ const pDailyData = useMemo(() => {
+ if (area !== 'charts') {
+ return null;
+ }
+ return getPDailyStatsData(pDailyStats);
+ }, [area, pDailyStats]);
+
+ const pDailyOpts = useMemo(() => {
+ if (area !== 'charts') {
+ return null;
+ }
+ return getPDailyStatsOpts(isDarkMode);
+ }, [area, isDarkMode]);
+
+ const cPieData = useMemo(() => {
+ if (area !== 'countries') {
+ return null;
+ }
+ return getCPieData(dailyCRanking);
+ }, [area, dailyCRanking]);
+
+ const cPieOpts = useMemo(() => {
+ if (area !== 'countries') {
+ return null;
+ }
+ return getCPieOpts(isDarkMode);
+ }, [area, isDarkMode]);
+
return (
<>
@@ -210,7 +143,7 @@ const Rankings = () => {
(area === 'total') ? 'modallink selected' : 'modallink'
}
onClick={() => setArea('total')}
- >{t`Total`}
+ > {t`Total`}
{
(area === 'today') ? 'modallink selected' : 'modallink'
}
onClick={() => setArea('today')}
- >{t`Today`}
+ > {t`Today`}
{
(area === 'yesterday') ? 'modallink selected' : 'modallink'
}
onClick={() => setArea('yesterday')}
- >{t`Yesterday`}
+ > {t`Yesterday`}
{
(area === 'countries') ? 'modallink selected' : 'modallink'
}
onClick={() => setArea('countries')}
- >{t`Countries Today`}
+ > {t`Countries Today`}
{
(area === 'charts') ? 'modallink selected' : 'modallink'
}
onClick={() => setArea('charts')}
- >{t`Chart`}
+ > {t`Charts`}
+
+ {(area === 'countries') && (
+ <>
+
+
+ >
+ )}
{(['total', 'today', 'yesterday', 'countries'].includes(area)) && (
{
)}
{(area === 'charts') && (
<>
-
-
+
+
+
+
>
)}
diff --git a/src/core/Ranks.js b/src/core/Ranks.js
index 7f78d5a..d7033f6 100644
--- a/src/core/Ranks.js
+++ b/src/core/Ranks.js
@@ -12,6 +12,10 @@ import {
getCountryDailyHistory,
getCountryRanks,
getTopDailyHistory,
+ storeHourlyPixelsPlaced,
+ getHourlyPixelStats,
+ getDailyPixelStats,
+ populateDailyTotal,
} from '../data/redis/ranks';
import socketEvents from '../socket/socketEvents';
import logger from './logger';
@@ -22,13 +26,24 @@ import { DailyCron, HourlyCron } from '../utils/cron';
class Ranks {
constructor() {
this.ranks = {
+ // ranking today of users by pixels
dailyRanking: [],
+ // ranking of users by pixels
ranking: [],
+ // ranking today of countries by pixels
dailyCRanking: [],
+ // yesterdays ranking of users by pixels
prevTop: [],
+ // online user amount by hour
onlineStats: [],
+ // ranking of countries by day
cHistStats: [],
+ // ranking of users by day
histStats: [],
+ // pixels placed by hour
+ pHourlyStats: [],
+ // pixels placed by day
+ pDailyStats: [],
};
/*
* we go through socketEvents for sharding
@@ -42,6 +57,7 @@ class Ranks {
}
async initialize() {
+ await populateDailyTotal();
try {
let someRanks = await Ranks.dailyUpdateRanking();
this.ranks = {
@@ -95,10 +111,12 @@ class Ranks {
const cHistStats = await getCountryDailyHistory();
const histStats = await getTopDailyHistory();
histStats.users = await populateRanking(histStats.users);
+ const pHourlyStats = await getHourlyPixelStats();
const ret = {
onlineStats,
cHistStats,
histStats,
+ pHourlyStats,
};
if (socketEvents.amIImportant()) {
// only main shard sends to others
@@ -111,8 +129,10 @@ class Ranks {
const prevTop = await populateRanking(
await getPrevTop(),
);
+ const pDailyStats = await getDailyPixelStats();
const ret = {
prevTop,
+ pDailyStats,
};
if (socketEvents.amIImportant()) {
// only main shard sends to others
@@ -127,6 +147,7 @@ class Ranks {
}
const amount = socketEvents.onlineCounter.total;
await storeOnlinUserAmount(amount);
+ await storeHourlyPixelsPlaced();
await Ranks.hourlyUpdateRanking();
}
diff --git a/src/core/chartSettings.js b/src/core/chartSettings.js
new file mode 100644
index 0000000..7eb2c4b
--- /dev/null
+++ b/src/core/chartSettings.js
@@ -0,0 +1,364 @@
+import { t } from 'ttag';
+import { colorFromText } from './utils';
+
+export function getCHistChartOpts(isDarkMode) {
+ const options = {
+ responsive: true,
+ aspectRatio: 1.2,
+ scales: {
+ x: {
+ grid: {
+ drawBorder: false,
+ },
+ },
+ y: {
+ grid: {
+ drawBorder: false,
+ },
+ },
+ },
+ interaction: {
+ mode: 'index',
+ intersect: false,
+ },
+ plugins: {
+ legend: {
+ position: 'top',
+ },
+ title: {
+ display: true,
+ text: t`Top 10 Countries [pxls / day]`,
+ },
+ },
+ };
+ if (isDarkMode) {
+ const sColor = '#e6e6e6';
+ const lColor = '#656565';
+ options.color = sColor;
+ options.scales.x.ticks = {
+ color: sColor,
+ };
+ options.scales.x.grid.color = lColor;
+ options.scales.y.ticks = {
+ color: sColor,
+ };
+ options.scales.y.grid.color = lColor;
+ options.plugins.title.color = sColor;
+ }
+ return options;
+}
+
+export function getCHistChartData(cHistStats) {
+ const dataPerCountry = {};
+ const labels = [];
+ let ts = Date.now();
+ let c = cHistStats.length;
+ while (c) {
+ const dAmount = cHistStats.length - c;
+ c -= 1;
+ // x label
+ const date = new Date(ts);
+ labels.unshift(`${date.getUTCMonth() + 1} / ${date.getUTCDate()}`);
+ ts -= 1000 * 3600 * 24;
+ // y data per country
+ const dailyRanks = cHistStats[c];
+ for (let i = 0; i < dailyRanks.length; i += 1) {
+ const { cc, px } = dailyRanks[i];
+ if (!dataPerCountry[cc]) {
+ dataPerCountry[cc] = [];
+ }
+ const countryDat = dataPerCountry[cc];
+ while (countryDat.length < dAmount) {
+ countryDat.push(null);
+ }
+ countryDat.push(px);
+ }
+ }
+ const countries = Object.keys(dataPerCountry);
+ const datasets = countries.map((cc) => {
+ const color = colorFromText(`${cc}${cc}${cc}${cc}${cc}`);
+ return {
+ label: cc,
+ data: dataPerCountry[cc],
+ borderColor: color,
+ backgroundColor: color,
+ };
+ });
+ return {
+ labels,
+ datasets,
+ };
+}
+
+export function getOnlineStatsOpts(isDarkMode) {
+ const options = {
+ responsive: true,
+ scales: {
+ x: {
+ grid: {
+ drawBorder: false,
+ },
+ },
+ y: {
+ grid: {
+ drawBorder: false,
+ },
+ },
+ },
+ interaction: {
+ mode: 'index',
+ intersect: false,
+ },
+ plugins: {
+ legend: {
+ display: false,
+ },
+ title: {
+ display: true,
+ text: t`Players Online per full hour`,
+ },
+ },
+ };
+ if (isDarkMode) {
+ const sColor = '#e6e6e6';
+ const lColor = '#656565';
+ options.color = sColor;
+ options.scales.x.ticks = {
+ color: sColor,
+ };
+ options.scales.x.grid.color = lColor;
+ options.scales.y.ticks = {
+ color: sColor,
+ };
+ options.scales.y.grid.color = lColor;
+ options.plugins.title.color = sColor;
+ }
+ return options;
+}
+
+export function getOnlineStatsData(onlineStats) {
+ const labels = [];
+ const data = [];
+ let ts = Date.now();
+ let c = onlineStats.length;
+ while (c) {
+ c -= 1;
+ const date = new Date(ts);
+ const hours = date.getHours();
+ const key = hours || `${date.getMonth() + 1} / ${date.getDate()}`;
+ labels.unshift(String(key));
+ ts -= 1000 * 3600;
+ data.push(onlineStats[c]);
+ }
+ return {
+ labels,
+ datasets: [{
+ label: 'Players',
+ data,
+ borderColor: '#3fadda',
+ backgroundColor: '#3fadda',
+ }],
+ };
+}
+
+export function getHistChartOpts(isDarkMode) {
+ const options = {
+ responsive: true,
+ aspectRatio: 1.4,
+ scales: {
+ x: {
+ grid: {
+ drawBorder: false,
+ },
+ },
+ y: {
+ grid: {
+ drawBorder: false,
+ },
+ },
+ },
+ interaction: {
+ mode: 'nearest',
+ axis: 'xy',
+ intersect: false,
+ },
+ plugins: {
+ legend: {
+ display: false,
+ },
+ title: {
+ display: true,
+ text: t`Top 10 Players [pxls / day]`,
+ },
+ },
+ };
+ if (isDarkMode) {
+ const sColor = '#e6e6e6';
+ const lColor = '#656565';
+ options.color = sColor;
+ options.scales.x.ticks = {
+ color: sColor,
+ };
+ options.scales.x.grid.color = lColor;
+ options.scales.y.ticks = {
+ color: sColor,
+ };
+ options.scales.y.grid.color = lColor;
+ options.plugins.title.color = sColor;
+ }
+ return options;
+}
+
+export function getHistChartData(histStats) {
+ const { users, stats } = histStats;
+ const dataPerUser = {};
+ users.forEach((u) => { dataPerUser[u.id] = { name: u.name, data: [] }; });
+ const labels = [];
+ let ts = Date.now();
+ let c = stats.length;
+ // skipping todays dataset
+ while (c > 1) {
+ const dAmount = stats.length - c;
+ c -= 1;
+ // x label
+ ts -= 1000 * 3600 * 24;
+ const date = new Date(ts);
+ labels.unshift(`${date.getUTCMonth() + 1} / ${date.getUTCDate()}`);
+ // y data per user
+ const dailyRanks = stats[c];
+ for (let i = 0; i < dailyRanks.length; i += 1) {
+ const { id, px } = dailyRanks[i];
+ const userDat = dataPerUser[id].data;
+ while (userDat.length < dAmount) {
+ userDat.push(null);
+ }
+ userDat.push(px);
+ }
+ }
+ const userIds = Object.keys(dataPerUser);
+ const datasets = userIds.map((id) => {
+ const { name, data } = dataPerUser[id];
+ const color = colorFromText(name);
+ return {
+ label: name,
+ data,
+ borderColor: color,
+ backgroundColor: color,
+ };
+ });
+ return {
+ labels,
+ datasets,
+ };
+}
+
+export function getCPieOpts(isDarkMode) {
+ const options = {
+ responsive: true,
+ plugins: {
+ legend: {
+ display: false,
+ },
+ title: {
+ display: true,
+ text: t`Countries by Pixels Today`,
+ },
+ },
+ };
+ if (isDarkMode) {
+ const sColor = '#e6e6e6';
+ options.plugins.title.color = sColor;
+ }
+ return options;
+}
+
+export function getCPieData(dailyCRanking) {
+ const labels = [];
+ const data = [];
+ const backgroundColor = [];
+ dailyCRanking.forEach((r) => {
+ const { cc, px } = r;
+ labels.push(cc);
+ data.push(px);
+ const color = colorFromText(`${cc}${cc}${cc}${cc}${cc}`);
+ backgroundColor.push(color);
+ });
+ return {
+ labels,
+ datasets: [{
+ label: '# of Pixels',
+ data,
+ backgroundColor,
+ borderWidth: 1,
+ }],
+ };
+}
+
+export function getPDailyStatsOpts(isDarkMode) {
+ const options = {
+ responsive: true,
+ scales: {
+ x: {
+ grid: {
+ drawBorder: false,
+ },
+ },
+ y: {
+ grid: {
+ drawBorder: false,
+ },
+ },
+ },
+ interaction: {
+ mode: 'index',
+ intersect: false,
+ },
+ plugins: {
+ legend: {
+ display: false,
+ },
+ title: {
+ display: true,
+ text: t`Total Pixels placed per day`,
+ },
+ },
+ };
+ if (isDarkMode) {
+ const sColor = '#e6e6e6';
+ const lColor = '#656565';
+ options.color = sColor;
+ options.scales.x.ticks = {
+ color: sColor,
+ };
+ options.scales.x.grid.color = lColor;
+ options.scales.y.ticks = {
+ color: sColor,
+ };
+ options.scales.y.grid.color = lColor;
+ options.plugins.title.color = sColor;
+ }
+ return options;
+}
+
+export function getPDailyStatsData(pDailyStats) {
+ const labels = [];
+ const data = [];
+ let ts = Date.now();
+ let c = pDailyStats.length;
+ while (c) {
+ c -= 1;
+ ts -= 1000 * 3600 * 24;
+ const date = new Date(ts);
+ labels.unshift(`${date.getUTCMonth() + 1} / ${date.getUTCDate()}`);
+ data.push(pDailyStats[c]);
+ }
+ return {
+ labels,
+ datasets: [{
+ label: 'Pixels',
+ data,
+ borderColor: '#3fadda',
+ backgroundColor: '#3fadda',
+ }],
+ };
+}
diff --git a/src/data/redis/ranks.js b/src/data/redis/ranks.js
index 304462c..1ddc1c8 100644
--- a/src/data/redis/ranks.js
+++ b/src/data/redis/ranks.js
@@ -11,6 +11,9 @@ const PREV_DAY_TOP_KEY = 'prankd';
const DAY_STATS_RANKS_KEY = 'ds';
const CDAY_STATS_RANKS_KEY = 'cds';
const ONLINE_CNTR_KEY = 'tonl';
+const PREV_HOURLY_PLACED_KEY = 'tmph';
+const HOURLY_PXL_CNTR_KEY = 'thpx';
+const DAILY_PXL_CNTR_KEY = 'tdpx';
/*
* get pixelcount and ranking
@@ -116,11 +119,11 @@ export async function getPrevTop() {
*/
export async function storeOnlinUserAmount(amount) {
await client.lPush(ONLINE_CNTR_KEY, String(amount));
- await client.lTrim(ONLINE_CNTR_KEY, 0, 14 * 24);
+ await client.lTrim(ONLINE_CNTR_KEY, 0, 7 * 24);
}
/*
- * get list of online counters
+ * get list of online counters per hour
*/
export async function getOnlineUserStats() {
let onlineStats = await client.lRange(ONLINE_CNTR_KEY, 0, -1);
@@ -128,6 +131,63 @@ export async function getOnlineUserStats() {
return onlineStats;
}
+/*
+ * calculate sum of scores of zset
+ * do NOT use it for large seets
+ */
+async function sumZSet(key) {
+ const ranks = await client.zRangeWithScores(key, 0, -1);
+ let total = 0;
+ ranks.forEach((r) => { total += Number(r.score); });
+ return total;
+}
+
+/*
+ * save hourly pixels placed by substracting
+ * the current daily total pixels set with the ones of an hour ago
+ */
+export async function storeHourlyPixelsPlaced() {
+ const tsNow = Date.now();
+ const prevData = await client.get(PREV_HOURLY_PLACED_KEY);
+ let prevTs;
+ let prevSum;
+ if (prevData) {
+ [prevTs, prevSum] = prevData.split(',').map((z) => Number(z));
+ }
+
+ let curSum = await sumZSet(DAILY_CRANKED_KEY);
+ await client.set(PREV_HOURLY_PLACED_KEY, `${tsNow},${curSum}`);
+
+ if (prevTs && prevTs > tsNow - 1000 * 3600 * 1.5) {
+ if (prevSum > curSum) {
+ // assume day change, add amount of yesterday
+ const dateKey = getDateKeyOfTs(tsNow - 1000 * 3600 * 24);
+ curSum += await sumZSet(`${CDAY_STATS_RANKS_KEY}:${dateKey}`);
+ }
+ const hourlyPixels = curSum - prevSum;
+ await client.lPush(HOURLY_PXL_CNTR_KEY, String(hourlyPixels));
+ await client.lTrim(HOURLY_PXL_CNTR_KEY, 0, 7 * 24);
+ }
+}
+
+/*
+ * get list of pixels placed per hour
+ */
+export async function getHourlyPixelStats() {
+ let pxlStats = await client.lRange(HOURLY_PXL_CNTR_KEY, 0, -1);
+ pxlStats = pxlStats.map((s) => Number(s));
+ return pxlStats;
+}
+
+/*
+ * get list of pixels placed per day
+ */
+export async function getDailyPixelStats() {
+ let pxlStats = await client.lRange(DAILY_PXL_CNTR_KEY, 0, -1);
+ pxlStats = pxlStats.map((s) => Number(s));
+ return pxlStats;
+}
+
/*
* get top 10 of daily pixels over the past days
*/
@@ -167,6 +227,20 @@ export async function getTopDailyHistory() {
};
}
+/*
+ * for populating past daily totals
+ */
+export async function populateDailyTotal() {
+ await client.del(DAILY_PXL_CNTR_KEY);
+ for (let i = 14; i > 0; i -= 1) {
+ const ts = Date.now() - 1000 * 3600 * 24 * i;
+ const key = `${CDAY_STATS_RANKS_KEY}:${getDateKeyOfTs(ts)}`;
+ // eslint-disable-next-line no-await-in-loop
+ const sum = await sumZSet(key);
+ client.lPush(DAILY_PXL_CNTR_KEY, String(sum));
+ }
+}
+
/*
* get top 10 countries over the past days
*/
@@ -209,12 +283,24 @@ export async function resetDailyRanks() {
const dateKey = getDateKeyOfTs(
Date.now() - 1000 * 3600 * 24,
);
+ // daily user rank
await client.rename(
DAILY_RANKED_KEY,
`${DAY_STATS_RANKS_KEY}:${dateKey}`,
);
+ // daily country rank
await client.rename(
DAILY_CRANKED_KEY,
`${CDAY_STATS_RANKS_KEY}:${dateKey}`,
);
+ // daily pixel counter
+ const sum = await sumZSet(`${CDAY_STATS_RANKS_KEY}:${dateKey}`);
+ await client.lPush(DAILY_PXL_CNTR_KEY, String(sum));
+ await client.lTrim(DAILY_PXL_CNTR_KEY, 0, 28);
+ // purge old data
+ const purgeDateKey = getDateKeyOfTs(
+ Date.now() - 1000 * 3600 * 24 * 21,
+ );
+ await client.del(`${DAY_STATS_RANKS_KEY}:${purgeDateKey}`);
+ await client.del(`${CDAY_STATS_RANKS_KEY}:${purgeDateKey}`);
}
diff --git a/src/store/actions/fetch.js b/src/store/actions/fetch.js
index 1d5a219..ac1166f 100644
--- a/src/store/actions/fetch.js
+++ b/src/store/actions/fetch.js
@@ -324,7 +324,7 @@ export function requestDeleteAccount(password) {
export function requestRankings() {
return makeAPIGETRequest(
- 'https://pixelplanet.fun/ranking',
+ '/ranking',
false,
);
}
diff --git a/src/store/actions/index.js b/src/store/actions/index.js
index 1b87f58..9339fba 100644
--- a/src/store/actions/index.js
+++ b/src/store/actions/index.js
@@ -279,6 +279,8 @@ export function receiveStats(
onlineStats,
cHistStats,
histStats,
+ pDailyStats,
+ pHourlyStats,
} = rankings;
return {
type: 'REC_STATS',
@@ -289,6 +291,8 @@ export function receiveStats(
onlineStats,
cHistStats,
histStats,
+ pDailyStats,
+ pHourlyStats,
};
}
diff --git a/src/store/reducers/ranks.js b/src/store/reducers/ranks.js
index c09d6a4..db45923 100644
--- a/src/store/reducers/ranks.js
+++ b/src/store/reducers/ranks.js
@@ -21,7 +21,9 @@ const initialState = {
prevTop: [],
onlineStats: [],
cHistStats: [],
- histStats: [],
+ histStats: { users: [], stats: [] },
+ pDailyStats: [],
+ pHourlyStats: [],
};
export default function ranks(
@@ -83,11 +85,10 @@ export default function ranks(
onlineStats,
cHistStats,
histStats,
+ pDailyStats,
+ pHourlyStats,
} = action;
- const lastFetch = Date.now();
- return {
- ...state,
- lastFetch,
+ const newStats = {
totalRanking,
totalDailyRanking,
dailyCRanking,
@@ -95,6 +96,14 @@ export default function ranks(
onlineStats,
cHistStats,
histStats,
+ pDailyStats,
+ pHourlyStats,
+ };
+ const lastFetch = Date.now();
+ return {
+ ...state,
+ lastFetch,
+ ...newStats,
};
}
diff --git a/src/store/selectors/gui.js b/src/store/selectors/gui.js
new file mode 100644
index 0000000..b812aa0
--- /dev/null
+++ b/src/store/selectors/gui.js
@@ -0,0 +1,9 @@
+/*
+ * selectors related to gui
+ */
+
+/* eslint-disable import/prefer-default-export */
+
+export const selectIsDarkMode = (state) => (
+ state.gui.style.indexOf('dark') !== -1
+);
diff --git a/src/store/selectors/ranks.js b/src/store/selectors/ranks.js
index ad09e9d..24b0004 100644
--- a/src/store/selectors/ranks.js
+++ b/src/store/selectors/ranks.js
@@ -12,4 +12,5 @@ export const selectStats = (state) => [
state.ranks.onlineStats,
state.ranks.cHistStats,
state.ranks.histStats,
+ state.ranks.pDailyStats,
];
diff --git a/src/store/sharedReducers.js b/src/store/sharedReducers.js
index 0027cc9..dfd5057 100644
--- a/src/store/sharedReducers.js
+++ b/src/store/sharedReducers.js
@@ -15,7 +15,7 @@ import canvas from './reducers/canvas';
import chat from './reducers/chat';
import fetching from './reducers/fetching';
-export const CURRENT_VERSION = 12;
+export const CURRENT_VERSION = 14;
export const migrate = (state, version) => {
// eslint-disable-next-line no-underscore-dangle