feat(procedures): U2 fold Mode B (Geführt wizard) (m/paliad#151)

Mounts mountWizard() into #procedures-panel-wizard when the Geführt tab
activates. Same 5-row wizard, same backend (event search + follow-ups
probe) as the legacy /tools/fristenrechner. On R4 launchResult, the
wizard hands off to mountResultView which renders into the same
overhaul-root inside the panel.

The wizard renders into #fristen-overhaul-mode-host while Mode A and
the result view write into #fristen-overhaul-root. To keep those IDs
unique in the DOM — both modes look up via document.getElementById —
the host scaffold is no longer static on the search panel. The new
installOverhaulHost() helper tears down any existing host and installs
a fresh one inside the active tab's panel before each mount, so two
parallel hosts can't cross-wire when the user toggles between the
Direkt-suchen and Geführt tabs.

The U1/U2 placeholders are dropped from the panel markup since the
panels are populated dynamically now.
This commit is contained in:
mAi
2026-05-27 20:23:23 +02:00
parent 0568d340a7
commit c8261da492
4 changed files with 35 additions and 41 deletions

View File

@@ -219,8 +219,6 @@ const translations: Record<Lang, Record<string, string>> = {
"procedures.tab.wizard": "Gef\u00fchrt",
"procedures.tab.akte": "Aus Akte",
"procedures.panel.proceeding.placeholder": "Verfahrenswahl folgt in U3 \u2014 das \u00dcbersichts-Baumdiagramm wird hier eingebettet.",
"procedures.panel.search.placeholder": "Direktsuche folgt in U1.",
"procedures.panel.wizard.placeholder": "Gef\u00fchrter Einstieg folgt in U2.",
"procedures.panel.akte.placeholder": "Akten-Einstieg folgt in einem sp\u00e4teren Slice.",
"nav.procedures": "Verfahren & Fristen",
@@ -3432,8 +3430,6 @@ const translations: Record<Lang, Record<string, string>> = {
"procedures.tab.wizard": "Guided",
"procedures.tab.akte": "From matter",
"procedures.panel.proceeding.placeholder": "Pick-proceeding view ships in U3 \u2014 the overview tree mounts here.",
"procedures.panel.search.placeholder": "Direct search ships in U1.",
"procedures.panel.wizard.placeholder": "Guided entry ships in U2.",
"procedures.panel.akte.placeholder": "Matter entry ships in a later slice.",
"nav.procedures": "Procedures & Deadlines",

View File

@@ -7,14 +7,23 @@
// its dimension-aware behaviour.
//
// U0 — Skeleton + tab toggling.
// U1 — Direkt suchen mounts Mode A (this slice).
// U2 — Geführt mounts Mode B wizard.
// U1 — Direkt suchen mounts Mode A.
// U2 — Geführt mounts Mode B wizard (this slice).
// U3 — Verfahren wählen mounts Verfahrensablauf tree + 3-way detail filter.
//
// Mode A renders its shell into #fristen-overhaul-root (replacing
// children); Mode B renders into #fristen-overhaul-mode-host; the
// result view (post-commit) writes into #fristen-overhaul-root. To
// keep those IDs unique in the DOM, only the active tab's panel ever
// hosts the overhaul scaffold — installOverhaulHost() tears down any
// existing host and installs a fresh one inside the target panel
// before handing off to the per-mode module.
import { initI18n } from "./i18n";
import { initSidebar } from "./sidebar";
import { mountModeA } from "./fristenrechner-mode-a";
import { mountResultView } from "./fristenrechner-result";
import { mountWizard } from "./fristenrechner-wizard";
type ProceduresTab = "proceeding" | "search" | "wizard" | "akte";
@@ -37,21 +46,25 @@ function writeTabToUrl(tab: ProceduresTab): void {
history.replaceState(null, "", url.pathname + url.search + url.hash);
}
// ensureSearchHost re-seeds the overhaul-root / mode-host scaffold
// inside the Direkt-suchen panel. Idempotent — re-clicking the search
// tab always restores a fresh Mode A surface, even if the user
// previously committed an event into the result view (which had
// replaced the root's innerHTML).
function ensureSearchHost(): void {
const panel = document.getElementById("procedures-panel-search");
if (!panel) return;
// installOverhaulHost moves the (legacy) #fristen-overhaul-root /
// #fristen-overhaul-mode-host scaffold under `panelId`. Always clears
// any existing host first, so the IDs stay unique across the page even
// when the user toggles between Direkt-suchen and Geführt — both Mode
// A and the wizard read these IDs from document.getElementById which
// returns the first match in DOM order, so two parallel hosts would
// cross-wire.
function installOverhaulHost(panelId: string): HTMLElement | null {
document.querySelectorAll("#fristen-overhaul-root").forEach((el) => el.remove());
const panel = document.getElementById(panelId);
if (!panel) return null;
panel.innerHTML = `
<div class="procedures-mode-a-host">
<div class="procedures-overhaul-host">
<div class="fristen-overhaul-root" id="fristen-overhaul-root">
<div id="fristen-overhaul-mode-host"></div>
</div>
</div>
`;
return panel;
}
function setActiveTabUI(tab: ProceduresTab): void {
@@ -70,10 +83,16 @@ function setActiveTabUI(tab: ProceduresTab): void {
async function activateTab(tab: ProceduresTab): Promise<void> {
setActiveTabUI(tab);
if (tab === "search") {
ensureSearchHost();
installOverhaulHost("procedures-panel-search");
await mountModeA();
return;
}
// U2 will mount the wizard here; U3 will mount Verfahrensablauf.
if (tab === "wizard") {
installOverhaulHost("procedures-panel-wizard");
await mountWizard();
return;
}
// U3 will mount Verfahrensablauf into proceeding-panel.
}
function wireTabs(): void {
@@ -97,7 +116,7 @@ async function boot(): Promise<void> {
if (eventRef) {
setActiveTabUI("search");
ensureSearchHost();
installOverhaulHost("procedures-panel-search");
await mountResultView({
eventRef,
triggerDate: params.get("trigger_date") || undefined,

View File

@@ -2213,8 +2213,6 @@ export type I18nKey =
| "procedures.heading"
| "procedures.panel.akte.placeholder"
| "procedures.panel.proceeding.placeholder"
| "procedures.panel.search.placeholder"
| "procedures.panel.wizard.placeholder"
| "procedures.subtitle"
| "procedures.tab.akte"
| "procedures.tab.proceeding"

View File

@@ -147,29 +147,10 @@ export function renderProcedures(): string {
</section>
<section className="procedures-panel" id="procedures-panel-search" role="tabpanel"
aria-labelledby="procedures-tab-search" hidden>
{/* Mode A host. procedures.ts (re-)seeds the inner
overhaul-root / mode-host structure each time the
Direkt-suchen tab activates, then defers to
mountModeA() / mountResultView() — the legacy
Fristenrechner overhaul code runs unchanged inside
this wrapper. U3 will replace the in-panel commit
behaviour with a pivot into the shared linear-output
region; for U1 the result view simply re-renders
into the same root. */}
<div className="procedures-mode-a-host">
<div className="fristen-overhaul-root" id="fristen-overhaul-root">
<div id="fristen-overhaul-mode-host"></div>
</div>
</div>
</section>
aria-labelledby="procedures-tab-search" hidden></section>
<section className="procedures-panel" id="procedures-panel-wizard" role="tabpanel"
aria-labelledby="procedures-tab-wizard" hidden>
<div className="procedures-panel-placeholder" data-i18n="procedures.panel.wizard.placeholder">
Gef&uuml;hrter Einstieg folgt in U2.
</div>
</section>
aria-labelledby="procedures-tab-wizard" hidden></section>
<section className="procedures-panel" id="procedures-panel-akte" role="tabpanel"
aria-labelledby="procedures-tab-akte" hidden>