export interface JournalEntrySearchParams { str?: string; cat?: string | null; enabled?: 'enabled' | 'all' | 'not_enabled'; hidden?: 'hidden' | 'all' | 'not_hidden'; limit?: number; } function normalize_search_value(value: unknown): string { if (value === null || value === undefined) return ''; if (typeof value === 'string') return value.toLowerCase(); if (typeof value === 'number' || typeof value === 'boolean') { return String(value).toLowerCase(); } try { return JSON.stringify(value).toLowerCase(); } catch { return String(value).toLowerCase(); } } function build_journal_entry_search_blob(entry: any): string { return [ entry?.code, entry?.name, entry?.short_name, entry?.summary, entry?.outline, entry?.content, entry?.history, entry?.notes, entry?.tags, entry?.activity_code, entry?.category_code, entry?.type_code, entry?.topic_code, entry?.group, entry?.journal_code, entry?.journal_name, entry?.alert_msg, entry?.default_qry_str ] .map(normalize_search_value) .filter(Boolean) .join(' '); } export function journal_entry_matches_search( entry: any, params: JournalEntrySearchParams ): boolean { if (!entry) return false; const qry_str = (params.str ?? '').toLowerCase().trim(); const category_code = params.cat ?? ''; const enabled_mode = params.enabled ?? 'all'; const hidden_mode = params.hidden ?? 'all'; const is_hidden = entry.hide === true || entry.hide === 1; const is_disabled = entry.enable === false || entry.enable === 0; if (category_code && entry.category_code !== category_code) return false; if (enabled_mode === 'enabled' && is_disabled) return false; if (enabled_mode === 'not_enabled' && !is_disabled) return false; if (hidden_mode === 'hidden' && !is_hidden) return false; if (hidden_mode === 'not_hidden' && is_hidden) return false; if (!qry_str) return true; return build_journal_entry_search_blob(entry).includes(qry_str); } export function journal_entry_compare_for_list(a: any, b: any): number { // tmp_sort_1 is built by build_tmp_sort() for ascending comparison: // priority=true encodes as '0', priority=false as '1', so ASC puts priority first. return ( (a?.tmp_sort_1 ?? '').localeCompare(b?.tmp_sort_1 ?? '') || (b?.updated_on ?? '').localeCompare(a?.updated_on ?? '') || (b?.journal_entry_id ?? '').localeCompare(a?.journal_entry_id ?? '') ); } export function journal_entry_filter_list( list: any[] | null | undefined, params: JournalEntrySearchParams ): any[] | null { if (list === undefined || list === null) return null; if (!Array.isArray(list)) return []; const has_text_search = Boolean((params.str ?? '').trim()); const filtered = list .filter((entry) => journal_entry_matches_search(entry, params)) .sort(journal_entry_compare_for_list); // Broad views should show the full local result set; only text searches // should be sliced to a page-sized window. if (has_text_search && params.limit && params.limit > 0) { return filtered.slice(0, params.limit); } return filtered; }