add db class
This commit is contained in:
@@ -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
31
src/client/serverApi.ts
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
|||||||
38
src/index.ts
38
src/index.ts
@@ -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
5
src/interfaces.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export type Group = {
|
||||||
|
id: number;
|
||||||
|
code: string;
|
||||||
|
created_at: string;
|
||||||
|
};
|
||||||
85
src/server/db.ts
Normal file
85
src/server/db.ts
Normal 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;
|
||||||
Reference in New Issue
Block a user