Fix: Event session cold-start bug - presentations/presenters now load on first render

CRITICAL BUG FIX: Session view required 1-2 manual refreshes to display
presentations and presenters when IndexedDB was empty.

Root Cause:
- Nested loaders passed try_cache: false, preventing IDB writes
- Missing microtask yields caused race conditions between IDB writes
  and liveQuery subscriptions

Changes:
- ae_events__event_session.ts: Preserve try_cache in nested loads
- ae_events__event_presentation.ts: Block on presenter loads with await
  Promise.all() + preserve try_cache
- ae_events__event_presenter.ts: Add microtask yield after IDB write

Result: Presentations AND presenters now render correctly on first
navigation without requiring manual page refresh.
This commit is contained in:
Scott Idem
2026-02-26 13:40:36 -05:00
parent 9da3e5326b
commit 3849118fec
3 changed files with 49 additions and 28 deletions

View File

@@ -151,7 +151,7 @@ export async function load_ae_obj_li__event_presentation({
if (cached_li && cached_li.length > 0) {
// Background refresh (non-blocking)
_refresh_presentation_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, inc_presenter_li, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl: 0 });
// Warm cache for nested loads in the background (FIRE AND FORGET)
// DEPRECATED Optimization: Don't fire child loads for every item in a list here.
// Let the specific Presentation component handle its own children to stagger requests.
@@ -176,7 +176,7 @@ async function _refresh_presentation_li_background({ api_cfg, for_obj_type, for_
const result_li = await api.get_ae_obj_li_v3({ api_cfg, obj_type: 'event_presentation', for_obj_type, for_obj_id, enabled, hidden, view, limit, offset, order_by_li, log_lvl });
if (result_li) {
const processed = await process_ae_obj__event_presentation_props({ obj_li: result_li, log_lvl });
// Ensure the linking ID is set correctly for indexing
if (for_obj_type === 'event_session') {
processed.forEach(p => p.event_session_id = for_obj_id);
@@ -184,11 +184,20 @@ async function _refresh_presentation_li_background({ api_cfg, for_obj_type, for_
if (try_cache) {
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presentation', obj_li: processed, properties_to_save, log_lvl });
// CRITICAL FIX (2026-02-26): Yield to microtask queue so Dexie liveQuery observers
// fire before we return. Without this, component-mounted liveQueries may subscribe
// to IDB *before* the write completes, causing empty results on cold-start.
await Promise.resolve();
}
// CRITICAL FIX (2026-02-26): Block on nested loads when explicitly requested.
// Previously fire-and-forget (forEach without await), which meant the function returned
// before presenter data was loaded, causing "refresh twice" bug on cold-start.
// Now we await all nested loads AND preserve try_cache so presenters are written to IDB.
if (inc_file_li || inc_presenter_li) {
await Promise.all(processed.map(p =>
_handle_nested_loads(p, { api_cfg, inc_file_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl: 0 })
));
}
// Background nested loads for refreshed items (FIRE AND FORGET)
processed.forEach(p => {
_handle_nested_loads(p, { api_cfg, inc_file_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache: false, log_lvl: 0 });
});
return processed;
}
} catch (e) {}