fix(logs): Ereignisprotokoll chronologisch nach Uhrzeit sortieren

Einträge werden beim Laden, Speichern und Export älteste-oben angezeigt (sortLogEventsByTime).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-30 19:05:46 +02:00
parent 2e83f1c6bb
commit 258fee31ab
4 changed files with 15 additions and 8 deletions
+5 -5
View File
@@ -20,7 +20,7 @@ import {
hasAnySignature
} from '../utils/signatures.js'
import type { SignatureValue } from '../types/signatures.js'
import { buildLogEntryPayload, type LogEventPayload } from '../utils/logEntryPayload.js'
import { buildLogEntryPayload, sortLogEventsByTime, type LogEventPayload } from '../utils/logEntryPayload.js'
import { hashEntryForSigning } from '../utils/entryCanonicalHash.js'
import { signLogEntry } from '../services/entrySigning.js'
import { getLogbookAccess } from '../services/logbookAccess.js'
@@ -483,7 +483,7 @@ export default function LogEntryEditor({
setSignSkipper(normalizeSignature(preloadedEntry.signSkipper) || '')
setSignCrew(normalizeSignature(preloadedEntry.signCrew) || '')
loadTrackStatsFromEntry(preloadedEntry)
setEvents(preloadedEntry.events || [])
setEvents(sortLogEventsByTime(preloadedEntry.events || []))
setSavedFingerprint(fingerprintFromStoredEntry(preloadedEntry))
return
}
@@ -516,7 +516,7 @@ export default function LogEntryEditor({
setSignSkipper(normalizeSignature(decrypted.signSkipper) || '')
setSignCrew(normalizeSignature(decrypted.signCrew) || '')
loadTrackStatsFromEntry(decrypted)
setEvents(decrypted.events || [])
setEvents(sortLogEventsByTime(decrypted.events || []))
setSavedFingerprint(fingerprintFromStoredEntry(decrypted))
}
}
@@ -871,7 +871,7 @@ export default function LogEntryEditor({
if (editingEventIndex !== null) {
const hadSkipperSignature = !!signSkipper
markSkipperSignatureClearedForEventChange()
nextEvents = events.map((ev, idx) => (idx === editingEventIndex ? eventData : ev))
nextEvents = sortLogEventsByTime(events.map((ev, idx) => (idx === editingEventIndex ? eventData : ev)))
if (hadSkipperSignature) {
void showAlertRef.current(
t('logs.sign_cleared_skipper_re_sign'),
@@ -879,7 +879,7 @@ export default function LogEntryEditor({
)
}
} else {
nextEvents = [...events, eventData]
nextEvents = sortLogEventsByTime([...events, eventData])
}
setEvents(nextEvents)
+2 -1
View File
@@ -3,6 +3,7 @@ import { getActiveMasterKey } from './auth.js'
import { getLogbookKey } from './logbookKeys.js'
import { decryptJson } from './crypto.js'
import { formatSignatureForExport, normalizeSignature } from '../utils/signatures.js'
import { sortLogEventsByTime } from '../utils/logEntryPayload.js'
import i18n from '../i18n/index.js'
function escapeCsvValue(val: string | number | undefined | null): string {
@@ -134,7 +135,7 @@ export async function exportLogbookToCsv(logbookId: string, preloadedData?: { ya
].map(escapeCsvValue));
} else {
// Sort events chronologically by time
const sortedEvents = [...eventsList].sort((a, b) => (a.time || '').localeCompare(b.time || ''));
const sortedEvents = sortLogEventsByTime(eventsList);
for (const ev of sortedEvents) {
rows.push([
dateVal, travelDay, dep, dest,
+2 -1
View File
@@ -4,6 +4,7 @@ import { getActiveMasterKey } from './auth.js'
import { getLogbookKey } from './logbookKeys.js'
import { decryptJson } from './crypto.js'
import { isSignatureImage, isPasskeySignature } from '../utils/signatures.js'
import { sortLogEventsByTime } from '../utils/logEntryPayload.js'
import i18n from '../i18n/index.js'
function formatPasskeySignDate(signedAt: string): string {
@@ -132,7 +133,7 @@ export async function generateLogbookPagePdf(logbookId: string, entryId: string,
// Draw Data Rows
const events = entry.events || [];
const maxRows = 16;
const sortedEvents = [...events].sort((a: any, b: any) => (a.time || '').localeCompare(b.time || ''));
const sortedEvents = sortLogEventsByTime(events);
doc.setFont('Helvetica', 'normal');
+6 -1
View File
@@ -17,6 +17,11 @@ export interface LogEventPayload {
remarks: string
}
/** Chronological order: earliest time first (HH:MM). */
export function sortLogEventsByTime<T extends Pick<LogEventPayload, 'time'>>(events: T[]): T[] {
return [...events].sort((a, b) => (a.time || '').localeCompare(b.time || ''))
}
export interface LogEntryPayloadInput {
date: string
dayOfTravel: string
@@ -38,7 +43,7 @@ export function buildLogEntryPayload(input: LogEntryPayloadInput): Record<string
destination: input.destination.trim(),
freshwater: { ...input.freshwater },
fuel: { ...input.fuel },
events: input.events.map((e) => ({ ...e }))
events: sortLogEventsByTime(input.events.map((e) => ({ ...e })))
}
if (input.trackDistanceNm !== undefined) payload.trackDistanceNm = input.trackDistanceNm