made bundle size smaller and added hover text to date set on a score
All checks were successful
deploy / deploy (push) Successful in 2m3s

This commit is contained in:
Lee 2023-10-23 08:37:18 +01:00
parent 86cfa7686f
commit 70ed248be7
9 changed files with 249 additions and 29 deletions

3
.gitignore vendored

@ -39,3 +39,6 @@ next-env.d.ts
# Sentry Config File # Sentry Config File
.sentryclirc .sentryclirc
# Webpack bundle analyzer
analyze

@ -1,4 +1,7 @@
const nextBuildId = require("next-build-id"); const nextBuildId = require("next-build-id");
const withBundleAnalyzer = require("@next/bundle-analyzer")({
enabled: false,
});
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = { const nextConfig = {
@ -26,10 +29,9 @@ const nextConfig = {
}, },
}; };
module.exports = nextConfig; module.exports = withBundleAnalyzer(nextConfig);
// // Injected content via Sentry wizard below
// Injected content via Sentry wizard below
const { withSentryConfig } = require("@sentry/nextjs"); const { withSentryConfig } = require("@sentry/nextjs");
@ -43,17 +45,17 @@ module.exports = withSentryConfig(
silent: true, silent: true,
org: "sentry", org: "sentry",
project: "scoresaber-reloaded", project: "scoresaber-reloaded",
url: "https://sentry.fascinated.cc/" url: "https://sentry.fascinated.cc/",
}, },
{ {
// For all available options, see: // For all available options, see:
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/ // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
// Upload a larger set of source maps for prettier stack traces (increases build time) // Upload a larger set of source maps for prettier stack traces (increases build time)
widenClientFileUpload: true, widenClientFileUpload: false,
// Transpiles SDK to be compatible with IE11 (increases bundle size) // Transpiles SDK to be compatible with IE11 (increases bundle size)
transpileClientSDK: true, transpileClientSDK: false,
// Routes browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers (increases server load) // Routes browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers (increases server load)
tunnelRoute: "/monitoring", tunnelRoute: "/monitoring",
@ -63,5 +65,5 @@ module.exports = withSentryConfig(
// Automatically tree-shake Sentry logger statements to reduce bundle size // Automatically tree-shake Sentry logger statements to reduce bundle size
disableLogger: true, disableLogger: true,
} },
); );

188
package-lock.json generated

@ -13,8 +13,8 @@
"bluebird": "^3.7.2", "bluebird": "^3.7.2",
"chart.js": "^4.4.0", "chart.js": "^4.4.0",
"clsx": "^2.0.0", "clsx": "^2.0.0",
"date-fns": "^2.30.0",
"encoding": "^0.1.13", "encoding": "^0.1.13",
"moment": "^2.29.4",
"next": "13.5.6", "next": "13.5.6",
"next-build-id": "^3.0.0", "next-build-id": "^3.0.0",
"node-fetch-cache": "^3.1.3", "node-fetch-cache": "^3.1.3",
@ -27,11 +27,13 @@
"zustand": "^4.4.3" "zustand": "^4.4.3"
}, },
"devDependencies": { "devDependencies": {
"@next/bundle-analyzer": "^13.5.6",
"@types/node": "^20", "@types/node": "^20",
"@types/node-fetch-cache": "^3.0.3", "@types/node-fetch-cache": "^3.0.3",
"@types/react": "^18", "@types/react": "^18",
"@types/react-dom": "^18", "@types/react-dom": "^18",
"autoprefixer": "^10.4.16", "autoprefixer": "^10.4.16",
"cross-env": "^7.0.3",
"eslint": "^8", "eslint": "^8",
"eslint-config-next": "13.5.6", "eslint-config-next": "13.5.6",
"postcss": "^8.4.31", "postcss": "^8.4.31",
@ -66,7 +68,6 @@
"version": "7.23.2", "version": "7.23.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz",
"integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==",
"dev": true,
"dependencies": { "dependencies": {
"regenerator-runtime": "^0.14.0" "regenerator-runtime": "^0.14.0"
}, },
@ -228,6 +229,15 @@
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
"integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw=="
}, },
"node_modules/@next/bundle-analyzer": {
"version": "13.5.6",
"resolved": "https://registry.npmjs.org/@next/bundle-analyzer/-/bundle-analyzer-13.5.6.tgz",
"integrity": "sha512-4P5YVpR3N/B5+p0TQ/rPAr+9fsjkdfCVTGzJhKwE7XHqS+QME4gYxAYeGKkfkHEkP2A3GKXs8QSp0LjIvWLI3g==",
"dev": true,
"dependencies": {
"webpack-bundle-analyzer": "4.7.0"
}
},
"node_modules/@next/env": { "node_modules/@next/env": {
"version": "13.5.6", "version": "13.5.6",
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.6.tgz", "resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.6.tgz",
@ -434,6 +444,12 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/@polka/url": {
"version": "1.0.0-next.23",
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.23.tgz",
"integrity": "sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==",
"dev": true
},
"node_modules/@rollup/plugin-commonjs": { "node_modules/@rollup/plugin-commonjs": {
"version": "24.0.0", "version": "24.0.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-24.0.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-24.0.0.tgz",
@ -960,6 +976,15 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
} }
}, },
"node_modules/acorn-walk": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
"dev": true,
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/agent-base": { "node_modules/agent-base": {
"version": "6.0.2", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@ -1657,6 +1682,24 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/cross-env": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
"dev": true,
"dependencies": {
"cross-spawn": "^7.0.1"
},
"bin": {
"cross-env": "src/bin/cross-env.js",
"cross-env-shell": "src/bin/cross-env-shell.js"
},
"engines": {
"node": ">=10.14",
"npm": ">=6",
"yarn": ">=1"
}
},
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.3", "version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@ -1695,6 +1738,21 @@
"integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
"dev": true "dev": true
}, },
"node_modules/date-fns": {
"version": "2.30.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
"integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
"dependencies": {
"@babel/runtime": "^7.21.0"
},
"engines": {
"node": ">=0.11"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/date-fns"
}
},
"node_modules/debug": { "node_modules/debug": {
"version": "4.3.4", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -1832,6 +1890,12 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/duplexer": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
"integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
"dev": true
},
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.4.557", "version": "1.4.557",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.557.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.557.tgz",
@ -2824,6 +2888,21 @@
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
"dev": true "dev": true
}, },
"node_modules/gzip-size": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz",
"integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==",
"dev": true,
"dependencies": {
"duplexer": "^0.1.2"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/has": { "node_modules/has": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz",
@ -3555,6 +3634,12 @@
"resolved": "https://registry.npmjs.org/locko/-/locko-1.0.0.tgz", "resolved": "https://registry.npmjs.org/locko/-/locko-1.0.0.tgz",
"integrity": "sha512-eK3TW5bJs6BrjmtzEb+RSyKt48etEitQviC6A6qMMSYl0dDFl0tIOD23QV/i0/rTuuXUgSYWX1yssbtop97Gog==" "integrity": "sha512-eK3TW5bJs6BrjmtzEb+RSyKt48etEitQviC6A6qMMSYl0dDFl0tIOD23QV/i0/rTuuXUgSYWX1yssbtop97Gog=="
}, },
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"node_modules/lodash.merge": { "node_modules/lodash.merge": {
"version": "4.6.2", "version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@ -3744,12 +3829,13 @@
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
}, },
"node_modules/moment": { "node_modules/mrmime": {
"version": "2.29.4", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz",
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==",
"dev": true,
"engines": { "engines": {
"node": "*" "node": ">=10"
} }
}, },
"node_modules/ms": { "node_modules/ms": {
@ -4072,6 +4158,15 @@
"wrappy": "1" "wrappy": "1"
} }
}, },
"node_modules/opener": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
"integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
"dev": true,
"bin": {
"opener": "bin/opener-bin.js"
}
},
"node_modules/optionator": { "node_modules/optionator": {
"version": "0.9.3", "version": "0.9.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
@ -4720,8 +4815,7 @@
"node_modules/regenerator-runtime": { "node_modules/regenerator-runtime": {
"version": "0.14.0", "version": "0.14.0",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
"integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA=="
"dev": true
}, },
"node_modules/regexp.prototype.flags": { "node_modules/regexp.prototype.flags": {
"version": "1.5.1", "version": "1.5.1",
@ -5047,6 +5141,20 @@
"is-arrayish": "^0.3.1" "is-arrayish": "^0.3.1"
} }
}, },
"node_modules/sirv": {
"version": "1.0.19",
"resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz",
"integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==",
"dev": true,
"dependencies": {
"@polka/url": "^1.0.0-next.20",
"mrmime": "^1.0.0",
"totalist": "^1.0.0"
},
"engines": {
"node": ">= 10"
}
},
"node_modules/slash": { "node_modules/slash": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@ -5432,6 +5540,15 @@
"node": ">=8.0" "node": ">=8.0"
} }
}, },
"node_modules/totalist": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz",
"integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/ts-api-utils": { "node_modules/ts-api-utils": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz",
@ -5681,6 +5798,38 @@
"node": ">=10.13.0" "node": ">=10.13.0"
} }
}, },
"node_modules/webpack-bundle-analyzer": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz",
"integrity": "sha512-j9b8ynpJS4K+zfO5GGwsAcQX4ZHpWV+yRiHDiL+bE0XHJ8NiPYLTNVQdlFYWxtpg9lfAQNlwJg16J9AJtFSXRg==",
"dev": true,
"dependencies": {
"acorn": "^8.0.4",
"acorn-walk": "^8.0.0",
"chalk": "^4.1.0",
"commander": "^7.2.0",
"gzip-size": "^6.0.0",
"lodash": "^4.17.20",
"opener": "^1.5.2",
"sirv": "^1.0.7",
"ws": "^7.3.1"
},
"bin": {
"webpack-bundle-analyzer": "lib/bin/analyzer.js"
},
"engines": {
"node": ">= 10.13.0"
}
},
"node_modules/webpack-bundle-analyzer/node_modules/commander": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
"dev": true,
"engines": {
"node": ">= 10"
}
},
"node_modules/webpack-sources": { "node_modules/webpack-sources": {
"version": "3.2.3", "version": "3.2.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
@ -5784,6 +5933,27 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
}, },
"node_modules/ws": {
"version": "7.5.9",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
"dev": true,
"engines": {
"node": ">=8.3.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/yallist": { "node_modules/yallist": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",

@ -14,8 +14,8 @@
"bluebird": "^3.7.2", "bluebird": "^3.7.2",
"chart.js": "^4.4.0", "chart.js": "^4.4.0",
"clsx": "^2.0.0", "clsx": "^2.0.0",
"date-fns": "^2.30.0",
"encoding": "^0.1.13", "encoding": "^0.1.13",
"moment": "^2.29.4",
"next": "13.5.6", "next": "13.5.6",
"next-build-id": "^3.0.0", "next-build-id": "^3.0.0",
"node-fetch-cache": "^3.1.3", "node-fetch-cache": "^3.1.3",
@ -28,11 +28,13 @@
"zustand": "^4.4.3" "zustand": "^4.4.3"
}, },
"devDependencies": { "devDependencies": {
"@next/bundle-analyzer": "^13.5.6",
"@types/node": "^20", "@types/node": "^20",
"@types/node-fetch-cache": "^3.0.3", "@types/node-fetch-cache": "^3.0.3",
"@types/react": "^18", "@types/react": "^18",
"@types/react-dom": "^18", "@types/react-dom": "^18",
"autoprefixer": "^10.4.16", "autoprefixer": "^10.4.16",
"cross-env": "^7.0.3",
"eslint": "^8", "eslint": "^8",
"eslint-config-next": "13.5.6", "eslint-config-next": "13.5.6",
"postcss": "^8.4.31", "postcss": "^8.4.31",

@ -19,8 +19,8 @@ import { useStore } from "zustand";
import Avatar from "../Avatar"; import Avatar from "../Avatar";
import Card from "../Card"; import Card from "../Card";
import Label from "../Label"; import Label from "../Label";
import PlayerChart from "./PlayerChart";
const PlayerChart = dynamic(() => import("./PlayerChart"));
const ReactCountryFlag = dynamic(() => import("react-country-flag")); const ReactCountryFlag = dynamic(() => import("react-country-flag"));
type PlayerInfoProps = { type PlayerInfoProps = {

@ -2,13 +2,13 @@ import { ScoresaberLeaderboardInfo } from "@/schemas/scoresaber/leaderboard";
import { ScoresaberPlayer } from "@/schemas/scoresaber/player"; import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
import { ScoresaberScore } from "@/schemas/scoresaber/score"; import { ScoresaberScore } from "@/schemas/scoresaber/score";
import { formatNumber } from "@/utils/number"; import { formatNumber } from "@/utils/number";
import { formatDate, formatTimeAgo } from "@/utils/timeUtils";
import { import {
CheckIcon, CheckIcon,
GlobeAsiaAustraliaIcon, GlobeAsiaAustraliaIcon,
XMarkIcon, XMarkIcon,
} from "@heroicons/react/20/solid"; } from "@heroicons/react/20/solid";
import clsx from "clsx"; import clsx from "clsx";
import moment from "moment";
import Image from "next/image"; import Image from "next/image";
import ScoreStatLabel from "./ScoreStatLabel"; import ScoreStatLabel from "./ScoreStatLabel";
@ -28,8 +28,11 @@ export default function Score({ score, player, leaderboard }: ScoreProps) {
<GlobeAsiaAustraliaIcon width={20} height={20} /> <GlobeAsiaAustraliaIcon width={20} height={20} />
<p>#{score.rank}</p> <p>#{score.rank}</p>
</div> </div>
<p className="hidden text-sm text-gray-200 md:block"> <p
{moment(score.timeSet).fromNow()} className="hidden text-sm text-gray-200 md:block"
title={formatDate(score.timeSet)}
>
{formatTimeAgo(score.timeSet)}
</p> </p>
</div> </div>
{/* Song Image */} {/* Song Image */}
@ -60,9 +63,11 @@ export default function Score({ score, player, leaderboard }: ScoreProps) {
{/* Time Set (Mobile) */} {/* Time Set (Mobile) */}
<div> <div>
{" "} <p
<p className="block text-sm text-gray-200 md:hidden"> className="block text-sm text-gray-200 md:hidden"
{moment(score.timeSet).fromNow()} title={formatDate(score.timeSet)}
>
{formatTimeAgo(score.timeSet)}
</p> </p>
</div> </div>
</div> </div>

@ -3,7 +3,6 @@
import { ScoresaberPlayer } from "@/schemas/scoresaber/player"; import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
import { ScoresaberSmallerPlayerScore } from "@/schemas/scoresaber/smaller/smallerPlayerScore"; import { ScoresaberSmallerPlayerScore } from "@/schemas/scoresaber/smaller/smallerPlayerScore";
import { ScoreSaberAPI } from "@/utils/scoresaber/api"; import { ScoreSaberAPI } from "@/utils/scoresaber/api";
import moment from "moment";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import { create } from "zustand"; import { create } from "zustand";
import { createJSONStorage, persist } from "zustand/middleware"; import { createJSONStorage, persist } from "zustand/middleware";
@ -215,8 +214,8 @@ export const useScoresaberScoresStore = create<ScoreSaberScoresStore>()(
if (timeUntilRefreshMs > 0) { if (timeUntilRefreshMs > 0) {
console.log( console.log(
"Waiting", "Waiting",
moment.duration(timeUntilRefreshMs).humanize(), timeUntilRefreshMs / 1000,
"to refresh scores for players", "seconds to refresh scores for players",
); );
setTimeout( setTimeout(
() => useScoresaberScoresStore.getState().updatePlayerScores(), () => useScoresaberScoresStore.getState().updatePlayerScores(),

@ -3,7 +3,6 @@
import { ScoresaberPlayer } from "@/schemas/scoresaber/player"; import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
import { SortType, SortTypes } from "@/types/SortTypes"; import { SortType, SortTypes } from "@/types/SortTypes";
import { ScoreSaberAPI } from "@/utils/scoresaber/api"; import { ScoreSaberAPI } from "@/utils/scoresaber/api";
import moment from "moment";
import { create } from "zustand"; import { create } from "zustand";
import { createJSONStorage, persist } from "zustand/middleware"; import { createJSONStorage, persist } from "zustand/middleware";
@ -81,7 +80,7 @@ export const useSettingsStore = create<SettingsStore>()(
if (timeUntilRefreshMs > 0) { if (timeUntilRefreshMs > 0) {
console.log( console.log(
"Waiting", "Waiting",
moment.duration(timeUntilRefreshMs).humanize(), timeUntilRefreshMs / 1000,
"to refresh profiles", "to refresh profiles",
); );
setTimeout(() => this.refreshProfiles(), timeUntilRefreshMs); setTimeout(() => this.refreshProfiles(), timeUntilRefreshMs);

40
src/utils/timeUtils.ts Normal file

@ -0,0 +1,40 @@
import { formatDistanceToNow, parseISO } from "date-fns";
/**
* Formats a timestamp to a human readable format
* eg: 1 minute ago, 2 hours ago, 3 days ago
*
* @param timestamp the timestamp to format
* @returns the formatted timestamp
*/
export function formatTimeAgo(timestamp: string) {
const date = parseISO(timestamp);
const now = new Date();
if (date > now) {
return "just now";
}
const timeDifference = formatDistanceToNow(date);
if (timeDifference === "less than a minute") {
return "just now";
} else {
return `${timeDifference.replace("about", "").replace("almost", "")} ago`;
}
}
/**
* Formats a timestamp to a human readable format
*
* @param timestamp the timestamp to format
* @returns the formatted timestamp
*/
export function formatDate(timestamp: string) {
const date = parseISO(timestamp);
return date.toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric",
});
}