diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 7e0d145..f1374a1 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -30,6 +30,7 @@ import AdminUserRestrictionsPage from './pages/AdminUserRestrictionsPage' import AdminTrainingTypesPage from './pages/AdminTrainingTypesPage' import AdminActivityMappingsPage from './pages/AdminActivityMappingsPage' import AdminTrainingProfiles from './pages/AdminTrainingProfiles' +import AdminPromptsPage from './pages/AdminPromptsPage' import SubscriptionPage from './pages/SubscriptionPage' import SleepPage from './pages/SleepPage' import RestDaysPage from './pages/RestDaysPage' @@ -184,6 +185,7 @@ function AppShell() { }/> }/> }/> + }/> }/> diff --git a/frontend/src/components/PromptEditModal.jsx b/frontend/src/components/PromptEditModal.jsx new file mode 100644 index 0000000..75e50a5 --- /dev/null +++ b/frontend/src/components/PromptEditModal.jsx @@ -0,0 +1,379 @@ +import { useState, useEffect } from 'react' +import { api } from '../utils/api' +import PromptGenerator from './PromptGenerator' + +export default function PromptEditModal({ prompt, onSave, onClose }) { + const [name, setName] = useState('') + const [slug, setSlug] = useState('') + const [description, setDescription] = useState('') + const [category, setCategory] = useState('ganzheitlich') + const [template, setTemplate] = useState('') + const [active, setActive] = useState(true) + + const [preview, setPreview] = useState(null) + const [unknownPlaceholders, setUnknownPlaceholders] = useState([]) + const [showGenerator, setShowGenerator] = useState(false) + const [optimization, setOptimization] = useState(null) + const [loading, setLoading] = useState(false) + const [saving, setSaving] = useState(false) + + const categories = [ + { id: 'körper', label: 'Körper' }, + { id: 'ernährung', label: 'Ernährung' }, + { id: 'training', label: 'Training' }, + { id: 'schlaf', label: 'Schlaf' }, + { id: 'vitalwerte', label: 'Vitalwerte' }, + { id: 'ziele', label: 'Ziele' }, + { id: 'ganzheitlich', label: 'Ganzheitlich' } + ] + + useEffect(() => { + if (prompt) { + setName(prompt.name || '') + setSlug(prompt.slug || '') + setDescription(prompt.description || '') + setCategory(prompt.category || 'ganzheitlich') + setTemplate(prompt.template || '') + setActive(prompt.active ?? true) + } + }, [prompt]) + + const handlePreview = async () => { + try { + setLoading(true) + const result = await api.previewPrompt(template) + setPreview(result.resolved) + setUnknownPlaceholders(result.unknown_placeholders || []) + } catch (e) { + alert('Fehler bei Vorschau: ' + e.message) + } finally { + setLoading(false) + } + } + + const handleOptimize = async () => { + if (!prompt?.id) { + alert('Prompt muss erst gespeichert werden bevor er optimiert werden kann') + return + } + + try { + setLoading(true) + const result = await api.optimizePrompt(prompt.id) + setOptimization(result) + } catch (e) { + alert('Fehler bei Optimierung: ' + e.message) + } finally { + setLoading(false) + } + } + + const handleApplyOptimized = () => { + if (optimization?.optimized_prompt) { + setTemplate(optimization.optimized_prompt) + setOptimization(null) + } + } + + const handleSave = async () => { + if (!name.trim()) { + alert('Bitte Titel eingeben') + return + } + if (!template.trim()) { + alert('Bitte Template eingeben') + return + } + + try { + setSaving(true) + + if (prompt?.id) { + // Update existing + await api.updatePrompt(prompt.id, { + name, + description, + category, + template, + active + }) + } else { + // Create new + if (!slug.trim()) { + alert('Bitte Slug eingeben') + return + } + await api.createPrompt({ + name, + slug, + description, + category, + template, + active + }) + } + + onSave() + } catch (e) { + alert('Fehler beim Speichern: ' + e.message) + } finally { + setSaving(false) + } + } + + const handleGeneratorResult = (generated) => { + setName(generated.suggested_title) + setCategory(generated.suggested_category) + setTemplate(generated.template) + setShowGenerator(false) + + // Auto-generate slug if new prompt + if (!prompt?.id) { + const autoSlug = generated.suggested_title + .toLowerCase() + .replace(/[^a-z0-9]+/g, '_') + .replace(/^_+|_+$/g, '') + setSlug(autoSlug) + } + } + + return ( +
+
+

+ {prompt ? 'Prompt bearbeiten' : 'Neuer Prompt'} +

+ + {/* Action Buttons */} +
+ + {prompt?.id && ( + + )} + +
+ + {/* Form Fields */} +
+
+ + setName(e.target.value)} + placeholder="z.B. Protein-Analyse" + /> +
+ + {!prompt?.id && ( +
+ + setSlug(e.target.value)} + placeholder="z.B. protein_analyse" + /> +
+ )} + +
+ +