feat(projects-form): "Wir vertreten" select for our_side (t-paliad-164 slice 2)

ProjectFormFields gains a fifth select between case-specific block and
the description textarea: "Wir vertreten" with options claimant /
defendant / court / both / "" (the unset sentinel labelled
"Unbekannt / nicht gesetzt"). Type-agnostic — every project type
carries it because the Determinator picks it up regardless. Form-hint
explains it predefines the Determinator perspective and stays
overridable.

client/project-form.ts: readPayload writes our_side as a normal
stringField (empty string in edit mode clears the column via the
nullableOurSide helper on the service); prefillForm hydrates the
select from p.our_side. Both gate on tryGet so /projects/new (which
shares the form) still loads if the field is later removed.

i18n already in slice 1; this commit only wires the markup +
client logic.
This commit is contained in:
m
2026-05-08 21:55:00 +02:00
parent 188d8ec9ba
commit 5d9c62d858
2 changed files with 28 additions and 0 deletions

View File

@@ -29,6 +29,7 @@ export interface ProjectFormState {
grantDate: string;
court: string;
caseNumber: string;
ourSide: string;
}
let parentCandidates: ProjectMini[] = [];
@@ -178,6 +179,17 @@ export function readPayload(
stringField("project-case-number", "case_number");
}
// our_side is type-agnostic — every project type can carry "Wir
// vertreten" because the Determinator picks it up regardless of
// type. The select uses "" for the unset option; the service maps
// empty string to NULL via nullableOurSide.
const osSel = tryGet("project-our-side") as HTMLSelectElement | null;
if (osSel) {
const v = osSel.value.trim();
if (v) payload.our_side = v;
else if (!opts.omitEmpty) payload.our_side = "";
}
const desc = ($("project-description") as HTMLTextAreaElement).value.trim();
if (desc) payload.description = desc;
else if (!opts.omitEmpty) payload.description = "";
@@ -214,6 +226,8 @@ export function prefillForm(p: Record<string, unknown>) {
get("project-grant-date").value = isoToDate(p.grant_date as string | null | undefined);
get("project-court").value = String(p.court ?? "");
get("project-case-number").value = String(p.case_number ?? "");
const osSel = tryGet("project-our-side") as HTMLSelectElement | null;
if (osSel) osSel.value = String(p.our_side ?? "");
getTA("project-description").value = String(p.description ?? "");
getSel("project-status").value = String(p.status ?? "active");
}

View File

@@ -153,6 +153,20 @@ export function ProjectFormFields(): string {
</div>
</div>
<div className="form-field">
<label htmlFor="project-our-side" data-i18n="projects.field.our_side">Wir vertreten</label>
<select id="project-our-side">
<option value="" data-i18n="projects.field.our_side.unset">Unbekannt / nicht gesetzt</option>
<option value="claimant" data-i18n="projects.field.our_side.claimant">Kl&auml;gerseite</option>
<option value="defendant" data-i18n="projects.field.our_side.defendant">Beklagtenseite</option>
<option value="court" data-i18n="projects.field.our_side.court">Gericht / Tribunal</option>
<option value="both" data-i18n="projects.field.our_side.both">Beide Seiten</option>
</select>
<p className="form-hint" data-i18n="projects.field.our_side.hint">
Bestimmt die Voreinstellung der Perspektive im Fristenrechner-Determinator. L&auml;sst sich dort jederzeit &uuml;berschreiben.
</p>
</div>
<div className="form-field">
<label htmlFor="project-description" data-i18n="projects.field.description">Notizen</label>
<textarea id="project-description" rows={4} placeholder="Kurznotizen zum Projekt (optional)..." data-i18n-placeholder="projects.field.description.placeholder" />