/* App shell — routing, persistence, Tweaks */
const { useState: useStateApp, useEffect: useEffectApp, useCallback: useCallbackApp } = React;
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
"specialty": "Kinderchirurgie",
"defaultFormat": "auto"
}/*EDITMODE-END*/;
function Toast({ msg }) {
return
{msg}
;
}
function Topbar({ page, onHome, onList, specialty }) {
return (
Diktat
{specialty}
);
}
function App() {
// Simple route state: "home" | "rec" | "list" | "detail"
const [page, setPage] = useStateApp("home");
const [currentId, setCurrentId] = useStateApp(null);
const [recordings, setRecordings] = useStateApp(() => Store.load());
const [toast, setToast] = useStateApp("");
// Tweaks
const tweaks = window.useTweaks ? window.useTweaks(TWEAK_DEFAULTS) : [TWEAK_DEFAULTS, () => {}];
const [tweakState, setTweakState] = tweaks;
const refresh = useCallbackApp(() => setRecordings(Store.load()), []);
const showToast = useCallbackApp((msg) => {
setToast(msg);
setTimeout(() => setToast(""), 2000);
}, []);
// Kicks the user back to the home screen so the inline recorder is visible.
const handleStartRecording = () => setPage("home");
const handleDoneRecording = async ({ transcript, duration }) => {
// Create recording skeleton
const id = uid();
const rec = {
id,
createdAt: Date.now(),
updatedAt: Date.now(),
duration,
transcript,
letter: "",
title: "Neue Aufnahme",
format: null,
status: "processing",
needsFormat: false,
};
Store.add(rec);
refresh();
setCurrentId(id);
setPage("detail");
// Detect format (unless user forced a specific one)
let fmt = tweakState.defaultFormat && tweakState.defaultFormat !== "auto" ? tweakState.defaultFormat : null;
if (!fmt) {
const detected = await detectFormat(transcript);
if (detected === "unsure") {
Store.update(id, { needsFormat: true, status: "ready" });
refresh();
// Also generate title in background
generateTitle(transcript).then(title => { Store.update(id, { title }); refresh(); });
return;
}
fmt = detected;
}
// Generate letter + title in parallel
try {
const [letter, title] = await Promise.all([
generateLetter(transcript, fmt, tweakState.specialty || "Kinderchirurgie"),
generateTitle(transcript),
]);
Store.update(id, { letter, title, format: fmt, status: "ready" });
refresh();
} catch (e) {
Store.update(id, {
letter: "Fehler bei der Briefgenerierung. Bitte im Ansicht-Modus Format wählen, um es erneut zu versuchen.",
format: fmt,
status: "ready",
needsFormat: true,
});
refresh();
}
};
const handleOpen = (id) => { setCurrentId(id); setPage("detail"); };
const handleChange = (id, patch) => { Store.update(id, patch); refresh(); };
const handleDelete = (id) => {
Store.remove(id);
refresh();
setPage("list");
showToast("Aufnahme gelöscht");
};
const currentRecording = recordings.find(r => r.id === currentId);
return (
setPage("home")}
onList={() => setPage("list")}
specialty={tweakState.specialty || "Kinderchirurgie"}
/>
{page === "home" && (
setPage("list")}
recordingsCount={recordings.length}
/>
)}
{page === "list" && (
)}
{page === "detail" && currentRecording && (
setPage("list")}
onChange={handleChange}
onDelete={handleDelete}
showToast={showToast}
/>
)}
{page === "detail" && !currentRecording && (
Aufnahme nicht gefunden.
)}
{/* Tweaks */}
{window.TweaksPanel && (
setTweakState({ specialty: v })}
options={[
{ value: "Kinderchirurgie", label: "Kinderchirurgie" },
{ value: "Allgemeinchirurgie", label: "Allgemeinchirurgie" },
{ value: "Pädiatrie", label: "Pädiatrie" },
{ value: "Viszeralchirurgie", label: "Viszeralchirurgie" },
{ value: "Unfallchirurgie", label: "Unfallchirurgie" },
{ value: "Urologie (Kinder)", label: "Kinderurologie" },
]}
/>
setTweakState({ defaultFormat: v })}
options={[
{ value: "auto", label: "Automatisch erkennen" },
{ value: "arztbrief", label: "Arztbrief" },
{ value: "konsult", label: "Konsultationsbericht" },
{ value: "soap", label: "SOAP-Notiz" },
{ value: "opbericht", label: "Operationsbericht" },
]}
/>
)}
);
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render();