export const SEARCH_RESULTS_SORT = Object.freeze({ RELEVANCE: "relevance", DATE_DESC: "date_desc", FILENAME_ASC: "filename_asc", }); function pad2(value) { return String(value || "").padStart(2, "0"); } /** * Build an ISO-like date key (YYYY-MM-DD) from a search item. * * Note: * - The backend guarantees year/month/day for search items. * - We still keep this defensive to avoid runtime crashes on malformed items. * * @param {any} item * @returns {string} */ export function toSearchItemIsoDateKey(item) { const y = String(item?.year || ""); const m = pad2(item?.month); const d = pad2(item?.day); return `${y}-${m}-${d}`; } /** * Format the search item date as German UI string: DD.MM.YYYY * * @param {any} item * @returns {string} */ export function formatSearchItemDateDe(item) { const y = String(item?.year || ""); const m = pad2(item?.month); const d = pad2(item?.day); return `${d}.${m}.${y}`; } /** * Sort search items according to the selected sort mode. * * Policy: * - RELEVANCE: keep backend order (we return a shallow copy to avoid accidental mutation) * - DATE_DESC: newest date first, then filename asc (stable & predictable) * - FILENAME_ASC: filename asc * * @param {any[]} items * @param {"relevance"|"date_desc"|"filename_asc"|string} sortMode * @returns {any[]} */ export function sortSearchItems(items, sortMode) { const arr = Array.isArray(items) ? [...items] : []; if (sortMode === SEARCH_RESULTS_SORT.RELEVANCE) return arr; if (sortMode === SEARCH_RESULTS_SORT.DATE_DESC) { return arr.sort((a, b) => { const da = toSearchItemIsoDateKey(a); const db = toSearchItemIsoDateKey(b); if (da !== db) return da < db ? 1 : -1; const fa = String(a?.filename || ""); const fb = String(b?.filename || ""); return fa.localeCompare(fb, "de"); }); } if (sortMode === SEARCH_RESULTS_SORT.FILENAME_ASC) { return arr.sort((a, b) => String(a?.filename || "").localeCompare(String(b?.filename || ""), "de") ); } // Unknown sort mode => fail-safe to backend order. return arr; }