From 16c154471f1774ee1730e8c104a9e3d6fa5f0ca7 Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Thu, 8 Jun 2023 18:52:29 -0500 Subject: [PATCH] stats --- package-lock.json | 21 +++++++++++ package.json | 1 + src-tauri/src/srs.rs | 49 ++++++++++++++++++++++--- src/App.tsx | 20 +++++++--- src/components/DashboardReviewStats.tsx | 39 ++++++++++++++++---- src/panes/SrsReviewPane.tsx | 3 ++ 6 files changed, 115 insertions(+), 18 deletions(-) create mode 100644 src/panes/SrsReviewPane.tsx diff --git a/package-lock.json b/package-lock.json index 9727889..8ccfafc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "houhou", "version": "0.1.0", "dependencies": { + "@chakra-ui/icons": "^2.0.19", "@chakra-ui/react": "^2.7.0", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", @@ -682,6 +683,18 @@ "react": ">=18" } }, + "node_modules/@chakra-ui/icons": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/@chakra-ui/icons/-/icons-2.0.19.tgz", + "integrity": "sha512-0A6U1ZBZhLIxh3QgdjuvIEhAZi3B9v8g6Qvlfa3mu6vSnXQn2CHBZXmJwxpXxO40NK/2gj/gKXrLeUaFR6H/Qw==", + "dependencies": { + "@chakra-ui/icon": "3.0.16" + }, + "peerDependencies": { + "@chakra-ui/system": ">=2.0.0", + "react": ">=18" + } + }, "node_modules/@chakra-ui/image": { "version": "2.0.16", "resolved": "https://registry.npmjs.org/@chakra-ui/image/-/image-2.0.16.tgz", @@ -4475,6 +4488,14 @@ "@chakra-ui/shared-utils": "2.0.5" } }, + "@chakra-ui/icons": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/@chakra-ui/icons/-/icons-2.0.19.tgz", + "integrity": "sha512-0A6U1ZBZhLIxh3QgdjuvIEhAZi3B9v8g6Qvlfa3mu6vSnXQn2CHBZXmJwxpXxO40NK/2gj/gKXrLeUaFR6H/Qw==", + "requires": { + "@chakra-ui/icon": "3.0.16" + } + }, "@chakra-ui/image": { "version": "2.0.16", "resolved": "https://registry.npmjs.org/@chakra-ui/image/-/image-2.0.16.tgz", diff --git a/package.json b/package.json index b6daeb0..e00a324 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "tauri": "tauri" }, "dependencies": { + "@chakra-ui/icons": "^2.0.19", "@chakra-ui/react": "^2.7.0", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", diff --git a/src-tauri/src/srs.rs b/src-tauri/src/srs.rs index c4cb1f6..605251b 100644 --- a/src-tauri/src/srs.rs +++ b/src-tauri/src/srs.rs @@ -1,3 +1,8 @@ +use std::{ + ops::Add, + time::{Duration, Instant, SystemTime, UNIX_EPOCH}, +}; + use sqlx::{Row, SqlitePool}; use tauri::State; @@ -18,6 +23,7 @@ pub struct SrsStats { #[tauri::command] pub async fn get_srs_stats(db: State<'_, SrsDb>) -> Result { + // counts query let row = sqlx::query( r#" SELECT @@ -31,12 +37,45 @@ pub async fn get_srs_stats(db: State<'_, SrsDb>) -> Result { .await .map_err(|err| err.to_string())?; + // reviews query + let utc_now = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map_err(|err| err.to_string())? + .as_secs() as i64 + * 1000000000; + let utc_tomorrow = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map_err(|err| err.to_string())? + .add(Duration::from_secs(60 * 60 * 24)) + .as_secs() as i64 + * 1000000000; + let row2 = sqlx::query( + r#" + SELECT COUNT(*) AS reviews + FROM SrsEntrySet + WHERE + SuspensionDate IS NULL + AND NextAnswerDate <= ? + UNION ALL + SELECT COUNT(*) AS reviews + FROM SrsEntrySet + WHERE + SuspensionDate IS NULL + AND NextAnswerDate <= ? + "#, + ) + .bind(&utc_now) + .bind(&utc_tomorrow) + .fetch_all(&db.0) + .await + .map_err(|err| err.to_string())?; + Ok(SrsStats { - reviews_available: 0, - reviews_today: 0, - total_items: row.get("total_items"), + reviews_available: row2[0].get("reviews"), + reviews_today: row2[1].get("reviews"), + total_items: row.try_get("total_items").unwrap_or(0), total_reviews: 0, - num_success: row.get("num_success"), - num_failure: row.get("num_failure"), + num_success: row.try_get("num_success").unwrap_or(0), + num_failure: row.try_get("num_failure").unwrap_or(0), }) } diff --git a/src/App.tsx b/src/App.tsx index 38bd979..f7eecb0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -11,6 +11,7 @@ import SettingsPane from "./panes/SettingsPane"; import { StrictMode } from "react"; import styles from "./App.module.scss"; +import SrsReviewPane from "./panes/SrsReviewPane"; function Layout() { const location = useLocation(); @@ -45,18 +46,19 @@ export default function App() { }> {navLinks.flatMap((route, idx) => { if (route.subPaths) { - return route.subPaths.map((subRoute, idx) => { + return route.subPaths.map((subRoute, idx2) => { return ( ); }); } else { return ( - + ); } })} @@ -74,8 +76,16 @@ export default function App() { } const navLinks = [ - { key: "home", path: "/", title: "Home", element: }, - { key: "srs", path: "/srs", title: "SRS", element: }, + // { key: "home", path: "/", title: "Home", element: }, + { + key: "srs", + title: "SRS", + element: , + subPaths: [ + { key: "index", path: "/srs" }, + { key: "review", path: "/srs/review", element: }, + ], + }, { key: "kanji", title: "Kanji", diff --git a/src/components/DashboardReviewStats.tsx b/src/components/DashboardReviewStats.tsx index 51920e5..5645c8b 100644 --- a/src/components/DashboardReviewStats.tsx +++ b/src/components/DashboardReviewStats.tsx @@ -1,4 +1,5 @@ import { + Button, Grid, GridItem, Stat, @@ -8,9 +9,11 @@ import { StatLabel, StatNumber, } from "@chakra-ui/react"; +import { ArrowRightIcon } from "@chakra-ui/icons"; import styles from "./DashboardReviewStats.module.scss"; import useSWR from "swr"; import { invoke } from "@tauri-apps/api/tauri"; +import { Link } from "react-router-dom"; interface SrsStats { reviews_available: number; @@ -31,28 +34,48 @@ export default function DashboardReviewStats() { isLoading, } = useSWR(["get_srs_stats"], ([command]) => invoke(command)); - if (!srsStats) return <>Loading...; + if (!srsStats) + return ( + <> + {JSON.stringify([srsStats, error, isLoading])} + Loading... + + ); const averageSuccess = srsStats.num_success / (srsStats.num_success + srsStats.num_failure); const averageSuccessStr = `${Math.round(averageSuccess * 10000) / 100}%`; const generateStat = (stat) => { return ( - - {stat.label} - {stat.value} - + + + {stat.label} + {stat.value} + + ); }; return ( <> - {/* JSON.stringify([srsStats, error, isLoading]) */} + + + + reviews available + {srsStats.reviews_available} + + + + + - + {generateStat({ label: "reviews available", value: srsStats.reviews_available })} + {generateStat({ label: "reviews today", value: srsStats.reviews_today })} {generateStat({ label: "total items", value: srsStats.total_items })} {generateStat({ label: "average success", value: averageSuccessStr })} - + ); } diff --git a/src/panes/SrsReviewPane.tsx b/src/panes/SrsReviewPane.tsx new file mode 100644 index 0000000..03c71cf --- /dev/null +++ b/src/panes/SrsReviewPane.tsx @@ -0,0 +1,3 @@ +export default function SrsReviewPane() { + return <>review; +}