m/paliad#60 (t-paliad-221) — Chrome's Issues tab flagged a label/for violation on the timeline wizard: <label for="trigger-event"> pointed at a <span> showing the selected trigger event name. <label for=…> must target a labelable form control (input/select/textarea/…), never a span; the browser strips the association and a11y tooling sees a dangling reference. Audit found two occurrences — verfahrensablauf.tsx and fristenrechner.tsx both use the same wizard markup. Switch both captions to plain <span class="date-label">; the .date-label rule already targets by class only, so visual styling is unchanged. No other label-for mismatches surfaced (194 label-fors scanned across frontend/src).
658 lines
38 KiB
TypeScript
658 lines
38 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";
|
|
|
|
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>
|
|
);
|
|
}
|
|
|
|
// Quick-pick chip definition. Each chip targets ONE deadline_concepts
|
|
// slug — clicking sets the search query to the concept's name in the
|
|
// active language so trigram search lands on the right concept card.
|
|
// Single source of truth for both fork-shortcut and B2-search-bar
|
|
// chip rows. Dedup invariant: no two chips share a slug. Label flips
|
|
// per language via the chip wiring in client/fristenrechner.ts.
|
|
interface QuickChip {
|
|
slug: string;
|
|
name_de: string;
|
|
name_en: string;
|
|
}
|
|
|
|
const QUICK_CHIPS: QuickChip[] = [
|
|
{ slug: "statement-of-defence", name_de: "Klageerwiderung", name_en: "Statement of Defence" },
|
|
{ slug: "notice-of-appeal", name_de: "Berufungsschrift", name_en: "Notice of Appeal" },
|
|
{ slug: "opposition", name_de: "Einspruchsfrist", name_en: "Opposition" },
|
|
{ slug: "reply-to-defence", name_de: "Replik", name_en: "Reply to Defence" },
|
|
{ slug: "nichtzulassungsbeschwerde", name_de: "Nichtzulassungsbeschwerde", name_en: "Non-admission Appeal (NZB)" },
|
|
{ slug: "application-for-determination-of-damages",name_de: "Antrag auf Schadensbemessung", name_en: "Application for Determination of Damages" },
|
|
{ slug: "wiedereinsetzung", name_de: "Wiedereinsetzung", name_en: "Re-establishment of Rights" },
|
|
];
|
|
|
|
function quickChip(c: QuickChip): string {
|
|
return (
|
|
<button type="button" className="fristen-search-chip"
|
|
data-chip-slug={c.slug}
|
|
data-chip-name-de={c.name_de}
|
|
data-chip-name-en={c.name_en}
|
|
data-q={c.name_de}>
|
|
{c.name_de}
|
|
</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\u00dfnahmen" },
|
|
{ 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 renderFristenrechner(): 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="deadlines.title">Fristenrechner — Paliad</title>
|
|
<link rel="stylesheet" href="/assets/global.css" />
|
|
</head>
|
|
<body className="has-sidebar">
|
|
<Sidebar currentPath="/tools/fristenrechner" />
|
|
<BottomNav currentPath="/tools/fristenrechner" />
|
|
|
|
<main>
|
|
<section className="tool-page">
|
|
<div className="container">
|
|
<div className="tool-header">
|
|
<h1 data-i18n="deadlines.heading">Fristenrechner</h1>
|
|
<p className="tool-subtitle" data-i18n="deadlines.subtitle">
|
|
Berechnung von Verfahrensfristen für UPC-, deutsche und EPA-Verfahren.
|
|
</p>
|
|
</div>
|
|
|
|
{/* m's 2026-05-08 18:08 Determinator redesign — Step 1: pick the
|
|
Akte (project) that scopes the rest of the flow. Filtered
|
|
list of visible projects + "Neue Akte anlegen" link +
|
|
four ad-hoc explore-mode chips for users who just want to
|
|
look up a rule without saving anywhere. */}
|
|
<div className="fristen-step1" id="fristen-step1" role="group" aria-label="Akte picker">
|
|
<h2 className="fristen-step-heading" data-i18n="deadlines.step1.heading">
|
|
Schritt 1 — Welche Akte?
|
|
</h2>
|
|
<div className="fristen-step1-search-row">
|
|
<svg className="fristen-search-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
<circle cx="11" cy="11" r="7"></circle>
|
|
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
|
</svg>
|
|
<input type="search" id="fristen-akte-search"
|
|
className="fristen-akte-search" autocomplete="off"
|
|
data-i18n-placeholder="deadlines.step1.search.placeholder"
|
|
placeholder="Akte suchen…" />
|
|
</div>
|
|
<ul className="fristen-akte-list" id="fristen-akte-list" role="listbox" aria-label="Akten"></ul>
|
|
|
|
<div className="fristen-step1-divider">
|
|
<span data-i18n="deadlines.step1.divider.new">oder eine neue Akte</span>
|
|
</div>
|
|
{/* return-bounce: projects-new.ts honours ?return= and
|
|
redirects back to /tools/fristenrechner?project=<new_uuid>
|
|
so the new Akte preselects itself in Step 1. */}
|
|
<a href="/projects/new?return=/tools/fristenrechner" className="fristen-step1-new" id="fristen-step1-new"
|
|
data-i18n="deadlines.step1.new.cta">
|
|
+ Neue Akte anlegen
|
|
</a>
|
|
|
|
<div className="fristen-step1-divider">
|
|
<span data-i18n="deadlines.step1.divider.adhoc">oder ad-hoc, ohne Akte</span>
|
|
</div>
|
|
<div className="fristen-adhoc-chips" role="group" aria-label="Ad-hoc proceeding">
|
|
<button type="button" className="fristen-adhoc-chip" data-ad-hoc="upc"
|
|
data-i18n="deadlines.step1.adhoc.upc">
|
|
Custom UPC proceeding
|
|
</button>
|
|
<button type="button" className="fristen-adhoc-chip" data-ad-hoc="de"
|
|
data-i18n="deadlines.step1.adhoc.de">
|
|
Custom DE proceeding
|
|
</button>
|
|
<button type="button" className="fristen-adhoc-chip" data-ad-hoc="epa"
|
|
data-i18n="deadlines.step1.adhoc.epa">
|
|
Custom EPA proceeding
|
|
</button>
|
|
<button type="button" className="fristen-adhoc-chip" data-ad-hoc="dpma"
|
|
data-i18n="deadlines.step1.adhoc.dpma">
|
|
Custom DPMA proceeding
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Step 1 collapsed summary, shown after a pick. Mirrors the
|
|
proceeding-summary collapse pattern from 097e21c. */}
|
|
<div className="fristen-step1-summary" id="fristen-step1-summary" style="display:none" role="group">
|
|
<span className="fristen-step1-summary-label" data-i18n="deadlines.step1.selected">Akte:</span>
|
|
<strong className="fristen-step1-summary-name" id="fristen-step1-summary-name">—</strong>
|
|
<span className="fristen-step1-summary-meta" id="fristen-step1-summary-meta"></span>
|
|
<button type="button" className="fristen-step1-summary-reselect" id="fristen-step1-summary-reselect"
|
|
data-i18n="deadlines.step1.reselect">
|
|
Andere Akte
|
|
</button>
|
|
</div>
|
|
|
|
{/* Step 2 — Do / Happened bifurcation. Hidden until Step 1 is
|
|
satisfied. Click on a card routes to the existing Pathway A
|
|
(Verfahrensablauf wizard) or Pathway B (cascade) shells —
|
|
we keep the routing primitive in showPathway()/showBMode(). */}
|
|
<div className="fristen-step2" id="fristen-step2" hidden>
|
|
<h2 className="fristen-step-heading" data-i18n="deadlines.step2.heading">
|
|
Schritt 2 — Was möchten Sie tun?
|
|
</h2>
|
|
<div className="fristen-step2-cards">
|
|
<button type="button" className="fristen-step2-card" data-action="file" id="fristen-step2-file">
|
|
<span className="fristen-step2-card-icon" aria-hidden="true">✏️</span>
|
|
<span className="fristen-step2-card-title" data-i18n="deadlines.step2.file.title">
|
|
Etwas einreichen
|
|
</span>
|
|
<span className="fristen-step2-card-desc" data-i18n="deadlines.step2.file.desc">
|
|
Outgoing — eine Frist tritt aus eigener Handlung ein.
|
|
</span>
|
|
</button>
|
|
<button type="button" className="fristen-step2-card" data-action="happened" id="fristen-step2-happened">
|
|
<span className="fristen-step2-card-icon" aria-hidden="true">📥</span>
|
|
<span className="fristen-step2-card-title" data-i18n="deadlines.step2.happened.title">
|
|
Etwas ist passiert
|
|
</span>
|
|
<span className="fristen-step2-card-desc" data-i18n="deadlines.step2.happened.desc">
|
|
Incoming — ein Ereignis hat eine Frist ausgelöst.
|
|
</span>
|
|
</button>
|
|
{/* t-paliad-179 Slice 1: the third "Verfahrensablauf
|
|
einsehen" card retired — abstract-browse intent now
|
|
owns its own route at /tools/verfahrensablauf. */}
|
|
</div>
|
|
<div className="fristen-step2-shortcut">
|
|
<div className="fristen-pathway-fork-shortcut-label" data-i18n="deadlines.pathway.shortcut.label">
|
|
oder direkt zu einer Frist springen:
|
|
</div>
|
|
<div className="fristen-search-chips" id="fristen-fork-chips" role="group" aria-label="Schnellzugriff">
|
|
{QUICK_CHIPS.map((c) => quickChip(c))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Pathway B container — search bar relocates here from the page top.
|
|
Mode toggle (B1 tree / B2 filter) sits above the panels.
|
|
Hidden until ?path=b. */}
|
|
<div className="fristen-pathway-shell" id="fristen-pathway-b" data-path="b" hidden>
|
|
<button type="button" className="fristen-pathway-back" id="fristen-pathway-b-back">
|
|
<span aria-hidden="true">←</span>{" "}
|
|
<span data-i18n="deadlines.pathway.back">zurück zur Auswahl</span>
|
|
</button>
|
|
<h2 className="fristen-pathway-heading">
|
|
<span aria-hidden="true">📅</span>{" "}
|
|
<span data-i18n="deadlines.pathway.b.title">Frist eintragen aufgrund Ereignis</span>
|
|
</h2>
|
|
|
|
{/* B1 panel — row-stack cascade.
|
|
`#fristen-row-stack` hosts the perspective / inbox /
|
|
cascade rows (t-paliad-180 Slice 1; t-paliad-197 Slice 2
|
|
added project-driven prefills + auto-walk). The
|
|
stack-header above carries the inline-search trigger
|
|
(t-paliad-198 Slice 3 — clicking expands
|
|
`#fristen-row-search-panel` over the row stack instead
|
|
of routing to the legacy B2 surface) and the reset link.
|
|
`#fristen-b1-results` is unchanged — it renders concept
|
|
cards for both cascade-narrowing AND inline-search
|
|
results, so users see the same card layout regardless
|
|
of how they reached a deadline rule. */}
|
|
<div className="fristen-b1-panel" id="fristen-b1-panel" data-mode="tree" hidden>
|
|
<div className="fristen-row-stack-header" id="fristen-row-stack-header">
|
|
<button type="button" className="fristen-row-search-link" id="fristen-row-search-link"
|
|
data-i18n-title="deadlines.row.search.link.title"
|
|
aria-expanded="false"
|
|
aria-controls="fristen-row-search-panel"
|
|
title="Direkt nach einer Frist suchen">
|
|
<span aria-hidden="true">🔍</span>{" "}
|
|
<span data-i18n="deadlines.row.search.link">Direkt suchen</span>
|
|
</button>
|
|
<button type="button" className="fristen-row-reset-link" id="fristen-row-reset"
|
|
data-i18n-title="deadlines.row.reset.title"
|
|
title="Pfad zurücksetzen — alle Cascade-Antworten verwerfen">
|
|
<span aria-hidden="true">↺</span>{" "}
|
|
<span data-i18n="deadlines.row.reset">Pfad zurücksetzen</span>
|
|
</button>
|
|
</div>
|
|
|
|
{/* Inline search overlay (t-paliad-198 Slice 3). Hidden by
|
|
default; the search icon-button in the stack header
|
|
toggles it open / closed. While open, the row stack is
|
|
hidden and the search input drives `#fristen-b1-results`
|
|
directly — same surface the cascade leaf populates so
|
|
the user sees one consistent concept-card list. */}
|
|
<div className="fristen-row-search-panel" id="fristen-row-search-panel" hidden role="search">
|
|
<button type="button" className="fristen-row-search-panel-back" id="fristen-row-search-panel-back"
|
|
data-i18n-title="deadlines.row.search.panel.back.title"
|
|
title="Zurück zum Entscheidungsbaum">
|
|
<span aria-hidden="true">←</span>{" "}
|
|
<span data-i18n="deadlines.row.search.panel.back">Zurück zum Entscheidungsbaum</span>
|
|
</button>
|
|
<div className="fristen-row-search-panel-input-wrap">
|
|
<svg className="fristen-row-search-panel-icon" width="18" height="18" viewBox="0 0 24 24"
|
|
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
|
stroke-linejoin="round" aria-hidden="true">
|
|
<circle cx="11" cy="11" r="7"></circle>
|
|
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
|
</svg>
|
|
<input
|
|
type="search"
|
|
id="fristen-row-search-panel-input"
|
|
className="fristen-row-search-panel-input"
|
|
autocomplete="off"
|
|
spellcheck="false"
|
|
data-i18n-placeholder="deadlines.row.search.panel.placeholder"
|
|
placeholder="Frist suchen…"
|
|
aria-label="Frist suchen"
|
|
/>
|
|
<button type="button" className="fristen-row-search-panel-clear" id="fristen-row-search-panel-clear"
|
|
data-i18n-title="deadlines.row.search.panel.clear" title="Eingabe leeren" hidden>
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="fristen-row-stack" id="fristen-row-stack" aria-live="polite"></div>
|
|
<div className="fristen-b1-results" id="fristen-b1-results" aria-live="polite"></div>
|
|
</div>
|
|
|
|
{/* B2 panel — search bar + chips + concept-card results.
|
|
The search input + chips + results host live here so
|
|
fristenrechner.ts can drive both Phase D (today) and the
|
|
B1↔B2 state-share in Phase D (forum filter). */}
|
|
<div className="fristen-b2-panel" id="fristen-b2-panel" data-mode="filter">
|
|
<div className="fristen-search">
|
|
<label htmlFor="fristen-search-input" className="visually-hidden" data-i18n="deadlines.search.label">Frist suchen</label>
|
|
<div className="fristen-search-row">
|
|
<svg className="fristen-search-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
<circle cx="11" cy="11" r="7"></circle>
|
|
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
|
</svg>
|
|
<input
|
|
type="search"
|
|
id="fristen-search-input"
|
|
className="fristen-search-input"
|
|
autocomplete="off"
|
|
spellcheck="false"
|
|
data-i18n-placeholder="deadlines.search.placeholder"
|
|
placeholder="Klageerwiderung, RoP 23, § 82, Wiedereinsetzung…"
|
|
/>
|
|
<button type="button" id="fristen-search-clear" className="fristen-search-clear" aria-label="Suche leeren" data-i18n-aria-label="deadlines.search.clear" hidden>
|
|
×
|
|
</button>
|
|
</div>
|
|
<div className="fristen-search-chips" id="fristen-search-chips" role="group" aria-label="Schnellzugriff">
|
|
<span className="fristen-search-chips-label" data-i18n="deadlines.search.chips.label">Schnellzugriff:</span>
|
|
{QUICK_CHIPS.map((c) => quickChip(c))}
|
|
</div>
|
|
{/* Forum filter row — populated by Phase D. */}
|
|
<div className="fristen-forum-filter" id="fristen-forum-filter" hidden>
|
|
<span className="fristen-forum-filter-label" data-i18n="deadlines.filter.forum.label">Gericht / System:</span>
|
|
<div className="fristen-forum-chips" id="fristen-forum-chips"></div>
|
|
</div>
|
|
<div id="fristen-search-results" className="fristen-search-results" aria-live="polite"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Step 3a — outgoing-intent chooser. Reached when the user
|
|
picks "Etwas einreichen" on Step 2. Three options per
|
|
m's 2026-05-08 18:09 spec: File (drives the Pathway A
|
|
wizard), Draft (future drafting surface; v1
|
|
placeholder), Enter (routes to the existing manual-
|
|
create form). */}
|
|
<div className="fristen-pathway-shell" id="fristen-step3a" data-path="outgoing" hidden>
|
|
<button type="button" className="fristen-pathway-back" id="fristen-step3a-back">
|
|
<span aria-hidden="true">←</span>{" "}
|
|
<span data-i18n="deadlines.step3a.back">zurück zur Auswahl</span>
|
|
</button>
|
|
<h2 className="fristen-pathway-heading">
|
|
<span aria-hidden="true">✏️</span>{" "}
|
|
<span data-i18n="deadlines.step3a.heading">Was möchten Sie einreichen?</span>
|
|
</h2>
|
|
<div className="fristen-step2-cards">
|
|
<button type="button" className="fristen-step2-card" id="fristen-step3a-file" data-action="file">
|
|
<span className="fristen-step2-card-icon" aria-hidden="true">📝</span>
|
|
<span className="fristen-step2-card-title" data-i18n="deadlines.step3a.file.title">
|
|
Schriftsatz einreichen
|
|
</span>
|
|
<span className="fristen-step2-card-desc" data-i18n="deadlines.step3a.file.desc">
|
|
Verfahrensablauf laden — Frist berechnen und zur Akte hinzufügen.
|
|
</span>
|
|
</button>
|
|
<button type="button" className="fristen-step2-card fristen-step2-card--soon" id="fristen-step3a-draft" data-action="draft" disabled
|
|
data-i18n-title="deadlines.step3a.soon">
|
|
<span className="fristen-step2-card-icon" aria-hidden="true">🖉</span>
|
|
<span className="fristen-step2-card-title" data-i18n="deadlines.step3a.draft.title">
|
|
Schriftsatz entwerfen
|
|
</span>
|
|
<span className="fristen-step2-card-desc" data-i18n="deadlines.step3a.draft.desc">
|
|
Vorbereitung — später mit Drafting-Surface verknüpft.
|
|
</span>
|
|
<span className="fristen-step2-card-soon" data-i18n="deadlines.step3a.soon">kommt bald</span>
|
|
</button>
|
|
<button type="button" className="fristen-step2-card" id="fristen-step3a-enter" data-action="enter">
|
|
<span className="fristen-step2-card-icon" aria-hidden="true">💾</span>
|
|
<span className="fristen-step2-card-title" data-i18n="deadlines.step3a.enter.title">
|
|
Frist manuell erfassen
|
|
</span>
|
|
<span className="fristen-step2-card-desc" data-i18n="deadlines.step3a.enter.desc">
|
|
Direkt eintragen — bereits bekanntes Datum / bekannter Typ.
|
|
</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Pathway A container — wraps the existing wizard.
|
|
Hidden until ?path=a. */}
|
|
<div className="fristen-pathway-shell" id="fristen-pathway-a" data-path="a" hidden>
|
|
<button type="button" className="fristen-pathway-back" id="fristen-pathway-a-back">
|
|
<span aria-hidden="true">←</span>{" "}
|
|
<span data-i18n="deadlines.pathway.back">zurück zur Auswahl</span>
|
|
</button>
|
|
<h2 className="fristen-pathway-heading">
|
|
<span aria-hidden="true">📖</span>{" "}
|
|
<span data-i18n="deadlines.pathway.a.title">Verfahrensablauf informieren</span>
|
|
</h2>
|
|
|
|
{/* v3: legacy mode tabs retired (m's spec lock §10 Q1, 2026-05-05).
|
|
Pathway A is Verfahrensablauf-only; trigger-event drill-in
|
|
surfaces via concept-card pills with ?path=a&trigger=N URL,
|
|
which resurfaces mode-event-panel programmatically below. */}
|
|
<div className="fristen-wizard mode-panel" id="mode-procedure-panel" data-mode="procedure" role="tabpanel">
|
|
<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>
|
|
|
|
{/* m's 2026-05-08 18:26: collapse the proceeding picker once
|
|
a choice is made; this summary line replaces the four
|
|
group blocks with a one-line "Selected: X [Reselect]"
|
|
affordance. JS toggles `.proceeding-summary` visibility
|
|
in lockstep with `.proceeding-group` blocks. */}
|
|
<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">Ausgangsdatum eingeben</span>
|
|
</h3>
|
|
|
|
<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>
|
|
<div className="date-field-row" id="priority-date-row" style="display:none">
|
|
<label htmlFor="priority-date" className="date-label" data-i18n="deadlines.priority.date">Prioritätstag (optional):</label>
|
|
<input type="date" id="priority-date" className="date-input" />
|
|
</div>
|
|
<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-save-cta" className="btn-primary btn-cta-lime" style="display:none" data-i18n="deadlines.save.cta">
|
|
Als Frist(en) speichern
|
|
</button>
|
|
<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>
|
|
|
|
<button type="button" id="reset-btn" className="reset-btn" style="display:none" data-i18n="deadlines.reset">
|
|
← Neu berechnen
|
|
</button>
|
|
</div>
|
|
|
|
<div className="fristen-wizard mode-panel" id="mode-event-panel" data-mode="event" role="tabpanel" hidden>
|
|
<div className="wizard-step" id="event-step-1">
|
|
<h3 className="wizard-step-label">
|
|
<span className="step-number">1</span>
|
|
<span data-i18n="deadlines.event.step1">Trigger-Ereignis wählen</span>
|
|
</h3>
|
|
<p className="wizard-step-hint" data-i18n="deadlines.event.step1.hint">
|
|
Welches Ereignis ist eingetreten? (z.B. Klageerhebung, Entscheidung des EPA, Zustellung einer Verfügung)
|
|
</p>
|
|
<div className="event-picker-row">
|
|
<label htmlFor="event-search" className="visually-hidden" data-i18n="deadlines.event.search.label">Trigger-Ereignis suchen</label>
|
|
<input
|
|
type="search"
|
|
id="event-search"
|
|
className="event-search-input"
|
|
autocomplete="off"
|
|
data-i18n-placeholder="deadlines.event.search.placeholder"
|
|
placeholder="Tippe, um zu suchen…"
|
|
/>
|
|
<ul id="event-list" className="event-list" role="listbox" aria-label="Trigger-Ereignisse"></ul>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="wizard-step" id="event-step-2" style="display:none">
|
|
<h3 className="wizard-step-label">
|
|
<span className="step-number">2</span>
|
|
<span data-i18n="deadlines.event.step2">Datum des Ereignisses</span>
|
|
</h3>
|
|
<div className="date-input-group">
|
|
<div className="date-field-row">
|
|
<label className="date-label" data-i18n="deadlines.event.selected">Gewähltes Ereignis:</label>
|
|
<span id="event-selected-name" className="trigger-event-name">—</span>
|
|
</div>
|
|
<div className="date-field-row">
|
|
<label htmlFor="event-date" className="date-label" data-i18n="deadlines.event.date">Eintrittsdatum:</label>
|
|
<input type="date" id="event-date" className="date-input" value={today} />
|
|
</div>
|
|
<button type="button" id="event-calculate-btn" className="calculate-btn" data-i18n="deadlines.event.calculate">
|
|
Folgefristen berechnen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="wizard-step" id="event-step-3" style="display:none">
|
|
<h3 className="wizard-step-label">
|
|
<span className="step-number">3</span>
|
|
<span data-i18n="deadlines.event.step3">Folgefristen</span>
|
|
</h3>
|
|
<div id="event-results-container"></div>
|
|
<div className="fristen-result-actions">
|
|
<button type="button" id="event-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>
|
|
|
|
<button type="button" id="event-reset-btn" className="reset-btn" style="display:none" data-i18n="deadlines.reset">
|
|
← Neu berechnen
|
|
</button>
|
|
</div>
|
|
</div>{/* /pathway-a */}
|
|
</div>
|
|
</section>
|
|
</main>
|
|
|
|
<Footer />
|
|
<PaliadinWidget />
|
|
<script src="/assets/fristenrechner.js"></script>
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|