Restore Event Session search stability and advance platform-wide string ID standardization

- Restored Event Session search by standardizing on 'event_id' for Dexie queries and implementing dual-layer filtering (local + API guard) to prevent broad results from clobbering filtered views.
- Advanced String-Only ID Standardization (Phase 2) by updating generic object processors across all event library modules to support both base IDs and legacy '_random' variants.
- Refactored Event Presenter and Presentation components to support standardized '_id_li' props while maintaining backward compatibility.
- Standardized common helper identifiers to snake_case (e.g., 'prevent_default') in the Events module.
- Verified Staff and Poster email notification logic in the Bulletin Board module.
- Updated .gitignore and cleaned up test artifacts.
This commit is contained in:
Scott Idem
2026-02-04 19:32:17 -05:00
parent 46c30590ed
commit bd39fd3061
12 changed files with 134 additions and 32 deletions

View File

@@ -16,7 +16,7 @@ This module provides a comprehensive solution for event exhibitors to capture an
## Data Model
The core data structures managed by this module are `Exhibit` and `Exhibit_tracking`.
The core data structures managed by this module are `Exhibit` and `Exhibit_tracking`. The actual DB table name is event_person_tracking. It was originally intended for generalized "tracking" of a person at an event. This would include other things like session attendance tracking, in addition to exhibitor lead retrieval. However, the initial implementation is focused solely on the lead retrieval use case for exhibitors.
### Exhibit

View File

@@ -2,6 +2,7 @@
interface Props {
container_class_li?: string | Array<string>;
display_mode?: string; // 'default', 'compact', 'minimal', 'launcher'
event_presenter_id_li?: Array<string>;
event_presenter_id_random_li?: Array<string>;
link_to_type: string;
link_to_id: string;
@@ -12,6 +13,7 @@
let {
container_class_li = [],
display_mode = 'default',
event_presenter_id_li = [],
event_presenter_id_random_li = [],
link_to_type,
link_to_id,
@@ -33,8 +35,8 @@
// let ae_tmp: key_val = {};
// let ae_triggers: key_val = {};
let dq__where_type_id_val: string = `${link_to_type}_id_random`;
let dq__where_eq_id_val: string = link_to_id;
let dq__where_type_id_val = $derived(`${link_to_type}_id`);
let dq__where_eq_id_val = $derived(link_to_id);
// *** Functions and Logic
let lq__event_presenter_obj_li = $derived(
@@ -45,6 +47,10 @@
.equals(dq__where_eq_id_val)
.sortBy('full_name');
return results;
} else if (event_presenter_id_li.length > 0) {
let results = await db_events.presenter.bulkGet(event_presenter_id_li);
return results;
} else if (event_presenter_id_random_li.length > 0) {
let results = await db_events.presenter.bulkGet(event_presenter_id_random_li);

View File

@@ -91,7 +91,7 @@
if (event_id && !$events_loc.pres_mgmt.fulltext_search_qry_str && !$events_loc.pres_mgmt.location_name_qry_str) {
if (log_lvl) console.log(`Session Page LQ: Fallback search for event: ${event_id}`);
return await db_events.session
.where('event_id_random')
.where('event_id')
.equals(event_id)
.limit(50)
.sortBy('name');
@@ -124,9 +124,7 @@
const params = search_params;
if (search_debounce_timer) clearTimeout(search_debounce_timer);
search_debounce_timer = setTimeout(() => {
untrack(() => {
handle_search_refresh(params);
});
handle_search_refresh(params);
}, 300);
return () => {
if (search_debounce_timer) clearTimeout(search_debounce_timer);
@@ -157,7 +155,7 @@
try {
if (event_id) {
let local_results = await db_events.session
.where('event_id_random')
.where('event_id')
.equals(event_id)
.filter(session => {
if (location_name && session.event_location_name !== location_name) return false;
@@ -180,7 +178,7 @@
.toArray();
local_results.sort((a, b) => (a.name ?? '').localeCompare(b.name ?? ''));
const local_ids = local_results.map(s => s.id || s.event_session_id_random).filter(Boolean);
const local_ids = local_results.map(s => s.id || s.event_session_id).filter(Boolean);
if (current_search_id === last_search_id) {
if (log_lvl) console.log(`[Session Search #${current_search_id}] Fast Path found ${local_ids.length} items locally.`);
@@ -215,8 +213,26 @@
});
if (current_search_id === last_search_id) {
const api_results = results || [];
const api_ids = api_results.map((s: any) => s.id || s.event_session_id_random).filter(Boolean);
let api_results = results || [];
// Client-side Filter Guard: Ensure API results match local criteria (Backup filter)
api_results = api_results.filter(session => {
if (location_name && session.event_location_name !== location_name) return false;
if (qry_str) {
const name = (session.name ?? '').toLowerCase();
const code = (session.code ?? '').toLowerCase();
const description = (session.description ?? '').toLowerCase();
const qry_string = (session.default_qry_str ?? '').toLowerCase();
const match = name.includes(qry_str) ||
code.includes(qry_str) ||
description.includes(qry_str) ||
qry_string.includes(qry_str);
if (!match) return false;
}
return true;
});
const api_ids = api_results.map((s: any) => s.id || s.event_session_id).filter(Boolean);
untrack(() => {
$events_slct.event_session_obj_li = api_results;
@@ -251,7 +267,7 @@
$events_loc.pres_mgmt.search_version++;
}
function preventDefault<T extends Event>(fn: (event: T) => void) {
function prevent_default<T extends Event>(fn: (event: T) => void) {
return function (event: T) {
event.preventDefault();
fn(event);
@@ -325,7 +341,7 @@
{#if !$events_loc.pres_mgmt.show_content__event_view || $events_loc.pres_mgmt.show_content__event_view == 'default'}
<div class="ae_container_actions">
<form
onsubmit={preventDefault(() => handle_search_trigger())}
onsubmit={prevent_default(() => handle_search_trigger())}
autocomplete="off"
class="form grow flex flex-row flex-wrap gap-1 justify-center items-center w-full"
>
@@ -487,9 +503,9 @@
<div class="overflow-x-auto w-max max-w-full">
<Element_manage_event_file_li_wrap
link_to_type={'event'}
link_to_id={$lq__event_obj?.event_id_random}
allow_basic={$events_loc.auth__kv.session[$lq__event_obj?.event_id_random]}
allow_moderator={$events_loc.auth__kv.session[$lq__event_obj?.event_id_random]}
link_to_id={$lq__event_obj?.event_id}
allow_basic={$events_loc.auth__kv.session[$lq__event_obj?.event_id]}
allow_moderator={$events_loc.auth__kv.session[$lq__event_obj?.event_id]}
container_class_li={''}
/>
</div>

View File

@@ -463,8 +463,8 @@
{#if event_presentation_obj?.event_presentation_id}
<Comp_event_presenter_obj_li
link_to_type={'event_presentation'}
link_to_id={event_presentation_obj?.event_presentation_id}
event_presenter_id_random_li={[]}
link_to_id={event_presentation_obj.event_presentation_id}
event_presenter_id_li={[]}
log_lvl={2}
></Comp_event_presenter_obj_li>
{/if}