diff --git a/comprl-web/app/components/DashboardContent.tsx b/comprl-web/app/components/DashboardContent.tsx index 2cfc5ab3..6cc37e6f 100644 --- a/comprl-web/app/components/DashboardContent.tsx +++ b/comprl-web/app/components/DashboardContent.tsx @@ -1,20 +1,26 @@ -import { Paper, Typography , ThemeProvider} from '@mui/material' +import { Paper, Typography , ThemeProvider, createTheme, styled } from '@mui/material' import { themeOptions } from "~/style/theme"; -interface DashboardContentProps { - caption: string; - children: React.ReactNode; +interface DashboardStatisticProps { + value: string; + description: string; } -function DashboardContent({ caption, children}: DashboardContentProps) { - return ( +const theme = createTheme(themeOptions); - - {caption} - {children} +export function DashboardsStatistic({ value, description}: DashboardStatisticProps) { + return ( + + + {value} + {description} - + ) } -export default DashboardContent \ No newline at end of file +export const DashboardPaper = styled(Paper)(() => ({ + padding: theme.spacing(5), + borderRadius:4, + height: '100%' +})); diff --git a/comprl-web/app/db/sqlite.data.tsx b/comprl-web/app/db/sqlite.data.tsx index 1db48443..651db012 100644 --- a/comprl-web/app/db/sqlite.data.tsx +++ b/comprl-web/app/db/sqlite.data.tsx @@ -1,10 +1,10 @@ import Database from 'better-sqlite3'; -import User from './types'; +import { User, Statistics } from './types'; import { v4 as uuidv4 } from 'uuid'; console.log('Creating users.db'); -const db = new Database('users.db', { verbose: console.log }); -db.prepare(` +const userDB = new Database('users.db', { verbose: console.log }); +userDB.prepare(` CREATE TABLE IF NOT EXISTS users( user_id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL UNIQUE, @@ -14,22 +14,55 @@ db.prepare(` mu FLOAT NOT NULL DEFAULT 25.0, sigma FLOAT NOT NULL DEFAULT 8.333) `).run(); -db.close(); +userDB.close(); + +console.log('Creating game.db'); +const gameDB = new Database('game.db', { verbose: console.log }); +gameDB.prepare(` + CREATE TABLE IF NOT EXISTS data ( + game_id TEXT NOT NULL PRIMARY KEY, + user1 INTEGER NOT NULL, + user2 INTEGER NOT NULL, + score1 FLOAT NOT NULL, + score2 FLOAT NOT NULL, + start_time, + end_state INTEGER NOT NULL, + winner INTEGER, + disconnected INTEGER) + `).run(); +gameDB.close(); export async function addUser(username: string, password: string, role: string = 'user') { - const db = new Database('users.db', { verbose: console.log }); + const userDB = new Database('users.db', { verbose: console.log }); const token = uuidv4(); - const stmt = db.prepare('INSERT INTO users(username, password, role, token) VALUES (?, ?, ?,?)'); + const stmt = userDB.prepare('INSERT INTO users(username, password, role, token) VALUES (?, ?, ?,?)'); stmt.run(username, password, role, token); - db.close(); + userDB.close(); } export async function getUser(username: string, password: string) { - const db = new Database('users.db', { verbose: console.log }); - const stmt = db.prepare('SELECT * FROM users WHERE username = ?'); + const userDB = new Database('users.db', { verbose: console.log }); + const stmt = userDB.prepare('SELECT * FROM users WHERE username = ?'); const res = stmt.get(username); - db.close(); + userDB.close(); if (!res) { return undefined } if (res.password != password) { return undefined } return { id: res.user_id, name: res.username, role: res.role, token: res.token } as User; +} + +export async function getStatistics(user_id: number) { + const gameDB = new Database('game.db', { verbose: console.log }); + + const stmt_played = gameDB.prepare('SELECT COUNT(*) FROM data WHERE user1 = ? OR user2 = ?'); + const playedGames = stmt_played.get(user_id, user_id)['COUNT(*)']; + + const stmt_won = gameDB.prepare('SELECT COUNT(winner) FROM data WHERE winner = ?'); + const wonGames = stmt_won.get(user_id)['COUNT(winner)']; + + const stmt_disconnect = gameDB.prepare('SELECT COUNT(disconnected) FROM data WHERE disconnected = ?'); + const disconnectedGames = stmt_disconnect.get(user_id)['COUNT(disconnected)']; + + gameDB.close(); + + return {playedGames: playedGames, wonGames: wonGames, disconnectedGames: disconnectedGames} as Statistics } \ No newline at end of file diff --git a/comprl-web/app/db/types.tsx b/comprl-web/app/db/types.tsx index dafc16e3..655b4a0c 100644 --- a/comprl-web/app/db/types.tsx +++ b/comprl-web/app/db/types.tsx @@ -1,8 +1,12 @@ -interface User { +export interface User { id: number; name: string; role: "admin" | "user"; token: string; } -export default User \ No newline at end of file +export interface Statistics { + playedGames: number; + wonGames: number; + disconnectedGames: number +} \ No newline at end of file diff --git a/comprl-web/app/routes/_dashboard.usr.$name.tsx b/comprl-web/app/routes/_dashboard.usr.$name.tsx index 43475b76..3274f9e3 100644 --- a/comprl-web/app/routes/_dashboard.usr.$name.tsx +++ b/comprl-web/app/routes/_dashboard.usr.$name.tsx @@ -1,9 +1,12 @@ -import { Typography, Stack } from "@mui/material"; +import { Typography, Grid, IconButton } from "@mui/material"; +import { Visibility, VisibilityOff } from '@mui/icons-material'; import { LoaderFunctionArgs, redirect } from "@remix-run/node"; import { authenticator } from "~/services/auth.server"; import { commitSession, getSession } from "~/services/session.server"; import { useLoaderData } from "@remix-run/react"; -import DashboardContent from '~/components/DashboardContent'; +import { getStatistics } from "~/db/sqlite.data"; +import { DashboardsStatistic, DashboardPaper } from '~/components/DashboardContent'; +import React from "react"; @@ -25,24 +28,50 @@ export async function loader({ request, params }: LoaderFunctionArgs) { }); } + const games = await getStatistics(user.id) + if (!user.token) { - return { token: "no token exists", username: user.name }; + return { token: "no token exists", username: user.name, games: games }; } - return { token: user.token, username: user.name }; + + return { token: user.token, username: user.name, games: games}; } export default function UserDashboard() { - const { token, username } = useLoaderData(); + const { token, username, games } = useLoaderData(); + const [selected, setSelected] = React.useState(false); return (
- - - - + + + + Username + {username} + + + + + Token + { setSelected(!selected); }}> + {selected ? : } + + + {selected ? token : "*************" } + + + + + Game Statistics + + + + + + + + +
); } \ No newline at end of file diff --git a/comprl-web/app/style/theme.tsx b/comprl-web/app/style/theme.tsx index 198889ed..183e3438 100644 --- a/comprl-web/app/style/theme.tsx +++ b/comprl-web/app/style/theme.tsx @@ -5,6 +5,7 @@ export const themeOptions: ThemeOptions = { mode: 'light', primary: { main: '#3f51b5', + light: '#e8edfc' }, secondary: { main: '#f50057', diff --git a/comprl-web/package-lock.json b/comprl-web/package-lock.json index ea7c1166..d8b5cb3b 100644 --- a/comprl-web/package-lock.json +++ b/comprl-web/package-lock.json @@ -8,7 +8,7 @@ "dependencies": { "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.15.10", + "@mui/icons-material": "^5.15.12", "@mui/material": "^5.15.10", "@remix-run/css-bundle": "^2.6.0", "@remix-run/node": "^2.6.0", @@ -1576,9 +1576,9 @@ } }, "node_modules/@mui/icons-material": { - "version": "5.15.10", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.15.10.tgz", - "integrity": "sha512-9cF8oUHZKo9oQ7EQ3pxPELaZuZVmphskU4OI6NiJNDVN7zcuvrEsuWjYo1Zh4fLiC39Nrvm30h/B51rcUjvSGA==", + "version": "5.15.12", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.15.12.tgz", + "integrity": "sha512-3BXiDlOd3AexZoEXa/VqpIpVIvosCzjLHsdMWzKMXbZdnBiJjmb9ECdqfjn5SpTClO49qvkKLhkTqdBH3fSFGw==", "dependencies": { "@babel/runtime": "^7.23.9" }, diff --git a/comprl-web/package.json b/comprl-web/package.json index f2fb1bb9..54a118bb 100644 --- a/comprl-web/package.json +++ b/comprl-web/package.json @@ -13,7 +13,7 @@ "dependencies": { "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.15.10", + "@mui/icons-material": "^5.15.12", "@mui/material": "^5.15.10", "@remix-run/css-bundle": "^2.6.0", "@remix-run/node": "^2.6.0",