mirror of
https://github.com/zkldi/Tachi.git
synced 2026-10-08 06:48:04 +03:00
feat(client): make session highlight btn functional
This commit is contained in:
@@ -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 }
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user