feat(determinator/slice-3a): outgoing-intent chooser (File / Draft / Enter)
m's 2026-05-08 18:09 spec: Step 3a is itself a 3-option fan-out. When
the user picks "Etwas einreichen" on Step 2 we no longer drop straight
into the Pathway A wizard; we ask "what kind of einreichen?" first.
Three cards:
- **File** (Schriftsatz einreichen) → navigates to Pathway A — the
existing wizard with proceeding picker, trigger date, flags,
timeline, save modal. The rule-library entry point.
- **Draft** (Schriftsatz entwerfen) → v1 placeholder. Disabled
button with a "kommt bald" pill in the corner. m specced this
as a link to a future drafting surface; for now we show the
intent without doing anything so the surface exists in the IA.
- **Enter** (Frist manuell erfassen) → routes to
`/projects/{id}/deadlines/new` (or `/deadlines/new` in ad-hoc
mode where there's no project to anchor against).
Pathway type extends to include "outgoing"; readPathwayFromURL +
showPathway both handle it. The Step 3a panel reuses .fristen-step2-
card visuals so File / Draft / Enter look consistent with the parent
Step 2 cards but distinct from Pathway A's proceeding picker.
Back-button policy:
- Step 3a back → Step 2 (the new "fork" state).
- Pathway A back → Step 3a (since that's where the user came from
in the new flow). Two clicks back to the fork.
- Pathway B back → fork directly (Step 2 happened-card jumps
straight to Pathway B; no intermediate chooser).
Out of scope for this slice:
- Step 3b's project-type-scoped event picker (Slice 3b).
- Klägerseite/Beklagtenseite role variants (Slice 3c).
- Real /drafts route — Draft stays a soft placeholder.
Refs t-paliad-157 / m/paliad#15.
This commit is contained in:
@@ -2296,7 +2296,12 @@ document.addEventListener("DOMContentLoaded", initSearch);
|
||||
// re-entry. ?legacy=1 keeps the pre-v3 layout (no fork) for parity testing
|
||||
// during the rollout window.
|
||||
|
||||
type Pathway = "fork" | "a" | "b";
|
||||
// Pathway values:
|
||||
// fork — Step 1 / Step 2 visible (the new front of the funnel)
|
||||
// outgoing — Step 3a chooser (File / Draft / Enter) visible
|
||||
// a — Pathway A wizard (Verfahrensablauf timeline)
|
||||
// b — Pathway B cascade
|
||||
type Pathway = "fork" | "outgoing" | "a" | "b";
|
||||
type BMode = "tree" | "filter";
|
||||
|
||||
const PATHWAY_STORAGE_KEY = "paliad.fristen.pathway";
|
||||
@@ -2304,7 +2309,7 @@ const PATHWAY_STORAGE_KEY = "paliad.fristen.pathway";
|
||||
function readPathwayFromURL(): Pathway {
|
||||
const sp = new URLSearchParams(window.location.search);
|
||||
const p = sp.get("path");
|
||||
if (p === "a" || p === "b") return p;
|
||||
if (p === "a" || p === "b" || p === "outgoing") return p;
|
||||
return "fork";
|
||||
}
|
||||
|
||||
@@ -2339,6 +2344,18 @@ function setPathwayURL(path: Pathway, mode?: BMode, replace = false) {
|
||||
}
|
||||
}
|
||||
|
||||
// resolveDeadlinesNewURL builds the Step 3a "Enter" destination. For a
|
||||
// real project: /projects/{id}/deadlines/new. For ad-hoc explore-mode:
|
||||
// /deadlines/new (the project picker is in the form itself, but the
|
||||
// user has no Akte to attach it to without picking one anew). m's
|
||||
// 2026-05-08 spec: this is the manual-entry escape hatch.
|
||||
function resolveDeadlinesNewURL(ctx: Step1Context): string {
|
||||
if (ctx.kind === "project" && ctx.projectId) {
|
||||
return `/projects/${encodeURIComponent(ctx.projectId)}/deadlines/new`;
|
||||
}
|
||||
return "/deadlines/new";
|
||||
}
|
||||
|
||||
function showPathway(path: Pathway, mode?: BMode) {
|
||||
// m's 2026-05-08 18:08 redesign retired the legacy fork; Step 1 and
|
||||
// Step 2 sit where it used to live. The "fork" Pathway value now
|
||||
@@ -2348,6 +2365,7 @@ function showPathway(path: Pathway, mode?: BMode) {
|
||||
const step1 = document.getElementById("fristen-step1");
|
||||
const step1Summary = document.getElementById("fristen-step1-summary");
|
||||
const step2 = document.getElementById("fristen-step2");
|
||||
const step3a = document.getElementById("fristen-step3a");
|
||||
const a = document.getElementById("fristen-pathway-a");
|
||||
const b = document.getElementById("fristen-pathway-b");
|
||||
if (!a || !b) return;
|
||||
@@ -2365,6 +2383,7 @@ function showPathway(path: Pathway, mode?: BMode) {
|
||||
step1Summary.style.display = (ctx.kind !== "none" && path !== "fork") ? "" : step1Summary.style.display;
|
||||
}
|
||||
if (step2) step2.hidden = path !== "fork";
|
||||
if (step3a) step3a.hidden = path !== "outgoing";
|
||||
a.hidden = path !== "a";
|
||||
b.hidden = path !== "b";
|
||||
|
||||
@@ -2617,23 +2636,39 @@ function initPathwayFork() {
|
||||
}
|
||||
});
|
||||
|
||||
// Step 2 cards — outgoing (Pathway A wizard) vs incoming (Pathway B
|
||||
// cascade). showPathway() owns the actual A/B transition; we just
|
||||
// drive it from the action choice.
|
||||
// Step 2 cards — outgoing (Step 3a chooser) vs incoming (Pathway B
|
||||
// cascade). showPathway() owns the actual transition; we just drive
|
||||
// it from the action choice.
|
||||
document.getElementById("fristen-step2-file")?.addEventListener("click", () => {
|
||||
navigateToPathway("a");
|
||||
navigateToPathway("outgoing");
|
||||
});
|
||||
document.getElementById("fristen-step2-happened")?.addEventListener("click", () => {
|
||||
navigateToPathway("b", "tree");
|
||||
});
|
||||
|
||||
// Step 3a cards — File / Draft / Enter. File drops into the existing
|
||||
// Pathway A wizard; Enter routes to the manual-create form;
|
||||
// Draft is a v1 placeholder (button disabled in markup, no handler).
|
||||
document.getElementById("fristen-step3a-file")?.addEventListener("click", () => {
|
||||
navigateToPathway("a");
|
||||
});
|
||||
document.getElementById("fristen-step3a-enter")?.addEventListener("click", () => {
|
||||
window.location.href = resolveDeadlinesNewURL(currentStep1Context);
|
||||
});
|
||||
|
||||
// Back-from-Pathway buttons return to Step 2 (the new "fork" state).
|
||||
// Pathway A's back returns to Step 3a since that's where the user
|
||||
// came from in the new flow; pre-Slice-3 muscle memory of Pathway A
|
||||
// back going all the way to fork is preserved by clicking back twice.
|
||||
document.getElementById("fristen-pathway-a-back")?.addEventListener("click", () => {
|
||||
navigateToPathway("fork");
|
||||
navigateToPathway("outgoing");
|
||||
});
|
||||
document.getElementById("fristen-pathway-b-back")?.addEventListener("click", () => {
|
||||
navigateToPathway("fork");
|
||||
});
|
||||
document.getElementById("fristen-step3a-back")?.addEventListener("click", () => {
|
||||
navigateToPathway("fork");
|
||||
});
|
||||
|
||||
// B1/B2 mode toggle inside Pathway B.
|
||||
const bModeRadios = document.querySelectorAll<HTMLInputElement>("input[name='fristen-b-mode']");
|
||||
|
||||
@@ -266,6 +266,15 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"deadlines.step2.happened.title": "Etwas ist passiert",
|
||||
"deadlines.step2.happened.desc": "Incoming — ein Ereignis hat eine Frist ausgelöst.",
|
||||
"deadlines.save.cta.adhoc.hint": "Ad-hoc — kein Projekt, kein Speichern",
|
||||
"deadlines.step3a.heading": "Was möchten Sie einreichen?",
|
||||
"deadlines.step3a.back": "zurück zur Auswahl",
|
||||
"deadlines.step3a.file.title": "Schriftsatz einreichen",
|
||||
"deadlines.step3a.file.desc": "Verfahrensablauf laden — Frist berechnen und zur Akte hinzufügen.",
|
||||
"deadlines.step3a.draft.title": "Schriftsatz entwerfen",
|
||||
"deadlines.step3a.draft.desc": "Vorbereitung — später mit Drafting-Surface verknüpft.",
|
||||
"deadlines.step3a.enter.title": "Frist manuell erfassen",
|
||||
"deadlines.step3a.enter.desc": "Direkt eintragen — bereits bekanntes Datum / bekannter Typ.",
|
||||
"deadlines.step3a.soon": "kommt bald",
|
||||
"deadlines.date.edit.hint": "Datum bearbeiten — Folgefristen werden neu berechnet",
|
||||
"deadlines.view.label": "Ansicht:",
|
||||
"deadlines.view.timeline": "Zeitstrahl",
|
||||
@@ -2362,6 +2371,15 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"deadlines.step2.happened.title": "Something happened",
|
||||
"deadlines.step2.happened.desc": "Incoming — an event triggered a deadline.",
|
||||
"deadlines.save.cta.adhoc.hint": "Ad-hoc — no matter, no save",
|
||||
"deadlines.step3a.heading": "What do you want to file?",
|
||||
"deadlines.step3a.back": "back to selection",
|
||||
"deadlines.step3a.file.title": "File a submission",
|
||||
"deadlines.step3a.file.desc": "Open the Verfahrensablauf — compute deadline and add to the matter.",
|
||||
"deadlines.step3a.draft.title": "Draft a submission",
|
||||
"deadlines.step3a.draft.desc": "Preparation — later linked to the drafting surface.",
|
||||
"deadlines.step3a.enter.title": "Enter deadline manually",
|
||||
"deadlines.step3a.enter.desc": "Direct entry — date and type already known.",
|
||||
"deadlines.step3a.soon": "coming soon",
|
||||
"deadlines.date.edit.hint": "Edit date — downstream deadlines will recalculate",
|
||||
"deadlines.view.label": "View:",
|
||||
"deadlines.view.timeline": "Timeline",
|
||||
|
||||
@@ -316,6 +316,54 @@ export function renderFristenrechner(): string {
|
||||
</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>
|
||||
|
||||
@@ -957,6 +957,15 @@ export type I18nKey =
|
||||
| "deadlines.step2.happened.title"
|
||||
| "deadlines.step2.heading"
|
||||
| "deadlines.step3"
|
||||
| "deadlines.step3a.back"
|
||||
| "deadlines.step3a.draft.desc"
|
||||
| "deadlines.step3a.draft.title"
|
||||
| "deadlines.step3a.enter.desc"
|
||||
| "deadlines.step3a.enter.title"
|
||||
| "deadlines.step3a.file.desc"
|
||||
| "deadlines.step3a.file.title"
|
||||
| "deadlines.step3a.heading"
|
||||
| "deadlines.step3a.soon"
|
||||
| "deadlines.subtitle"
|
||||
| "deadlines.summary.completed"
|
||||
| "deadlines.summary.later"
|
||||
|
||||
@@ -7217,6 +7217,28 @@ input[type="range"]::-moz-range-thumb {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
/* Step 3a draft card — disabled placeholder for the future drafting
|
||||
* surface. Greyed out, no hover lift, "kommt bald" pill on the card. */
|
||||
.fristen-step2-card--soon {
|
||||
opacity: 0.55;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.fristen-step2-card--soon:hover {
|
||||
background: var(--color-bg, #fff);
|
||||
border-color: var(--color-border, #ddd);
|
||||
transform: none;
|
||||
}
|
||||
.fristen-step2-card-soon {
|
||||
align-self: flex-end;
|
||||
padding: 1px 6px;
|
||||
border-radius: 9999px;
|
||||
background: var(--color-bg-subtle, #f4f4f4);
|
||||
color: var(--color-muted, #666);
|
||||
font-size: 0.7rem;
|
||||
font-style: italic;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
/* Compact one-line summary that replaces the four proceeding-group
|
||||
* blocks once the user picks a Verfahren. m's 2026-05-08 18:26 ask. */
|
||||
.proceeding-summary {
|
||||
|
||||
Reference in New Issue
Block a user