From 2114b43664fb0a6ec28eba9a9ce681a00a883675 Mon Sep 17 00:00:00 2001
From: zkldi <20380519+zkldi@users.noreply.github.com>
Date: Mon, 19 Dec 2022 16:42:25 +0000
Subject: [PATCH 1/3] feat: insights infrastructure + jubility as poc
---
.../games/_game/_playtype/ScoresPage.tsx | 6 +-
.../_game/_playtype/insights/InsightsPage.tsx | 80 ++++++++++++
.../games/_game/_playtype/tools/ToolsPage.tsx | 2 +-
client/src/app/routes/UserRoutes.tsx | 4 +
.../tools-insights/ToolsAndInsights.tsx | 67 ++++++++++
.../insights/JubilityBreakdownInsight.tsx | 123 ++++++++++++++++++
.../tools/BMSCustomTablesTool.tsx | 4 +-
.../tools/IIDXEamusementExportTool.tsx | 4 +-
.../tools/IIDXPlaylistsTool.tsx | 4 +-
client/src/components/tools/Tools.tsx | 37 ------
client/src/components/user/UGPTHeader.tsx | 18 ++-
client/src/types/ugpt.ts | 2 +-
.../framework/user-game-stats/rating.ts | 18 ++-
.../@gameSpecificRoutes/jubeat/router.ts | 35 +++++
.../games/@gameSpecificRoutes/router.ts | 2 +
15 files changed, 348 insertions(+), 58 deletions(-)
create mode 100644 client/src/app/pages/dashboard/users/games/_game/_playtype/insights/InsightsPage.tsx
create mode 100644 client/src/components/tools-insights/ToolsAndInsights.tsx
create mode 100644 client/src/components/tools-insights/insights/JubilityBreakdownInsight.tsx
rename client/src/components/{ => tools-insights}/tools/BMSCustomTablesTool.tsx (94%)
rename client/src/components/{ => tools-insights}/tools/IIDXEamusementExportTool.tsx (94%)
rename client/src/components/{ => tools-insights}/tools/IIDXPlaylistsTool.tsx (95%)
delete mode 100644 client/src/components/tools/Tools.tsx
create mode 100644 server/src/server/router/api/v1/users/_userID/games/@gameSpecificRoutes/jubeat/router.ts
diff --git a/client/src/app/pages/dashboard/users/games/_game/_playtype/ScoresPage.tsx b/client/src/app/pages/dashboard/users/games/_game/_playtype/ScoresPage.tsx
index 4ccd21aac..ce0c66ec5 100644
--- a/client/src/app/pages/dashboard/users/games/_game/_playtype/ScoresPage.tsx
+++ b/client/src/app/pages/dashboard/users/games/_game/_playtype/ScoresPage.tsx
@@ -144,9 +144,9 @@ function AlgSelector({
function useFetchPBs(url: string, reqUser: UserDocument) {
const { data, error } = useQuery(url, async () => {
const res = await APIFetchV1<{
- pbs: PBScoreDocument<"iidx:SP">[];
- charts: ChartDocument<"iidx:SP">[];
- songs: SongDocument<"iidx">[];
+ pbs: PBScoreDocument[];
+ charts: ChartDocument[];
+ songs: SongDocument[];
}>(url);
if (!res.success) {
diff --git a/client/src/app/pages/dashboard/users/games/_game/_playtype/insights/InsightsPage.tsx b/client/src/app/pages/dashboard/users/games/_game/_playtype/insights/InsightsPage.tsx
new file mode 100644
index 000000000..2d542ef16
--- /dev/null
+++ b/client/src/app/pages/dashboard/users/games/_game/_playtype/insights/InsightsPage.tsx
@@ -0,0 +1,80 @@
+import useSetSubheader from "components/layout/header/useSetSubheader";
+import Card from "components/layout/page/Card";
+import { GetGPTInsights } from "components/tools-insights/ToolsAndInsights";
+import Divider from "components/util/Divider";
+import LinkButton from "components/util/LinkButton";
+import React from "react";
+import { Col, Row } from "react-bootstrap";
+import { Link, Route, Switch } from "react-router-dom";
+import { FormatGame, GetGameConfig } from "tachi-common";
+import { UGPT } from "types/react";
+
+export default function InsightsPage({ reqUser, game, playtype }: UGPT) {
+ const gameConfig = GetGameConfig(game);
+ useSetSubheader(
+ ["Users", reqUser.username, "Games", gameConfig.name, playtype, "Insights"],
+ [reqUser, game, playtype],
+ `${reqUser.username}'s ${FormatGame(game, playtype)} Insights`
+ );
+
+ const insights = GetGPTInsights(game, playtype);
+
+ if (insights.length === 0) {
+ return (
+
+ {FormatGame(game, playtype)} has no insights. How'd you get here!
+
+ );
+ }
+
+ return (
+
+
+ {insights.map((tool) => (
+
+
+
+ < Back to all insights...
+
+ }
+ >
+ {tool.description}
+
+
+
+ {tool.component({ reqUser, game, playtype })}
+
+ ))}
+
+
+ {insights.map((tool) => (
+
+
+
+ View
+
+
+ }
+ >
+ {tool.description}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/client/src/app/pages/dashboard/users/games/_game/_playtype/tools/ToolsPage.tsx b/client/src/app/pages/dashboard/users/games/_game/_playtype/tools/ToolsPage.tsx
index db0a0ab17..db29333a6 100644
--- a/client/src/app/pages/dashboard/users/games/_game/_playtype/tools/ToolsPage.tsx
+++ b/client/src/app/pages/dashboard/users/games/_game/_playtype/tools/ToolsPage.tsx
@@ -1,6 +1,6 @@
import useSetSubheader from "components/layout/header/useSetSubheader";
import Card from "components/layout/page/Card";
-import { GetGPTTools } from "components/tools/Tools";
+import { GetGPTTools } from "components/tools-insights/ToolsAndInsights";
import Divider from "components/util/Divider";
import LinkButton from "components/util/LinkButton";
import React from "react";
diff --git a/client/src/app/routes/UserRoutes.tsx b/client/src/app/routes/UserRoutes.tsx
index 6db0c6657..c3005c20d 100644
--- a/client/src/app/routes/UserRoutes.tsx
+++ b/client/src/app/routes/UserRoutes.tsx
@@ -32,6 +32,7 @@ import { UGPTStatsReturn } from "types/api-returns";
import UserImportsPage from "app/pages/dashboard/users/UserImportsPage";
import { TargetsContextProvider } from "context/TargetsContext";
import ToolsPage from "app/pages/dashboard/users/games/_game/_playtype/tools/ToolsPage";
+import InsightsPage from "app/pages/dashboard/users/games/_game/_playtype/insights/InsightsPage";
import ScoresPage from "../pages/dashboard/users/games/_game/_playtype/ScoresPage";
import UserPage from "../pages/dashboard/users/UserPage";
@@ -267,6 +268,9 @@ function UserGamePlaytypeRoutes({ reqUser, game }: { reqUser: UserDocument; game
+
+
+
diff --git a/client/src/components/tools-insights/ToolsAndInsights.tsx b/client/src/components/tools-insights/ToolsAndInsights.tsx
new file mode 100644
index 000000000..9457e5a1d
--- /dev/null
+++ b/client/src/components/tools-insights/ToolsAndInsights.tsx
@@ -0,0 +1,67 @@
+import { Game, GetIDString, IDStrings, Playtype } from "tachi-common";
+import { GPTToolOrInsight } from "types/ugpt";
+import { BMSCustomTablesTool } from "./tools/BMSCustomTablesTool";
+import { IIDXEamusementExportTool } from "./tools/IIDXEamusementExportTool";
+import { IIDXPlaylistsTool } from "./tools/IIDXPlaylistsTool";
+import { JubilityBreakdownInsight } from "./insights/JubilityBreakdownInsight";
+
+// A tool is something that users can use, like exporting to a specific format
+// or having things integrate with the game in a neat way.
+// Tools are **NOT** displayed on someone elses profile. For that, you want
+// Insights (Fancy score renderers, basically).
+
+// What tools does each game support?
+const GPT_TOOLS: Record> = {
+ "bms:7K": [BMSCustomTablesTool],
+ "bms:14K": [BMSCustomTablesTool],
+ "chunithm:Single": [],
+ "gitadora:Dora": [],
+ "gitadora:Gita": [],
+ "iidx:DP": [IIDXEamusementExportTool, IIDXPlaylistsTool],
+ "iidx:SP": [IIDXEamusementExportTool, IIDXPlaylistsTool],
+ "itg:Stamina": [],
+ "jubeat:Single": [],
+ "museca:Single": [],
+ "pms:Controller": [],
+ "pms:Keyboard": [],
+ "popn:9B": [],
+ "sdvx:Single": [],
+ "usc:Controller": [],
+ "usc:Keyboard": [],
+ "wacca:Single": [],
+};
+
+// An insight is a page for a unique kind of data viz that tachi (generically) does not
+// pick up. Good examples of this would be something like viewing what goes into your
+// jubility.
+const GPT_INSIGHTS: Record> = {
+ "bms:7K": [],
+ "bms:14K": [],
+ "chunithm:Single": [],
+ "gitadora:Dora": [],
+ "gitadora:Gita": [],
+ "iidx:DP": [],
+ "iidx:SP": [],
+ "itg:Stamina": [],
+ "jubeat:Single": [JubilityBreakdownInsight],
+ "museca:Single": [],
+ "pms:Controller": [],
+ "pms:Keyboard": [],
+ "popn:9B": [],
+ "sdvx:Single": [],
+ "usc:Controller": [],
+ "usc:Keyboard": [],
+ "wacca:Single": [],
+};
+
+export function GetGPTTools(game: Game, playtype: Playtype) {
+ const idString = GetIDString(game, playtype);
+
+ return GPT_TOOLS[idString];
+}
+
+export function GetGPTInsights(game: Game, playtype: Playtype) {
+ const idString = GetIDString(game, playtype);
+
+ return GPT_INSIGHTS[idString];
+}
diff --git a/client/src/components/tools-insights/insights/JubilityBreakdownInsight.tsx b/client/src/components/tools-insights/insights/JubilityBreakdownInsight.tsx
new file mode 100644
index 000000000..7642c27aa
--- /dev/null
+++ b/client/src/components/tools-insights/insights/JubilityBreakdownInsight.tsx
@@ -0,0 +1,123 @@
+import { CreateChartMap } from "util/data";
+import { NumericSOV } from "util/sorts";
+import Card from "components/layout/page/Card";
+import PBTable from "components/tables/pbs/PBTable";
+import ApiError from "components/util/ApiError";
+import Divider from "components/util/Divider";
+import Loading from "components/util/Loading";
+import useApiQuery from "components/util/query/useApiQuery";
+import usePreferredRanking from "components/util/usePreferredRanking";
+import React from "react";
+import { Col, Row } from "react-bootstrap";
+import { ChartDocument, CreateSongMap, PBScoreDocument, SongDocument } from "tachi-common";
+import { UGPT } from "types/react";
+import { PBDataset } from "types/tables";
+import { GPTToolOrInsight } from "types/ugpt";
+
+function Component({ game, playtype, reqUser }: UGPT) {
+ const { data, error } = useApiQuery<{
+ songs: Array;
+ charts: Array;
+ pickUp: Array;
+ other: Array;
+ }>(`/users/${reqUser.id}/games/${game}/${playtype}/jubility`);
+
+ const preferredRanking = usePreferredRanking();
+
+ if (error) {
+ return ;
+ }
+
+ if (!data) {
+ return ;
+ }
+
+ const songMap = CreateSongMap(data.songs);
+ const chartMap = CreateChartMap(data.charts);
+
+ const pickUpDataset: PBDataset = [];
+ const normalDataset: PBDataset = [];
+
+ const sortedJubilities = [...data.pickUp, ...data.other]
+ .map((e) => e.calculatedData.jubility)
+ .sort(NumericSOV((x) => x ?? -Infinity, true));
+
+ for (const pb of data.pickUp) {
+ const song = songMap.get(pb.songID);
+ const chart = chartMap.get(pb.chartID);
+
+ if (!song) {
+ continue;
+ }
+
+ if (!chart) {
+ continue;
+ }
+
+ pickUpDataset.push({
+ ...pb,
+ __related: {
+ chart,
+ song,
+ index: sortedJubilities.indexOf(pb.calculatedData.jubility),
+ },
+ });
+ }
+
+ for (const pb of data.other) {
+ const song = songMap.get(pb.songID);
+ const chart = chartMap.get(pb.chartID);
+
+ if (!song) {
+ continue;
+ }
+
+ if (!chart) {
+ continue;
+ }
+
+ normalDataset.push({
+ ...pb,
+ __related: {
+ chart,
+ song,
+ index: sortedJubilities.indexOf(pb.calculatedData.jubility),
+ },
+ });
+ }
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export const JubilityBreakdownInsight: GPTToolOrInsight = {
+ name: "Jubility Breakdown",
+ urlPath: "jubility",
+ description: `See what PBs are going into profile jubility!`,
+ component: Component,
+};
diff --git a/client/src/components/tools/BMSCustomTablesTool.tsx b/client/src/components/tools-insights/tools/BMSCustomTablesTool.tsx
similarity index 94%
rename from client/src/components/tools/BMSCustomTablesTool.tsx
rename to client/src/components/tools-insights/tools/BMSCustomTablesTool.tsx
index ed03c899e..f9ae732ce 100644
--- a/client/src/components/tools/BMSCustomTablesTool.tsx
+++ b/client/src/components/tools-insights/tools/BMSCustomTablesTool.tsx
@@ -8,7 +8,7 @@ import { TachiConfig } from "lib/config";
import React from "react";
import { Col, Row } from "react-bootstrap";
import { UGPT } from "types/react";
-import { GPTTool } from "types/ugpt";
+import { GPTToolOrInsight } from "types/ugpt";
import Icon from "components/util/Icon";
import Divider from "components/util/Divider";
@@ -66,7 +66,7 @@ function Component({ game, playtype, reqUser }: UGPT) {
);
}
-export const BMSCustomTablesTool: GPTTool = {
+export const BMSCustomTablesTool: GPTToolOrInsight = {
name: `${TachiConfig.name} BMS Tables`,
urlPath: "custom-tables",
description: `${TachiConfig.name} has its own BMS tables that you can use in-game!`,
diff --git a/client/src/components/tools/IIDXEamusementExportTool.tsx b/client/src/components/tools-insights/tools/IIDXEamusementExportTool.tsx
similarity index 94%
rename from client/src/components/tools/IIDXEamusementExportTool.tsx
rename to client/src/components/tools-insights/tools/IIDXEamusementExportTool.tsx
index 6f952d511..38361564e 100644
--- a/client/src/components/tools/IIDXEamusementExportTool.tsx
+++ b/client/src/components/tools-insights/tools/IIDXEamusementExportTool.tsx
@@ -8,7 +8,7 @@ import { TachiConfig } from "lib/config";
import React from "react";
import { Alert, Button, Col, Row } from "react-bootstrap";
import { UGPT } from "types/react";
-import { GPTTool } from "types/ugpt";
+import { GPTToolOrInsight } from "types/ugpt";
function Component({ game, playtype, reqUser }: UGPT) {
const { data, error } = useApiQuery(
@@ -60,7 +60,7 @@ function Component({ game, playtype, reqUser }: UGPT) {
);
}
-export const IIDXEamusementExportTool: GPTTool = {
+export const IIDXEamusementExportTool: GPTToolOrInsight = {
name: `e-amusement CSV Export`,
urlPath: "eam-csv-export",
description: `Export your ${TachiConfig.name} scores into e-amusement format.`,
diff --git a/client/src/components/tools/IIDXPlaylistsTool.tsx b/client/src/components/tools-insights/tools/IIDXPlaylistsTool.tsx
similarity index 95%
rename from client/src/components/tools/IIDXPlaylistsTool.tsx
rename to client/src/components/tools-insights/tools/IIDXPlaylistsTool.tsx
index c386b965a..bf71786e1 100644
--- a/client/src/components/tools/IIDXPlaylistsTool.tsx
+++ b/client/src/components/tools-insights/tools/IIDXPlaylistsTool.tsx
@@ -8,7 +8,7 @@ import { TachiConfig } from "lib/config";
import React from "react";
import { Col, Row } from "react-bootstrap";
import { UGPT } from "types/react";
-import { GPTTool } from "types/ugpt";
+import { GPTToolOrInsight } from "types/ugpt";
import Icon from "components/util/Icon";
import Divider from "components/util/Divider";
@@ -76,7 +76,7 @@ function Component({ game, playtype, reqUser }: UGPT) {
);
}
-export const IIDXPlaylistsTool: GPTTool = {
+export const IIDXPlaylistsTool: GPTToolOrInsight = {
name: `${TachiConfig.name} IIDX Playlists`,
urlPath: "custom-tables",
description: `${TachiConfig.name} has its own IIDX playlists that you can use in-game via playlister!`,
diff --git a/client/src/components/tools/Tools.tsx b/client/src/components/tools/Tools.tsx
deleted file mode 100644
index 599c6b2e7..000000000
--- a/client/src/components/tools/Tools.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import { Game, GetIDString, IDStrings, Playtype } from "tachi-common";
-import { GPTTool } from "types/ugpt";
-import { BMSCustomTablesTool } from "./BMSCustomTablesTool";
-import { IIDXEamusementExportTool } from "./IIDXEamusementExportTool";
-import { IIDXPlaylistsTool } from "./IIDXPlaylistsTool";
-
-// A tool is something that users can use, like exporting to a specific format
-// or having things integrate with the game in a neat way.
-// Tools are **NOT** displayed on someone elses profile. For that, you want
-// Insights (Fancy score renderers, basically).
-
-// What tools does each game support?
-const GPT_TOOLS: Record> = {
- "bms:7K": [BMSCustomTablesTool],
- "bms:14K": [BMSCustomTablesTool],
- "chunithm:Single": [],
- "gitadora:Dora": [],
- "gitadora:Gita": [],
- "iidx:DP": [IIDXEamusementExportTool, IIDXPlaylistsTool],
- "iidx:SP": [IIDXEamusementExportTool, IIDXPlaylistsTool],
- "itg:Stamina": [],
- "jubeat:Single": [],
- "museca:Single": [],
- "pms:Controller": [],
- "pms:Keyboard": [],
- "popn:9B": [],
- "sdvx:Single": [],
- "usc:Controller": [],
- "usc:Keyboard": [],
- "wacca:Single": [],
-};
-
-export function GetGPTTools(game: Game, playtype: Playtype) {
- const idString = GetIDString(game, playtype);
-
- return GPT_TOOLS[idString];
-}
diff --git a/client/src/components/user/UGPTHeader.tsx b/client/src/components/user/UGPTHeader.tsx
index 255d1509c..658d6111a 100644
--- a/client/src/components/user/UGPTHeader.tsx
+++ b/client/src/components/user/UGPTHeader.tsx
@@ -10,11 +10,10 @@ import React, { useContext } from "react";
import { Button } from "react-bootstrap";
import { Game, Playtype, UserDocument } from "tachi-common";
import { UGPTStatsReturn } from "types/api-returns";
-import { UserContext } from "context/UserContext";
import useLUGPTSettings from "components/util/useLUGPTSettings";
import { UserSettingsContext } from "context/UserSettingsContext";
import FollowUserButton from "components/util/FollowUserButton";
-import { GetGPTTools } from "components/tools/Tools";
+import { GetGPTInsights, GetGPTTools } from "components/tools-insights/ToolsAndInsights";
import ProfileBadges from "./ProfileBadges";
import ProfilePicture from "./ProfilePicture";
import RankingData from "./UGPTRankingData";
@@ -201,10 +200,21 @@ export function UGPTBottomNav({
Sessions
,
+ ];
+
+ if (GetGPTInsights(game, playtype).length > 0) {
+ navItems.push(
+
+ Insights
+
+ );
+ }
+
+ navItems.push(
Leaderboard
- ,
- ];
+
+ );
if (isRequestedUser) {
navItems.push(
diff --git a/client/src/types/ugpt.ts b/client/src/types/ugpt.ts
index b41602d1e..85bbfc247 100644
--- a/client/src/types/ugpt.ts
+++ b/client/src/types/ugpt.ts
@@ -1,7 +1,7 @@
import React from "react";
import { UGPT } from "./react";
-export interface GPTTool {
+export interface GPTToolOrInsight {
urlPath: string;
name: string;
description: React.ReactChild;
diff --git a/server/src/lib/score-import/framework/user-game-stats/rating.ts b/server/src/lib/score-import/framework/user-game-stats/rating.ts
index b2f1b2b44..94491bac5 100644
--- a/server/src/lib/score-import/framework/user-game-stats/rating.ts
+++ b/server/src/lib/score-import/framework/user-game-stats/rating.ts
@@ -390,12 +390,7 @@ async function GetBestJubilityOnSongs(
const CURRENT_JUBEAT_HOT_VERSION: GPTSupportedVersions["jubeat:Single"] = "festo";
-async function CalculateJubility(
- game: Game,
- playtype: Playtype,
- userID: integer,
- _logger: KtLogger
-): Promise {
+export async function GetPBsForJubility(userID: integer) {
const hotSongs = await db.songs.jubeat.find(
{ "data.displayVersion": CURRENT_JUBEAT_HOT_VERSION },
{ projection: { id: 1 } }
@@ -415,6 +410,17 @@ async function CalculateJubility(
GetBestJubilityOnSongs(coldSongIDs, userID, "jubeat", "Single", 30),
]);
+ return { bestHotScores, bestScores };
+}
+
+async function CalculateJubility(
+ game: Game,
+ playtype: Playtype,
+ userID: integer,
+ _logger: KtLogger
+): Promise {
+ const { bestHotScores, bestScores } = await GetPBsForJubility(userID);
+
let jubility = 0;
jubility = jubility + bestHotScores.reduce((a, e) => a + (e.calculatedData.jubility ?? 0), 0);
diff --git a/server/src/server/router/api/v1/users/_userID/games/@gameSpecificRoutes/jubeat/router.ts b/server/src/server/router/api/v1/users/_userID/games/@gameSpecificRoutes/jubeat/router.ts
new file mode 100644
index 000000000..97c2cd005
--- /dev/null
+++ b/server/src/server/router/api/v1/users/_userID/games/@gameSpecificRoutes/jubeat/router.ts
@@ -0,0 +1,35 @@
+import { Router } from "express";
+import { GetPBsForJubility } from "lib/score-import/framework/user-game-stats/rating";
+import { GetRelevantSongsAndCharts } from "utils/db";
+import { GetUser } from "utils/req-tachi-data";
+
+const router: Router = Router({ mergeParams: true });
+
+/**
+ * Retrieve the PBs that went into this users jubility ranking.
+ *
+ * @name GET /api/v1/users/:userID/games/jubeat/Single/jubility
+ */
+router.get("/Single/jubility", async (req, res) => {
+ const user = GetUser(req);
+
+ const { bestHotScores, bestScores } = await GetPBsForJubility(user.id);
+
+ const { songs, charts } = await GetRelevantSongsAndCharts(
+ [...bestHotScores, ...bestScores],
+ "jubeat"
+ );
+
+ return res.status(200).json({
+ success: true,
+ description: `Retrieved scores that went into this users jubility.`,
+ body: {
+ songs,
+ charts,
+ pickUp: bestHotScores,
+ other: bestScores,
+ },
+ });
+});
+
+export default router;
diff --git a/server/src/server/router/api/v1/users/_userID/games/@gameSpecificRoutes/router.ts b/server/src/server/router/api/v1/users/_userID/games/@gameSpecificRoutes/router.ts
index d1081d5ed..4da9a2ced 100644
--- a/server/src/server/router/api/v1/users/_userID/games/@gameSpecificRoutes/router.ts
+++ b/server/src/server/router/api/v1/users/_userID/games/@gameSpecificRoutes/router.ts
@@ -4,11 +4,13 @@
import bmsRouter from "./bms/router";
import iidxRouter from "./iidx/router";
+import jubeatRouter from "./jubeat/router";
import { Router } from "express";
const router: Router = Router({ mergeParams: true });
router.use("/bms", bmsRouter);
router.use("/iidx", iidxRouter);
+router.use("/jubeat", jubeatRouter);
export default router;
From 7a4dc9f70664c05171506c55fd278d181606b691 Mon Sep 17 00:00:00 2001
From: zkldi <20380519+zkldi@users.noreply.github.com>
Date: Tue, 20 Dec 2022 05:01:42 +0000
Subject: [PATCH 2/3] fix: invalid chart link and tidy up "most played"
---
.../dashboard/games/_game/_playtype/GPTSongsPage.tsx | 3 ++-
client/src/util/data.ts | 8 ++++----
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/client/src/app/pages/dashboard/games/_game/_playtype/GPTSongsPage.tsx b/client/src/app/pages/dashboard/games/_game/_playtype/GPTSongsPage.tsx
index 8b48d2bf1..66c6550e9 100644
--- a/client/src/app/pages/dashboard/games/_game/_playtype/GPTSongsPage.tsx
+++ b/client/src/app/pages/dashboard/games/_game/_playtype/GPTSongsPage.tsx
@@ -82,7 +82,8 @@ function SearchSongsTable({ game, playtype, search }: { search: string } & GameP
<>
{search === "" && (
- Displaying the most played charts for {FormatGame(game, playtype)}
+
Displaying the most played charts for {FormatGame(game, playtype)}
+
)}
(scores: ScoreD
export function CreateChartLink(chart: ChartDocument, game: Game) {
if (chart.isPrimary) {
- return `/dashboard/games/${game}/${chart.playtype}/songs/${
- chart.songID
- }/${encodeURIComponent(chart.difficulty)}`;
+ return `/games/${game}/${chart.playtype}/songs/${chart.songID}/${encodeURIComponent(
+ chart.difficulty
+ )}`;
}
- return `/dashboard/games/${game}/${chart.playtype}/songs/${chart.songID}/${chart.chartID}`;
+ return `/games/${game}/${chart.playtype}/songs/${chart.songID}/${chart.chartID}`;
}
// stolen from server
From 48c3a9d23bd75243a677dd0bf79d009e7b085128 Mon Sep 17 00:00:00 2001
From: zkldi <20380519+zkldi@users.noreply.github.com>
Date: Tue, 20 Dec 2022 06:04:13 +0000
Subject: [PATCH 3/3] feat: squish tools and insights together
---
.../_game/_playtype/insights/InsightsPage.tsx | 80 -------------------
.../ToolsPage.tsx => utils/UGPTUtilsPage.tsx} | 75 ++++++++---------
client/src/app/routes/UserRoutes.tsx | 34 ++++----
client/src/components/gpt-utils/GPTUtils.tsx | 62 ++++++++++++++
.../insights/JubilityBreakdownInsight.tsx | 4 +-
.../tools/BMSCustomTablesTool.tsx | 5 +-
.../tools/IIDXEamusementExportTool.tsx | 6 +-
.../tools/IIDXPlaylistsTool.tsx | 10 +--
.../tools-insights/ToolsAndInsights.tsx | 67 ----------------
client/src/components/user/UGPTHeader.tsx | 40 ++++------
client/src/types/ugpt.ts | 3 +-
11 files changed, 146 insertions(+), 240 deletions(-)
delete mode 100644 client/src/app/pages/dashboard/users/games/_game/_playtype/insights/InsightsPage.tsx
rename client/src/app/pages/dashboard/users/games/_game/_playtype/{tools/ToolsPage.tsx => utils/UGPTUtilsPage.tsx} (56%)
create mode 100644 client/src/components/gpt-utils/GPTUtils.tsx
rename client/src/components/{tools-insights => gpt-utils}/insights/JubilityBreakdownInsight.tsx (96%)
rename client/src/components/{tools-insights => gpt-utils}/tools/BMSCustomTablesTool.tsx (94%)
rename client/src/components/{tools-insights => gpt-utils}/tools/IIDXEamusementExportTool.tsx (91%)
rename client/src/components/{tools-insights => gpt-utils}/tools/IIDXPlaylistsTool.tsx (87%)
delete mode 100644 client/src/components/tools-insights/ToolsAndInsights.tsx
diff --git a/client/src/app/pages/dashboard/users/games/_game/_playtype/insights/InsightsPage.tsx b/client/src/app/pages/dashboard/users/games/_game/_playtype/insights/InsightsPage.tsx
deleted file mode 100644
index 2d542ef16..000000000
--- a/client/src/app/pages/dashboard/users/games/_game/_playtype/insights/InsightsPage.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import useSetSubheader from "components/layout/header/useSetSubheader";
-import Card from "components/layout/page/Card";
-import { GetGPTInsights } from "components/tools-insights/ToolsAndInsights";
-import Divider from "components/util/Divider";
-import LinkButton from "components/util/LinkButton";
-import React from "react";
-import { Col, Row } from "react-bootstrap";
-import { Link, Route, Switch } from "react-router-dom";
-import { FormatGame, GetGameConfig } from "tachi-common";
-import { UGPT } from "types/react";
-
-export default function InsightsPage({ reqUser, game, playtype }: UGPT) {
- const gameConfig = GetGameConfig(game);
- useSetSubheader(
- ["Users", reqUser.username, "Games", gameConfig.name, playtype, "Insights"],
- [reqUser, game, playtype],
- `${reqUser.username}'s ${FormatGame(game, playtype)} Insights`
- );
-
- const insights = GetGPTInsights(game, playtype);
-
- if (insights.length === 0) {
- return (
-
- {FormatGame(game, playtype)} has no insights. How'd you get here!
-
- );
- }
-
- return (
-
-
- {insights.map((tool) => (
-
-
-
- < Back to all insights...
-
- }
- >
- {tool.description}
-
-
-
- {tool.component({ reqUser, game, playtype })}
-
- ))}
-
-
- {insights.map((tool) => (
-
-
-
- View
-
-
- }
- >
- {tool.description}
-
-
- ))}
-
-
-
- );
-}
diff --git a/client/src/app/pages/dashboard/users/games/_game/_playtype/tools/ToolsPage.tsx b/client/src/app/pages/dashboard/users/games/_game/_playtype/utils/UGPTUtilsPage.tsx
similarity index 56%
rename from client/src/app/pages/dashboard/users/games/_game/_playtype/tools/ToolsPage.tsx
rename to client/src/app/pages/dashboard/users/games/_game/_playtype/utils/UGPTUtilsPage.tsx
index db29333a6..98f8d33c6 100644
--- a/client/src/app/pages/dashboard/users/games/_game/_playtype/tools/ToolsPage.tsx
+++ b/client/src/app/pages/dashboard/users/games/_game/_playtype/utils/UGPTUtilsPage.tsx
@@ -1,47 +1,67 @@
import useSetSubheader from "components/layout/header/useSetSubheader";
import Card from "components/layout/page/Card";
-import { GetGPTTools } from "components/tools-insights/ToolsAndInsights";
+import { GetGPTUtils, GetGPTUtilsName } from "components/gpt-utils/GPTUtils";
import Divider from "components/util/Divider";
import LinkButton from "components/util/LinkButton";
-import React from "react";
+import { UserContext } from "context/UserContext";
+import React, { useContext } from "react";
import { Col, Row } from "react-bootstrap";
import { Link, Route, Switch } from "react-router-dom";
import { FormatGame, GetGameConfig } from "tachi-common";
import { UGPT } from "types/react";
+import { GPTUtility } from "types/ugpt";
-export default function ToolsPage({ reqUser, game, playtype }: UGPT) {
+export default function UGPTUtilsPage({ reqUser, game, playtype }: UGPT) {
const gameConfig = GetGameConfig(game);
+ const { user } = useContext(UserContext);
+
+ const isViewingOwnProfile = user?.id === reqUser.id;
+
+ const utils = GetGPTUtils(game, playtype);
+ const pageName = GetGPTUtilsName(game, playtype, isViewingOwnProfile);
+
useSetSubheader(
- ["Users", reqUser.username, "Games", gameConfig.name, playtype, "Tools"],
+ ["Users", reqUser.username, "Games", gameConfig.name, playtype, pageName ?? "Utils"],
[reqUser, game, playtype],
- `${reqUser.username}'s ${FormatGame(game, playtype)} Tools`
+ `${reqUser.username}'s ${FormatGame(game, playtype)} ${pageName ?? "Utils"}`
);
- const tools = GetGPTTools(game, playtype);
-
- if (tools.length === 0) {
- return (
-
- {FormatGame(game, playtype)} has no tools. How'd you get here!
-
- );
- }
-
return (
- {tools.map((tool) => (
+
+ {utils.map((util) => (
+
+
+
+ View
+
+
+ }
+ >
+ {util.description}
+
+
+ ))}
+
+
+ {utils.map((tool) => (
< Back to all tools...
@@ -55,25 +75,6 @@ export default function ToolsPage({ reqUser, game, playtype }: UGPT) {
{tool.component({ reqUser, game, playtype })}
))}
-
-
- {tools.map((tool) => (
-
-
-
- Use Tool
-
-
- }
- >
- {tool.description}
-
-
- ))}
-
);
diff --git a/client/src/app/routes/UserRoutes.tsx b/client/src/app/routes/UserRoutes.tsx
index c3005c20d..b6141db0f 100644
--- a/client/src/app/routes/UserRoutes.tsx
+++ b/client/src/app/routes/UserRoutes.tsx
@@ -1,19 +1,20 @@
import { APIFetchV1, APIFetchV1Return, ToAPIURL } from "util/api";
import { IsSupportedGame, IsSupportedPlaytype } from "util/asserts";
+import { ErrorPage } from "app/pages/ErrorPage";
import PlaytypeSelect from "app/pages/dashboard/games/_game/PlaytypeSelect";
-import FoldersMainPage from "app/pages/dashboard/users/games/_game/_playtype/folders/FoldersMainPage";
-import LeaderboardsPage from "app/pages/dashboard/users/games/_game/_playtype/LeaderboardsPage";
-import OverviewPage from "app/pages/dashboard/users/games/_game/_playtype/OverviewPage";
-import RivalsMainPage from "app/pages/dashboard/users/games/_game/_playtype/rivals/RivalsMainPage";
-import SessionsPage from "app/pages/dashboard/users/games/_game/_playtype/SessionsPage";
-import SpecificSessionPage from "app/pages/dashboard/users/games/_game/_playtype/SpecificSessionPage";
-import TargetsPage from "app/pages/dashboard/users/games/_game/_playtype/targets/TargetsPage";
-import UGPTSettingsPage from "app/pages/dashboard/users/games/_game/_playtype/UGPTSettingsPage";
import UserGamesPage from "app/pages/dashboard/users/UserGamesPage";
+import UserImportsPage from "app/pages/dashboard/users/UserImportsPage";
import UserIntegrationsPage from "app/pages/dashboard/users/UserIntegrationsPage";
import UserInvitesPage from "app/pages/dashboard/users/UserInvitesPage";
import UserSettingsPage from "app/pages/dashboard/users/UserSettingsPage";
-import { ErrorPage } from "app/pages/ErrorPage";
+import LeaderboardsPage from "app/pages/dashboard/users/games/_game/_playtype/LeaderboardsPage";
+import OverviewPage from "app/pages/dashboard/users/games/_game/_playtype/OverviewPage";
+import SessionsPage from "app/pages/dashboard/users/games/_game/_playtype/SessionsPage";
+import SpecificSessionPage from "app/pages/dashboard/users/games/_game/_playtype/SpecificSessionPage";
+import UGPTSettingsPage from "app/pages/dashboard/users/games/_game/_playtype/UGPTSettingsPage";
+import FoldersMainPage from "app/pages/dashboard/users/games/_game/_playtype/folders/FoldersMainPage";
+import RivalsMainPage from "app/pages/dashboard/users/games/_game/_playtype/rivals/RivalsMainPage";
+import TargetsPage from "app/pages/dashboard/users/games/_game/_playtype/targets/TargetsPage";
import RequireAuthAsUserParam from "components/auth/RequireAuthAsUserParam";
import LayoutHeaderContainer from "components/layout/LayoutHeaderContainer";
import { UGPTBottomNav, UGPTHeaderBody } from "components/user/UGPTHeader";
@@ -21,6 +22,7 @@ import { UserBottomNav, UserHeaderBody } from "components/user/UserHeader";
import Loading from "components/util/Loading";
import useApiQuery from "components/util/query/useApiQuery";
import { BackgroundContext } from "context/BackgroundContext";
+import { TargetsContextProvider } from "context/TargetsContext";
import { UGPTContextProvider } from "context/UGPTContext";
import { UserContext } from "context/UserContext";
import { UserSettingsContext } from "context/UserSettingsContext";
@@ -29,12 +31,9 @@ import { useQuery } from "react-query";
import { Redirect, Route, Switch, useHistory, useParams } from "react-router-dom";
import { FormatGame, Game, GetGameConfig, UserDocument, UserGameStats } from "tachi-common";
import { UGPTStatsReturn } from "types/api-returns";
-import UserImportsPage from "app/pages/dashboard/users/UserImportsPage";
-import { TargetsContextProvider } from "context/TargetsContext";
-import ToolsPage from "app/pages/dashboard/users/games/_game/_playtype/tools/ToolsPage";
-import InsightsPage from "app/pages/dashboard/users/games/_game/_playtype/insights/InsightsPage";
-import ScoresPage from "../pages/dashboard/users/games/_game/_playtype/ScoresPage";
+import UGPTUtilsPage from "app/pages/dashboard/users/games/_game/_playtype/utils/UGPTUtilsPage";
import UserPage from "../pages/dashboard/users/UserPage";
+import ScoresPage from "../pages/dashboard/users/games/_game/_playtype/ScoresPage";
export default function UserRoutes() {
const params = useParams<{ userID: string }>();
@@ -265,11 +264,8 @@ function UserGamePlaytypeRoutes({ reqUser, game }: { reqUser: UserDocument; game
-
-
-
-
-
+
+
diff --git a/client/src/components/gpt-utils/GPTUtils.tsx b/client/src/components/gpt-utils/GPTUtils.tsx
new file mode 100644
index 000000000..43d782a57
--- /dev/null
+++ b/client/src/components/gpt-utils/GPTUtils.tsx
@@ -0,0 +1,62 @@
+import { Game, IDStrings, Playtype } from "tachi-common";
+import { GPTUtility } from "types/ugpt";
+import { BMSCustomTablesTool } from "./tools/BMSCustomTablesTool";
+import { IIDXEamusementExportTool } from "./tools/IIDXEamusementExportTool";
+import { IIDXPlaylistsTool } from "./tools/IIDXPlaylistsTool";
+import { JubilityBreakdownInsight } from "./insights/JubilityBreakdownInsight";
+
+// What utils does each game support?
+const GPT_UTILS: Record> = {
+ "bms:7K": [BMSCustomTablesTool],
+ "bms:14K": [BMSCustomTablesTool],
+ "chunithm:Single": [],
+ "gitadora:Dora": [],
+ "gitadora:Gita": [],
+ "iidx:DP": [IIDXEamusementExportTool, IIDXPlaylistsTool],
+ "iidx:SP": [IIDXEamusementExportTool, IIDXPlaylistsTool],
+ "itg:Stamina": [],
+ "jubeat:Single": [JubilityBreakdownInsight],
+ "museca:Single": [],
+ "pms:Controller": [],
+ "pms:Keyboard": [],
+ "popn:9B": [],
+ "sdvx:Single": [],
+ "usc:Controller": [],
+ "usc:Keyboard": [],
+ "wacca:Single": [],
+};
+
+export function GetGPTUtils(game: Game, playtype: Playtype) {
+ const idString = `${game}:${playtype}` as IDStrings;
+
+ return GPT_UTILS[idString];
+}
+
+export function GetGPTUtilsName(game: Game, playtype: Playtype, isViewingOwnProfile: boolean) {
+ const utils = GetGPTUtils(game, playtype);
+
+ // things for personal use only are called "tools"
+ // things everyone might want to view about a person are called "insights".
+ // an example of an insight would be a jubility breakdown
+ // an example of a tool would be a eamusement csv export thing.
+ const tools = utils.filter((e) => e.personalUseOnly);
+ const insights = utils.filter((e) => e.personalUseOnly !== true);
+
+ if (isViewingOwnProfile) {
+ if (tools.length > 0 && insights.length > 0) {
+ return "Tools & Insights";
+ } else if (insights.length > 0) {
+ return "Insights";
+ } else if (tools.length > 0) {
+ return "Tools";
+ }
+
+ return null;
+ }
+
+ if (insights.length > 0) {
+ return "Insights";
+ }
+
+ return null;
+}
diff --git a/client/src/components/tools-insights/insights/JubilityBreakdownInsight.tsx b/client/src/components/gpt-utils/insights/JubilityBreakdownInsight.tsx
similarity index 96%
rename from client/src/components/tools-insights/insights/JubilityBreakdownInsight.tsx
rename to client/src/components/gpt-utils/insights/JubilityBreakdownInsight.tsx
index 7642c27aa..d3e31c826 100644
--- a/client/src/components/tools-insights/insights/JubilityBreakdownInsight.tsx
+++ b/client/src/components/gpt-utils/insights/JubilityBreakdownInsight.tsx
@@ -12,7 +12,7 @@ import { Col, Row } from "react-bootstrap";
import { ChartDocument, CreateSongMap, PBScoreDocument, SongDocument } from "tachi-common";
import { UGPT } from "types/react";
import { PBDataset } from "types/tables";
-import { GPTToolOrInsight } from "types/ugpt";
+import { GPTUtility } from "types/ugpt";
function Component({ game, playtype, reqUser }: UGPT) {
const { data, error } = useApiQuery<{
@@ -115,7 +115,7 @@ function Component({ game, playtype, reqUser }: UGPT) {
);
}
-export const JubilityBreakdownInsight: GPTToolOrInsight = {
+export const JubilityBreakdownInsight: GPTUtility = {
name: "Jubility Breakdown",
urlPath: "jubility",
description: `See what PBs are going into profile jubility!`,
diff --git a/client/src/components/tools-insights/tools/BMSCustomTablesTool.tsx b/client/src/components/gpt-utils/tools/BMSCustomTablesTool.tsx
similarity index 94%
rename from client/src/components/tools-insights/tools/BMSCustomTablesTool.tsx
rename to client/src/components/gpt-utils/tools/BMSCustomTablesTool.tsx
index f9ae732ce..43795f1a8 100644
--- a/client/src/components/tools-insights/tools/BMSCustomTablesTool.tsx
+++ b/client/src/components/gpt-utils/tools/BMSCustomTablesTool.tsx
@@ -8,7 +8,7 @@ import { TachiConfig } from "lib/config";
import React from "react";
import { Col, Row } from "react-bootstrap";
import { UGPT } from "types/react";
-import { GPTToolOrInsight } from "types/ugpt";
+import { GPTUtility } from "types/ugpt";
import Icon from "components/util/Icon";
import Divider from "components/util/Divider";
@@ -66,9 +66,10 @@ function Component({ game, playtype, reqUser }: UGPT) {
);
}
-export const BMSCustomTablesTool: GPTToolOrInsight = {
+export const BMSCustomTablesTool: GPTUtility = {
name: `${TachiConfig.name} BMS Tables`,
urlPath: "custom-tables",
description: `${TachiConfig.name} has its own BMS tables that you can use in-game!`,
component: Component,
+ personalUseOnly: true,
};
diff --git a/client/src/components/tools-insights/tools/IIDXEamusementExportTool.tsx b/client/src/components/gpt-utils/tools/IIDXEamusementExportTool.tsx
similarity index 91%
rename from client/src/components/tools-insights/tools/IIDXEamusementExportTool.tsx
rename to client/src/components/gpt-utils/tools/IIDXEamusementExportTool.tsx
index 38361564e..e8997615c 100644
--- a/client/src/components/tools-insights/tools/IIDXEamusementExportTool.tsx
+++ b/client/src/components/gpt-utils/tools/IIDXEamusementExportTool.tsx
@@ -1,6 +1,5 @@
import { CopyToClipboard } from "util/misc";
import ApiError from "components/util/ApiError";
-import DebugContent from "components/util/DebugContent";
import Divider from "components/util/Divider";
import Loading from "components/util/Loading";
import useApiQuery from "components/util/query/useApiQuery";
@@ -8,7 +7,7 @@ import { TachiConfig } from "lib/config";
import React from "react";
import { Alert, Button, Col, Row } from "react-bootstrap";
import { UGPT } from "types/react";
-import { GPTToolOrInsight } from "types/ugpt";
+import { GPTUtility } from "types/ugpt";
function Component({ game, playtype, reqUser }: UGPT) {
const { data, error } = useApiQuery(
@@ -60,9 +59,10 @@ function Component({ game, playtype, reqUser }: UGPT) {
);
}
-export const IIDXEamusementExportTool: GPTToolOrInsight = {
+export const IIDXEamusementExportTool: GPTUtility = {
name: `e-amusement CSV Export`,
urlPath: "eam-csv-export",
description: `Export your ${TachiConfig.name} scores into e-amusement format.`,
component: Component,
+ personalUseOnly: true,
};
diff --git a/client/src/components/tools-insights/tools/IIDXPlaylistsTool.tsx b/client/src/components/gpt-utils/tools/IIDXPlaylistsTool.tsx
similarity index 87%
rename from client/src/components/tools-insights/tools/IIDXPlaylistsTool.tsx
rename to client/src/components/gpt-utils/tools/IIDXPlaylistsTool.tsx
index bf71786e1..d0f3b9c59 100644
--- a/client/src/components/tools-insights/tools/IIDXPlaylistsTool.tsx
+++ b/client/src/components/gpt-utils/tools/IIDXPlaylistsTool.tsx
@@ -1,5 +1,4 @@
import { ToAPIURL } from "util/api";
-import { CopyToClipboard } from "util/misc";
import Card from "components/layout/page/Card";
import ApiError from "components/util/ApiError";
import Loading from "components/util/Loading";
@@ -8,9 +7,7 @@ import { TachiConfig } from "lib/config";
import React from "react";
import { Col, Row } from "react-bootstrap";
import { UGPT } from "types/react";
-import { GPTToolOrInsight } from "types/ugpt";
-import Icon from "components/util/Icon";
-import Divider from "components/util/Divider";
+import { GPTUtility } from "types/ugpt";
function Component({ game, playtype, reqUser }: UGPT) {
const { data, error } = useApiQuery<
@@ -76,9 +73,10 @@ function Component({ game, playtype, reqUser }: UGPT) {
);
}
-export const IIDXPlaylistsTool: GPTToolOrInsight = {
+export const IIDXPlaylistsTool: GPTUtility = {
name: `${TachiConfig.name} IIDX Playlists`,
- urlPath: "custom-tables",
+ urlPath: "playlists",
description: `${TachiConfig.name} has its own IIDX playlists that you can use in-game via playlister!`,
component: Component,
+ personalUseOnly: true,
};
diff --git a/client/src/components/tools-insights/ToolsAndInsights.tsx b/client/src/components/tools-insights/ToolsAndInsights.tsx
deleted file mode 100644
index 9457e5a1d..000000000
--- a/client/src/components/tools-insights/ToolsAndInsights.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import { Game, GetIDString, IDStrings, Playtype } from "tachi-common";
-import { GPTToolOrInsight } from "types/ugpt";
-import { BMSCustomTablesTool } from "./tools/BMSCustomTablesTool";
-import { IIDXEamusementExportTool } from "./tools/IIDXEamusementExportTool";
-import { IIDXPlaylistsTool } from "./tools/IIDXPlaylistsTool";
-import { JubilityBreakdownInsight } from "./insights/JubilityBreakdownInsight";
-
-// A tool is something that users can use, like exporting to a specific format
-// or having things integrate with the game in a neat way.
-// Tools are **NOT** displayed on someone elses profile. For that, you want
-// Insights (Fancy score renderers, basically).
-
-// What tools does each game support?
-const GPT_TOOLS: Record> = {
- "bms:7K": [BMSCustomTablesTool],
- "bms:14K": [BMSCustomTablesTool],
- "chunithm:Single": [],
- "gitadora:Dora": [],
- "gitadora:Gita": [],
- "iidx:DP": [IIDXEamusementExportTool, IIDXPlaylistsTool],
- "iidx:SP": [IIDXEamusementExportTool, IIDXPlaylistsTool],
- "itg:Stamina": [],
- "jubeat:Single": [],
- "museca:Single": [],
- "pms:Controller": [],
- "pms:Keyboard": [],
- "popn:9B": [],
- "sdvx:Single": [],
- "usc:Controller": [],
- "usc:Keyboard": [],
- "wacca:Single": [],
-};
-
-// An insight is a page for a unique kind of data viz that tachi (generically) does not
-// pick up. Good examples of this would be something like viewing what goes into your
-// jubility.
-const GPT_INSIGHTS: Record> = {
- "bms:7K": [],
- "bms:14K": [],
- "chunithm:Single": [],
- "gitadora:Dora": [],
- "gitadora:Gita": [],
- "iidx:DP": [],
- "iidx:SP": [],
- "itg:Stamina": [],
- "jubeat:Single": [JubilityBreakdownInsight],
- "museca:Single": [],
- "pms:Controller": [],
- "pms:Keyboard": [],
- "popn:9B": [],
- "sdvx:Single": [],
- "usc:Controller": [],
- "usc:Keyboard": [],
- "wacca:Single": [],
-};
-
-export function GetGPTTools(game: Game, playtype: Playtype) {
- const idString = GetIDString(game, playtype);
-
- return GPT_TOOLS[idString];
-}
-
-export function GetGPTInsights(game: Game, playtype: Playtype) {
- const idString = GetIDString(game, playtype);
-
- return GPT_INSIGHTS[idString];
-}
diff --git a/client/src/components/user/UGPTHeader.tsx b/client/src/components/user/UGPTHeader.tsx
index 658d6111a..4c3aa4697 100644
--- a/client/src/components/user/UGPTHeader.tsx
+++ b/client/src/components/user/UGPTHeader.tsx
@@ -13,7 +13,7 @@ import { UGPTStatsReturn } from "types/api-returns";
import useLUGPTSettings from "components/util/useLUGPTSettings";
import { UserSettingsContext } from "context/UserSettingsContext";
import FollowUserButton from "components/util/FollowUserButton";
-import { GetGPTInsights, GetGPTTools } from "components/tools-insights/ToolsAndInsights";
+import { GetGPTUtilsName } from "components/gpt-utils/GPTUtils";
import ProfileBadges from "./ProfileBadges";
import ProfilePicture from "./ProfilePicture";
import RankingData from "./UGPTRankingData";
@@ -202,10 +202,23 @@ export function UGPTBottomNav({
,
];
- if (GetGPTInsights(game, playtype).length > 0) {
+ const utilsName = GetGPTUtilsName(game, playtype, isRequestedUser);
+
+ if (utilsName) {
navItems.push(
-
- Insights
+
+ {utilsName}
+
+ );
+ }
+
+ if (isRequestedUser) {
+ navItems.push(
+
+ Rivals
+ ,
+
+ Goals & Quests
);
}
@@ -217,25 +230,6 @@ export function UGPTBottomNav({
);
if (isRequestedUser) {
- navItems.push(
-
- Rivals
- ,
-
- Goals & Quests
-
- );
-
- const tools = GetGPTTools(game, playtype);
-
- if (tools.length > 0) {
- navItems.push(
-
- Tools
-
- );
- }
-
navItems.push(
Settings
diff --git a/client/src/types/ugpt.ts b/client/src/types/ugpt.ts
index 85bbfc247..4b676ce84 100644
--- a/client/src/types/ugpt.ts
+++ b/client/src/types/ugpt.ts
@@ -1,9 +1,10 @@
import React from "react";
import { UGPT } from "./react";
-export interface GPTToolOrInsight {
+export interface GPTUtility {
urlPath: string;
name: string;
description: React.ReactChild;
component: (ugpt: UGPT) => JSX.Element;
+ personalUseOnly?: boolean;
}