mirror of
https://github.com/zkldi/Tachi.git
synced 2026-10-02 03:48:14 +03:00
Goals Work
This commit is contained in:
@@ -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>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
Reference in New Issue
Block a user