Skip to content

Commit

Permalink
ui improvements to opening practice
Browse files Browse the repository at this point in the history
  • Loading branch information
franciscoBSalgueiro committed Sep 22, 2023
1 parent dc5a750 commit c10cb96
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 67 deletions.
4 changes: 3 additions & 1 deletion src/components/common/ConfirmModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ function ConfirmModal({
opened,
onClose,
onConfirm,
confirmLabel,
}: {
title: string;
description: string;
opened: boolean;
onClose: () => void;
onConfirm: () => void;
confirmLabel?: string;
}) {
return (
<Modal withCloseButton={false} opened={opened} onClose={onClose}>
Expand All @@ -29,7 +31,7 @@ function ConfirmModal({
Cancel
</Button>
<Button color="red" onClick={() => onConfirm()}>
Delete
{confirmLabel || "Delete"}
</Button>
</Group>
</Stack>
Expand Down
1 change: 0 additions & 1 deletion src/components/panels/database/DatabasePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ function DatabasePanel({ height, fen }: { height: number; fen: string }) {
isLoading,
error,
} = useSWR([dbType, query], async ([dbType, query]) => {
console.log("fetching opening", query);
return fetchOpening(query, dbType);
});

Expand Down
165 changes: 103 additions & 62 deletions src/components/panels/info/PracticePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@ import {
currentTabAtom,
deckAtomFamily,
} from "@/atoms/atoms";
import ConfirmModal from "@/components/common/ConfirmModal";
import {
TreeDispatchContext,
TreeStateContext,
} from "@/components/common/TreeStateContext";
import { getCardForReview, getStats } from "@/components/files/opening";
import {
buildFromTree,
getCardForReview,
getStats,
} from "@/components/files/opening";
import {
Text,
ActionIcon,
Expand All @@ -17,18 +22,25 @@ import {
Button,
RingProgress,
} from "@mantine/core";
import { useToggle } from "@mantine/hooks";
import { IconX } from "@tabler/icons-react";
import { useAtomValue, useSetAtom } from "jotai";
import { useAtom, useAtomValue, useSetAtom } from "jotai";
import { useContext } from "react";
import { match } from "ts-pattern";

function PracticePanel() {
const dispatch = useContext(TreeDispatchContext);
const { root, headers } = useContext(TreeStateContext);
const currentTab = useAtomValue(currentTabAtom);
const [resetModal, toggleResetModal] = useToggle();

const deck = useAtomValue(
deckAtomFamily({ id: currentTab?.file?.name || "", root, headers, game: currentTab?.gameNumber || 0 }),
const [deck, setDeck] = useAtom(
deckAtomFamily({
id: currentTab?.file?.name || "",
root,
headers,
game: currentTab?.gameNumber || 0,
})
);

const stats = getStats(deck);
Expand All @@ -51,65 +63,94 @@ function PracticePanel() {
}

return (
<Stack>
<Group position="apart" m={12}>
<Text fw="bold">Practicing</Text>
<ActionIcon onClick={() => { setPracticing(false); setInvisible(false) }}>
<IconX />
</ActionIcon>
</Group>
<Group>
<RingProgress
size={150}
thickness={16}
label={
<Text align="center" px="xs" sx={{ pointerEvents: "none" }}>
{Math.round((stats.mastered / stats.total) * 100)}% mastered
</Text>
}
sections={[
{
value: (stats.mastered / stats.total) * 100,
color: "blue",
tooltip: `${stats.mastered} mastered`,
},
{
value: (stats.reviewing / stats.total) * 100,
color: "red",
tooltip: `${stats.reviewing} reviewing`,
},
{
value: (stats.learning / stats.total) * 100,
color: "cyan",
tooltip: `${stats.learning} learning`,
},
{
value: (stats.unseen / stats.total) * 100,
color: "gray",
tooltip: `${stats.unseen} unseen`,
},
]}
/>
{stats.due === 0 && <p>You have practiced all positions. Well done!</p>}
</Group>
<>
<Stack>
<Group position="apart" m={12}>
<Text fw="bold">Practicing</Text>
<ActionIcon
onClick={() => {
setPracticing(false);
setInvisible(false);
}}
>
<IconX />
</ActionIcon>
</Group>
<Group>
<RingProgress
size={150}
thickness={16}
label={
<Text align="center" px="xs" sx={{ pointerEvents: "none" }}>
{Math.round((stats.mastered / stats.total) * 100)}% mastered
</Text>
}
sections={[
{
value: (stats.mastered / stats.total) * 100,
color: "blue",
tooltip: `${stats.mastered} mastered`,
},
{
value: (stats.reviewing / stats.total) * 100,
color: "red",
tooltip: `${stats.reviewing} reviewing`,
},
{
value: (stats.learning / stats.total) * 100,
color: "cyan",
tooltip: `${stats.learning} learning`,
},
{
value: (stats.unseen / stats.total) * 100,
color: "gray",
tooltip: `${stats.unseen} unseen`,
},
]}
/>
{stats.due === 0 && (
<p>You have practiced all positions. Well done!</p>
)}
</Group>

<Group>
<Button onClick={() => newPractice("new")}>
Practice next position
</Button>
<Button onClick={() => newPractice("random")}>
Practice random position
</Button>
<Button
onClick={() => {
setInvisible(false);
dispatch({ type: "GO_TO_NEXT" });
}}
>
See Answer
</Button>
</Group>
</Stack>
<Group>
<Button variant="default" onClick={() => newPractice("new")}>
Practice next position
</Button>
<Button variant="default" onClick={() => newPractice("random")}>
Practice random position
</Button>
<Button
variant="default"
onClick={() => {
setInvisible(false);
dispatch({ type: "GO_TO_NEXT" });
}}
>
See Answer
</Button>
<Button variant="default" onClick={() => toggleResetModal()}>
Reset
</Button>
</Group>
</Stack>
<ConfirmModal
title={"Reset opening data"}
description={`Are you sure you want to reset the opening data for "${currentTab?.file?.name}"? All the learning progress will be lost.`}
opened={resetModal}
onClose={toggleResetModal}
onConfirm={() => {
const cards = buildFromTree(
root,
headers.orientation || "white",
headers.start || []
);
setDeck(cards);
toggleResetModal();
}}
confirmLabel="Reset"
/>
</>
);
}

Expand Down
10 changes: 8 additions & 2 deletions src/components/panels/info/RepertoireInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,15 @@ function RepertoireInfo() {
</Group>

<Button
variant="default"
onClick={() => setPracticing(true)}
leftIcon={<IconTargetArrow />}
>
Practice
</Button>

{!loading && !missingMoves && (
<Button onClick={() => searchForMissingMoves()}>
<Button variant="default" onClick={() => searchForMissingMoves()}>
Look for missing moves
</Button>
)}
Expand Down Expand Up @@ -176,7 +177,12 @@ function MissingMoves({
noRecordsText="No games found"
/>

<Button mt={20} rightIcon={<IconReload />} onClick={search}>
<Button
variant="default"
mt={20}
rightIcon={<IconReload />}
onClick={search}
>
Reload missing moves
</Button>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/utils/treeReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,6 @@ const treeReducer = (state: TreeState, action: TreeAction) => {
state.headers.start = payload;
})
.with({ type: "MAKE_MOVE" }, ({ payload }) => {
state.dirty = true;
makeMove(state, payload);
})
.with({ type: "MAKE_MOVES" }, ({ payload }) => {
Expand Down Expand Up @@ -322,6 +321,7 @@ function makeMove(
if (i !== -1) {
state.position.push(i);
} else {
state.dirty = true;
const newMoveNode = createNode({
fen: chess.fen(),
move: m,
Expand Down

0 comments on commit c10cb96

Please sign in to comment.