diff --git a/client/src/components/LogEntryEditor.tsx b/client/src/components/LogEntryEditor.tsx index e234ad0..32b7444 100644 --- a/client/src/components/LogEntryEditor.tsx +++ b/client/src/components/LogEntryEditor.tsx @@ -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) diff --git a/client/src/services/csvExport.ts b/client/src/services/csvExport.ts index 7a569bf..b7c11e4 100644 --- a/client/src/services/csvExport.ts +++ b/client/src/services/csvExport.ts @@ -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, diff --git a/client/src/services/pdfExport.ts b/client/src/services/pdfExport.ts index a3b4638..bb2c4f5 100644 --- a/client/src/services/pdfExport.ts +++ b/client/src/services/pdfExport.ts @@ -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'); diff --git a/client/src/utils/logEntryPayload.ts b/client/src/utils/logEntryPayload.ts index e3b221a..7731ef5 100644 --- a/client/src/utils/logEntryPayload.ts +++ b/client/src/utils/logEntryPayload.ts @@ -17,6 +17,11 @@ export interface LogEventPayload { remarks: string } +/** Chronological order: earliest time first (HH:MM). */ +export function sortLogEventsByTime>(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 ({ ...e })) + events: sortLogEventsByTime(input.events.map((e) => ({ ...e }))) } if (input.trackDistanceNm !== undefined) payload.trackDistanceNm = input.trackDistanceNm