feat(client): make session highlight btn functional

This commit is contained in:
zkldi
2022-07-25 21:54:06 +01:00
parent 174d36dacd
commit e0fb4de202
5 changed files with 161 additions and 73 deletions
@@ -50,7 +50,8 @@ export default function SpecificSessionPage({ reqUser, game, playtype }: Props)
}
function SessionPage({ data, game, playtype }: Props & { data: SessionReturns }) {
const { session, user, charts, scores, songs } = data;
const [sessionData, setSessionData] = useState(data);
const { session, user, charts, scores, songs } = sessionData;
const { user: loggedInUser } = useContext(UserContext);
@@ -105,7 +106,7 @@ function SessionPage({ data, game, playtype }: Props & { data: SessionReturns })
}
return d;
}, [data]);
}, [sessionData]);
const [highlight, setHighlight] = useState(session.highlight);
const [showEditModal, setShowEditModal] = useState(false);
@@ -215,7 +216,11 @@ function SessionPage({ data, game, playtype }: Props & { data: SessionReturns })
<Divider />
</Col>
{view === "overview" ? (
<SessionOverview scoreDataset={scoreDataset} sessionData={data} />
<SessionOverview
scoreDataset={scoreDataset}
sessionData={sessionData}
setSessionData={setSessionData}
/>
) : (
<Col xs={12}>
<ScoreTable
@@ -3,22 +3,32 @@ import { FormatDuration } from "util/time";
import Card from "components/layout/page/Card";
import ScoreTable from "components/tables/scores/ScoreTable";
import Divider from "components/util/Divider";
import React from "react";
import React, { useState } from "react";
import { Col, Row } from "react-bootstrap";
import { GetGamePTConfig, SessionDocument } from "tachi-common";
import { GetGamePTConfig, ScoreDocument, SessionDocument } from "tachi-common";
import { SessionReturns } from "types/api-returns";
import { ScoreDataset } from "types/tables";
import { SetState } from "types/react";
import SessionRaiseBreakdown from "./SessionRaiseBreakdown";
export default function SessionOverview({
sessionData,
setSessionData,
scoreDataset,
}: {
sessionData: SessionReturns;
setSessionData: SetState<SessionReturns>;
scoreDataset: ScoreDataset;
}) {
const { scores, session } = sessionData;
const setScores = (scores: ScoreDocument[]) => {
setSessionData({
...sessionData,
scores,
});
};
return (
<>
<StatThing name="Scores" value={session.scoreInfo.length} />
@@ -32,7 +42,7 @@ export default function SessionOverview({
<Card header="Breakdown">
<Row>
<SessionRaiseBreakdown sessionData={sessionData} />
<SessionRaiseBreakdown sessionData={sessionData} setScores={setScores} />
</Row>
</Card>
</Col>
@@ -30,8 +30,19 @@ import {
TableDocument,
} from "tachi-common";
import { SessionReturns } from "types/api-returns";
import { ModifyScore } from "components/tables/dropdowns/components/ScoreEditButtons";
import { SetState } from "types/react";
import { ScoreDataset } from "types/tables";
export default function SessionRaiseBreakdown({ sessionData }: { sessionData: SessionReturns }) {
type SetScores = (scores: ScoreDocument[]) => void;
export default function SessionRaiseBreakdown({
sessionData,
setScores,
}: {
sessionData: SessionReturns;
setScores: SetScores;
}) {
const game = sessionData.session.game;
const playtype = sessionData.session.playtype;
@@ -178,7 +189,7 @@ export default function SessionRaiseBreakdown({ sessionData }: { sessionData: Se
<Divider className="mt-4 mb-4" />
</div>
<SessionScoreStatBreakdown {...{ sessionData, chartIDs, filter, view }} />
<SessionScoreStatBreakdown {...{ sessionData, chartIDs, filter, view, setScores }} />
</>
);
}
@@ -188,8 +199,10 @@ function SessionScoreStatBreakdown({
chartIDs,
filter,
view,
setScores,
}: {
sessionData: SessionReturns;
setScores: SetScores;
chartIDs: string[] | null;
filter: "folder" | "all" | "highlighted";
view: "lamps" | "both" | "grades";
@@ -255,6 +268,8 @@ function SessionScoreStatBreakdown({
className="table-sm"
>
<ElementStatTable
scores={sessionData.scores}
setScores={setScores}
chartMap={chartMap}
songMap={songMap}
counts={newLamps}
@@ -271,6 +286,8 @@ function SessionScoreStatBreakdown({
className="table-sm"
>
<ElementStatTable
scores={sessionData.scores}
setScores={setScores}
chartMap={chartMap}
songMap={songMap}
counts={newGrades}
@@ -285,6 +302,8 @@ function SessionScoreStatBreakdown({
<div className="col-12">
<MiniTable headers={["Grade", "New Grades"]} colSpan={[1, 100]}>
<ElementStatTable
scores={sessionData.scores}
setScores={setScores}
fullSize
chartMap={chartMap}
songMap={songMap}
@@ -299,6 +318,8 @@ function SessionScoreStatBreakdown({
<div className="col-12">
<MiniTable headers={["Lamps", "New Lamps"]} colSpan={[1, 100]}>
<ElementStatTable
scores={sessionData.scores}
setScores={setScores}
fullSize
chartMap={chartMap}
songMap={songMap}
@@ -322,8 +343,12 @@ function ElementStatTable({
chartMap,
game,
fullSize = false,
scores,
setScores,
}: {
type: "lamp" | "grade";
setScores: SetScores;
scores: ScoreDocument[];
counts: Record<string, { score: ScoreDocument; scoreInfo: SessionScoreInfo }[]>;
gptConfig: GamePTConfig;
songMap: Map<integer, SongDocument<Game>>;
@@ -331,6 +356,26 @@ function ElementStatTable({
game: Game;
fullSize?: boolean;
}) {
function makeModifyScoreFn(score: ScoreDocument) {
return ({ highlight, comment }: { highlight?: boolean; comment?: string }) => {
const scoreID = score.scoreID;
const filtered = scores.filter((e) => e.scoreID !== scoreID);
ModifyScore(scoreID, { highlight, comment });
const newScore = { ...score };
if (highlight !== undefined) {
newScore.highlight = highlight;
}
if (comment !== undefined) {
newScore.comment = comment;
}
setScores([...filtered, newScore]);
};
}
const tableContents = useMemo(() => {
// relements.. haha
const relevantElements =
@@ -350,6 +395,8 @@ function ElementStatTable({
const firstData = counts[element][0];
const firstModify = makeModifyScoreFn(firstData.score);
tableContents.push(
<tr key={element} className="breakdown-hover-row">
<td
@@ -364,16 +411,19 @@ function ElementStatTable({
<BreakdownChartContents
{...firstData}
{...{ chartMap, songMap, fullSize, game, gptConfig, type }}
modifyScore={firstModify}
/>
</tr>
);
for (const data of counts[element]!.slice(1)) {
const modifyScore = makeModifyScoreFn(data.score);
tableContents.push(
<tr key={data.score.scoreID} className="breakdown-hover-row">
<BreakdownChartContents
{...data}
{...{ chartMap, songMap, fullSize, game, gptConfig, type }}
{...{ chartMap, songMap, fullSize, game, gptConfig, type, modifyScore }}
/>
</tr>
);
@@ -403,6 +453,7 @@ function BreakdownChartContents({
fullSize,
gptConfig,
type,
modifyScore,
}: {
score: ScoreDocument;
scoreInfo: SessionScoreInfo;
@@ -411,11 +462,24 @@ function BreakdownChartContents({
songMap: Map<integer, SongDocument>;
chartMap: Map<string, ChartDocument>;
gptConfig: GamePTConfig;
modifyScore: ({ highlight, comment }: { highlight?: boolean; comment?: string }) => void;
type: "lamp" | "grade";
}) {
const chart = chartMap.get(score.chartID)!;
const song = songMap.get(score.songID)!;
const [highlight, setHighlight] = useState(score.highlight);
const [firstRun, setFirstRun] = useState(true);
useEffect(() => {
if (firstRun) {
setFirstRun(false);
return;
}
modifyScore({ highlight });
}, [highlight]);
if (!chart || !song) {
console.error(`No chart for ${score.chartID}/${score.songID}???`);
return null;
@@ -466,7 +530,7 @@ function BreakdownChartContents({
return (
<>
<TitleCell noArtist chart={chart} game={game} song={song} />
<PseudHighlight highlight={score.highlight} onHighlightChange={() => void 0} />
<PseudHighlight highlight={highlight} setHighlight={setHighlight} />
<DifficultyCell alwaysShort chart={chart} game={game} />
</>
);
@@ -474,18 +538,23 @@ function BreakdownChartContents({
function PseudHighlight({
highlight,
onHighlightChange,
setHighlight,
}: {
highlight: boolean;
onHighlightChange: (hl: boolean) => void;
setHighlight: (hl: boolean) => void;
}) {
return (
<td style={{ verticalAlign: "center" }}>
{highlight ? (
<Icon colour="warning" type="star" style={{ paddingTop: "0.1rem" }} />
<Icon
onClick={() => setHighlight(false)}
colour="warning"
type="star"
style={{ paddingTop: "0.1rem" }}
/>
) : (
<span className="breakdown-hover-highlight-button">
<Icon type="star" regular noPad />
<Icon onClick={() => setHighlight(true)} type="star" regular noPad />
</span>
)}
</td>
@@ -1,67 +1,71 @@
import { APIFetchV1 } from "util/api";
import SessionRaiseBreakdown from "components/sessions/SessionRaiseBreakdown";
import DebugContent from "components/util/DebugContent";
import HasDevModeOn from "components/util/HasDevModeOn";
import Icon from "components/util/Icon";
import Loading from "components/util/Loading";
import SelectButton from "components/util/SelectButton";
import React, { useState } from "react";
import { useQuery } from "react-query";
import { SessionReturns } from "types/api-returns";
import { SessionDataset } from "../sessions/GenericSessionTable";
import DropdownStructure from "./components/DropdownStructure";
export {}
export default function GenericSessionDropdown({ data }: { data: SessionDataset[0] }) {
const {
isLoading,
error,
data: sessionData,
} = useQuery(`/sessions/${data.sessionID}`, async () => {
const res = await APIFetchV1<SessionReturns>(`/sessions/${data.sessionID}`);
// unused?
if (!res.success) {
throw new Error(res.description);
}
// import { APIFetchV1 } from "util/api";
// import SessionRaiseBreakdown from "components/sessions/SessionRaiseBreakdown";
// import DebugContent from "components/util/DebugContent";
// import HasDevModeOn from "components/util/HasDevModeOn";
// import Icon from "components/util/Icon";
// import Loading from "components/util/Loading";
// import SelectButton from "components/util/SelectButton";
// import React, { useState } from "react";
// import { useQuery } from "react-query";
// import { SessionReturns } from "types/api-returns";
// import { SessionDataset } from "../sessions/GenericSessionTable";
// import DropdownStructure from "./components/DropdownStructure";
return res.body;
});
// export default function GenericSessionDropdown({ data }: { data: SessionDataset[0] }) {
// const {
// isLoading,
// error,
// data: sessionData,
// } = useQuery(`/sessions/${data.sessionID}`, async () => {
// const res = await APIFetchV1<SessionReturns>(`/sessions/${data.sessionID}`);
const [view, setView] = useState<"raises" | "debug">("raises");
// if (!res.success) {
// throw new Error(res.description);
// }
if (error) {
return <>{(error as Error).message}</>;
}
// return res.body;
// });
if (isLoading || !sessionData) {
return <Loading />;
}
// const [view, setView] = useState<"raises" | "debug">("raises");
let content;
// if (error) {
// return <>{(error as Error).message}</>;
// }
if (view === "raises") {
content = <SessionRaiseBreakdown sessionData={sessionData} />;
} else if (view === "debug") {
content = <DebugContent data={sessionData} />;
}
// if (isLoading || !sessionData) {
// return <Loading />;
// }
return (
<DropdownStructure
buttons={
<>
<SelectButton setValue={setView} value={view} id="raises">
<Icon type="receipt" />
Raises
</SelectButton>
<HasDevModeOn>
<SelectButton setValue={setView} value={view} id="debug">
<Icon type="bug" />
Debug Info
</SelectButton>
</HasDevModeOn>
</>
}
>
{content}
</DropdownStructure>
);
}
// let content;
// if (view === "raises") {
// content = <SessionRaiseBreakdown sessionData={sessionData} />;
// } else if (view === "debug") {
// content = <DebugContent data={sessionData} />;
// }
// return (
// <DropdownStructure
// buttons={
// <>
// <SelectButton setValue={setView} value={view} id="raises">
// <Icon type="receipt" />
// Raises
// </SelectButton>
// <HasDevModeOn>
// <SelectButton setValue={setView} value={view} id="debug">
// <Icon type="bug" />
// Debug Info
// </SelectButton>
// </HasDevModeOn>
// </>
// }
// >
// {content}
// </DropdownStructure>
// );
// }
@@ -110,7 +110,7 @@ export default function ScoreEditButtons({
);
}
async function ModifyScore(
export async function ModifyScore(
scoreID: string,
content: { comment?: string | null; highlight?: boolean }
) {