diff --git a/._index.html b/._index.html deleted file mode 100644 index 988359c..0000000 Binary files a/._index.html and /dev/null differ diff --git a/._package.json b/._package.json deleted file mode 100644 index 988359c..0000000 Binary files a/._package.json and /dev/null differ diff --git a/._postcss.config.js b/._postcss.config.js deleted file mode 100644 index 988359c..0000000 Binary files a/._postcss.config.js and /dev/null differ diff --git a/._src b/._src deleted file mode 100755 index 988359c..0000000 Binary files a/._src and /dev/null differ diff --git a/._tailwind.config.js b/._tailwind.config.js deleted file mode 100644 index 988359c..0000000 Binary files a/._tailwind.config.js and /dev/null differ diff --git a/backend/lib/mail.js b/backend/lib/mail.js index 8368e5f..ef35312 100644 --- a/backend/lib/mail.js +++ b/backend/lib/mail.js @@ -58,7 +58,7 @@ export async function sendTestMail(to) { const html = `
Diese Test-Mail bestaetigt, dass der Mail-Versand ueber +
Diese Test-Mail bestätigt, dass der Mail-Versand über
${process.env.SMTP_HOST || 'kein SMTP'} funktioniert.
Absender: ${FROM}
Zeitstempel: ${new Date().toISOString()}
diff --git a/backend/lib/seed.js b/backend/lib/seed.js index d671904..3dd2b45 100644 --- a/backend/lib/seed.js +++ b/backend/lib/seed.js @@ -1,12 +1,12 @@ import crypto from 'crypto'; -// Befuellt einen frischen Demo-Tenant mit Beispieldaten -// (5 Kunden, 3 Artikel, 6 Lieferungen, 2 Geraete). +// Befüllt einen frischen Demo-Tenant mit Beispieldaten +// (5 Kunden, 3 Artikel, 6 Lieferungen, 2 Geräte). export async function seedDemoTenant(conn, tenantId) { // Artikel const artikel = [ { id: crypto.randomUUID(), name: 'Brotkorb klein', pfand: 2.50 }, - { id: crypto.randomUUID(), name: 'Brotkorb gross', pfand: 5.00 }, + { id: crypto.randomUUID(), name: 'Brotkorb groß', pfand: 5.00 }, { id: crypto.randomUUID(), name: 'Transportbox', pfand: 10.00 } ]; for (const a of artikel) { @@ -18,11 +18,11 @@ export async function seedDemoTenant(conn, tenantId) { // Kunden const kunden = [ - { name: 'Cafe Sonnenschein', adresse: 'Bahnhofstr. 12, 10115 Berlin', zeit: '05:00', hinweis: 'Anlieferung Hintertuer. Code 1234#.' }, - { name: 'Restaurant Roma', adresse: 'Hauptstr. 88, 10117 Berlin', zeit: '06:30', hinweis: 'Schluesselkasten links neben Eingang.' }, - { name: 'Hotel Adlerhorst', adresse: 'Seestrasse 5, 14193 Berlin', zeit: '05:30', hinweis: 'Anlieferung Tiefgarage Ebene -1, Tor 3.' }, + { name: 'Cafe Sonnenschein', adresse: 'Bahnhofstr. 12, 10115 Berlin', zeit: '05:00', hinweis: 'Anlieferung Hintertür. Code 1234#.' }, + { name: 'Restaurant Roma', adresse: 'Hauptstr. 88, 10117 Berlin', zeit: '06:30', hinweis: 'Schlüsselkasten links neben Eingang.' }, + { name: 'Hotel Adlerhorst', adresse: 'Seestraße 5, 14193 Berlin', zeit: '05:30', hinweis: 'Anlieferung Tiefgarage Ebene -1, Tor 3.' }, { name: 'Kantine Werk Nord', adresse: 'Industriestr. 200, 13407 Berlin', zeit: '06:00', hinweis: 'Werkschutz Bescheid geben, Tor B.' }, - { name: 'Baeckerei Schmitt', adresse: 'Marktplatz 4, 10178 Berlin', zeit: '04:45', hinweis: 'Direkt in den Verkaufsraum stellen.' } + { name: 'Bäckerei Schmitt', adresse: 'Marktplatz 4, 10178 Berlin', zeit: '04:45', hinweis: 'Direkt in den Verkaufsraum stellen.' } ]; const kundenIds = []; for (const k of kunden) { @@ -35,7 +35,7 @@ export async function seedDemoTenant(conn, tenantId) { ); } - // Lieferungen (verteilt ueber die letzten 14 Tage) + // Lieferungen (verteilt über die letzten 14 Tage) for (let i = 0; i < 6; i++) { const kid = kundenIds[i % kundenIds.length]; const aid = artikel[i % artikel.length].id; @@ -47,12 +47,12 @@ export async function seedDemoTenant(conn, tenantId) { ); } - // Geraete - const geraete = [ + // Geräte + const geraeteList = [ { sn: 'OF-2024-001', typ: 'Ofen', bez: 'Miwe Condo 3-Etagen', kid: kundenIds[0] }, - { sn: 'KS-2024-007', typ: 'Kuehlschrank', bez: 'Liebherr GKv 5710', kid: kundenIds[2] } + { sn: 'KS-2024-007', typ: 'Kühlschrank', bez: 'Liebherr GKv 5710', kid: kundenIds[2] } ]; - for (const g of geraete) { + for (const g of geraeteList) { await conn.query( `INSERT INTO geraete (id, tenant_id, seriennummer, typ, bezeichnung, kunde_id, status) VALUES (UUID(), ?, ?, ?, ?, ?, 'aktiv')`, diff --git a/backend/middleware/auth.js b/backend/middleware/auth.js index 636c299..d4598b7 100644 --- a/backend/middleware/auth.js +++ b/backend/middleware/auth.js @@ -3,7 +3,7 @@ import pool from '../config/database.js'; // Verifiziert JWT und stellt req.user bereit // req.user enthaelt: { id, email, name, rolle, tenant_id } -// tenant_id ist NULL fuer SuperAdmins. +// tenant_id ist NULL für SuperAdmins. export const authenticateToken = (req, res, next) => { const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; @@ -14,7 +14,7 @@ export const authenticateToken = (req, res, next) => { jwt.verify(token, process.env.JWT_SECRET, (err, user) => { if (err) { - return res.status(403).json({ error: 'Ungueltiger oder abgelaufener Token' }); + return res.status(403).json({ error: 'Ungültiger oder abgelaufener Token' }); } req.user = user; next(); diff --git a/backend/package.json b/backend/package.json index 1a38926..d30390b 100644 --- a/backend/package.json +++ b/backend/package.json @@ -2,7 +2,7 @@ "name": "pfandsystem-backend", "version": "1.0.0", "type": "module", - "description": "Backend API fuer Pfandsystem mit MySQL", + "description": "Backend API für Pfandsystem mit MySQL", "main": "server.js", "scripts": { "start": "node server.js", diff --git a/backend/routes/artikel.js b/backend/routes/artikel.js index dac6c9b..296e63e 100644 --- a/backend/routes/artikel.js +++ b/backend/routes/artikel.js @@ -69,7 +69,7 @@ router.delete('/:id', async (req, res) => { const [r] = await pool.query('DELETE FROM artikel WHERE id=? AND tenant_id=?', [req.params.id, req.user.tenant_id]); if (r.affectedRows === 0) return res.status(404).json({ error: 'Artikel nicht gefunden' }); - res.json({ message: 'Artikel geloescht' }); + res.json({ message: 'Artikel gelöscht' }); } catch (e) { res.status(500).json({ error: 'Serverfehler' }); } }); diff --git a/backend/routes/auth.js b/backend/routes/auth.js index 8023e4b..3c8a696 100644 --- a/backend/routes/auth.js +++ b/backend/routes/auth.js @@ -46,13 +46,13 @@ router.post('/login', [ ); } - if (rows.length === 0) return res.status(401).json({ error: 'Ungueltige Anmeldedaten' }); + if (rows.length === 0) return res.status(401).json({ error: 'Ungültige Anmeldedaten' }); const m = rows[0]; const ok = await bcrypt.compare(password, m.password_hash); - if (!ok) return res.status(401).json({ error: 'Ungueltige Anmeldedaten' }); + if (!ok) return res.status(401).json({ error: 'Ungültige Anmeldedaten' }); - // Demo-Ablauf-Pruefung + // Demo-Ablauf-Prüfung if (m.tenant_id) { const [tr] = await pool.query( 'SELECT status, demo_expires_at, typ, name FROM tenants WHERE id = ?', @@ -114,7 +114,7 @@ router.post('/change-password', authenticateToken, [ if (!ok) return res.status(401).json({ error: 'Aktuelles Passwort ist falsch' }); const hash = await bcrypt.hash(req.body.newPassword, 10); await pool.query('UPDATE mitarbeiter SET password_hash = ? WHERE id = ?', [hash, req.user.id]); - res.json({ message: 'Passwort erfolgreich geaendert' }); + res.json({ message: 'Passwort erfolgreich geändert' }); } catch (e) { console.error('change-password-Fehler:', e); res.status(500).json({ error: 'Serverfehler' }); diff --git a/backend/routes/geraete.js b/backend/routes/geraete.js index d552f18..ac84b16 100644 --- a/backend/routes/geraete.js +++ b/backend/routes/geraete.js @@ -28,7 +28,7 @@ router.get('/:id', async (req, res) => { WHERE g.id = ? AND g.tenant_id = ?`, [req.params.id, req.user.tenant_id] ); - if (rows.length === 0) return res.status(404).json({ error: 'Geraet nicht gefunden' }); + if (rows.length === 0) return res.status(404).json({ error: 'Gerät nicht gefunden' }); res.json(rows[0]); } catch (e) { res.status(500).json({ error: 'Serverfehler' }); } }); @@ -63,7 +63,7 @@ router.post('/', [ res.status(201).json(rows[0]); } catch (e) { if (e.code === 'ER_DUP_ENTRY') return res.status(400).json({ error: 'Seriennummer bereits vergeben' }); - console.error('POST geraete:', e); + console.error('POST geräte:', e); res.status(500).json({ error: 'Serverfehler' }); } }); @@ -88,7 +88,7 @@ router.put('/:id', [ [seriennummer, typ, bezeichnung || null, kunde_id || null, status || 'aktiv', notiz || null, req.params.id, req.user.tenant_id] ); - if (r.affectedRows === 0) return res.status(404).json({ error: 'Geraet nicht gefunden' }); + if (r.affectedRows === 0) return res.status(404).json({ error: 'Gerät nicht gefunden' }); const [rows] = await pool.query('SELECT * FROM geraete WHERE id=? AND tenant_id=?', [req.params.id, req.user.tenant_id]); res.json(rows[0]); @@ -102,8 +102,8 @@ router.delete('/:id', async (req, res) => { try { const [r] = await pool.query('DELETE FROM geraete WHERE id=? AND tenant_id=?', [req.params.id, req.user.tenant_id]); - if (r.affectedRows === 0) return res.status(404).json({ error: 'Geraet nicht gefunden' }); - res.json({ message: 'Geraet geloescht' }); + if (r.affectedRows === 0) return res.status(404).json({ error: 'Gerät nicht gefunden' }); + res.json({ message: 'Gerät gelöscht' }); } catch (e) { res.status(500).json({ error: 'Serverfehler' }); } }); diff --git a/backend/routes/kunden-bilder.js b/backend/routes/kunden-bilder.js index ad55a76..065e9e9 100644 --- a/backend/routes/kunden-bilder.js +++ b/backend/routes/kunden-bilder.js @@ -51,7 +51,7 @@ router.patch('/bild/:id', async (req, res) => { const values = []; if (req.body.beschreibung !== undefined) { updates.push('beschreibung = ?'); values.push(req.body.beschreibung); } if (req.body.sortierung !== undefined) { updates.push('sortierung = ?'); values.push(parseInt(req.body.sortierung)); } - if (updates.length === 0) return res.status(400).json({ error: 'Keine Aenderungen' }); + if (updates.length === 0) return res.status(400).json({ error: 'Keine Änderungen' }); values.push(req.params.id, req.user.tenant_id); try { const [r] = await pool.query( @@ -73,11 +73,11 @@ router.delete('/bild/:id', async (req, res) => { if (rows.length === 0) return res.status(404).json({ error: 'Bild nicht gefunden' }); await pool.query('DELETE FROM kunden_bilder WHERE id = ? AND tenant_id = ?', [req.params.id, req.user.tenant_id]); - // Datei loeschen (best effort) + // Datei löschen (best effort) const filename = rows[0].dateiname.replace(/^\/uploads\//, ''); const fullPath = path.join(process.env.UPLOAD_DIR || '/app/uploads', filename); try { fs.unlinkSync(fullPath); } catch {} - res.json({ message: 'Bild geloescht' }); + res.json({ message: 'Bild gelöscht' }); } catch (e) { res.status(500).json({ error: 'Serverfehler' }); } }); diff --git a/backend/routes/kunden.js b/backend/routes/kunden.js index 8a179c8..233b61b 100644 --- a/backend/routes/kunden.js +++ b/backend/routes/kunden.js @@ -93,7 +93,7 @@ router.delete('/:id', async (req, res) => { const [r] = await pool.query('DELETE FROM kunden WHERE id=? AND tenant_id=?', [req.params.id, req.user.tenant_id]); if (r.affectedRows === 0) return res.status(404).json({ error: 'Kunde nicht gefunden' }); - res.json({ message: 'Kunde geloescht' }); + res.json({ message: 'Kunde gelöscht' }); } catch (e) { res.status(500).json({ error: 'Serverfehler' }); } }); diff --git a/backend/routes/lieferungen.js b/backend/routes/lieferungen.js index 1ed27f7..e8bebdb 100644 --- a/backend/routes/lieferungen.js +++ b/backend/routes/lieferungen.js @@ -70,7 +70,7 @@ router.delete('/:id', async (req, res) => { const [r] = await pool.query('DELETE FROM lieferungen WHERE id=? AND tenant_id=?', [req.params.id, req.user.tenant_id]); if (r.affectedRows === 0) return res.status(404).json({ error: 'Lieferung nicht gefunden' }); - res.json({ message: 'Lieferung geloescht' }); + res.json({ message: 'Lieferung gelöscht' }); } catch (e) { res.status(500).json({ error: 'Serverfehler' }); } }); diff --git a/backend/routes/mitarbeiter.js b/backend/routes/mitarbeiter.js index b08808a..7110c6c 100644 --- a/backend/routes/mitarbeiter.js +++ b/backend/routes/mitarbeiter.js @@ -27,7 +27,7 @@ router.post('/', requireRole(['admin']), [ const errors = validationResult(req); if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() }); try { - // Pruefe Limit + // Prüfe Limit const [[t]] = await pool.query('SELECT max_users FROM tenants WHERE id = ?', [req.user.tenant_id]); const [[c]] = await pool.query('SELECT COUNT(*) AS n FROM mitarbeiter WHERE tenant_id = ?', [req.user.tenant_id]); @@ -64,7 +64,7 @@ router.put('/:id', [ return res.status(403).json({ error: 'Keine Berechtigung' }); } if ((req.body.rolle || req.body.aktiv !== undefined) && req.user.rolle !== 'admin') { - return res.status(403).json({ error: 'Nur Admin darf Rolle/Aktiv aendern' }); + return res.status(403).json({ error: 'Nur Admin darf Rolle/Aktiv ändern' }); } const updates = []; @@ -72,7 +72,7 @@ router.put('/:id', [ if (req.body.name) { updates.push('name = ?'); values.push(req.body.name); } if (req.body.rolle) { updates.push('rolle = ?'); values.push(req.body.rolle); } if (req.body.aktiv !== undefined) { updates.push('aktiv = ?'); values.push(req.body.aktiv ? 1 : 0); } - if (updates.length === 0) return res.status(400).json({ error: 'Keine Aenderungen' }); + if (updates.length === 0) return res.status(400).json({ error: 'Keine Änderungen' }); values.push(req.params.id, req.user.tenant_id); try { @@ -90,12 +90,12 @@ router.put('/:id', [ }); router.delete('/:id', requireRole(['admin']), async (req, res) => { - if (req.params.id === req.user.id) return res.status(400).json({ error: 'Sie koennen sich nicht selbst loeschen' }); + if (req.params.id === req.user.id) return res.status(400).json({ error: 'Sie koennen sich nicht selbst löschen' }); try { const [r] = await pool.query('DELETE FROM mitarbeiter WHERE id=? AND tenant_id=?', [req.params.id, req.user.tenant_id]); if (r.affectedRows === 0) return res.status(404).json({ error: 'Mitarbeiter nicht gefunden' }); - res.json({ message: 'Mitarbeiter geloescht' }); + res.json({ message: 'Mitarbeiter gelöscht' }); } catch (e) { res.status(500).json({ error: 'Serverfehler' }); } }); diff --git a/backend/routes/ruecknahmen.js b/backend/routes/ruecknahmen.js index d4b2bab..d5775d0 100644 --- a/backend/routes/ruecknahmen.js +++ b/backend/routes/ruecknahmen.js @@ -59,7 +59,7 @@ router.post('/', upload.single('foto'), [ const [rows] = await pool.query(`${baseSelect} WHERE r.id = ?`, [result.insertId]); res.status(201).json(rows[0]); } catch (e) { - console.error('POST ruecknahmen:', e); + console.error('POST rücknahmen:', e); res.status(500).json({ error: 'Serverfehler' }); } }); @@ -68,8 +68,8 @@ router.delete('/:id', async (req, res) => { try { const [r] = await pool.query('DELETE FROM ruecknahmen WHERE id=? AND tenant_id=?', [req.params.id, req.user.tenant_id]); - if (r.affectedRows === 0) return res.status(404).json({ error: 'Ruecknahme nicht gefunden' }); - res.json({ message: 'Ruecknahme geloescht' }); + if (r.affectedRows === 0) return res.status(404).json({ error: 'Rücknahme nicht gefunden' }); + res.json({ message: 'Rücknahme gelöscht' }); } catch (e) { res.status(500).json({ error: 'Serverfehler' }); } }); diff --git a/backend/routes/tenants.js b/backend/routes/tenants.js index ef1e32f..763be8c 100644 --- a/backend/routes/tenants.js +++ b/backend/routes/tenants.js @@ -89,7 +89,7 @@ router.post('/', [ res.status(201).json({ tenant_id: tenantId, slug, admin_email: kontakt_email, - // Passwort wird ausnahmsweise im Response zurueckgegeben, damit der SuperAdmin + // Passwort wird ausnahmsweise im Response zurückgegeben, damit der SuperAdmin // es ggf. manuell weitergeben kann, falls die Mail nicht ankommt. admin_password_oneshot: plainPw, demo_expires_in_days: days @@ -103,7 +103,7 @@ router.post('/', [ } }); -// PATCH /api/tenants/:id -> Demo verlaengern, Status aendern, Limits aendern +// PATCH /api/tenants/:id -> Demo verlaengern, Status ändern, Limits ändern router.patch('/:id', async (req, res) => { const updates = []; const values = []; @@ -115,7 +115,7 @@ router.patch('/:id', async (req, res) => { if (req.body.status) { updates.push('status = ?'); values.push(req.body.status); } if (req.body.max_users) { updates.push('max_users = ?'); values.push(parseInt(req.body.max_users)); } if (req.body.typ) { updates.push('typ = ?'); values.push(req.body.typ); } - if (updates.length === 0) return res.status(400).json({ error: 'Keine Aenderungen' }); + if (updates.length === 0) return res.status(400).json({ error: 'Keine Änderungen' }); values.push(req.params.id); try { await pool.query(`UPDATE tenants SET ${updates.join(', ')} WHERE id = ?`, values); @@ -127,11 +127,11 @@ router.patch('/:id', async (req, res) => { } }); -// DELETE /api/tenants/:id -> Tenant inkl. aller Daten loeschen (CASCADE) +// DELETE /api/tenants/:id -> Tenant inkl. aller Daten löschen (CASCADE) router.delete('/:id', async (req, res) => { try { await pool.query('DELETE FROM tenants WHERE id = ?', [req.params.id]); - res.json({ message: 'Tenant geloescht' }); + res.json({ message: 'Tenant gelöscht' }); } catch (e) { res.status(500).json({ error: 'Serverfehler' }); } diff --git a/backend/server.js b/backend/server.js index 2e7a050..876ae13 100644 --- a/backend/server.js +++ b/backend/server.js @@ -44,7 +44,7 @@ app.use('/api/geraete', geraeteRoutes); app.use((err, req, res, next) => { console.error('Fehler:', err); if (err.name === 'MulterError') { - if (err.code === 'LIMIT_FILE_SIZE') return res.status(400).json({ error: 'Datei zu gross (max. 10MB)' }); + if (err.code === 'LIMIT_FILE_SIZE') return res.status(400).json({ error: 'Datei zu groß (max. 10MB)' }); return res.status(400).json({ error: err.message }); } res.status(err.status || 500).json({ error: err.message || 'Interner Serverfehler' }); diff --git a/nginx.conf b/nginx.conf index 8dbb5e1..9a9382d 100644 --- a/nginx.conf +++ b/nginx.conf @@ -7,7 +7,6 @@ http { sendfile on; keepalive_timeout 65; - # gzip gzip on; gzip_vary on; gzip_min_length 1024; @@ -19,8 +18,8 @@ http { root /usr/share/nginx/html; index index.html; - # API → Backend - location /api/ { + # API -> Backend (^~ damit Regex-Locations darunter nicht greifen) + location ^~ /api/ { proxy_pass http://backend:3001/api/; proxy_http_version 1.1; proxy_set_header Host $host; @@ -29,23 +28,24 @@ http { proxy_set_header X-Forwarded-Proto $scheme; } - # Uploads → Backend - location /uploads/ { + # Uploads -> Backend (^~ wichtig, sonst greift die .jpg-Regex-Location unten) + location ^~ /uploads/ { proxy_pass http://backend:3001/uploads/; proxy_http_version 1.1; proxy_set_header Host $host; + add_header Cache-Control "public, max-age=86400"; + } + + # Cache fuer statische Assets im SPA + location ~* \.(?:js|css|woff2?|ttf|eot|jpg|jpeg|png|gif|svg|ico|webp)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + try_files $uri =404; } # SPA fallback location / { try_files $uri $uri/ /index.html; } - - # Cache statische Assets - location ~* \.(?:js|css|woff2?|ttf|eot|jpg|jpeg|png|gif|svg|ico|webp)$ { - expires 1y; - add_header Cache-Control "public, immutable"; - try_files $uri =404; - } } } diff --git a/src/._App.jsx b/src/._App.jsx deleted file mode 100644 index 988359c..0000000 Binary files a/src/._App.jsx and /dev/null differ diff --git a/src/._api b/src/._api deleted file mode 100755 index 988359c..0000000 Binary files a/src/._api and /dev/null differ diff --git a/src/._components b/src/._components deleted file mode 100755 index 988359c..0000000 Binary files a/src/._components and /dev/null differ diff --git a/src/._index.css b/src/._index.css deleted file mode 100644 index 988359c..0000000 Binary files a/src/._index.css and /dev/null differ diff --git a/src/._main.jsx b/src/._main.jsx deleted file mode 100644 index 988359c..0000000 Binary files a/src/._main.jsx and /dev/null differ diff --git a/src/api/._client.js b/src/api/._client.js deleted file mode 100644 index 988359c..0000000 Binary files a/src/api/._client.js and /dev/null differ diff --git a/src/api/client.js b/src/api/client.js index 6bb4846..a460fe2 100644 --- a/src/api/client.js +++ b/src/api/client.js @@ -17,7 +17,7 @@ class ApiClient { const res = await fetch(`${API_BASE_URL}${endpoint}`, { ...options, headers }); const text = await res.text(); let data = null; - try { data = text ? JSON.parse(text) : null; } catch { throw new Error('Ungueltige Server-Antwort'); } + try { data = text ? JSON.parse(text) : null; } catch { throw new Error('Ungültige Server-Antwort'); } if (!res.ok) throw new Error(data?.error || `HTTP ${res.status}`); return data; } @@ -89,7 +89,7 @@ class ApiClient { } deleteLieferung(id) { return this.request(`/lieferungen/${id}`, { method: 'DELETE' }); } - // Ruecknahmen + // Rücknahmen getRuecknahmen() { return this.request('/ruecknahmen'); } async createRuecknahme(r, foto) { const fd = new FormData(); @@ -113,7 +113,7 @@ class ApiClient { updateMitarbeiter(id, m) { return this.request(`/mitarbeiter/${id}`, { method: 'PUT', body: JSON.stringify(m) }); } deleteMitarbeiter(id) { return this.request(`/mitarbeiter/${id}`, { method: 'DELETE' }); } - // Geraete + // Geräte getGeraete() { return this.request('/geraete'); } createGeraet(g) { return this.request('/geraete', { method: 'POST', body: JSON.stringify(g) }); } updateGeraet(id, g) { return this.request(`/geraete/${id}`, { method: 'PUT', body: JSON.stringify(g) }); } diff --git a/src/components/._Auth b/src/components/._Auth deleted file mode 100755 index 988359c..0000000 Binary files a/src/components/._Auth and /dev/null differ diff --git a/src/components/._Dashboard b/src/components/._Dashboard deleted file mode 100755 index 988359c..0000000 Binary files a/src/components/._Dashboard and /dev/null differ diff --git a/src/components/._Eingabe b/src/components/._Eingabe deleted file mode 100755 index 988359c..0000000 Binary files a/src/components/._Eingabe and /dev/null differ diff --git a/src/components/._Geraete.jsx b/src/components/._Geraete.jsx deleted file mode 100644 index 988359c..0000000 Binary files a/src/components/._Geraete.jsx and /dev/null differ diff --git a/src/components/._KundenVerwaltung.jsx b/src/components/._KundenVerwaltung.jsx deleted file mode 100644 index 988359c..0000000 Binary files a/src/components/._KundenVerwaltung.jsx and /dev/null differ diff --git a/src/components/._MitarbeiterVerwaltung.jsx b/src/components/._MitarbeiterVerwaltung.jsx deleted file mode 100644 index 988359c..0000000 Binary files a/src/components/._MitarbeiterVerwaltung.jsx and /dev/null differ diff --git a/src/components/._SuperAdmin.jsx b/src/components/._SuperAdmin.jsx deleted file mode 100644 index 988359c..0000000 Binary files a/src/components/._SuperAdmin.jsx and /dev/null differ diff --git a/src/components/._TourPlanung.jsx b/src/components/._TourPlanung.jsx deleted file mode 100644 index 988359c..0000000 Binary files a/src/components/._TourPlanung.jsx and /dev/null differ diff --git a/src/components/Auth/._Login.jsx b/src/components/Auth/._Login.jsx deleted file mode 100644 index 988359c..0000000 Binary files a/src/components/Auth/._Login.jsx and /dev/null differ diff --git a/src/components/Auth/._PasswordChange.jsx b/src/components/Auth/._PasswordChange.jsx deleted file mode 100644 index 988359c..0000000 Binary files a/src/components/Auth/._PasswordChange.jsx and /dev/null differ diff --git a/src/components/Auth/PasswordChange.jsx b/src/components/Auth/PasswordChange.jsx index 1ee4823..9db8efe 100644 --- a/src/components/Auth/PasswordChange.jsx +++ b/src/components/Auth/PasswordChange.jsx @@ -11,18 +11,18 @@ export default function PasswordChange() { const submit = async (e) => { e.preventDefault(); if (form.newPassword.length < 6) return setErr('Neues Passwort min. 6 Zeichen'); - if (form.newPassword !== form.confirm) return setErr('Passwoerter stimmen nicht ueberein'); + if (form.newPassword !== form.confirm) return setErr('Passwoerter stimmen nicht überein'); setBusy(true); try { await api.changePassword(form.currentPassword, form.newPassword); - setOk('Passwort geaendert'); + setOk('Passwort geändert'); setForm({ currentPassword: '', newPassword: '', confirm: '' }); } catch (e) { setErr(e.message); } finally { setBusy(false); } }; return ( ); } diff --git a/src/components/Dashboard/._Account.jsx b/src/components/Dashboard/._Account.jsx deleted file mode 100644 index 988359c..0000000 Binary files a/src/components/Dashboard/._Account.jsx and /dev/null differ diff --git a/src/components/Dashboard/._AdminDashboard.jsx b/src/components/Dashboard/._AdminDashboard.jsx deleted file mode 100644 index 988359c..0000000 Binary files a/src/components/Dashboard/._AdminDashboard.jsx and /dev/null differ diff --git a/src/components/Dashboard/._BildModal.jsx b/src/components/Dashboard/._BildModal.jsx deleted file mode 100644 index 988359c..0000000 Binary files a/src/components/Dashboard/._BildModal.jsx and /dev/null differ diff --git a/src/components/Dashboard/._Dashboard.jsx b/src/components/Dashboard/._Dashboard.jsx deleted file mode 100644 index 988359c..0000000 Binary files a/src/components/Dashboard/._Dashboard.jsx and /dev/null differ diff --git a/src/components/Dashboard/._TopNav.jsx b/src/components/Dashboard/._TopNav.jsx deleted file mode 100644 index 988359c..0000000 Binary files a/src/components/Dashboard/._TopNav.jsx and /dev/null differ diff --git a/src/components/Dashboard/._VorgangsListe.jsx b/src/components/Dashboard/._VorgangsListe.jsx deleted file mode 100644 index 988359c..0000000 Binary files a/src/components/Dashboard/._VorgangsListe.jsx and /dev/null differ diff --git a/src/components/Dashboard/AdminDashboard.jsx b/src/components/Dashboard/AdminDashboard.jsx index 38a978f..00f1595 100644 --- a/src/components/Dashboard/AdminDashboard.jsx +++ b/src/components/Dashboard/AdminDashboard.jsx @@ -18,7 +18,7 @@ function downloadCSV(rows, filename) { } export default function AdminDashboard() { - const [data, setData] = useState({ kunden: [], artikel: [], mitarbeiter: [], lieferungen: [], ruecknahmen: [] }); + const [data, setData] = useState({ kunden: [], artikel: [], mitarbeiter: [], lieferungen: [], rücknahmen: [] }); const [loading, setLoading] = useState(true); const [selectedKunde, setSelectedKunde] = useState(''); const [selectedMitarbeiter, setSelectedMitarbeiter] = useState(''); @@ -27,7 +27,7 @@ export default function AdminDashboard() { useEffect(() => { Promise.all([api.getKunden(), api.getArtikel(), api.getMitarbeiter(), api.getLieferungen(), api.getRuecknahmen()]) - .then(([k, a, m, l, r]) => setData({ kunden: k, artikel: a, mitarbeiter: m, lieferungen: l, ruecknahmen: r })) + .then(([k, a, m, l, r]) => setData({ kunden: k, artikel: a, mitarbeiter: m, lieferungen: l, rücknahmen: r })) .finally(() => setLoading(false)); }, []); @@ -41,7 +41,7 @@ export default function AdminDashboard() { }; const l = data.lieferungen.filter(x => x.kunde_id === selectedKunde && inRange(x) && (!selectedMitarbeiter || x.mitarbeiter_id === selectedMitarbeiter)); - const r = data.ruecknahmen.filter(x => x.kunde_id === selectedKunde && inRange(x) + const r = data.rücknahmen.filter(x => x.kunde_id === selectedKunde && inRange(x) && (!selectedMitarbeiter || x.mitarbeiter_id === selectedMitarbeiter)); const artikelIds = Array.from(new Set([...l.map(x => x.artikel_id), ...r.map(x => x.artikel_id)])); return artikelIds.map(aid => { @@ -70,7 +70,7 @@ export default function AdminDashboard() {
- Dockly-Pfandsystem
+
+ Dockly-Pfandsystem
{user.tenant_typ === 'demo' && (
- Demo
+ Demo
)}