From 1e438c9b97db2cc49f26332bbd0b3ad463efcaa6 Mon Sep 17 00:00:00 2001 From: DarkIntaqt <61588850+DarkIntaqt@users.noreply.github.com> Date: Sat, 12 Aug 2023 14:21:40 +0200 Subject: [PATCH] add calendar --- package-lock.json | 77 ++++++++++ package.json | 1 + src/css/user.module.css | 3 +- src/css/userCalendar.module.css | 76 ++++++++++ src/module/user/UserCalendar.js | 242 ++++++++++++++++++++++++++++++++ 5 files changed, 398 insertions(+), 1 deletion(-) create mode 100644 src/css/userCalendar.module.css create mode 100644 src/module/user/UserCalendar.js diff --git a/package-lock.json b/package-lock.json index 8b1f35d..f1f577c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "react-loadable": "^5.5.0", "react-router-dom": "^6.8.0", "react-timestamps": "github:DarkIntaqt/react-timestamps", + "react-tooltip": "^5.20.0", "web-vitals": "^3.1.0" }, "devDependencies": { @@ -2259,6 +2260,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@floating-ui/core": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.4.1.tgz", + "integrity": "sha512-jk3WqquEJRlcyu7997NtR5PibI+y5bi+LS3hPmguVClypenMsCY3CBa3LAQnozRCtCrYWSEtAdiskpamuJRFOQ==", + "dependencies": { + "@floating-ui/utils": "^0.1.1" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.1.tgz", + "integrity": "sha512-KwvVcPSXg6mQygvA1TjbN/gh///36kKtllIF8SUm0qpFj8+rvYrpvlYdL1JoA71SHpDqgSSdGOSoQ0Mp3uY5aw==", + "dependencies": { + "@floating-ui/core": "^1.4.1", + "@floating-ui/utils": "^0.1.1" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.1.tgz", + "integrity": "sha512-m0G6wlnhm/AX0H12IOWtK8gASEMffnX08RtKkCgTdHb9JpHKGloI7icFfLg9ZmQeavcvR0PKmzxClyuFPSjKWw==" + }, "node_modules/@humanwhocodes/config-array": { "version": "0.9.5", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", @@ -5670,6 +5693,11 @@ "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, + "node_modules/classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, "node_modules/clean-css": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.0.tgz", @@ -14920,6 +14948,19 @@ "react": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-tooltip": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.20.0.tgz", + "integrity": "sha512-LWBIHEZjwDW9ZJ/Dn2xeZrsz+WKMii61CIsx2XPfs1IiIRnWyvKJXrgy6uEGOXYvrnCd4jiEvurn8Y+zJ1bw5Q==", + "dependencies": { + "@floating-ui/dom": "^1.0.0", + "classnames": "^2.3.0" + }, + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -19311,6 +19352,28 @@ } } }, + "@floating-ui/core": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.4.1.tgz", + "integrity": "sha512-jk3WqquEJRlcyu7997NtR5PibI+y5bi+LS3hPmguVClypenMsCY3CBa3LAQnozRCtCrYWSEtAdiskpamuJRFOQ==", + "requires": { + "@floating-ui/utils": "^0.1.1" + } + }, + "@floating-ui/dom": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.1.tgz", + "integrity": "sha512-KwvVcPSXg6mQygvA1TjbN/gh///36kKtllIF8SUm0qpFj8+rvYrpvlYdL1JoA71SHpDqgSSdGOSoQ0Mp3uY5aw==", + "requires": { + "@floating-ui/core": "^1.4.1", + "@floating-ui/utils": "^0.1.1" + } + }, + "@floating-ui/utils": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.1.tgz", + "integrity": "sha512-m0G6wlnhm/AX0H12IOWtK8gASEMffnX08RtKkCgTdHb9JpHKGloI7icFfLg9ZmQeavcvR0PKmzxClyuFPSjKWw==" + }, "@humanwhocodes/config-array": { "version": "0.9.5", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", @@ -21899,6 +21962,11 @@ "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, + "classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, "clean-css": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.0.tgz", @@ -28592,6 +28660,15 @@ "from": "react-timestamps@github:DarkIntaqt/react-timestamps", "requires": {} }, + "react-tooltip": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.20.0.tgz", + "integrity": "sha512-LWBIHEZjwDW9ZJ/Dn2xeZrsz+WKMii61CIsx2XPfs1IiIRnWyvKJXrgy6uEGOXYvrnCd4jiEvurn8Y+zJ1bw5Q==", + "requires": { + "@floating-ui/dom": "^1.0.0", + "classnames": "^2.3.0" + } + }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", diff --git a/package.json b/package.json index 05c9784..1f710c6 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "react-loadable": "^5.5.0", "react-router-dom": "^6.8.0", "react-timestamps": "github:DarkIntaqt/react-timestamps", + "react-tooltip": "^5.20.0", "web-vitals": "^3.1.0" }, "devDependencies": { diff --git a/src/css/user.module.css b/src/css/user.module.css index 5932666..80d264e 100644 --- a/src/css/user.module.css +++ b/src/css/user.module.css @@ -252,7 +252,8 @@ img.mclogo { .selectedFilteroverview>.overview, .selectedFiltertitles>.titles, .selectedFilterstatistics>.statistics, -.selectedFilterhistory>.history { +.selectedFilterhistory>.history, +.selectedFiltercalendar>.calendar { color: var(--selected); border-bottom: 2px solid var(--selected) } diff --git a/src/css/userCalendar.module.css b/src/css/userCalendar.module.css new file mode 100644 index 0000000..e1dfb61 --- /dev/null +++ b/src/css/userCalendar.module.css @@ -0,0 +1,76 @@ +.calendar { + width: 100%; + float: left; +} + +.buttons { + width: 100%; +} + +.buttons button { + padding: 10px 15px; + background-color: var(--dark2); + color: var(--light0); + + font-size: .8rem; + cursor: pointer; + + border-radius: 5px; + margin: 10px; + + border: 2px solid var(--dark3); + outline: none; +} + +.buttons.matches button.matches, +.buttons.progress button.progress, +.buttons.upgrades button.upgrades { + border-color: var(--selected); + box-shadow: 0 0 5px var(--selected); +} + +.calendarElement { + margin: 20px; + float: left; + + display: grid; + + grid-template-rows: repeat(7, 1fr); + grid-template-columns: repeat(13, 1fr); + + grid-auto-flow: column; + + grid-gap: 5px; + + width: fit-content; +} + +.calendarElement>div:not(.day) { + width: 30px; + height: 30px; + + border-radius: 4px; +} + + +.calendarElement>div.day { + width: 30px; + height: 30px; + + display: flex; + align-items: center; + justify-content: center; + color: var(--light3); + text-align: center; + font-size: .8rem; +} + +.calendarElement>div.on { + background-color: rgba(13, 189, 255, var(--opacity, .15)); +} + +.calendarElement>div.off { + background-color: transparent; + border: 2px solid var(--dark3); + box-sizing: border-box; +} \ No newline at end of file diff --git a/src/module/user/UserCalendar.js b/src/module/user/UserCalendar.js new file mode 100644 index 0000000..79fd70d --- /dev/null +++ b/src/module/user/UserCalendar.js @@ -0,0 +1,242 @@ +import { Fragment, useEffect, useState } from "react"; +import Loader from "../Loader"; +import get from "../../func/get"; +import css from "../../css/userCalendar.module.css"; + +import { Tooltip } from 'react-tooltip' + +function rewrap(challenges) { + try { + let response = {} + for (let i = 0; i < challenges.length; i++) { + response[challenges[i][0]] = challenges[i] + } + return response + } catch (e) { + console.warn({ error: "Error: Most likely no matches played since feature activation" }) + } +} + +var getDaysArray = function (start, end) { + for (var arr = [], dt = new Date(start); dt <= new Date(end); dt.setDate(dt.getDate() + 1)) { + arr.push([`${dt.getMonth() + 1}-${dt.getDate()}`, dt.toDateString()]); + } + return arr; +}; + +function toObject(list) { + const response = {}; + + list.forEach(item => { + response[item.challengeId] = item; + }); + + return response; +} + +export default function Calendar({ user, verified }) { + + + function loadHistory() { + get("https://challenges.darkintaqt.com/api/v1/history/?id=" + user.id, setHistory) + } + + const [history, setHistory] = useState({}); + const [currentFilter, setCurrentFilter] = useState("progress"); + + function setFilter(evt) { + setCurrentFilter(evt.currentTarget.getAttribute("data-action")); + } + + + if (verified === 0 || user.challenges.length === 0) { + return
+ +

Loading Summoner...

+
+ } + if (verified === false) { + return ""; + } + + if (Object.keys(history).length === 0) { + loadHistory(); + return
+ +

Loading Calendar...

+
+ } + + + const dates = {}; + let challenges = rewrap(history.start); + + history.response.forEach(game => { + const date = new Date(game.date * 1000); + const dateString = `${date.getMonth() + 1}-${date.getDate()}` + + if (!dates[dateString]) { + dates[dateString] = [[game.changes, game.matchId]]; + } else { + dates[dateString].push([game.changes, game.matchId]); + } + }); + + let datesFormatted = Object.keys(dates).map((key) => [key, dates[key]]); + + const datesFinal = {}; + let mostProgress = 0; + let mostMatches = 0; + let mostUpgrades = 0; + + for (let i = 0; i < datesFormatted.length; i++) { + const date = datesFormatted[i]; + + const [dateId, data] = date; + + for (let j = 0; j < data.length; j++) { + const [changes, matchId] = data[j]; + let newChanges = [] + + for (let k = 0; k < changes.length; k++) { + const change = changes[k]; + let old = { + tier: -1, + points: 0 + } + try { + old = { + tier: challenges[change[0]][1], + points: challenges[change[0]][2] + } + } catch (e) { + console.warn(`${change[0]} does not exist`) + } finally { + + if (old.tier !== change[1] || old.points !== change[2]) { + + newChanges.push({ + challengeId: change[0], + new: { + tier: change[1], + points: change[2] + }, + old: old + }) + + challenges[change[0]] = change + } + } + } + datesFormatted[i][1][j][0] = newChanges; + } + + const newData = datesFormatted[i][1]; + let totalProgress = toObject(newData[0][0]); + let matchIds = []; + let upgrades = 0; + + for (let i = 0; i < newData.length; i++) { + const day = newData[i]; + matchIds.push(day[1]); + + for (let k = 0; k < day[0].length; k++) { + const oneDayData = day[0][k]; + + if (!totalProgress[oneDayData.challengeId]) { + totalProgress[oneDayData.challengeId] = oneDayData; + } else { + const today = totalProgress[oneDayData.challengeId]; + if (today.new.tier < oneDayData.new.tier || today.new.points < oneDayData.new.points) { + totalProgress[oneDayData.challengeId].new = today.new; + if (today.new.tier < oneDayData.new.tier) { + upgrades++; + } + } + } + } + } + + datesFinal[dateId] = { + matchIds, + totalProgress, + upgrades + } + + if (Object.keys(totalProgress).length > mostProgress) { + mostProgress = Object.keys(totalProgress).length + } + if (matchIds.length > mostMatches) { + mostMatches = matchIds.length; + } + if (upgrades > mostUpgrades) { + mostUpgrades = upgrades; + } + } + + let firstDate = Date.now() - (1000 * 60 * 60 * 24 * 90); + let datesArray = getDaysArray(firstDate, Date.now()); + + const datesComponent = datesArray.map((dateIds) => { + + const date = dateIds[0]; + + if (!datesFinal[date]) { + return
+ +
; + } else { + + if (Object.keys(datesFinal[date].totalProgress).length > 200) { + console.log(datesFinal[date]) + } + + let offset = .5; + if (currentFilter === "matches") { + offset = Math.min(datesFinal[date].matchIds.length / mostMatches, 1); + } + if (currentFilter === "progress") { + offset = Object.keys(datesFinal[date].totalProgress).length / mostProgress + } + if (currentFilter === "upgrades") { + console.log(datesFinal[date].upgrades); + offset = datesFinal[date].upgrades / mostUpgrades + } + + return

" + datesFinal[date].matchIds.length + " Game" + (datesFinal[date].matchIds.length === 1 ? "" : "s") + "
" + Object.keys(datesFinal[date].totalProgress).length + " progressed
" + datesFinal[date].upgrades + " upgraded"}> + +
; + } + + }); + + function overflow(min, max, num) { + while (num > max && num > min) { + num -= max; + } + return num; + } + + for (let i = 0; i < overflow(0, 6, new Date(firstDate).getDay() + 6); i++) { + datesComponent.unshift(
) + } + + ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"].reverse().forEach(day => { + datesComponent.unshift(
{day}
); + }) + + + + return
+ +
+ + + +
+ +
+ {datesComponent} +
+
; +} \ No newline at end of file