diff --git a/client/src/app/pages/dashboard/DashboardPage.tsx b/client/src/app/pages/dashboard/DashboardPage.tsx index 518ec4a6f..10d1720d9 100644 --- a/client/src/app/pages/dashboard/DashboardPage.tsx +++ b/client/src/app/pages/dashboard/DashboardPage.tsx @@ -2,11 +2,14 @@ import { APIFetchV1 } from "util/api"; import { RFA } from "util/misc"; import { NumericSOV } from "util/sorts"; import { heySplashes } from "util/splashes"; +import { ChangeOpacity } from "util/color-opacity"; +import { CreateGoalMap } from "util/data"; import useSetSubheader from "components/layout/header/useSetSubheader"; import SessionCard from "components/sessions/SessionCard"; import ApiError from "components/util/ApiError"; import AsyncLoader from "components/util/AsyncLoader"; import Divider from "components/util/Divider"; +import GentleLink from "components/util/GentleLink"; import LinkButton from "components/util/LinkButton"; import Loading from "components/util/Loading"; import useApiQuery from "components/util/query/useApiQuery"; @@ -17,8 +20,9 @@ import { TachiConfig } from "lib/config"; import React, { useContext } from "react"; import { Alert } from "react-bootstrap"; import { Link } from "react-router-dom"; -import { GetGameConfig, PublicUserDocument } from "tachi-common"; +import { COLOUR_SET, GetGameConfig, PublicUserDocument } from "tachi-common"; import { UGSWithRankingData, UserRecentSummary } from "types/api-returns"; +import { FolderInfoComponent } from "./users/games/_game/_playtype/folders/FolderSelectPage"; import { GameStatContainer } from "./users/UserGamesPage"; export function DashboardPage() { @@ -73,33 +77,100 @@ function RecentInfo({ user }: { user: PublicUserDocument }) { return ; } - if (!data.recentSessions.length) { - return <>; + const folderInfoMap = new Map(); + for (const folderInfo of data.recentFolderStats) { + folderInfoMap.set(folderInfo.folderID, folderInfo); } + const goalMap = CreateGoalMap(data.recentGoals); + return ( <> - -
-

Today's Summary

- You've gotten {data.recentPlaycount} new score - {data.recentPlaycount !== 1 ? "s" : ""} today! -
-
- -

New Sessions

- You've had {data.recentSessions.length} session - {data.recentSessions.length !== 1 ? "s" : ""} today! - - {data.recentSessions.sort(NumericSOV(x => x.timeEnded, true)).map(e => ( - - ))} - + {data.recentSessions.length !== 0 && ( + <> + +
+

Today's Summary

+ You've gotten {data.recentPlaycount} new score + {data.recentPlaycount !== 1 ? "s" : ""} today! +
+
+ +

New Sessions

+ You've had {data.recentSessions.length} session + {data.recentSessions.length !== 1 ? "s" : ""} today! + + {data.recentSessions.sort(NumericSOV(x => x.timeEnded, true)).map(e => ( + + ))} + + + )} + {data.recentAchievedGoals.length !== 0 && ( + <> + +
+

+ {RFA([ + "Sweet!", + "Nice!", + "Lookin' good!", + "Good Stuff!", + "owo", + "Cool!", + "Awesome!", + "Epic!", + ])} +

+ You've achieved {data.recentAchievedGoals.length} new goal + {data.recentAchievedGoals.length !== 1 ? "s" : ""} today! +
+ +
+
    + {data.recentAchievedGoals.map(e => ( + +
  • {goalMap.get(e.goalID)?.title}
  • +
    + ))} +
+
+
+ + + )} + {data.recentFolders.length !== 0 && ( + <> +

Here's some folders you checked out recently.

+ +
+ {data.recentFolders.map(e => ( + + ))} +
+ + + )} ); } diff --git a/client/src/components/game/charts/ChartInfoFormat.tsx b/client/src/components/game/charts/ChartInfoFormat.tsx index eb48edb33..82bb9e1cf 100644 --- a/client/src/components/game/charts/ChartInfoFormat.tsx +++ b/client/src/components/game/charts/ChartInfoFormat.tsx @@ -6,6 +6,7 @@ import Loading from "components/util/Loading"; import Muted from "components/util/Muted"; import useApiQuery from "components/util/query/useApiQuery"; import { UserContext } from "context/UserContext"; +import { UserGameStatsContext } from "context/UserGameStatsContext"; import React, { useContext } from "react"; import { Col, Row } from "react-bootstrap"; import { Link } from "react-router-dom"; @@ -26,6 +27,7 @@ export default function ChartInfoFormat({ ); const { user } = useContext(UserContext); + const { ugs } = useContext(UserGameStatsContext); if (error) { ; @@ -48,7 +50,7 @@ export default function ChartInfoFormat({ {data.length !== 0 ? ( data.map(e => (
  • - {user ? ( + {user && ugs ? ( [] = [ + ["User", "User", StrSOV(x => x.__related.user.username)], + ["Goal", "Goal", StrSOV(x => x.__related.goal.title)], + [ + "Progress", + "Progress", + NumericSOV(x => (x.progress === null ? -Infinity : x.progress / x.outOf)), + ], + ["Achieved On", "Achieved", NumericSOV(x => x.timeAchieved ?? -Infinity)], + ]; + + return ( + k.__related.user.username, + goal: k => k.__related.goal.title, + timestamp: k => k.timeAchieved, + }} + rowFunction={d => ( + + + + + {d.__related.goal.title} + + + + {d.achieved ? ( + Achieved! + ) : ( + <> + {d.progress ?? "N/A"} + /{d.outOfHuman} + + )} + + + + )} + /> + ); +} diff --git a/client/src/types/api-returns.ts b/client/src/types/api-returns.ts index 071f38d6e..765303c4f 100644 --- a/client/src/types/api-returns.ts +++ b/client/src/types/api-returns.ts @@ -4,6 +4,7 @@ import { ClassAchievementDocument, FolderDocument, GamePTConfig, + GoalDocument, Grades, IDStrings, IDStringToGame, @@ -20,6 +21,7 @@ import { UGSRatingsLookup, UserGameStats, UserGameStatsSnapshot, + UserGoalDocument, } from "tachi-common"; export interface UGPTStatsReturn { @@ -162,6 +164,10 @@ export interface UserRecentSummary { recentPlaycount: integer; recentSessions: SessionDocument[]; recentFolders: FolderDocument[]; + recentFolderStats: FolderStatsInfo[]; + recentGoals: GoalDocument[]; + recentImprovedGoals: UserGoalDocument[]; + recentAchievedGoals: UserGoalDocument[]; } export interface ServerStatus { diff --git a/client/src/util/data.ts b/client/src/util/data.ts index 2c1c39cc7..f4df10dd4 100644 --- a/client/src/util/data.ts +++ b/client/src/util/data.ts @@ -1,6 +1,7 @@ import { ChartDocument, Game, + GoalDocument, IDStrings, integer, PublicUserDocument, @@ -33,6 +34,16 @@ export function CreateUserMap(users: PublicUserDocument[]) { return userMap; } +export function CreateGoalMap(goals: GoalDocument[]) { + const goalMap = new Map(); + + for (const goal of goals) { + goalMap.set(goal.goalID, goal); + } + + return goalMap; +} + export function CreateChartIDMap(arr: T[]): Map { const map = new Map(); diff --git a/client/src/util/splashes.ts b/client/src/util/splashes.ts index 35b5c31ae..c5ccb2ae0 100644 --- a/client/src/util/splashes.ts +++ b/client/src/util/splashes.ts @@ -110,6 +110,13 @@ export const loggedInSplashes = [ "ok deraadt miod", "What good are notebooks?", "Ladies and Gentlemen We Are...", + "Source: It came to me in a dream.", + "It's called solidarity, you wouldn't get it.", + "Come to my house and play BMS.", + "There is a leviathan in play.", + "Touch Grass.", + "arch btw", + "Upon Such Great Heights", ]; // Stuff that's bad for the kids, you know? @@ -126,8 +133,9 @@ export const contentiousSplashes = [ "I have the transfeminine urge to pee.", "I HAVE TO LIE IN THE MIDDLE OF THE FLOOR", "COMPLETELY MOTIONLESS NOT DARING TO BREATHE", - "I wouldn't trade one stupid decision<