feat: frontend pages — recordings, protocols, templates, settings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-05 16:24:17 +05:00
parent 106c82bdf4
commit ffab9cbc8e
7 changed files with 433 additions and 0 deletions
+89
View File
@@ -0,0 +1,89 @@
import { useState } from 'react'
import { useTemplates } from '../hooks/useTemplates'
export default function TemplatesPage() {
const { templates, isLoading, createTemplate, deleteTemplate } = useTemplates()
const [showForm, setShowForm] = useState(false)
const [form, setForm] = useState({ name: '', description: '', system_prompt: '', user_prompt: '', type: 'custom' as const })
const handleCreate = async () => {
await createTemplate(form)
setShowForm(false)
setForm({ name: '', description: '', system_prompt: '', user_prompt: '', type: 'custom' })
}
return (
<div>
<div className="flex items-center justify-between mb-6">
<h1 className="text-2xl font-bold">Шаблоны протоколов</h1>
<button
onClick={() => setShowForm(!showForm)}
className="bg-blue-600 text-white px-4 py-2 rounded text-sm hover:bg-blue-700"
>
+ Новый шаблон
</button>
</div>
{showForm && (
<div className="bg-white p-4 rounded-lg shadow-sm mb-6 space-y-3">
<input
placeholder="Название"
value={form.name}
onChange={(e) => setForm({ ...form, name: e.target.value })}
className="w-full border rounded px-3 py-2 text-sm"
/>
<input
placeholder="Описание"
value={form.description}
onChange={(e) => setForm({ ...form, description: e.target.value })}
className="w-full border rounded px-3 py-2 text-sm"
/>
<textarea
placeholder="System prompt"
value={form.system_prompt}
onChange={(e) => setForm({ ...form, system_prompt: e.target.value })}
className="w-full border rounded px-3 py-2 text-sm h-24"
/>
<textarea
placeholder="User prompt (используйте {transcription} для вставки текста)"
value={form.user_prompt}
onChange={(e) => setForm({ ...form, user_prompt: e.target.value })}
className="w-full border rounded px-3 py-2 text-sm h-24"
/>
<button onClick={handleCreate} className="bg-green-600 text-white px-4 py-2 rounded text-sm">
Создать
</button>
</div>
)}
{isLoading ? (
<p>Загрузка...</p>
) : (
<div className="space-y-4">
{templates.map((tpl) => (
<div key={tpl.id} className="bg-white p-4 rounded-lg shadow-sm">
<div className="flex items-center justify-between mb-2">
<div>
<h3 className="font-semibold">{tpl.name}</h3>
<p className="text-sm text-gray-500">{tpl.description}</p>
</div>
<div className="flex items-center gap-2">
<span className="text-xs bg-gray-100 px-2 py-1 rounded">{tpl.type}</span>
{tpl.is_default && <span className="text-xs bg-blue-100 text-blue-700 px-2 py-1 rounded">По умолчанию</span>}
{tpl.type === 'custom' && (
<button
onClick={() => deleteTemplate(tpl.id)}
className="text-red-500 text-xs hover:text-red-700"
>
Удалить
</button>
)}
</div>
</div>
</div>
))}
</div>
)}
</div>
)
}