import { useEffect, useId, useState } from 'react' import { useAuth } from '../context/AuthContext.jsx' import { api } from '../api.js' const KIND_LABELS = { journal_entry: 'Finale Fassung (Stimme)', imported_text: 'Import', dialogue_style: 'Dialogstil (schwächer)' } const GOVERNANCE_LABELS = { learning: 'Lernen — geeignete Quellen dürfen das Profil weiterentwickeln', advising: 'Vorschlagen — Änderungen erst nach deiner Bestätigung', frozen: 'Eingefroren — neue Beobachtungen ändern nichts, du kannst weiter manuell editieren' } function kindLabel(kind) { return KIND_LABELS[kind] || kind } function downloadJson(filename, data) { const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }) const url = URL.createObjectURL(blob) const link = document.createElement('a') link.href = url link.download = filename document.body.appendChild(link) link.click() link.remove() URL.revokeObjectURL(url) } function DocumentTransfer({ token, exportPath, restorePath, filename, confirmText, onRestored, onError }) { const inputId = useId() const exportDoc = async () => { onError('') try { downloadJson(filename, await api(exportPath, { token })) } catch (err) { onError(err.message) } } const restoreFile = async (event) => { const file = event.target.files?.[0] event.target.value = '' if (!file) return onError('') if (!window.confirm(confirmText)) return try { const document = JSON.parse(await file.text()) onRestored(await api(restorePath, { token, method: 'POST', body: document })) } catch (err) { onError(err.message || 'JSON konnte nicht gelesen werden.') } } return (
) } const CONTEXT_HINTS = [ { value: 'vacation_diary', label: 'Urlaubstagebuch → autobiografisches Journal' }, { value: 'autobiographical_journal', label: 'Autobiografisches Journal' }, { value: 'reflective', label: 'Reflektierender Text' } ] const LIFECYCLE_LABELS = { uninitialized: 'Noch kein bestätigtes Profil. Quellen sammeln, dann Initial Profile Build.', initial_pending: 'Initiales Profilpaket ist offen. Nach der Prüfung wird das Profil bestätigt.', confirmed: 'Profilhülle bestätigt. Neue Texte gehen in die Review-Queue, nicht in ein Blind-Reinfer.' } function FacetRow({ item, onSave }) { const [value, setValue] = useState(item.value || '') const [locked, setLocked] = useState(Boolean(item.locked)) useEffect(() => { setValue(item.value || '') setLocked(Boolean(item.locked)) }, [item.id, item.value, item.locked]) const dirty = value !== (item.value || '') || locked !== Boolean(item.locked) return (
  • {item.label || item.facet_key} {item.layer || 'context'} · {item.origin}{item.locked ? ' · geschützt' : ''}
    {item.evidence &&

    {item.evidence}

    }