Score Tables

This commit is contained in:
zkldi
2021-08-20 02:33:27 +01:00
parent d914fdda3c
commit 3d8f9c2f84
28 changed files with 657 additions and 107 deletions
+2 -2
View File
@@ -6,7 +6,7 @@
"start": "node scripts/start.js -o",
"build": "node scripts/build.js",
"test": "node scripts/test.js",
"lint": "eslint src --fix --ext .ts"
"lint": "eslint src --fix"
},
"browserslist": {
"production": [
@@ -74,7 +74,7 @@
"resolve": "1.12.0",
"resolve-url-loader": "3.1.0",
"socicon": "3.0.5",
"tachi-common": "0.1.30"
"tachi-common": "0.1.31"
},
"devDependencies": {
"@types/humanize-duration": "3.25.1",
+4 -4
View File
@@ -77,7 +77,7 @@ specifiers:
serve: 11.2.0
socicon: 3.0.5
style-loader: 1.0.0
tachi-common: 0.1.30
tachi-common: 0.1.31
terser-webpack-plugin: 1.4.1
ts-pnp: 1.1.4
typescript: 4.3.5
@@ -141,7 +141,7 @@ dependencies:
resolve: 1.12.0
resolve-url-loader: 3.1.0
socicon: 3.0.5
tachi-common: 0.1.30_typescript@4.3.5
tachi-common: 0.1.31_typescript@4.3.5
devDependencies:
'@types/humanize-duration': 3.25.1
@@ -11483,8 +11483,8 @@ packages:
strip-ansi: 6.0.0
dev: true
/tachi-common/0.1.30_typescript@4.3.5:
resolution: {integrity: sha512-bQOhX5VSmfaMpdbkgci1C/r4mcc68bl41fovZcfqvxUv2SFKa4fJL5rc+5durudZy1QGcnmUioexul2ZhdaofA==}
/tachi-common/0.1.31_typescript@4.3.5:
resolution: {integrity: sha512-jaJhv/zW+ye/GAKrYBiJb31shP4hSFhpssM56LUccZJKppDtd56lUu6fFtPWgydt3EIG7fVLqmTQJtDC0WRugg==}
dependencies:
monk: 7.3.4
tap: 15.0.9_typescript@4.3.5
+1
View File
@@ -52,6 +52,7 @@
"react/no-unescaped-entities": ["error", {"forbid": [">", "}"]}],
"react/display-name": "off",
"import/no-unresolved": "off",
"import/no-named-as-default": "off",
"react/prop-types": "warn",
"require-await": "warn",
"no-await-in-loop": "warn",
+1 -3
View File
@@ -76,9 +76,7 @@ export default function LoginPage() {
</div>
<div className="text-center mb-10 mb-lg-20">
<h3 className="font-size-h1">Log In</h3>
<span className="font-weight-bold text-dark-50">
Don't have an account?
</span>
<span className="font-weight-bold text-dark-50">Don't have an account?</span>
<Link to="/register" className="font-weight-bold ml-2">
Sign Up!
</Link>
+1 -2
View File
@@ -154,8 +154,7 @@ export default function RegisterPage() {
<br />I know it sucks to wait around, but the few rules we have are
enforced strictly.
<br />
The last thing you'd want is to accidentally get yourself
banned!
The last thing you'd want is to accidentally get yourself banned!
</p>
) : (
<></>
@@ -168,9 +168,7 @@ export default function CreditsPage() {
<li>
<ExternalLink href="https://node-tap.org">Node TAP</ExternalLink>
<br />
<small>
Node TAP is a testing framework that is.not.a("mess")
</small>
<small>Node TAP is a testing framework that is.not.a("mess")</small>
</li>
<li>
<ExternalLink href="https://automattic.github.io/monk/docs/GETTING_STARTED.html">
@@ -2,17 +2,17 @@ import React from "react";
import { GetGamePTConfig, PBScoreDocument, ScoreDocument } from "tachi-common";
import { ChangeOpacity } from "util/color-opacity";
export default function LampCell({ sc }: { sc: ScoreDocument | PBScoreDocument }) {
console.log(sc.game, sc.playtype);
const gptConfig = GetGamePTConfig(sc.game, sc.playtype);
export default function LampCell({ score }: { score: ScoreDocument | PBScoreDocument }) {
console.log(score.game, score.playtype);
const gptConfig = GetGamePTConfig(score.game, score.playtype);
return (
<td
style={{
backgroundColor: ChangeOpacity(gptConfig.lampColours[sc.scoreData.lamp], 0.2),
backgroundColor: ChangeOpacity(gptConfig.lampColours[score.scoreData.lamp], 0.2),
}}
>
<strong>{sc.scoreData.lamp}</strong>
<strong>{score.scoreData.lamp}</strong>
</td>
);
}
@@ -4,8 +4,8 @@ import { GamePT } from "types/react";
import { ChangeOpacity } from "util/color-opacity";
import { FormatMillions } from "util/misc";
export default function SDVXScoreCell({ score }: { score: PBScoreDocument | ScoreDocument }) {
const gptConfig = GetGamePTConfig("sdvx", "Single");
export default function MillionsScoreCell({ score }: { score: PBScoreDocument | ScoreDocument }) {
const gptConfig = GetGamePTConfig(score.game, score.playtype);
return (
<td
@@ -0,0 +1,41 @@
import React from "react";
import { COLOUR_SET, PBScoreDocument, ScoreDocument } from "tachi-common";
import { IsNullish } from "util/misc";
export default function SDVXJudgementCell({
score,
}: {
score: ScoreDocument<"museca:Single"> | PBScoreDocument<"museca:Single">;
}) {
// even if we dont have judgement data, we know what they got.
if (score.scoreData.lamp === "PERFECT CONNECT ALL") {
return (
<td>
<strong>
<span style={{ color: COLOUR_SET.teal }}>0</span>-
<span style={{ color: COLOUR_SET.red }}>0</span>
</strong>
</td>
);
}
// safety
if (score.scoreData.lamp === "CONNECT ALL") {
score.scoreData.judgements.miss = 0;
}
const judgements = score.scoreData.judgements;
if (IsNullish(judgements.miss) || IsNullish(judgements.near)) {
return <td>No Data.</td>;
}
return (
<td>
<strong>
<span style={{ color: COLOUR_SET.teal }}>{judgements.near}</span>-
<span style={{ color: COLOUR_SET.red }}>{judgements.miss}</span>
</strong>
</td>
);
}
@@ -0,0 +1,11 @@
import React from "react";
import { GetGamePTConfig, PBScoreDocument, ScoreDocument } from "tachi-common";
import { IsNotNullish } from "util/misc";
export default function RatingCell({ score }: { score: ScoreDocument | PBScoreDocument }) {
const gptConfig = GetGamePTConfig(score.game, score.playtype);
const v = score.calculatedData[gptConfig.defaultScoreRatingAlg];
return <td>{IsNotNullish(v) ? v!.toFixed(2) : "No Data"}</td>;
}
@@ -0,0 +1,41 @@
import React from "react";
import { COLOUR_SET, PBScoreDocument, ScoreDocument } from "tachi-common";
import { IsNullish } from "util/misc";
export default function SDVXJudgementCell({
score,
}: {
score: ScoreDocument<"sdvx:Single"> | PBScoreDocument<"sdvx:Single">;
}) {
// even if we dont have judgement data, we know what they got.
if (score.scoreData.lamp === "PERFECT ULTIMATE CHAIN") {
return (
<td>
<strong>
<span style={{ color: COLOUR_SET.teal }}>0</span>-
<span style={{ color: COLOUR_SET.red }}>0</span>
</strong>
</td>
);
}
// safety
if (score.scoreData.lamp === "ULTIMATE CHAIN") {
score.scoreData.judgements.miss = 0;
}
const judgements = score.scoreData.judgements;
if (IsNullish(judgements.miss) || IsNullish(judgements.near)) {
return <td>No Data.</td>;
}
return (
<td>
<strong>
<span style={{ color: COLOUR_SET.teal }}>{judgements.near}</span>-
<span style={{ color: COLOUR_SET.red }}>{judgements.miss}</span>
</strong>
</td>
);
}
@@ -5,17 +5,15 @@ import { ChangeOpacity } from "util/color-opacity";
import { FormatMillions } from "util/misc";
export default function ScoreCell({
game,
playtype,
score,
showScore = true,
scoreRenderFn,
}: GamePT & {
}: {
score: PBScoreDocument | ScoreDocument;
showScore?: boolean;
scoreRenderFn?: (s: number) => string;
}) {
const gptConfig = GetGamePTConfig(game, playtype);
const gptConfig = GetGamePTConfig(score.game, score.playtype);
return (
<td
@@ -34,13 +34,15 @@ export default function GenericScoreDropdown<I extends IDStrings = IDStrings>({
reqUser,
chart,
scoreState,
thisScore,
defaultView = "moreInfo",
DocComponent = GenericScoreContentDropdown,
DocComponent = props => GenericScoreContentDropdown({ renderScoreInfo: false, ...props }),
}: {
reqUser: PublicUserDocument;
chart: ChartDocument;
scoreState: ScoreState;
defaultView?: "vsPB" | "moreInfo" | "history" | "debug";
thisScore: ScoreDocument;
DocComponent?: (props: {
score: ScoreDocument<I> | PBScoreDocument<I>;
scoreState: ScoreState;
@@ -64,26 +66,6 @@ export default function GenericScoreDropdown<I extends IDStrings = IDStrings>({
}
);
const currentScoreDoc: ScoreDocument<I> | PBScoreDocument<I> | null = useMemo(() => {
if (!data) {
// dont worry about this null, it never gets below the rquery checks
return null;
}
if (view === "pb") {
return data.pb;
}
const idMap = {
scorePB: data.pb.composedFrom.scorePB,
lampPB: data.pb.composedFrom.lampPB,
...Object.fromEntries((data.pb.composedFrom.other ?? []).map(e => [e.name, e.scoreID])),
};
// @ts-expect-error awful
return data.scores.filter(e => e.scoreID === idMap[view])[0];
}, [view, data]);
if (error) {
return <>An error has occured. Whoops.</>;
}
@@ -102,25 +84,21 @@ export default function GenericScoreDropdown<I extends IDStrings = IDStrings>({
body = <></>; // todo
} else if (view === "debug") {
body = <DebugContent data={data} />;
} else {
body = <DocComponent score={currentScoreDoc!} scoreState={scoreState} />;
} else if (view === "moreInfo") {
body = <DocComponent score={thisScore as any} scoreState={scoreState} />;
}
return (
<DropdownStructure
buttons={
<>
<SelectButton setValue={setView} value={view} id="pb">
<Icon type="trophy" />
PB Info
<SelectButton setValue={setView} value={view} id="moreInfo">
<Icon type="chart-bar" />
This Score
</SelectButton>
<SelectButton setValue={setView} value={view} id="scorePB">
<Icon type="star-half-alt" />
Best Score
</SelectButton>
<SelectButton setValue={setView} value={view} id="lampPB">
<Icon type="lightbulb" />
Best Lamp
<SelectButton setValue={setView} value={view} id="vsPB">
<Icon type="balance-scale-right" />
Versus PB
</SelectButton>
<SelectButton setValue={setView} value={view} id="history" disabled>
<Icon type="history" />
@@ -416,13 +416,11 @@ function ElementStatTable({
}) as ScoreDocument;
if (type === "grade") {
preScoreCell = (
<ScoreCell score={mockScore} game={game} playtype={mockScore.playtype} />
);
preScoreCell = <ScoreCell score={mockScore} />;
} else {
preScoreCell = (
// @ts-expect-error temp
<IIDXLampCell sc={mockScore} game={game} playtype={mockScore.playtype} />
<IIDXLampCell sc={mockScore} />
);
}
}
@@ -22,7 +22,7 @@ export function ScoreInfo({ score }: { score: ScoreDocument }) {
</thead>
<tbody>
<tr>
<ScoreCell score={score} game={score.game} playtype={score.playtype} />
<ScoreCell score={score} />
<DeltaCell
game={score.game}
playtype={score.playtype}
@@ -30,7 +30,7 @@ export function ScoreInfo({ score }: { score: ScoreDocument }) {
percent={score.scoreData.percent}
grade={score.scoreData.grade}
/>
<LampCell sc={score} />
<LampCell score={score} />
<TimestampCell time={score.timeAchieved} />
</tr>
</tbody>
@@ -42,9 +42,11 @@ export function ScoreInfo({ score }: { score: ScoreDocument }) {
export default function GenericScoreContentDropdown({
score,
scoreState,
renderScoreInfo = true,
}: {
score: ScoreDocument | PBScoreDocument;
scoreState: { highlight: boolean; setHighlight: SetState<boolean> };
renderScoreInfo?: boolean;
}) {
const [comment, setComment] = useState(IsScore(score) ? score.comment : null);
@@ -55,10 +57,13 @@ export default function GenericScoreContentDropdown({
return (
<>
<div className="col-9">
<div className="row">
<div className="row h-100 justify-content-center">
<div className="d-flex align-items-center" style={{ height: "200px" }}>
<span className="text-muted">No graphs available :(</span>
</div>
{IsScore(score) ? (
<>
<ScoreInfo score={score} />
{renderScoreInfo && <ScoreInfo score={score} />}
<CommentContainer comment={comment} />
<ScoreEditButtons
score={score}
@@ -66,7 +71,7 @@ export default function GenericScoreContentDropdown({
/>
</>
) : (
<div className="col-12">
<div className="col-12 align-self-end">
<PBNote />
</div>
)}
@@ -21,10 +21,10 @@ export function ScoreInfo({ score }: { score: ScoreDocument<"iidx:SP" | "iidx:DP
</thead>
<tbody>
<tr>
<ScoreCell score={score} game="iidx" playtype="SP" />
<ScoreCell score={score} />
<DeltaCell
game="iidx"
playtype="SP"
playtype={score.playtype}
score={score.scoreData.score}
percent={score.scoreData.percent}
grade={score.scoreData.grade}
@@ -133,7 +133,7 @@ function Row({
<GenericPBDropdown
chart={pb.__related.chart}
reqUser={reqUser}
game="bms"
game={pb.game}
playtype={pb.playtype}
scoreState={scoreState}
/>
@@ -143,7 +143,7 @@ function Row({
{indexCol && <IndexCell index={pb.__related.index} />}
<BMSDifficultyCell chart={pb.__related.chart} />
<TitleCell song={pb.__related.song} chart={pb.__related.chart} game="bms" />
<ScoreCell score={pb} game="bms" playtype={pb.playtype} />
<ScoreCell score={pb} />
<DeltaCell
game="bms"
playtype={pb.playtype}
@@ -151,7 +151,7 @@ function Row({
percent={pb.scoreData.percent}
grade={pb.scoreData.grade}
/>
<LampCell sc={pb} />
<LampCell score={pb} />
<td>
{!IsNullish(pb.calculatedData.sieglinde)
? pb.calculatedData.sieglinde!.toFixed(2)
@@ -0,0 +1,131 @@
import React, { useState } from "react";
import TitleCell from "../cells/TitleCell";
import RankingCell from "../cells/RankingCell";
import TimestampCell from "../cells/TimestampCell";
import { NumericSOV, StrSOV } from "util/sorts";
import { PBDataset } from "types/tables";
import { Game, GetGamePTConfig, PublicUserDocument } from "tachi-common";
import TachiTable, { Header } from "../components/TachiTable";
import IndexCell from "../cells/IndexCell";
import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/str-to-num";
import DropdownRow from "../components/DropdownRow";
import { IsNullish } from "util/misc";
import LampCell from "../cells/LampCell";
import DifficultyCell from "../cells/DifficultyCell";
import MillionsScoreCell from "../cells/MillionsScoreCell";
import GenericPBDropdown from "../dropdowns/GenericPBDropdown";
import SDVXJudgementCell from "../cells/SDVXJudgementCell";
import ScoreCell from "../cells/ScoreCell";
import RatingCell from "../cells/RatingCell";
import { Playtype } from "types/tachi";
export default function GenericPBTable({
dataset,
indexCol = true,
reqUser,
game,
playtype,
showScore,
}: {
dataset: PBDataset;
indexCol?: boolean;
reqUser: PublicUserDocument;
game: Game;
playtype: Playtype;
showScore?: boolean;
}) {
const gptConfig = GetGamePTConfig(game, playtype);
const headers: Header<PBDataset[0]>[] = [
["Chart", "Ch.", NumericSOV(x => x.__related.chart.levelNum)],
["Song", "Song", StrSOV(x => x.__related.song.title)],
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
["Lamp", "Lamp", NumericSOV(x => x.scoreData.lampIndex)],
[
gptConfig.defaultScoreRatingAlg,
gptConfig.defaultScoreRatingAlg,
NumericSOV(x => x.calculatedData[gptConfig.defaultScoreRatingAlg] ?? 0),
],
["Ranking", "Rank", NumericSOV(x => x.rankingData.rank)],
["Last Raised", "Last Raised", NumericSOV(x => x.timeAchieved ?? 0)],
];
if (indexCol) {
headers.unshift(["#", "#", NumericSOV(x => x.__related.index)]);
}
return (
<TachiTable
dataset={dataset}
headers={headers}
entryName="PBs"
searchFunctions={{
artist: x => x.__related.song.artist,
title: x => x.__related.song.title,
difficulty: x => x.__related.chart.difficulty,
level: x => x.__related.chart.levelNum,
score: x => x.scoreData.score,
percent: x => x.scoreData.percent,
ranking: x => x.rankingData.rank,
lamp: {
valueGetter: x => [x.scoreData.lamp, x.scoreData.lampIndex],
strToNum: HumanFriendlyStrToLampIndex(game, playtype),
},
grade: {
valueGetter: x => [x.scoreData.grade, x.scoreData.gradeIndex],
strToNum: HumanFriendlyStrToGradeIndex(game, playtype),
},
}}
defaultSortMode={indexCol ? "#" : undefined}
rowFunction={pb => (
<Row
pb={pb}
key={`${pb.chartID}:${pb.userID}`}
reqUser={reqUser}
indexCol={indexCol}
showScore={showScore}
/>
)}
/>
);
}
function Row({
pb,
indexCol,
reqUser,
showScore,
}: {
pb: PBDataset[0];
indexCol: boolean;
reqUser: PublicUserDocument;
showScore?: boolean;
}) {
const [highlight, setHighlight] = useState(pb.highlight);
const scoreState = { highlight, setHighlight };
return (
<DropdownRow
dropdown={
<GenericPBDropdown
chart={pb.__related.chart}
reqUser={reqUser}
game={pb.game}
playtype={pb.playtype}
scoreState={scoreState}
/>
}
className={highlight ? "highlighted-row" : ""}
>
{indexCol && <IndexCell index={pb.__related.index} />}
<DifficultyCell game={pb.game} chart={pb.__related.chart} />
<TitleCell song={pb.__related.song} chart={pb.__related.chart} game={pb.game} />
<ScoreCell score={pb} showScore={showScore} />
<LampCell score={pb} />
<RatingCell score={pb} />
<RankingCell rankingData={pb.rankingData} />
<TimestampCell time={pb.timeAchieved} />
</DropdownRow>
);
}
@@ -132,7 +132,7 @@ function Row({
{indexCol && <IndexCell index={pb.__related.index} />}
<DifficultyCell chart={pb.__related.chart} game={"iidx"} />
<TitleCell song={pb.__related.song} chart={pb.__related.chart} game="iidx" />
<ScoreCell score={pb} game="iidx" playtype={pb.playtype} />
<ScoreCell score={pb} />
<DeltaCell
game="iidx"
playtype={pb.playtype}
@@ -0,0 +1,119 @@
import React, { useState } from "react";
import TitleCell from "../cells/TitleCell";
import RankingCell from "../cells/RankingCell";
import TimestampCell from "../cells/TimestampCell";
import { NumericSOV, StrSOV } from "util/sorts";
import { PBDataset } from "types/tables";
import { PublicUserDocument } from "tachi-common";
import TachiTable, { Header } from "../components/TachiTable";
import IndexCell from "../cells/IndexCell";
import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/str-to-num";
import DropdownRow from "../components/DropdownRow";
import { IsNullish } from "util/misc";
import LampCell from "../cells/LampCell";
import DifficultyCell from "../cells/DifficultyCell";
import MillionsScoreCell from "../cells/MillionsScoreCell";
import GenericPBDropdown from "../dropdowns/GenericPBDropdown";
import SDVXJudgementCell from "../cells/SDVXJudgementCell";
import RatingCell from "../cells/RatingCell";
import MusecaJudgementCell from "../cells/MusecaJudgementCell";
export default function MusecaPBTable({
dataset,
indexCol = true,
reqUser,
playtype,
}: {
dataset: PBDataset<"museca:Single">;
indexCol?: boolean;
reqUser: PublicUserDocument;
playtype: "Single";
}) {
const headers: Header<PBDataset<"museca:Single">[0]>[] = [
["Chart", "Ch.", NumericSOV(x => x.__related.chart.levelNum)],
["Song", "Song", StrSOV(x => x.__related.song.title)],
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
["Judgements", "Judge", NumericSOV(x => x.scoreData.percent)],
["Lamp", "Lamp", NumericSOV(x => x.scoreData.lampIndex)],
["ktRating", "ktRating", NumericSOV(x => x.calculatedData.ktRating ?? 0)],
["Ranking", "Rank", NumericSOV(x => x.rankingData.rank)],
["Last Raised", "Last Raised", NumericSOV(x => x.timeAchieved ?? 0)],
];
if (indexCol) {
headers.unshift(["#", "#", NumericSOV(x => x.__related.index)]);
}
return (
<TachiTable
dataset={dataset}
headers={headers}
entryName="PBs"
searchFunctions={{
artist: x => x.__related.song.artist,
title: x => x.__related.song.title,
difficulty: x => x.__related.chart.difficulty,
level: x => x.__related.chart.levelNum,
score: x => x.scoreData.score,
percent: x => x.scoreData.percent,
ranking: x => x.rankingData.rank,
lamp: {
valueGetter: x => [x.scoreData.lamp, x.scoreData.lampIndex],
strToNum: HumanFriendlyStrToLampIndex("museca", playtype),
},
grade: {
valueGetter: x => [x.scoreData.grade, x.scoreData.gradeIndex],
strToNum: HumanFriendlyStrToGradeIndex("museca", playtype),
},
}}
defaultSortMode={indexCol ? "#" : undefined}
rowFunction={pb => (
<Row
pb={pb}
key={`${pb.chartID}:${pb.userID}`}
reqUser={reqUser}
indexCol={indexCol}
/>
)}
/>
);
}
function Row({
pb,
indexCol,
reqUser,
}: {
pb: PBDataset<"museca:Single">[0];
indexCol: boolean;
reqUser: PublicUserDocument;
}) {
const [highlight, setHighlight] = useState(pb.highlight);
const scoreState = { highlight, setHighlight };
return (
<DropdownRow
dropdown={
<GenericPBDropdown
chart={pb.__related.chart}
reqUser={reqUser}
game={pb.game}
playtype={pb.playtype}
scoreState={scoreState}
/>
}
className={highlight ? "highlighted-row" : ""}
>
{indexCol && <IndexCell index={pb.__related.index} />}
<DifficultyCell game="museca" chart={pb.__related.chart} />
<TitleCell song={pb.__related.song} chart={pb.__related.chart} game="museca" />
<MillionsScoreCell score={pb} />
<MusecaJudgementCell score={pb} />
<LampCell score={pb} />
<RatingCell score={pb} />
<RankingCell rankingData={pb.rankingData} />
<TimestampCell time={pb.timeAchieved} />
</DropdownRow>
);
}
+9 -2
View File
@@ -5,6 +5,8 @@ import { PublicUserDocument } from "tachi-common";
import IIDXPBTable from "./IIDXPBTable";
import BMSPBTable from "./BMSPBTable";
import SDVXPBTable from "./SDVXPBTable";
import GenericPBTable from "./GenericPBTable";
import MusecaPBTable from "./MusecaPBTable";
export default function PBTable({
dataset,
@@ -22,13 +24,18 @@ export default function PBTable({
// ever.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const props = { dataset, indexCol, reqUser, playtype } as any;
if (game === "iidx") {
return <IIDXPBTable {...props} />;
} else if (game === "bms") {
return <BMSPBTable {...props} />;
} else if (game === "sdvx") {
} else if (game === "sdvx" || game === "usc") {
return <SDVXPBTable {...props} />;
} else if (game === "maimai") {
return <GenericPBTable {...props} game={game} playtype={playtype} showScore={false} />;
} else if (game === "museca") {
return <MusecaPBTable {...props} />;
}
return <></>;
return <GenericPBTable {...props} game={game} playtype={playtype} />;
}
@@ -12,7 +12,9 @@ import DropdownRow from "../components/DropdownRow";
import { IsNullish } from "util/misc";
import LampCell from "../cells/LampCell";
import DifficultyCell from "../cells/DifficultyCell";
import SDVXScoreCell from "../cells/SDVXScoreCell";
import MillionsScoreCell from "../cells/MillionsScoreCell";
import GenericPBDropdown from "../dropdowns/GenericPBDropdown";
import SDVXJudgementCell from "../cells/SDVXJudgementCell";
export default function SDVXPBTable({
dataset,
@@ -29,6 +31,7 @@ export default function SDVXPBTable({
["Chart", "Ch.", NumericSOV(x => x.__related.chart.levelNum)],
["Song", "Song", StrSOV(x => x.__related.song.title)],
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
["Judgements", "Judge", NumericSOV(x => x.scoreData.percent)],
["Lamp", "Lamp", NumericSOV(x => x.scoreData.lampIndex)],
["VF6", "VF6", NumericSOV(x => x.calculatedData.VF6 ?? 0)],
["Ranking", "Rank", NumericSOV(x => x.rankingData.rank)],
@@ -90,22 +93,22 @@ function Row({
return (
<DropdownRow
dropdown={
<></>
// <IIDXPBDropdown
// chart={pb.__related.chart}
// reqUser={reqUser}
// game="sdvx"
// playtype={pb.playtype}
// scoreState={scoreState}
// />
<GenericPBDropdown
chart={pb.__related.chart}
reqUser={reqUser}
game={pb.game}
playtype={pb.playtype}
scoreState={scoreState}
/>
}
className={highlight ? "highlighted-row" : ""}
>
{indexCol && <IndexCell index={pb.__related.index} />}
<DifficultyCell game="sdvx" chart={pb.__related.chart} />
<TitleCell song={pb.__related.song} chart={pb.__related.chart} game="sdvx" />
<SDVXScoreCell score={pb} />
<LampCell sc={pb} />
<MillionsScoreCell score={pb} />
<SDVXJudgementCell score={pb} />
<LampCell score={pb} />
<td>
{!IsNullish(pb.calculatedData.VF6) ? pb.calculatedData.VF6!.toFixed(3) : "No Data."}
</td>
@@ -14,7 +14,8 @@ import { IsNullish } from "util/misc";
import LampCell from "../cells/LampCell";
import BMSDifficultyCell from "../cells/BMSDifficultyCell";
import { Playtype } from "types/tachi";
import GenericPBDropdown from "../dropdowns/GenericPBDropdown";
import GenericScoreDropdown from "../dropdowns/GenericScoreDropdown";
import SDVXJudgementCell from "../cells/SDVXJudgementCell";
export default function BMSScoreTable({
reqUser,
@@ -83,10 +84,11 @@ function Row({
<DropdownRow
className={highlight ? "highlighted-row" : ""}
dropdown={
<GenericPBDropdown
<GenericScoreDropdown
chart={sc.__related.chart}
reqUser={reqUser}
game="bms"
game={sc.game}
thisScore={sc}
playtype={sc.playtype}
scoreState={scoreState}
/>
@@ -94,7 +96,7 @@ function Row({
>
<BMSDifficultyCell chart={sc.__related.chart} />
<TitleCell song={sc.__related.song} chart={sc.__related.chart} game="bms" />
<ScoreCell score={sc} game="bms" playtype={playtype} />
<ScoreCell score={sc} />
<DeltaCell
game="bms"
playtype={playtype}
@@ -102,7 +104,7 @@ function Row({
percent={sc.scoreData.percent}
grade={sc.scoreData.grade}
/>
<LampCell sc={sc} />
<LampCell score={sc} />
<td>
{!IsNullish(sc.calculatedData.sieglinde)
? sc.calculatedData.sieglinde!.toFixed(2)
@@ -0,0 +1,113 @@
import React, { useState } from "react";
import { FormatDifficulty } from "tachi-common/js/utils/util";
import TitleCell from "../cells/TitleCell";
import TimestampCell from "../cells/TimestampCell";
import { NumericSOV, StrSOV } from "util/sorts";
import { ScoreDataset } from "types/tables";
import { integer, PublicUserDocument, Playtypes, Game, GetGamePTConfig } from "tachi-common";
import TachiTable from "../components/TachiTable";
import DifficultyCell from "../cells/DifficultyCell";
import ScoreCell from "../cells/ScoreCell";
import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/str-to-num";
import DropdownRow from "../components/DropdownRow";
import { IsNullish } from "util/misc";
import LampCell from "../cells/LampCell";
import MillionsScoreCell from "../cells/MillionsScoreCell";
import GenericScoreDropdown from "../dropdowns/GenericScoreDropdown";
import RatingCell from "../cells/RatingCell";
import { Playtype } from "types/tachi";
export default function GenericScoreTable({
reqUser,
dataset,
pageLen,
playtype,
showScore,
game,
}: {
reqUser: PublicUserDocument;
dataset: ScoreDataset;
pageLen?: integer;
playtype: Playtype;
game: Game;
showScore?: boolean;
}) {
const gptConfig = GetGamePTConfig(game, playtype);
return (
<TachiTable
dataset={dataset}
pageLen={pageLen}
headers={[
["Chart", "Ch.", NumericSOV(x => x.__related.chart.levelNum)],
["Song", "Song", StrSOV(x => x.__related.song.title)],
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
["Lamp", "Lamp", NumericSOV(x => x.scoreData.lampIndex)],
[
gptConfig.defaultScoreRatingAlg,
gptConfig.defaultScoreRatingAlg,
NumericSOV(x => x.calculatedData[gptConfig.defaultScoreRatingAlg] ?? 0),
],
["Timestamp", "Timestamp", NumericSOV(x => x.timeAchieved ?? 0)],
]}
entryName="Scores"
searchFunctions={{
artist: x => x.__related.song.artist,
title: x => x.__related.song.title,
difficulty: x => FormatDifficulty(x.__related.chart, game),
level: x => x.__related.chart.levelNum,
score: x => x.scoreData.score,
percent: x => x.scoreData.percent,
lamp: {
valueGetter: x => [x.scoreData.lamp, x.scoreData.lampIndex],
strToNum: HumanFriendlyStrToLampIndex(game, playtype),
},
grade: {
valueGetter: x => [x.scoreData.grade, x.scoreData.gradeIndex],
strToNum: HumanFriendlyStrToGradeIndex(game, playtype),
},
}}
rowFunction={sc => (
<Row key={sc.scoreID} sc={sc} reqUser={reqUser} showScore={showScore} />
)}
/>
);
}
function Row({
sc,
reqUser,
showScore,
}: {
sc: ScoreDataset[0];
reqUser: PublicUserDocument;
showScore?: boolean;
}) {
const [highlight, setHighlight] = useState(sc.highlight);
const [comment, setComment] = useState(sc.comment);
const scoreState = { highlight, comment, setHighlight, setComment };
return (
<DropdownRow
className={highlight ? "highlighted-row" : ""}
dropdown={
<GenericScoreDropdown
chart={sc.__related.chart}
reqUser={reqUser}
game={sc.game}
thisScore={sc}
playtype={sc.playtype}
scoreState={scoreState}
/>
}
>
<DifficultyCell chart={sc.__related.chart} game={sc.game} />
<TitleCell song={sc.__related.song} chart={sc.__related.chart} game={sc.game} />
<ScoreCell score={sc} showScore={showScore} />
<LampCell score={sc} />
<RatingCell score={sc} />
<TimestampCell time={sc.timeAchieved} />
</DropdownRow>
);
}
@@ -130,7 +130,7 @@ function Row({
>
<DifficultyCell chart={sc.__related.chart} game="iidx" />
<TitleCell song={sc.__related.song} chart={sc.__related.chart} game="iidx" />
<ScoreCell score={sc} game="iidx" playtype={playtype} />
<ScoreCell score={sc} />
<DeltaCell
game="iidx"
playtype={playtype}
@@ -0,0 +1,101 @@
import React, { useState } from "react";
import { FormatDifficulty } from "tachi-common/js/utils/util";
import TitleCell from "../cells/TitleCell";
import TimestampCell from "../cells/TimestampCell";
import { NumericSOV, StrSOV } from "util/sorts";
import { ScoreDataset } from "types/tables";
import { integer, PublicUserDocument, Playtypes } from "tachi-common";
import TachiTable from "../components/TachiTable";
import DifficultyCell from "../cells/DifficultyCell";
import ScoreCell from "../cells/ScoreCell";
import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/str-to-num";
import DropdownRow from "../components/DropdownRow";
import { IsNullish } from "util/misc";
import LampCell from "../cells/LampCell";
import MillionsScoreCell from "../cells/MillionsScoreCell";
import GenericScoreDropdown from "../dropdowns/GenericScoreDropdown";
import RatingCell from "../cells/RatingCell";
import MusecaJudgementCell from "../cells/MusecaJudgementCell";
export default function MusecaScoreTable({
reqUser,
dataset,
pageLen,
}: {
reqUser: PublicUserDocument;
dataset: ScoreDataset<"museca:Single">;
pageLen?: integer;
playtype: Playtypes["museca"];
}) {
return (
<TachiTable
dataset={dataset}
pageLen={pageLen}
headers={[
["Chart", "Ch.", NumericSOV(x => x.__related.chart.levelNum)],
["Song", "Song", StrSOV(x => x.__related.song.title)],
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
["Judgements", "Judge", NumericSOV(x => x.scoreData.percent)],
["Lamp", "Lamp", NumericSOV(x => x.scoreData.lampIndex)],
["KtRating", "KtRating", NumericSOV(x => x.calculatedData.ktRating ?? 0)],
["Timestamp", "Timestamp", NumericSOV(x => x.timeAchieved ?? 0)],
]}
entryName="Scores"
searchFunctions={{
artist: x => x.__related.song.artist,
title: x => x.__related.song.title,
difficulty: x => FormatDifficulty(x.__related.chart, "museca"),
level: x => x.__related.chart.levelNum,
score: x => x.scoreData.score,
percent: x => x.scoreData.percent,
lamp: {
valueGetter: x => [x.scoreData.lamp, x.scoreData.lampIndex],
strToNum: HumanFriendlyStrToLampIndex("museca", "Single"),
},
grade: {
valueGetter: x => [x.scoreData.grade, x.scoreData.gradeIndex],
strToNum: HumanFriendlyStrToGradeIndex("museca", "Single"),
},
}}
rowFunction={sc => <Row key={sc.scoreID} sc={sc} reqUser={reqUser} />}
/>
);
}
function Row({
sc,
reqUser,
}: {
sc: ScoreDataset<"museca:Single">[0];
reqUser: PublicUserDocument;
}) {
const [highlight, setHighlight] = useState(sc.highlight);
const [comment, setComment] = useState(sc.comment);
const scoreState = { highlight, comment, setHighlight, setComment };
return (
<DropdownRow
className={highlight ? "highlighted-row" : ""}
dropdown={
<GenericScoreDropdown
chart={sc.__related.chart}
reqUser={reqUser}
game={sc.game}
thisScore={sc}
playtype={sc.playtype}
scoreState={scoreState}
/>
}
>
<DifficultyCell chart={sc.__related.chart} game="museca" />
<TitleCell song={sc.__related.song} chart={sc.__related.chart} game="museca" />
<MillionsScoreCell score={sc} />
<MusecaJudgementCell score={sc} />
<LampCell score={sc} />
<RatingCell score={sc} />
<TimestampCell time={sc.timeAchieved} />
</DropdownRow>
);
}
@@ -12,7 +12,8 @@ import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/
import DropdownRow from "../components/DropdownRow";
import { IsNullish } from "util/misc";
import LampCell from "../cells/LampCell";
import SDVXScoreCell from "../cells/SDVXScoreCell";
import MillionsScoreCell from "../cells/MillionsScoreCell";
import GenericScoreDropdown from "../dropdowns/GenericScoreDropdown";
export default function SDVXScoreTable({
reqUser,
@@ -69,22 +70,21 @@ function Row({ sc, reqUser }: { sc: ScoreDataset<"sdvx:Single">[0]; reqUser: Pub
<DropdownRow
className={highlight ? "highlighted-row" : ""}
dropdown={
<></>
// <sdvxScoreDropdown
// chart={sc.__related.chart}
// game="sdvx"
// playtype={sc.playtype}
// reqUser={reqUser}
// thisScore={sc}
// scoreState={scoreState}
// />
<GenericScoreDropdown
chart={sc.__related.chart}
reqUser={reqUser}
game={sc.game}
thisScore={sc}
playtype={sc.playtype}
scoreState={scoreState}
/>
}
>
<DifficultyCell chart={sc.__related.chart} game="sdvx" />
<TitleCell song={sc.__related.song} chart={sc.__related.chart} game="sdvx" />
<SDVXScoreCell score={sc} />
<LampCell sc={sc} />
<td>{!IsNullish(sc.calculatedData.VF6) ? sc.calculatedData.VF6!.toFixed(2) : "N/A"}</td>
<MillionsScoreCell score={sc} />
<LampCell score={sc} />
<td>{!IsNullish(sc.calculatedData.VF6) ? sc.calculatedData.VF6!.toFixed(3) : "N/A"}</td>
<TimestampCell time={sc.timeAchieved} />
</DropdownRow>
);
@@ -5,6 +5,8 @@ import { PublicUserDocument, integer } from "tachi-common";
import IIDXScoreTable from "./IIDXScoreTable";
import BMSScoreTable from "./BMSScoreTable";
import SDVXScoreTable from "./SDVXScoreTable";
import GenericScoreTable from "./GenericScoreTable";
import MusecaScoreTable from "./MusecaScoreTable";
export default function ScoreTable({
dataset,
@@ -28,9 +30,13 @@ export default function ScoreTable({
return <IIDXScoreTable {...props} />;
} else if (game === "bms") {
return <BMSScoreTable {...props} />;
} else if (game === "sdvx") {
} else if (game === "sdvx" || game === "usc") {
return <SDVXScoreTable {...props} />;
} else if (game === "maimai") {
return <GenericScoreTable {...props} game={game} playtype={playtype} showScore={false} />;
} else if (game === "museca") {
return <MusecaScoreTable {...props} />;
}
return <></>;
return <GenericScoreTable {...props} game={game} playtype={playtype} />;
}