add item stats

This commit is contained in:
Michael Zhang 2023-06-14 13:49:11 -05:00
parent 41016c184d
commit b2ff5d8416
7 changed files with 221 additions and 95 deletions

View file

@ -1,4 +1,4 @@
use std::{path::PathBuf, time::Duration};
use std::{collections::HashMap, path::PathBuf, time::Duration};
use sqlx::{Row, SqlitePool};
use tauri::State;
@ -18,10 +18,12 @@ pub struct SrsStats {
total_items: u32,
total_reviews: u32,
next_review: Option<i64>,
grades: HashMap<u32, u32>,
/// Used to calculate average success
num_success: u32,
num_failure: u32,
next_review: Option<i64>,
}
#[tauri::command]
@ -65,6 +67,21 @@ pub async fn get_srs_stats(db: State<'_, SrsDb>) -> Result<SrsStats, String> {
.await
.map_err(|err| err.to_string())?;
// current grades query
let row3 = sqlx::query(
r#"
SELECT CurrentGrade, COUNT(*) FROM SrsEntrySet
GROUP BY CurrentGrade
"#,
)
.fetch_all(&db.0)
.await
.map_err(|err| err.to_string())?;
let grades = row3
.into_iter()
.map(|row| (row.get::<u32, _>(0), row.get::<u32, _>(1)))
.collect::<HashMap<_, _>>();
let next_review = row
.try_get::<i64, _>("next_review")
.ok()
@ -78,6 +95,7 @@ pub async fn get_srs_stats(db: State<'_, SrsDb>) -> Result<SrsStats, String> {
num_success: row.try_get("num_success").unwrap_or(0),
num_failure: row.try_get("num_failure").unwrap_or(0),
next_review,
grades,
})
}

View file

@ -0,0 +1,40 @@
.container {
width: 100%;
display: flex;
gap: 8px;
justify-content: space-between;
}
.group {
flex-grow: 1;
color: white;
text-align: center;
border-radius: 4px;
padding: 12px;
display: flex;
flex-direction: column;
gap: 12px;
}
.groupHeader {
h1 {
font-size: 2.5em;
text-shadow: 1px 1px black;
}
}
.groupLevels {
display: flex;
gap: 4px;
justify-content: space-evenly;
h3 {
border: 1px solid rgba(255, 255, 255, 0.5);
background-color: rgba(255, 255, 255, 0.25);
}
}
.level {
flex-grow: 1;
}

View file

@ -0,0 +1,51 @@
import srsLevels from "../data/srslevels.json";
import { SrsStats } from "../panes/SrsPane";
import styles from "./DashboardItemStats.module.scss";
export interface DashboardItemStatsProps {
srsStats: SrsStats;
}
const srsLevelsByGroups = new Map(
srsLevels.groups.map((group) => [
group,
srsLevels.levels.filter((level) => level.group == group.name),
]),
);
export default function DashboardItemStats({ srsStats }: DashboardItemStatsProps) {
const grades = new Map(Object.entries(srsStats.grades).map(([k, v]) => [parseInt(k), v]));
return (
<div className={styles.container}>
{srsLevels.groups.map((group) => {
const groupLevels = srsLevelsByGroups.get(group);
if (!groupLevels) return null;
const groupCount = groupLevels
.map((level) => grades.get(level.value) ?? 0)
.reduce((a, b) => a + b);
return (
<div style={{ backgroundColor: group.color }} className={styles.group} key={group.name}>
<div className={styles.groupHeader}>
<h1>{groupCount}</h1>
{group.name}
</div>
<div className={styles.groupLevels}>
{groupLevels.map((level) => (
<div className={styles.level} key={level.name}>
<h3>{level.name}</h3>
{grades.get(level.value)}
</div>
))}
</div>
</div>
);
})}
</div>
);
}

View file

@ -7,18 +7,10 @@ import { Link } from "react-router-dom";
import ConditionalWrapper from "./utils/ConditionalWrapper";
import ReactTimeago, { Formatter } from "react-timeago";
import { isValid } from "date-fns";
import { SrsStats } from "../panes/SrsPane";
interface SrsStats {
reviews_available: number;
reviews_today: number;
total_items: number;
total_reviews: number;
next_review: number;
/// Used to calculate average success
num_success: number;
num_failure: number;
export interface DashboardReviewStatsProps {
srsStats: SrsStats;
}
interface Stat {
@ -26,21 +18,7 @@ interface Stat {
value: any;
}
export default function DashboardReviewStats() {
const {
data: srsStats,
error,
isLoading,
} = useSWR(["get_srs_stats"], ([command]) => invoke<SrsStats>(command));
if (!srsStats)
return (
<>
{JSON.stringify([srsStats, error, isLoading])}
Loading...
</>
);
export default function DashboardReviewStats({ srsStats }: DashboardReviewStatsProps) {
const averageSuccess = srsStats.num_success / (srsStats.num_success + srsStats.num_failure || 1);
const averageSuccessStr = `${Math.round(averageSuccess * 10000) / 100}%`;

View file

@ -1,69 +1,78 @@
[
{
"group": "Set In Stone",
"name": "★",
"value": 8,
"delay": null,
"color": "#1C1C1C"
},
{
"groups": [
{ "name": "Discovering", "color": "#1A814D" },
{ "name": "Committing", "color": "#004E8E" },
{ "name": "Bolstering", "color": "#5C1696" },
{ "name": "Assimilating", "color": "#890062" },
{ "name": "Set In Stone", "color": "#1C1C1C" }
],
"levels": [
{
"group": "Set In Stone",
"name": "★",
"value": 8,
"delay": null,
"color": "#1C1C1C"
},
{
"group": "Assimilating",
"name": "A2",
"value": 7,
"delay": 10368000,
"color": "#890062"
},
{
"group": "Assimilating",
"name": "A1",
"value": 6,
"delay": 2592000,
"color": "#890062"
},
{
"group": "Assimilating",
"name": "A2",
"value": 7,
"delay": 10368000,
"color": "#890062"
},
{
"group": "Assimilating",
"name": "A1",
"value": 6,
"delay": 2592000,
"color": "#890062"
},
{
"group": "Bolstering",
"name": "B2",
"value": 5,
"delay": 1209600,
"color": "#5C1696"
},
{
"group": "Bolstering",
"name": "B1",
"value": 4,
"delay": 604800,
"color": "#5C1696"
},
{
"group": "Bolstering",
"name": "B2",
"value": 5,
"delay": 1209600,
"color": "#5C1696"
},
{
"group": "Bolstering",
"name": "B1",
"value": 4,
"delay": 604800,
"color": "#5C1696"
},
{
"group": "Committing",
"name": "C2",
"value": 3,
"delay": 259200,
"color": "#004E8E"
},
{
"group": "Committing",
"name": "C1",
"value": 2,
"delay": 86400,
"color": "#004E8E"
},
{
"group": "Committing",
"name": "C2",
"value": 3,
"delay": 259200,
"color": "#004E8E"
},
{
"group": "Committing",
"name": "C1",
"value": 2,
"delay": 86400,
"color": "#004E8E"
},
{
"group": "Discovering",
"name": "D2",
"value": 1,
"delay": 28800,
"color": "#1A814D"
},
{
"group": "Discovering",
"name": "D1",
"value": 0,
"delay": 14400,
"color": "#1A814D"
}
]
{
"group": "Discovering",
"name": "D2",
"value": 1,
"delay": 28800,
"color": "#1A814D"
},
{
"group": "Discovering",
"name": "D1",
"value": 0,
"delay": 14400,
"color": "#1A814D"
}
]
}

View file

@ -16,7 +16,9 @@ export interface SrsLevel {
}
import srsLevelMap from "../data/srslevels.json";
export const srsLevels: Map<number, SrsLevel> = new Map(srsLevelMap.map((v) => [v.value, v]));
export const srsLevels: Map<number, SrsLevel> = new Map(
srsLevelMap.levels.map((v) => [v.value, v]),
);
export interface SrsQuestionGroup {
srsEntry: SrsEntry;

View file

@ -1,12 +1,40 @@
import useSWR from "swr";
import DashboardItemStats from "../components/DashboardItemStats";
import DashboardReviewStats from "../components/DashboardReviewStats";
import styles from "./SrsPane.module.scss";
import { invoke } from "@tauri-apps/api";
export interface SrsStats {
reviews_available: number;
reviews_today: number;
total_items: number;
total_reviews: number;
grades: { string: number };
next_review: number;
/// Used to calculate average success
num_success: number;
num_failure: number;
}
export function Component() {
const {
data: srsStats,
error,
isLoading,
} = useSWR(["get_srs_stats"], ([command]) => invoke<SrsStats>(command));
if (!srsStats) return <>Loading...</>;
return (
<main className={styles.main}>
<DashboardReviewStats />
<DashboardReviewStats srsStats={srsStats} />
<hr />
<DashboardItemStats srsStats={srsStats} />
</main>
);
}