Reorder Verfahrensablauf 'Browse a proceeding' so the user-input flow matches the importance hierarchy: proceeding-type → side → appellant → date / court / flags. Side was previously below the date input; it is the most-defining input after proceeding-type, so it belongs above. - frontend/src/verfahrensablauf.tsx: move .verfahrensablauf-perspective block above .date-input-group inside step-2. Wrap the side radio cluster in #side-radio-cluster and add a sibling #side-chip (hidden by default) that the client swaps in when a project pre-fills the side. Add a 1px divider between perspective and date-input groups. Update step-2 heading from "Ausgangsdatum eingeben" → "Perspektive und Datum" to honestly describe both controls now under the heading. - frontend/src/client/verfahrensablauf.ts: read ?project=<id> on init, fetch /api/projects/<id>, map our_side onto the side axis (mirrors fristenrechner.ts ourSideToPerspective: claimant/applicant/appellant → claimant, defendant/respondent → defendant, else null) and render the side row as a read-only chip + "Andere Seite wählen" override link. The chip respects ?side= as an explicit user pick — URL wins over project auto-fill, same precedence as fristenrechner. Override swaps back to the radio cluster and drops ?project= from the URL. Side-chip label is language-aware via onLangChange. - frontend/src/styles/global.css: .verfahrensablauf-step2-divider (1px hr between perspective and date blocks); .side-chip / -tag / -value / -override styles mirror .proceeding-summary's chip look so the two read as the same visual family. - frontend/src/client/i18n.ts + i18n-keys.ts: 3 new keys (deadlines.step2.perspective, deadlines.side.from_project, deadlines.side.override) in DE + EN. URL state stays backward-compatible: ?side= and ?appellant= survive the reorder unchanged. Adding ?project= opts in to auto-fill; without it the page behaves identically to before. No backend / projection logic change.
333 lines
18 KiB
TypeScript
333 lines
18 KiB
TypeScript
import { h } from "./jsx";
|
|
import { Sidebar } from "./components/Sidebar";
|
|
import { PaliadinWidget } from "./components/PaliadinWidget";
|
|
import { BottomNav } from "./components/BottomNav";
|
|
import { Footer } from "./components/Footer";
|
|
import { PWAHead } from "./components/PWAHead";
|
|
|
|
// Slice 1 (t-paliad-179) — the dedicated abstract-browse surface for
|
|
// procedural shape. Same backend (POST /api/tools/fristenrechner) +
|
|
// same renderer module (./client/views/verfahrensablauf-core) as
|
|
// /tools/fristenrechner; this page strips the Step 1 Akte picker /
|
|
// Step 2 cards / Pathway A wizard / Pathway B cascade / save modal,
|
|
// leaving just: proceeding-type tile picker + trigger date + court
|
|
// picker + result panel. Variant chips, lane view and compare arrive in
|
|
// Slices 2-4.
|
|
|
|
interface ProceedingDef {
|
|
code: string;
|
|
i18nKey: string;
|
|
name: string;
|
|
}
|
|
|
|
function proceedingBtn(p: ProceedingDef): string {
|
|
return (
|
|
<button type="button" className="proceeding-btn" data-code={p.code}>
|
|
<strong data-i18n={p.i18nKey}>{p.name}</strong>
|
|
</button>
|
|
);
|
|
}
|
|
|
|
const UPC_TYPES: ProceedingDef[] = [
|
|
{ code: "upc.inf.cfi", i18nKey: "deadlines.upc.inf.cfi", name: "Verletzungsverfahren" },
|
|
{ code: "upc.rev.cfi", i18nKey: "deadlines.upc.rev.cfi", name: "Nichtigkeitsklage" },
|
|
{ code: "upc.ccr.cfi", i18nKey: "deadlines.upc.ccr.cfi", name: "Widerklage auf Nichtigkeit" },
|
|
{ code: "upc.pi.cfi", i18nKey: "deadlines.upc.pi.cfi", name: "Einstw. Maßnahmen" },
|
|
{ code: "upc.apl.merits", i18nKey: "deadlines.upc.apl.merits", name: "Berufung" },
|
|
{ code: "upc.dmgs.cfi", i18nKey: "deadlines.upc.dmgs.cfi", name: "Schadensbemessung" },
|
|
{ code: "upc.disc.cfi", i18nKey: "deadlines.upc.disc.cfi", name: "Bucheinsicht" },
|
|
{ code: "upc.apl.cost", i18nKey: "deadlines.upc.apl.cost", name: "Berufung Kosten" },
|
|
{ code: "upc.apl.order", i18nKey: "deadlines.upc.apl.order", name: "Berufung Anordnungen" },
|
|
];
|
|
|
|
// DE proceedings split by type (Verletzung / Nichtigkeit) per m's
|
|
// 2026-05-18 ask. Labels are parallel: <court> (<procedural role>),
|
|
// so a user scanning the picker sees the instance-and-role at a glance
|
|
// without one tile reading "Berufung OLG" and another "Nichtigkeits-
|
|
// verfahren". Sub-group headers convey the type grouping. Combined-
|
|
// timeline behaviour (LG→OLG→BGH as one calc) is filed as m/paliad#41.
|
|
const DE_INF_TYPES: ProceedingDef[] = [
|
|
{ code: "de.inf.lg", i18nKey: "deadlines.de.inf.lg", name: "LG (1. Instanz)" },
|
|
{ code: "de.inf.olg", i18nKey: "deadlines.de.inf.olg", name: "OLG (Berufung)" },
|
|
{ code: "de.inf.bgh", i18nKey: "deadlines.de.inf.bgh", name: "BGH (Revision / NZB)" },
|
|
];
|
|
|
|
const DE_NULL_TYPES: ProceedingDef[] = [
|
|
{ code: "de.null.bpatg", i18nKey: "deadlines.de.null.bpatg", name: "BPatG (1. Instanz)" },
|
|
{ code: "de.null.bgh", i18nKey: "deadlines.de.null.bgh", name: "BGH (Berufung)" },
|
|
];
|
|
|
|
const EPA_TYPES: ProceedingDef[] = [
|
|
{ code: "epa.opp.opd", i18nKey: "deadlines.epa.opp.opd", name: "Einspruchsverfahren" },
|
|
{ code: "epa.opp.boa", i18nKey: "deadlines.epa.opp.boa", name: "Beschwerdeverfahren" },
|
|
{ code: "epa.grant.exa", i18nKey: "deadlines.epa.grant.exa", name: "EP-Erteilungsverfahren" },
|
|
];
|
|
|
|
const DPMA_TYPES: ProceedingDef[] = [
|
|
{ code: "dpma.opp.dpma", i18nKey: "deadlines.dpma.opp.dpma", name: "Einspruch DPMA" },
|
|
{ code: "dpma.appeal.bpatg", i18nKey: "deadlines.dpma.appeal.bpatg", name: "Beschwerde BPatG (DPMA)" },
|
|
{ code: "dpma.appeal.bgh", i18nKey: "deadlines.dpma.appeal.bgh", name: "Rechtsbeschwerde BGH" },
|
|
];
|
|
|
|
export function renderVerfahrensablauf(): string {
|
|
const today = new Date().toISOString().split("T")[0];
|
|
|
|
return "<!DOCTYPE html>" + (
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
<meta name="theme-color" content="#BFF355" />
|
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
|
<PWAHead />
|
|
<title data-i18n="tools.verfahrensablauf.title">Verfahrensablauf — Paliad</title>
|
|
<link rel="stylesheet" href="/assets/global.css" />
|
|
</head>
|
|
<body className="has-sidebar page-verfahrensablauf">
|
|
<Sidebar currentPath="/tools/verfahrensablauf" />
|
|
<BottomNav currentPath="/tools/verfahrensablauf" />
|
|
|
|
<main>
|
|
<section className="tool-page">
|
|
<div className="container">
|
|
<div className="tool-header">
|
|
<h1 data-i18n="tools.verfahrensablauf.heading">Verfahrensablauf</h1>
|
|
<p className="tool-subtitle" data-i18n="tools.verfahrensablauf.subtitle">
|
|
Typischen Verfahrensablauf einsehen — Verfahrensart wählen, Datum optional setzen.
|
|
</p>
|
|
</div>
|
|
|
|
{/* Verfahrensart picker (single-tile mode — same DOM ids as
|
|
/tools/fristenrechner so the shared renderer module and
|
|
court-picker primitives bind without parameterisation). */}
|
|
<div className="fristen-wizard" id="verfahrensablauf-wizard" data-mode="procedure">
|
|
<div className="wizard-step" id="step-1">
|
|
<h3 className="wizard-step-label">
|
|
<span className="step-number">1</span>
|
|
<span data-i18n="deadlines.step1">Verfahrensart wählen</span>
|
|
</h3>
|
|
|
|
<div className="proceeding-group" data-forum="upc">
|
|
<h4 data-i18n="deadlines.upc">UPC</h4>
|
|
<div className="proceeding-btns">
|
|
{UPC_TYPES.map((p) => proceedingBtn(p))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="proceeding-group" data-forum="de">
|
|
<h4 data-i18n="deadlines.de">Deutsche Gerichte</h4>
|
|
<div className="proceeding-subgroup">
|
|
<h5 className="proceeding-subgroup-heading" data-i18n="deadlines.de.group.inf">Verletzungsverfahren</h5>
|
|
<div className="proceeding-btns">
|
|
{DE_INF_TYPES.map((p) => proceedingBtn(p))}
|
|
</div>
|
|
</div>
|
|
<div className="proceeding-subgroup">
|
|
<h5 className="proceeding-subgroup-heading" data-i18n="deadlines.de.group.null">Nichtigkeitsverfahren</h5>
|
|
<div className="proceeding-btns">
|
|
{DE_NULL_TYPES.map((p) => proceedingBtn(p))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="proceeding-group" data-forum="epa">
|
|
<h4 data-i18n="deadlines.epa">EPA</h4>
|
|
<div className="proceeding-btns">
|
|
{EPA_TYPES.map((p) => proceedingBtn(p))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="proceeding-group" data-forum="dpma">
|
|
<h4 data-i18n="deadlines.dpma">DPMA</h4>
|
|
<div className="proceeding-btns">
|
|
{DPMA_TYPES.map((p) => proceedingBtn(p))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="proceeding-summary" id="proceeding-summary" style="display:none" role="group">
|
|
<span className="proceeding-summary-label" data-i18n="deadlines.proceeding.selected">Verfahren:</span>
|
|
<strong className="proceeding-summary-name" id="proceeding-summary-name">—</strong>
|
|
<button type="button" className="proceeding-summary-reselect" id="proceeding-summary-reselect"
|
|
data-i18n="deadlines.proceeding.reselect">
|
|
Anderes Verfahren wählen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="wizard-step" id="step-2" style="display:none">
|
|
<h3 className="wizard-step-label">
|
|
<span className="step-number">2</span>
|
|
<span data-i18n="deadlines.step2.perspective">Perspektive und Datum</span>
|
|
</h3>
|
|
|
|
{/* Perspective strip (t-paliad-250 / m/paliad#81, reordered
|
|
in t-paliad-279 / m/paliad#111). Side defines whose
|
|
perspective the columns project; appellant collapses
|
|
party=both rows for role-swap proceedings (Appeal etc.).
|
|
Moved above .date-input-group because party-side is the
|
|
most-defining input after proceeding-type — without
|
|
side, the column labels can't pick "your filings". Both
|
|
selectors are URL-driven (?side= + ?appellant=) so the
|
|
perspective survives reload and is shareable.
|
|
|
|
When the page is opened with ?project=<id> and that
|
|
project's our_side is set, side-row renders as a
|
|
read-only chip with an "Andere Seite wählen" override
|
|
link — see client/verfahrensablauf.ts. */}
|
|
<div className="verfahrensablauf-perspective" id="verfahrensablauf-perspective">
|
|
<div className="verfahrensablauf-perspective-row" id="side-row">
|
|
<span className="date-label" data-i18n="deadlines.side.label">Seite:</span>
|
|
<div className="side-radio-cluster" id="side-radio-cluster">
|
|
<div className="fristen-view-toggle" role="radiogroup" aria-label="Side">
|
|
<label className="fristen-view-option">
|
|
<input type="radio" name="side" value="claimant" />
|
|
<span data-i18n="deadlines.side.claimant">Klägerseite</span>
|
|
</label>
|
|
<label className="fristen-view-option">
|
|
<input type="radio" name="side" value="defendant" />
|
|
<span data-i18n="deadlines.side.defendant">Beklagtenseite</span>
|
|
</label>
|
|
<label className="fristen-view-option">
|
|
<input type="radio" name="side" value="" checked />
|
|
<span data-i18n="deadlines.side.both">Beide</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
{/* Auto-fill chip — populated by the client when a
|
|
?project=<id> URL resolves a project with our_side
|
|
set. Hidden by default; the radio cluster above is
|
|
hidden whenever this chip is shown. */}
|
|
<div className="side-chip" id="side-chip" style="display:none">
|
|
<span className="side-chip-tag" data-i18n="deadlines.side.from_project">Aus Akte:</span>
|
|
<strong className="side-chip-value" id="side-chip-value">—</strong>
|
|
<button type="button" className="side-chip-override" id="side-chip-override"
|
|
data-i18n="deadlines.side.override">
|
|
Andere Seite wählen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div className="verfahrensablauf-perspective-row" id="appellant-row" style="display:none">
|
|
<span className="date-label" data-i18n="deadlines.appellant.label">Berufung durch:</span>
|
|
<div className="fristen-view-toggle" role="radiogroup" aria-label="Appellant">
|
|
<label className="fristen-view-option">
|
|
<input type="radio" name="appellant" value="claimant" />
|
|
<span data-i18n="deadlines.appellant.claimant">Klägerseite</span>
|
|
</label>
|
|
<label className="fristen-view-option">
|
|
<input type="radio" name="appellant" value="defendant" />
|
|
<span data-i18n="deadlines.appellant.defendant">Beklagtenseite</span>
|
|
</label>
|
|
<label className="fristen-view-option">
|
|
<input type="radio" name="appellant" value="" checked />
|
|
<span data-i18n="deadlines.appellant.none">—</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Visual divider — keeps the perspective block (most-
|
|
defining inputs after proceeding-type) optically
|
|
separate from the date / court / flag knobs below. */}
|
|
<div className="verfahrensablauf-step2-divider" aria-hidden="true"></div>
|
|
|
|
<div className="date-input-group">
|
|
<div className="date-field-row">
|
|
{/* Read-only caption labelling the value <span>. Not a
|
|
<label htmlFor> — m/paliad#60: <label for=…> must
|
|
point at a labelable form control, never a span. */}
|
|
<span className="date-label" data-i18n="deadlines.trigger.event">Auslösendes Ereignis:</span>
|
|
<span id="trigger-event" className="trigger-event-name">—</span>
|
|
</div>
|
|
<div className="date-field-row">
|
|
<label htmlFor="trigger-date" className="date-label" data-i18n="deadlines.trigger.date">Datum:</label>
|
|
<input type="date" id="trigger-date" className="date-input" value={today} />
|
|
</div>
|
|
<div className="date-field-row" id="court-picker-row" style="display:none">
|
|
<label htmlFor="court-picker" className="date-label" data-i18n="deadlines.court.label">Gericht:</label>
|
|
<select id="court-picker" className="date-input"></select>
|
|
</div>
|
|
{/* Proceeding-specific flag rows — mirror /tools/fristenrechner
|
|
so an abstract-browse user can model the same variants
|
|
(CCR, Patentänderung, Verletzungswiderklage,
|
|
Vorab-Einrede). Show/hide driven by selectedType in
|
|
the client. */}
|
|
<div className="date-field-row" id="ccr-flag-row" style="display:none">
|
|
<label className="date-label">
|
|
<input type="checkbox" id="ccr-flag" />
|
|
<span data-i18n="deadlines.flag.ccr">Mit Widerklage auf Nichtigkeit</span>
|
|
</label>
|
|
</div>
|
|
<div className="date-field-row date-field-row--nested" id="inf-amend-flag-row" style="display:none">
|
|
<label className="date-label">
|
|
<input type="checkbox" id="inf-amend-flag" />
|
|
<span data-i18n="deadlines.flag.inf_amend">Mit Antrag auf Patentänderung (R.30)</span>
|
|
</label>
|
|
</div>
|
|
<div className="date-field-row" id="rev-amend-flag-row" style="display:none">
|
|
<label className="date-label">
|
|
<input type="checkbox" id="rev-amend-flag" />
|
|
<span data-i18n="deadlines.flag.rev_amend">Mit Antrag auf Patentänderung (R.49.2.a)</span>
|
|
</label>
|
|
</div>
|
|
<div className="date-field-row" id="rev-cci-flag-row" style="display:none">
|
|
<label className="date-label">
|
|
<input type="checkbox" id="rev-cci-flag" />
|
|
<span data-i18n="deadlines.flag.rev_cci">Mit Verletzungswiderklage (R.49.2.b)</span>
|
|
</label>
|
|
</div>
|
|
<button type="button" id="calculate-btn" className="calculate-btn" data-i18n="deadlines.calculate">
|
|
Fristen berechnen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="wizard-step" id="step-3" style="display:none">
|
|
<h3 className="wizard-step-label">
|
|
<span className="step-number">3</span>
|
|
<span data-i18n="deadlines.step3">Ergebnis</span>
|
|
</h3>
|
|
|
|
<div className="fristen-view-toggle" id="fristen-view-toggle" role="radiogroup" aria-label="Ansicht">
|
|
<span className="fristen-view-label" data-i18n="deadlines.view.label">Ansicht:</span>
|
|
<label className="fristen-view-option">
|
|
<input type="radio" name="fristen-view" value="columns" checked />
|
|
<span data-i18n="deadlines.view.columns">Spalten</span>
|
|
</label>
|
|
<label className="fristen-view-option">
|
|
<input type="radio" name="fristen-view" value="timeline" />
|
|
<span data-i18n="deadlines.view.timeline">Zeitstrahl</span>
|
|
</label>
|
|
<label className="fristen-notes-option">
|
|
<input type="checkbox" id="fristen-notes-show" />
|
|
<span data-i18n="deadlines.notes.show">Hinweise anzeigen</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div id="timeline-container">
|
|
</div>
|
|
|
|
<div className="fristen-result-actions">
|
|
<button type="button" id="fristen-print-btn" className="print-btn" style="display:none">
|
|
<svg className="print-btn-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
<polyline points="6 9 6 2 18 2 18 9"></polyline>
|
|
<path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"></path>
|
|
<rect x="6" y="14" width="12" height="8"></rect>
|
|
</svg>
|
|
<span data-i18n="deadlines.print">Drucken</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
|
|
<Footer />
|
|
<PaliadinWidget />
|
|
<script src="/assets/verfahrensablauf.js"></script>
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|