add db class

This commit is contained in:
2025-11-07 16:29:26 +01:00
parent a81cb671b8
commit 43824ce284
10 changed files with 153 additions and 42 deletions

View File

@@ -1,9 +1,7 @@
import * as React from 'react'; import * as React from 'react';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
import Checkbox from '@mui/material/Checkbox';
import CssBaseline from '@mui/material/CssBaseline'; import CssBaseline from '@mui/material/CssBaseline';
import FormControlLabel from '@mui/material/FormControlLabel';
import Divider from '@mui/material/Divider'; import Divider from '@mui/material/Divider';
import FormLabel from '@mui/material/FormLabel'; import FormLabel from '@mui/material/FormLabel';
import FormControl from '@mui/material/FormControl'; import FormControl from '@mui/material/FormControl';
@@ -19,10 +17,8 @@ import Card from './Card';
const SignIn = () => { const SignIn = () => {
const [email, setEmail] = React.useState(''); const [email, setEmail] = React.useState('');
const [emailError, setEmailError] = React.useState(false); const [emailError, setEmailError] = React.useState(false);
const [emailErrorMessage, setEmailErrorMessage] = React.useState('');
const [group, setGroup] = React.useState(''); const [group, setGroup] = React.useState('');
const [groupError, setGroupError] = React.useState(false); const [groupError, setGroupError] = React.useState(false);
const [groupErrorMessage, setGroupErrorMessage] = React.useState('');
const [open, setOpen] = React.useState(false); const [open, setOpen] = React.useState(false);
const theme = useTheme(); const theme = useTheme();
@@ -36,26 +32,26 @@ const SignIn = () => {
}; };
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => { const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
if (emailError || groupError) { if ((emailError || email === '')) {
event.preventDefault(); event.preventDefault();
setEmailError(true);
return; return;
} }
console.log({ if ((groupError || group === '')) {
email: email, event.preventDefault();
groupcode: group, setGroupError(true);
}); return;
}
}; };
const validateEmail = (): boolean => { const validateEmail = (): boolean => {
let isValid = true; let isValid = true;
if (email !== '' && !/\S+@\S+\.\S+/.test(email)) { if (email !== '' && !/\S+@\S+\.\S+/.test(email)) {
setEmailError(true); setEmailError(true);;
setEmailErrorMessage('Bitte gib eine gültige E-Mail Adresse ein.');
isValid = false; isValid = false;
} else { } else {
setEmailError(false); setEmailError(false);
setEmailErrorMessage('');
} }
return isValid; return isValid;
}; };
@@ -63,12 +59,10 @@ const SignIn = () => {
const validateGroup = (): boolean => { const validateGroup = (): boolean => {
let isValid = true; let isValid = true;
if (group !== '' && !/\S+@\S+\.\S+/.test(email)) { if (group !== '' && !/\S+@\S+\.\S+/.test(email)) {
setEmailError(true); setGroupError(true);
setEmailErrorMessage('Bitte gib eine gültige E-Mail Adresse ein.');
isValid = false; isValid = false;
} else { } else {
setEmailError(false); setGroupError(false);
setEmailErrorMessage('');
} }
return isValid; return isValid;
}; };
@@ -119,7 +113,7 @@ const SignIn = () => {
<TextField <TextField
error={emailError} error={emailError}
helperText={emailErrorMessage} helperText={emailError && 'Bitte gib eine gültige E-Mail Adresse ein.'}
id="email" id="email"
type="email" type="email"
name="email" name="email"
@@ -137,7 +131,7 @@ const SignIn = () => {
<FormLabel htmlFor="password">{'Gruppencode'}</FormLabel> <FormLabel htmlFor="password">{'Gruppencode'}</FormLabel>
<TextField <TextField
error={groupError} error={groupError}
helperText={groupErrorMessage} helperText={groupError && 'Bitte gib einen gültigen Gruppencode ein.'}
name="groupcode" name="groupcode"
placeholder="Gruppe123" placeholder="Gruppe123"
type="text" type="text"
@@ -151,10 +145,6 @@ const SignIn = () => {
color={groupError ? 'error' : 'primary'} /> color={groupError ? 'error' : 'primary'} />
</FormControl> </FormControl>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Anmeldedaten speichern" />
<ForgotPassword open={open} handleClose={handleClose} /> <ForgotPassword open={open} handleClose={handleClose} />
<Button <Button

31
src/client/serverApi.ts Normal file
View File

@@ -0,0 +1,31 @@
import type { Group } from '@/interfaces';
export async function fetchGroup(id: string): Promise<Group | null> {
try {
const res = await fetch(`/api/group/${id}`);
if (!res.ok) return null;
const data: Group = await res.json();
return data;
} catch (err) {
console.error('Failed to fetch group:', err);
return null;
}
}
export async function createGroup(group: Group): Promise<Group | null> {
try {
const res = await fetch('/api/group', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ group }),
});
if (!res.ok) return null;
const data: Group = await res.json();
return data;
} catch (err) {
console.error('Failed to create group:', err);
return null;
}
}

View File

@@ -8,6 +8,6 @@
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>
<script type="module" src="./frontend.tsx"></script> <script type="module" src="./client/frontend.tsx"></script>
</body> </body>
</html> </html>

View File

@@ -1,32 +1,32 @@
import { serve } from 'bun'; import { serve } from 'bun';
import index from './index.html'; import index from './index.html';
import DB from './server/db';
const server = serve({ const server = serve({
routes: { routes: {
// Serve index.html for all unmatched routes. // Serve index.html for all unmatched routes.
'/*': index, '/*': index,
'/api/hello': { '/api/group/:id': async req => {
async GET(req) { const id = req.params.id;
return Response.json({ const group = await new DB().getGroup(id);
message: 'Hello, world!', console.log('Fetching group with ID:', id, 'Result:', group);
method: 'GET', if (!group) return new Response(JSON.stringify({ error: 'Not found' }), { status: 404 });
}); return new Response(JSON.stringify(group), { headers: { 'Content-Type': 'application/json' } });
},
async PUT(req) {
return Response.json({
message: 'Hello, world!',
method: 'PUT',
});
},
}, },
'/api/hello/:name': async req => { '/api/group': {
const name = req.params.name; async POST(req) {
return Response.json({ try {
message: `Hello, ${name}!`, const group = (await req.formData() as FormData).get('code') as string;
}); const response = await new DB().createGroup(group);
}, return new Response(JSON.stringify(response), { headers: { 'Content-Type': 'application/json' } });
} catch (err) {
console.error('Error creating group:', err);
return new Response(JSON.stringify({ error: 'Failed to create group' }), { status: 500 });
}
}
}
}, },
development: process.env.NODE_ENV !== 'production' && { development: process.env.NODE_ENV !== 'production' && {

5
src/interfaces.ts Normal file
View File

@@ -0,0 +1,5 @@
export type Group = {
id: number;
code: string;
created_at: string;
};

85
src/server/db.ts Normal file
View File

@@ -0,0 +1,85 @@
import { Database } from 'bun:sqlite';
// create tables if they don't exist
const createTableScript = `
-- GROUP TRABLE --
CREATE TABLE IF NOT EXISTS group (
id INTEGER PRIMARY KEY AUTOINCREMENT,
code TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
mail TEXT NOT NULL,
image BLOB,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- USER TABLE --
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
mail TEXT NOT NULL,
image BLOB,
);
-- GROUP_MEMBER TABLE --
CREATE TABLE IF NOT EXISTS group_member (
id INTEGER PRIMARY KEY AUTOINCREMENT,
group_id INTEGER,
user_id INTEGER,
UNIQUE(email, group_id),
FOREIGN KEY(group_id) REFERENCES groups(id),
FOREIGN KEY(user_id) REFERENCES users(id)
);
-- BAN TABLE --
CREATE TABLE IF NOT EXISTS ban (
id INTEGER PRIMARY KEY AUTOINCREMENT,
group_id INTEGER,
user_id INTEGER,
user_id2 INTEGER,
FOREIGN KEY(group_id) REFERENCES groups(id),
FOREIGN KEY(user_id) REFERENCES users(id),
FOREIGN KEY(user_id2) REFERENCES users(id)
UNIQUE(group_id, user_id, user_id2),
);
-- WHISHLIST TABLE --
CREATE TABLE IF NOT EXISTS wishlist (
id INTEGER PRIMARY KEY AUTOINCREMENT,
group_id INTEGER,
user_id INTEGER,
item TEXT NOT NULL,
FOREIGN KEY(group_id) REFERENCES groups(id),
FOREIGN KEY(user_id) REFERENCES users(id)
);
`;
class DB {
private instance: Database = new Database();
private prepareDB () {
this.instance.run(createTableScript);
}
public async getGroup(id: string) {
const stmt = this.instance.prepare('SELECT * FROM groups WHERE code = ?');
const group = await stmt.get(id);
return group;
}
public createGroup(code: string): { id: number | bigint} {
const stmt = this.instance.prepare('INSERT INTO groups (code) VALUES (?)');
const changes = stmt.run(code);
console.log('Inserted group with ID:', changes);
return { id: changes.lastInsertRowid };
};
constructor(url: string = './data.sqlite') {
if (this.instance) {
this.instance = new Database(url);
this.prepareDB();
console.log('Database initialized at', url);
}
}
}
export default DB;