Standardized robust chronological sorting across modules.

Updated '_process_generic_props' in multiple libraries to ensure 'updated' timestamp always falls back to 'created_on' or epoch start, preventing null values from breaking newest-first ordering in IndexedDB.

Aligned Recovery Meetings and Archives list views to use these pre-computed sort keys for consistent UI behavior even when 'updated_on' is null.
This commit is contained in:
Scott Idem
2026-02-16 15:40:00 -05:00
parent fdfba0f752
commit f34e24aa02
8 changed files with 32 additions and 27 deletions

View File

@@ -388,7 +388,7 @@ async function _process_generic_props<T extends Record<string, any>>({ obj_li, o
const group = processed_obj.group ?? '0';
const priority = processed_obj.priority ? 1 : 0;
const sort = processed_obj.sort ?? '0';
const updated = processed_obj.updated_on ?? processed_obj.created_on;
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
const name = processed_obj.name ?? '';
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;

View File

@@ -814,7 +814,7 @@ async function _process_generic_props<T extends Record<string, any>>({
const group = processed_obj.group ?? '0';
const priority = processed_obj.priority ? 1 : 0;
const sort = processed_obj.sort ?? '0';
const updated = processed_obj.updated_on ?? processed_obj.created_on;
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
const name = processed_obj.name ?? '';
(processed_obj as any).tmp_sort_1 =

View File

@@ -943,7 +943,7 @@ async function _process_generic_props<T extends Record<string, any>>({
const group = processed_obj.group ?? '0';
const priority = processed_obj.priority ? 1 : 0;
const sort = processed_obj.sort ?? '0';
const updated = processed_obj.updated_on ?? processed_obj.created_on;
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
const name = processed_obj.name ?? '';
(processed_obj as any).tmp_sort_1 =

View File

@@ -512,7 +512,7 @@ async function _process_generic_props<T extends Record<string, any>>({
const group = processed_obj.group ?? '0';
const priority = processed_obj.priority ? 1 : 0;
const sort = processed_obj.sort ?? '0';
const updated = processed_obj.updated_on ?? processed_obj.created_on;
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
const name = processed_obj.username ?? processed_obj.name ?? '';
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;

View File

@@ -336,7 +336,7 @@ async function _process_generic_props<T extends Record<string, any>>({
const group = processed_obj.group ?? '0';
const priority = processed_obj.priority ? 1 : 0;
const sort = processed_obj.sort ?? '0';
const updated = processed_obj.updated_on ?? processed_obj.created_on;
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
const name = processed_obj.name ?? '';
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;

View File

@@ -43,9 +43,11 @@
const sortB = b.sort ?? 0;
if (sortA !== sortB) return sortB - sortA;
} else if (qry_sort_mode === 'updated_desc') {
const dateA = new Date(a.updated_on || a.created_on).getTime();
const dateB = new Date(b.updated_on || b.created_on).getTime();
return dateB - dateA;
// SORT: Most recently updated or created at the top (Refactored 2026-02-16)
// ROBUSTNESS: Ensure fallback to created_on then to 0 to prevent NaN comparison issues
const date_a = new Date(a.updated_on ?? a.created_on ?? 0).getTime() || 0;
const date_b = new Date(b.updated_on ?? b.created_on ?? 0).getTime() || 0;
return date_b - date_a;
}
// Default fallback: Name

View File

@@ -143,21 +143,15 @@
})
.toArray();
// Sort local results matching UI selection
// Sort local results matching UI selection (Refactored 2026-02-16)
if ($idaa_loc.recovery_meetings.qry__order_by === 'name') {
local_results.sort((a, b) =>
(a.name ?? '').localeCompare(b.name ?? '')
);
} else {
local_results.sort((a, b) => {
const dateA = a.updated_on
? new Date(a.updated_on).getTime()
: 0;
const dateB = b.updated_on
? new Date(b.updated_on).getTime()
: 0;
return dateB - dateA;
});
// Robust Chronological Sort using pre-computed tmp_sort_1
// Handles Priority, Manual Sort, and the updated_on/created_on fallback
local_results.sort((a, b) => (b.tmp_sort_1 ?? '').localeCompare(a.tmp_sort_1 ?? ''));
}
local_ids = local_results
@@ -226,6 +220,13 @@
return true;
});
// RE-SORT: Ensure perfect chronological order even if API puts NULLs last (Refactored 2026-02-16)
if ($idaa_loc.recovery_meetings.qry__order_by === 'name') {
api_results.sort((a, b) => (a.name ?? '').localeCompare(b.name ?? ''));
} else {
api_results.sort((a, b) => (b.tmp_sort_1 ?? '').localeCompare(a.tmp_sort_1 ?? ''));
}
const api_ids = api_results
.map((e: any) => String(e.id))
.filter(Boolean);

View File

@@ -78,17 +78,19 @@
.where(dq__where_type_id_val)
.equals(link_to_id);
if (order_by == 'name') {
return await base_query
.and((ev) => !ev.hide && !!ev.enable)
.limit(limit > 0 ? limit : 500)
.sortBy('name');
const results = await base_query
.and((ev) => !ev.hide && !!ev.enable)
.limit(limit > 0 ? limit : 500)
.toArray();
if (order_by === 'name') {
results.sort((a, b) => (a.name ?? '').localeCompare(b.name ?? ''));
} else {
return await base_query
.and((ev) => !ev.hide && !!ev.enable)
.limit(limit > 0 ? limit : 500)
.sortBy('updated_on');
// Robust Chronological Sort using pre-computed tmp_sort_1 (Refactored 2026-02-16)
// This handles Group > Priority > Manual Sort > Date (with updated_on fallback)
results.sort((a, b) => (b.tmp_sort_1 ?? '').localeCompare(a.tmp_sort_1 ?? ''));
}
return results;
}
return null;
});