Enhance SEO and feedback features across the application

- Updated index.html with improved meta tags for SEO, including author and theme color.
- Added a feedback dialog in ImprintContainer.vue for user feedback submission.
- Refactored LoginForm.vue to utilize a utility for cookie management, simplifying profile persistence.
- Introduced new routes and schemas for feedback in the router and server, enhancing SEO and user experience.
- Improved ChatView.vue with better error handling and command table display.
- Implemented feedback API endpoints in server routes for managing user feedback submissions and admin access.

These changes collectively improve the application's SEO, user interaction, and feedback management capabilities.
This commit is contained in:
Torsten Schulz (local)
2026-03-19 15:21:54 +01:00
parent 0205352ae9
commit 47373a27af
13 changed files with 1184 additions and 238 deletions

View File

@@ -7,6 +7,8 @@ import crypto from 'crypto';
import axios from 'axios';
import { getSessionStatus, getClientsMap, getSessionIdForSocket, extractSessionId } from './broadcast.js';
import { verifyChatUser } from './chat-auth.js';
import { loadFeedback, saveFeedback, createFeedbackEntry } from './feedback-store.js';
// __dirname für ES-Module
const __filename = fileURLToPath(import.meta.url);
@@ -87,6 +89,102 @@ export function setupRoutes(app, __dirname) {
res.status(500).json({ success: false });
}
});
app.get('/api/feedback', (req, res) => {
try {
const feedback = loadFeedback(__dirname)
.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
res.json({
items: feedback,
admin: !!req.session.feedbackAdmin
});
} catch (error) {
console.error('Fehler beim Laden des Feedbacks:', error);
res.status(500).json({ error: 'Fehler beim Laden des Feedbacks' });
}
});
app.get('/api/feedback/admin-status', (req, res) => {
res.json({
authenticated: !!req.session.feedbackAdmin,
username: req.session.feedbackAdmin?.username || null
});
});
app.post('/api/feedback', (req, res) => {
try {
const ageValue = req.body.age === '' || req.body.age === null || req.body.age === undefined
? null
: Number.parseInt(req.body.age, 10);
const entry = createFeedbackEntry({
name: req.body.name,
age: Number.isNaN(ageValue) ? null : ageValue,
country: req.body.country,
gender: req.body.gender,
comment: req.body.comment
});
if (!entry.comment) {
return res.status(400).json({ error: 'Kommentar ist erforderlich.' });
}
const feedback = loadFeedback(__dirname);
feedback.push(entry);
saveFeedback(__dirname, feedback);
res.status(201).json({ success: true, item: entry });
} catch (error) {
console.error('Fehler beim Speichern des Feedbacks:', error);
res.status(500).json({ error: 'Fehler beim Speichern des Feedbacks' });
}
});
app.post('/api/feedback/admin-login', (req, res) => {
try {
const { username, password } = req.body || {};
const auth = verifyChatUser(__dirname, username, password);
if (!auth) {
return res.status(401).json({ error: 'Login fehlgeschlagen.' });
}
req.session.feedbackAdmin = {
username: auth.username
};
res.json({ success: true, username: auth.username });
} catch (error) {
console.error('Fehler beim Feedback-Admin-Login:', error);
res.status(500).json({ error: 'Fehler beim Login' });
}
});
app.post('/api/feedback/admin-logout', (req, res) => {
delete req.session.feedbackAdmin;
res.json({ success: true });
});
app.delete('/api/feedback/:id', (req, res) => {
try {
if (!req.session.feedbackAdmin) {
return res.status(403).json({ error: 'Nicht erlaubt.' });
}
const feedback = loadFeedback(__dirname);
const nextFeedback = feedback.filter((item) => item.id !== req.params.id);
if (nextFeedback.length === feedback.length) {
return res.status(404).json({ error: 'Eintrag nicht gefunden.' });
}
saveFeedback(__dirname, nextFeedback);
res.json({ success: true });
} catch (error) {
console.error('Fehler beim Löschen des Feedbacks:', error);
res.status(500).json({ error: 'Fehler beim Löschen des Feedbacks' });
}
});
// Bild-Upload-Endpoint
app.post('/api/upload-image', upload.single('image'), (req, res) => {