From 9aa46c75395cfc8b7e59d1626fdb53975b00bcf3 Mon Sep 17 00:00:00 2001 From: Jan-Willem van Bremen Date: Fri, 12 Jul 2024 02:33:42 +0200 Subject: [PATCH] statistics.jsx graph with chart.js --- package-lock.json | 60 ++++++++++++++++++++++++++++++----------- package.json | 2 ++ pages/statistics.jsx | 64 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 108 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9e8ad01..f8b7a62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,10 +4,12 @@ "requires": true, "packages": { "": { + "name": "tricks", "dependencies": { "@formkit/auto-animate": "^0.8.1", "@heroicons/react": "^2.1.1", "@next/bundle-analyzer": "^14.2.3", + "chart.js": "^4.4.3", "dotenv": "^16.4.5", "mongoose": "^8.4.1", "next": "^14.2.3", @@ -15,6 +17,7 @@ "next-pwa": "^5.6.0", "nextjs-progressbar": "^0.0.16", "react": "^18.3.1", + "react-chartjs-2": "^5.2.0", "react-dom": "^18.3.1", "react-toastify": "^10.0.5", "react-transition-scroll": "^1.1.2", @@ -2661,6 +2664,11 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" + }, "node_modules/@mongodb-js/saslprep": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.7.tgz", @@ -3975,11 +3983,11 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -4148,6 +4156,17 @@ "node": ">=10" } }, + "node_modules/chart.js": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz", + "integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -4845,9 +4864,9 @@ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" }, "node_modules/ejs": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", - "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dependencies": { "jake": "^10.8.5" }, @@ -5283,9 +5302,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -7448,9 +7467,9 @@ } }, "node_modules/jsdom/node_modules/ws": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, "engines": { "node": ">=10.0.0" @@ -8722,6 +8741,15 @@ "node": ">=0.10.0" } }, + "node_modules/react-chartjs-2": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz", + "integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==", + "peerDependencies": { + "chart.js": "^4.1.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -10699,9 +10727,9 @@ } }, "node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "engines": { "node": ">=8.3.0" }, diff --git a/package.json b/package.json index cdebb4c..27842df 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "@formkit/auto-animate": "^0.8.1", "@heroicons/react": "^2.1.1", "@next/bundle-analyzer": "^14.2.3", + "chart.js": "^4.4.3", "dotenv": "^16.4.5", "mongoose": "^8.4.1", "next": "^14.2.3", @@ -18,6 +19,7 @@ "next-pwa": "^5.6.0", "nextjs-progressbar": "^0.0.16", "react": "^18.3.1", + "react-chartjs-2": "^5.2.0", "react-dom": "^18.3.1", "react-toastify": "^10.0.5", "react-transition-scroll": "^1.1.2", diff --git a/pages/statistics.jsx b/pages/statistics.jsx index ac00e4b..fdc99cb 100644 --- a/pages/statistics.jsx +++ b/pages/statistics.jsx @@ -1,5 +1,15 @@ import Stats from '../components/stats/Stats'; import { statsDef } from './index'; +import dbConnect from '../lib/dbConnect'; +import FlatgroundTrick from '../models/FlatgroundTrick'; +import { Line } from 'react-chartjs-2'; +import { requireAuth } from '../lib/serverUtils'; +import { capitalize } from '../lib/commonUtils'; +import { baseStyle, hiddenStyle } from '../lib/clientUtils'; +import TransitionScroll from 'react-transition-scroll'; +import { CategoryScale, Chart as ChartJS, LinearScale, LineElement, PointElement, Tooltip } from 'chart.js'; + +ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Tooltip); const userStatsDef = { 'Account Age': { endpoint: '/mine/profile/account-age', value: '...', suffix: 'Days' }, @@ -19,7 +29,44 @@ const comboStatsDef = { 'Manual Combos': { endpoint: '/mine/combos/manual-combos', value: '...' }, }; -export default function Statistics({}) { +export async function getServerSideProps({ params, req, res }) { + await dbConnect(); + + const { authQuery } = await requireAuth(req, res); + + const labels = Array.from({ length: 12 }, (_, i) => { + const date = new Date(); + date.setMonth(date.getMonth() - i); + return capitalize(date.toLocaleString('default', { month: 'short' })); + }).reverse(); + + const tricks = await FlatgroundTrick.find({ ...authQuery, landed: true }).lean(); + const data = { + labels, + datasets: [ + { + id: 1, + label: 'Landed Flatground Tricks', + tension: 0.3, + borderColor: '#fff', + data: labels.map( + (month) => + tricks.filter( + (trick) => capitalize(new Date(trick.landedAt).toLocaleString('default', { month: 'short' })) === month, + ).length, + ), + }, + ], + }; + + return { + props: { + data, + }, + }; +} + +export default function Statistics(props) { return (

Detailed Stats

@@ -28,7 +75,6 @@ export default function Statistics({}) { title="Account" description="Here are some basic statistics about your account." /> - + +
+

{'Landed over time'}

+

Here is a graph showing the number of tricks you have landed each month over the last year.

+
+
+ +
+
); }