Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

web: update home dashboard #111

Merged
merged 3 commits into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 17 additions & 11 deletions comprl-web/app/components/DashboardContent.tsx
Original file line number Diff line number Diff line change
@@ -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);

<Paper elevation={5} sx={{p:4, borderRadius:6, bgcolor: '#d3e0eb' }}>
<Typography variant="h5" align="left">{caption}</Typography>
{children}
export function DashboardsStatistic({ value, description}: DashboardStatisticProps) {
return (
<ThemeProvider theme={theme}>
<Paper variant="outlined" sx={{p:4, borderRadius:3, bgcolor: 'primary.light', paddingTop: theme.spacing(6), paddingBottom: theme.spacing(6), height: '100%' }}>
<Typography variant="h3" align="center" color='primary.main'>{value}</Typography>
<Typography variant="body1" align="center" color='primary.main'>{description}</Typography>
</Paper>

</ThemeProvider>
)
}

export default DashboardContent
export const DashboardPaper = styled(Paper)(() => ({
padding: theme.spacing(5),
borderRadius:4,
height: '100%'
}));
53 changes: 43 additions & 10 deletions comprl-web/app/db/sqlite.data.tsx
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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
}
8 changes: 6 additions & 2 deletions comprl-web/app/db/types.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
interface User {
export interface User {
id: number;
name: string;
role: "admin" | "user";
token: string;
}

export default User
export interface Statistics {
playedGames: number;
wonGames: number;
disconnectedGames: number
}
53 changes: 41 additions & 12 deletions comprl-web/app/routes/_dashboard.usr.$name.tsx
Original file line number Diff line number Diff line change
@@ -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";



Expand All @@ -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<typeof loader>();
const { token, username, games } = useLoaderData<typeof loader>();
const [selected, setSelected] = React.useState(false);
return (
<div>
<Stack
direction={{ xs: 'column', sm: 'row' }}
spacing={{ xs: 1, sm: 2, md: 4 }}
>
<DashboardContent caption="Username" children={username} />
<DashboardContent caption="Token" children={token} />
</Stack>
<Grid container spacing={3} alignItems="stretch">
<Grid item xs={12} md={6}>
<DashboardPaper>
<Typography variant="h5" > Username </Typography>
<Typography>{username}</Typography>
</DashboardPaper>
</Grid>
<Grid item xs={12} md={6}>
<DashboardPaper>
<Typography variant="h5" > Token
<IconButton onClick={() => { setSelected(!selected); }}>
{selected ? <VisibilityOff /> : <Visibility />}
</IconButton>
</Typography>
<Typography>{selected ? token : "*************" }</Typography>
</DashboardPaper>
</Grid>
<Grid item xs={12}>
<DashboardPaper>
<Typography variant="h5"> Game Statistics </Typography>
<Grid container spacing={8} padding={5}>
<Grid item xs={12} md={6} lg={3}><DashboardsStatistic value={games.playedGames.toString()} description="games played" /></Grid>
<Grid item xs={12} md={6} lg={3}><DashboardsStatistic value={games.wonGames.toString()} description="games won" /></Grid>
<Grid item xs={12} md={6} lg={3}><DashboardsStatistic value={Math.round((games.wonGames/games.playedGames)*100) + "%"} description="win rate" /></Grid>
<Grid item xs={12} md={6} lg={3}><DashboardsStatistic value={games.disconnectedGames.toString()} description="disconnects" /></Grid>
</Grid>
</DashboardPaper>
</Grid>
</Grid>
</div>
);
}
1 change: 1 addition & 0 deletions comprl-web/app/style/theme.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const themeOptions: ThemeOptions = {
mode: 'light',
primary: {
main: '#3f51b5',
light: '#e8edfc'
},
secondary: {
main: '#f50057',
Expand Down
8 changes: 4 additions & 4 deletions comprl-web/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion comprl-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading