Goals Work

This commit is contained in:
zkldi
2022-03-26 23:45:43 +00:00
parent 200c3c6790
commit c61efe0c3e
6 changed files with 197 additions and 26 deletions
@@ -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 <Loading />;
}
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 (
<>
<Alert
style={{
backgroundColor: TachiConfig.type === "ktchi" ? "#e61c6e44" : "#527acc44",
color: "white",
}}
>
<div className="text-center">
<h1>Today's Summary</h1>
You've gotten <b>{data.recentPlaycount}</b> new score
{data.recentPlaycount !== 1 ? "s" : ""} today!
</div>
</Alert>
<Divider />
<h1>New Sessions</h1>
You've had <b>{data.recentSessions.length}</b> session
{data.recentSessions.length !== 1 ? "s" : ""} today!
<Divider />
{data.recentSessions.sort(NumericSOV(x => x.timeEnded, true)).map(e => (
<SessionCard sessionID={e.sessionID} key={e.sessionID} />
))}
<Divider />
{data.recentSessions.length !== 0 && (
<>
<Alert
style={{
backgroundColor:
TachiConfig.type === "ktchi" ? "#e61c6e44" : "#527acc44",
color: "white",
}}
>
<div className="text-center">
<h1>Today's Summary</h1>
You've gotten <b>{data.recentPlaycount}</b> new score
{data.recentPlaycount !== 1 ? "s" : ""} today!
</div>
</Alert>
<Divider />
<h1>New Sessions</h1>
You've had <b>{data.recentSessions.length}</b> session
{data.recentSessions.length !== 1 ? "s" : ""} today!
<Divider />
{data.recentSessions.sort(NumericSOV(x => x.timeEnded, true)).map(e => (
<SessionCard sessionID={e.sessionID} key={e.sessionID} />
))}
<Divider />
</>
)}
{data.recentAchievedGoals.length !== 0 && (
<>
<Alert
style={{
backgroundColor: ChangeOpacity(COLOUR_SET.gold, 0.2),
}}
>
<div className="text-center text-white">
<h1>
{RFA([
"Sweet!",
"Nice!",
"Lookin' good!",
"Good Stuff!",
"owo",
"Cool!",
"Awesome!",
"Epic!",
])}
</h1>
You've achieved <b>{data.recentAchievedGoals.length}</b> new goal
{data.recentAchievedGoals.length !== 1 ? "s" : ""} today!
</div>
<Divider />
<div className="text-white">
<ul>
{data.recentAchievedGoals.map(e => (
<GentleLink
to={`/dashboard/games/${e.game}/${e.playtype}/goals/${e.goalID}`}
key={e.goalID}
>
<li>{goalMap.get(e.goalID)?.title}</li>
</GentleLink>
))}
</ul>
</div>
</Alert>
<Divider />
</>
)}
{data.recentFolders.length !== 0 && (
<>
<h1>Here's some folders you checked out recently.</h1>
<Divider />
<div className="row">
{data.recentFolders.map(e => (
<FolderInfoComponent
key={e.folderID}
folder={e}
game={e.game}
playtype={e.playtype}
reqUser={user}
folderStats={folderInfoMap.get(e.folderID)!}
/>
))}
</div>
<Divider />
</>
)}
</>
);
}
@@ -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) {
<ApiError error={error} />;
@@ -48,7 +50,7 @@ export default function ChartInfoFormat({
{data.length !== 0 ? (
data.map(e => (
<li key={e.folderID}>
{user ? (
{user && ugs ? (
<Link
className="gentle-link"
to={`/dashboard/users/${user.username}/games/${game}/${playtype}/folders/${e.folderID}`}
@@ -0,0 +1,73 @@
import { ChangeOpacity } from "util/color-opacity";
import { NumericSOV, StrSOV } from "util/sorts";
import GentleLink from "components/util/GentleLink";
import React from "react";
import { COLOUR_SET, GoalDocument, PublicUserDocument, UserGoalDocument } from "tachi-common";
import { GamePT } from "types/react";
import TimestampCell from "../cells/TimestampCell";
import UserCell from "../cells/UserCell";
import TachiTable, { Header } from "../components/TachiTable";
export type UserGoalDataset = (UserGoalDocument & {
__related: {
user: PublicUserDocument;
goal: GoalDocument;
};
})[];
export default function UserGoalTable({
game,
playtype,
dataset,
}: GamePT & { dataset: UserGoalDataset }) {
const headers: Header<UserGoalDataset[0]>[] = [
["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 (
<TachiTable
dataset={dataset}
headers={headers}
entryName="Goals"
searchFunctions={{
user: k => k.__related.user.username,
goal: k => k.__related.goal.title,
timestamp: k => k.timeAchieved,
}}
rowFunction={d => (
<tr>
<UserCell game={game} playtype={playtype} user={d.__related.user} />
<td>
<GentleLink to={`/dashboard/games/${game}/${playtype}/goals/${d.goalID}`}>
{d.__related.goal.title}
</GentleLink>
</td>
<td
style={{
backgroundColor: d.achieved
? ChangeOpacity(COLOUR_SET.green, 0.2)
: ChangeOpacity(COLOUR_SET.red, 0.2),
}}
>
{d.achieved ? (
<b>Achieved!</b>
) : (
<>
<b>{d.progress ?? "N/A"}</b>
<small>/{d.outOfHuman}</small>
</>
)}
</td>
<TimestampCell time={d.timeAchieved} />
</tr>
)}
/>
);
}
+6
View File
@@ -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<I extends IDStrings = IDStrings> {
@@ -162,6 +164,10 @@ export interface UserRecentSummary {
recentPlaycount: integer;
recentSessions: SessionDocument[];
recentFolders: FolderDocument[];
recentFolderStats: FolderStatsInfo[];
recentGoals: GoalDocument[];
recentImprovedGoals: UserGoalDocument[];
recentAchievedGoals: UserGoalDocument[];
}
export interface ServerStatus {
+11
View File
@@ -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<string, GoalDocument>();
for (const goal of goals) {
goalMap.set(goal.goalID, goal);
}
return goalMap;
}
export function CreateChartIDMap<T extends { chartID: string }>(arr: T[]): Map<string, T> {
const map = new Map();
+9 -1
View File
@@ -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<<for another 5 years of life",
"I wouldn't trade one stupid decision for another 5 years of life",
"TRACKED.com",
"and you'll never believe what JK Rowling just said!",
];
export const heySplashes = [