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

View File

@@ -1,32 +1,32 @@
import { serve } from 'bun';
import index from './index.html';
import DB from './server/db';
const server = serve({
routes: {
// Serve index.html for all unmatched routes.
'/*': index,
'/api/hello': {
async GET(req) {
return Response.json({
message: 'Hello, world!',
method: 'GET',
});
},
async PUT(req) {
return Response.json({
message: 'Hello, world!',
method: 'PUT',
});
},
'/api/group/:id': async req => {
const id = req.params.id;
const group = await new DB().getGroup(id);
console.log('Fetching group with ID:', id, 'Result:', group);
if (!group) return new Response(JSON.stringify({ error: 'Not found' }), { status: 404 });
return new Response(JSON.stringify(group), { headers: { 'Content-Type': 'application/json' } });
},
'/api/hello/:name': async req => {
const name = req.params.name;
return Response.json({
message: `Hello, ${name}!`,
});
},
'/api/group': {
async POST(req) {
try {
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' && {

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;