Skip to content

Commit

Permalink
Added card statistics modal, updated packages
Browse files Browse the repository at this point in the history
- very basic right now, only card history graph
- accessible via card menu
- updated packages (mantine to 7.5.1)
- installed @mantine/charts
  • Loading branch information
h16nning committed Feb 9, 2024
1 parent 7f987a2 commit b51f682
Show file tree
Hide file tree
Showing 11 changed files with 1,498 additions and 261 deletions.
1,586 changes: 1,357 additions & 229 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"private": true,
"dependencies": {
"@mantine/carousel": "^7.5.1",
"@mantine/charts": "^7.5.1",
"@mantine/core": "^7.5.1",
"@mantine/dates": "^7.5.1",
"@mantine/dropzone": "^7.5.1",
Expand Down Expand Up @@ -76,6 +77,7 @@
},
"devDependencies": {
"@biomejs/biome": "1.5.3",
"@types/lodash": "^4.14.202",
"@types/react": "^18.2.46",
"@types/react-dom": "^18.2.18",
"@vitejs/plugin-react": "^4.2.1",
Expand Down
7 changes: 0 additions & 7 deletions src/components/CardHistory.tsx

This file was deleted.

1 change: 1 addition & 0 deletions src/components/CardManagerView/CardManagerView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { IconChevronLeft, IconSearch } from "@tabler/icons-react";
import SelectDecksHeader from "../custom/SelectDecksHeader";
import { useDebouncedState } from "@mantine/hooks";
import selectCards from "../../logic/card_filter";
import CardHistory from "../statistics/CardHistory";

function CardManagerView() {
const navigate = useNavigate();
Expand Down
40 changes: 29 additions & 11 deletions src/components/DebugCardModal/DebugCardTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import classes from "./DebugCard.module.css";
import { Fragment } from "react";
import { Card, CardType } from "../../logic/card";
import { Anchor, Space, Text } from "@mantine/core";
import { Rating, State } from "fsrs.js";

export default function DebugCardTable({
card,
Expand Down Expand Up @@ -35,9 +36,8 @@ export default function DebugCardTable({
<tr>
<th>Due:</th>
<td>
{card.model.due.toLocaleTimeString() +
" " +
card.model.due.toDateString()}
{card.model.due.toLocaleDateString()},
{card.model.due.toLocaleTimeString()}
</td>
</tr>
<tr>
Expand Down Expand Up @@ -70,27 +70,45 @@ export default function DebugCardTable({
</tr>
<tr>
<th>Last Review:</th>
<td>{card.model.last_review.toDateString()}</td>
<td>
{card.model.last_review.toLocaleDateString()},
{card.model.last_review.toLocaleTimeString()}
</td>
</tr>
</tbody>
<tbody>
<thead>
<th>History</th>
</thead>
{card.history.map((repetition) => (
<Fragment key={repetition.date.toISOString()}>
{card.history.length}
{card.history.map((log) => (
<Fragment key={log.review.toISOString()}>
<tr>
<th>Date: </th>
<td>
{(typeof repetition.date === "number"
? new Date(repetition.date)
: repetition.date
).toLocaleString()}
{log.review.toLocaleDateString()},
{log.review.toLocaleTimeString()}
</td>
</tr>
<tr>
<th>Result: </th>
<td>{repetition.result}</td>
<td>
{Rating[log.rating]} ({log.rating})
</td>
</tr>
<tr>
<th>State: </th>
<td>
{State[log.state]} ({log.state})
</td>
</tr>
<tr>
<th>Elapsed Days: </th>
<td>{log.elapsed_days}</td>
</tr>
<tr>
<th>Scheduled Days: </th>
<td>{log.scheduled_days}</td>
</tr>
<tr>
<Space h="xs" />
Expand Down
17 changes: 17 additions & 0 deletions src/components/editcard/CardMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ActionIcon, Menu } from "@mantine/core";
import {
IconAdjustmentsHorizontal,
IconArrowsExchange,
IconChartBar,
IconCode,
IconDots,
IconTrash,
Expand All @@ -16,6 +17,8 @@ import {
successfullyDeleted,
} from "../custom/Notification/Notification";
import MoveCardModal from "./MoveCardModal";
import { IconGraphOff } from "@tabler/icons-react";
import CardStatisticsModal from "../statistics/CardStatisticsModal";

interface CardMenuProps {
card: Card<CardType> | undefined;
Expand All @@ -26,6 +29,9 @@ function CardMenu({ card, onDelete }: CardMenuProps) {
const [developerMode] = useSetting("developerMode");

const [debugModalOpened, setDebugModalOpened] = useState<boolean>(false);
const [statisticsModalOpened, setStatisticsModalOpened] =
useState<boolean>(false);

const [moveModalOpened, setMoveModalOpened] = useState<boolean>(false);
const [deleteModalOpened, setDeleteModalOpened] = useState<boolean>(false);
async function tryDeleteCard() {
Expand Down Expand Up @@ -68,6 +74,12 @@ function CardMenu({ card, onDelete }: CardMenuProps) {
>
Options
</Menu.Item>
<Menu.Item
leftSection={<IconChartBar size={16} />}
onClick={() => setStatisticsModalOpened(true)}
>
Statistics
</Menu.Item>
<Menu.Item
leftSection={<IconArrowsExchange size={16} />}
onClick={() => setMoveModalOpened(true)}
Expand All @@ -83,6 +95,11 @@ function CardMenu({ card, onDelete }: CardMenuProps) {
</Menu.Item>
</Menu.Dropdown>
</Menu>
<CardStatisticsModal
opened={statisticsModalOpened}
setOpened={setStatisticsModalOpened}
card={card}
/>
<DebugCardModal
opened={debugModalOpened}
setOpened={setDebugModalOpened}
Expand Down
58 changes: 58 additions & 0 deletions src/components/statistics/CardHistory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React, { useMemo } from "react";
import { AreaChart } from "@mantine/charts";
import { Card, CardType } from "../../logic/card";

interface CardHistoryProps {
card?: Card<CardType>;
}

export default function CardHistory({ card }: CardHistoryProps) {
const data = useMemo(() => {
if (card) {
return card.history.map((h) => {
return {
date: h.review.getTime(),
rating: h.rating,
};
});
}
return [];
}, [card]);

console.log(card?.model.due.getTime());

return (
<AreaChart
h={300}
data={data}
series={[{ name: "rating", color: "forest" }]}
dataKey="date"
curveType="monotone"
withTooltip={false}
gridAxis="x"
yAxisProps={{
domain: [1, 4],
tickCount: 4,
tickFormatter: (value) => {
switch (value) {
case 1:
return "Again";
case 2:
return "Hard";
case 3:
return "Good";
case 4:
return "Easy";
}
return "";
},
}}
xAxisProps={{
domain: ["dataMin", new Date(Date.now()).getTime()],
scale: "linear",
tickFormatter: (value) => new Date(value).toLocaleDateString(),
}}
connectNulls
/>
);
}
18 changes: 18 additions & 0 deletions src/components/statistics/CardStatisticsModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Modal } from "@mantine/core";
import { Card, CardType } from "../../logic/card";
import ModalProps from "../custom/ModalProps";
import CardHistory from "./CardHistory";

interface DeckOptionsModalProps extends ModalProps {
card?: Card<CardType>;
}

function DeckOptionsModal({ opened, setOpened, card }: DeckOptionsModalProps) {
return (
<Modal opened={opened} onClose={() => setOpened(false)} title="Statistics">
<CardHistory card={card} />
</Modal>
);
}

export default DeckOptionsModal;
8 changes: 0 additions & 8 deletions src/logic/Repetition.ts

This file was deleted.

16 changes: 11 additions & 5 deletions src/logic/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import { v4 as uuidv4 } from "uuid";
import { Deck } from "./deck";
import { db } from "./db";
import { useLiveQuery } from "dexie-react-hooks";
import { newRepetition, Repetition } from "./Repetition";
import { useMemo } from "react";
import { Table } from "dexie";
import { Card as Model, State } from "fsrs.js";
import { Card as Model, ReviewLog, State } from "fsrs.js";
import { scheduler } from "./CardScheduler";

export enum CardType {
Expand All @@ -19,7 +18,7 @@ export enum CardType {

export interface CardSkeleton {
id: string;
history: Repetition[];
history: ReviewLog[];
model: Model;
deck: string;
creationDate: Date;
Expand Down Expand Up @@ -71,8 +70,15 @@ export async function updateCard(
return db.cards.update(id, changes);
}

export async function updateCardModel(card: Card<CardType>, model: Model) {
return db.cards.update(card.id, { model: model });
export async function updateCardModel(
card: Card<CardType>,
model: Model,
log: ReviewLog
) {
return db.cards.update(card.id, {
model: model,
history: [...card.history, log],
});
}

export async function moveCard(card: Card<CardType>, newDeck: Deck) {
Expand Down
6 changes: 5 additions & 1 deletion src/logic/learn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,11 @@ export function useLearning(
const answer = useCallback(
(rating: Rating) => {
if (currentCard && currentCardRepeatInfo) {
updateCardModel(currentCard, currentCardRepeatInfo[rating].card);
updateCardModel(
currentCard,
currentCardRepeatInfo[rating].card,
currentCardRepeatInfo[rating].review_log
);
if (currentCardRepeatInfo[rating].card.scheduled_days === 0) {
setTimeCriticalCards((tcCards) =>
[
Expand Down

0 comments on commit b51f682

Please sign in to comment.