fix(fristenrechner/columns): preserve sequence_order for undated events
Undated events (Urteil, Beschluss, court-set placeholders) were keyed by the empty string and collapsed into a single trailing row, so Urteil and Berufungseinlegung ended up adjacent even though Urteil precedes Berufung in the proceeding's sequence_order. Each undated event now gets its own row keyed by its index in the backend response (which is already sorted by sequence_order), and dated/unscheduled keys are sorted into separate buckets before concatenation so the dateless tail still sits below the dated rows. Refs #14 (section D).
This commit is contained in:
@@ -601,13 +601,15 @@ function renderTimelineBody(data: DeadlineResponse): string {
|
||||
// (defendant). Each grid row corresponds to a distinct dueDate, so events on
|
||||
// the same day line up across columns. Deadlines with party=both render in
|
||||
// BOTH the Proactive and Reactive cells of their row with a "beide Seiten"
|
||||
// caption so the duplication is legible as intentional. Court-set / dateless
|
||||
// rows collapse into a single trailing row at the bottom.
|
||||
// caption so the duplication is legible as intentional. Undated events
|
||||
// (Urteil, Beschluss, court-set placeholders) trail the dated rows; each
|
||||
// gets its own row in the backend's sequence_order so e.g. Urteil precedes
|
||||
// Berufungseinlegung visually instead of stacking in one bucket.
|
||||
function renderColumnsBody(data: DeadlineResponse): string {
|
||||
type Cell = CalculatedDeadline[];
|
||||
type Row = { proactive: Cell; court: Cell; reactive: Cell };
|
||||
|
||||
const NO_DATE = "";
|
||||
const UNSCHEDULED_PREFIX = "__unscheduled__";
|
||||
const rowsMap = new Map<string, Row>();
|
||||
const ensureRow = (key: string): Row => {
|
||||
let r = rowsMap.get(key);
|
||||
@@ -618,8 +620,11 @@ function renderColumnsBody(data: DeadlineResponse): string {
|
||||
return r;
|
||||
};
|
||||
|
||||
for (const dl of data.deadlines) {
|
||||
const key = dl.dueDate || NO_DATE;
|
||||
data.deadlines.forEach((dl, idx) => {
|
||||
// Dated rows share a row by date; undated rows each get their own row,
|
||||
// keyed by index so the backend's sequence_order is preserved in the
|
||||
// dateless tail.
|
||||
const key = dl.dueDate || `${UNSCHEDULED_PREFIX}${String(idx).padStart(4, "0")}`;
|
||||
const row = ensureRow(key);
|
||||
switch (dl.party) {
|
||||
case "claimant":
|
||||
@@ -640,16 +645,22 @@ function renderColumnsBody(data: DeadlineResponse): string {
|
||||
// Unknown party: keep visible by parking in the Court column.
|
||||
row.court.push(dl);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort row keys chronologically; the dateless bucket (court-set rows) sinks
|
||||
// to the bottom because it has no temporal anchor.
|
||||
const keys = Array.from(rowsMap.keys()).sort((a, b) => {
|
||||
if (a === NO_DATE) return 1;
|
||||
if (b === NO_DATE) return -1;
|
||||
return a < b ? -1 : a > b ? 1 : 0;
|
||||
});
|
||||
|
||||
// Dated keys (YYYY-MM-DD) sort chronologically by lexicographic compare.
|
||||
// Unscheduled keys carry the sequence-order index in their padded suffix
|
||||
// so they likewise sort by source order. Concatenate so the dateless tail
|
||||
// sits below the dated rows.
|
||||
const datedKeys: string[] = [];
|
||||
const unscheduledKeys: string[] = [];
|
||||
for (const k of rowsMap.keys()) {
|
||||
if (k.startsWith(UNSCHEDULED_PREFIX)) unscheduledKeys.push(k);
|
||||
else datedKeys.push(k);
|
||||
}
|
||||
datedKeys.sort();
|
||||
unscheduledKeys.sort();
|
||||
const keys = [...datedKeys, ...unscheduledKeys];
|
||||
|
||||
const renderCell = (items: CalculatedDeadline[]): string => {
|
||||
if (items.length === 0) {
|
||||
return `<div class="fr-col-cell fr-col-cell--empty"></div>`;
|
||||
|
||||
Reference in New Issue
Block a user