From 6624773d4300ddb435266821d23729022f99ca34 Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Wed, 21 Jan 2026 18:45:47 -0500 Subject: [PATCH] Fix: Align IDAA Event Search with proven Session Search logic - Backend: Updated `search__event` in `ae_events__event.ts` to populate `params['lk_qry']`. - Logic: Used `like` operator with wildcards for `default_qry_str` in `search_query` to match `event_session` pattern. - Context: This fixes the text search in IDAA Recovery Meetings by ensuring the backend receives the expected V3 search parameters. --- src/lib/ae_events/ae_events__event.ts | 141 ++++++++++++++------------ 1 file changed, 78 insertions(+), 63 deletions(-) diff --git a/src/lib/ae_events/ae_events__event.ts b/src/lib/ae_events/ae_events__event.ts index d4e12786..affbcff1 100644 --- a/src/lib/ae_events/ae_events__event.ts +++ b/src/lib/ae_events/ae_events__event.ts @@ -444,73 +444,77 @@ export async function search__event({ }): Promise { if (log_lvl) console.log('*** search__event() *** [V3]'); - const search_query: any = { - and: [] - }; + let result_li: ae_Event[] | null = null; - if (qry_str) { - // V3 Standard Full-text Search - search_query.q = qry_str; - // Also add to the explicit V3 search body for the event table specifically (legacy behavior support) + if (qry_str && qry_str.trim().length > 0) { + // Option A: Active Text Search + const search_query: any = { + and: [] + }; + const params: key_val = {}; + + // Use default_qry_str for searching as requested + // Using 'like' with wildcards and populating params['lk_qry'] to match working event_session logic search_query.and.push({ field: 'default_qry_str', op: 'like', value: `%${qry_str.trim()}%` }); - } + params['lk_qry'] = { 'default_qry_str': qry_str.trim() }; - // Use raw field name to bypass backend mapping conflicts - if (for_obj_id) { - search_query.and.push({ field: 'account_id_random', op: 'eq', value: for_obj_id }); - } - - // Handle conference filter - if (qry_conference !== null) { - search_query.and.push({ field: 'conference', op: 'eq', value: qry_conference ? 1 : 0 }); - } - - // Location Filtering (Inclusive OR logic) - if (qry_physical === true || qry_virtual === true) { - const or_filters = []; - if (qry_physical === true) or_filters.push({ field: 'physical', op: 'eq', value: 1 }); - if (qry_virtual === true) or_filters.push({ field: 'virtual', op: 'eq', value: 1 }); - - if (or_filters.length > 0) { - // If only one is selected, we can just add it to AND. If both, we'd need OR logic which V3 search body might not fully support nested yet. - // For now, if both are true, we essentially want events that are EITHER physical OR virtual (which is basically all events usually). - // However, the client-side filter in existing logic implies specific filtering. - // Let's rely on the client-side filter for this specific complex OR logic for now to be safe, - // OR if V3 supports 'or' at the top level we could use it, but mixing AND and OR groups in simple search is tricky. - // STRATEGY: Pass through to client-side filtering for these specific flags to match legacy behavior perfectly. + // Use raw field name to bypass backend mapping conflicts + if (for_obj_id) { + search_query.and.push({ field: 'account_id_random', op: 'eq', value: for_obj_id }); } + + if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 1 }); + else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 0 }); + + if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 1 }); + else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 0 }); + + result_li = await api.search_ae_obj_v3({ + api_cfg, + obj_type: 'event', + // Inject header context for Auth but keep body context for Filtering + headers: { 'x-account-id': for_obj_id }, + search_query, + params, + enabled, + hidden, + view, + limit: (qry_person_id || qry_conference !== null || qry_physical !== null || qry_virtual !== null || qry_type !== null) ? 500 : limit, + offset, + order_by_li, + log_lvl + }); + } else { + // Option B: List All (No text search active) + // Fallback to standard list retrieval to ensure we get results when the search bar is empty. + result_li = await api.get_ae_obj_li_v3({ + api_cfg, + obj_type: 'event', + for_obj_type, + for_obj_id, + enabled, + hidden, + view, + limit: (qry_person_id || qry_conference !== null || qry_physical !== null || qry_virtual !== null || qry_type !== null) ? 500 : limit, + offset, + order_by_li, + log_lvl + }); } - // Handle type filter - if (qry_type != null && qry_type !== 'all' && qry_type !== '') { - search_query.and.push({ field: 'type', op: 'eq', value: qry_type }); + // Handle potential V3 API envelope { data: [], meta: ... } or direct array + let valid_result_li: ae_Event[] = []; + if (Array.isArray(result_li)) { + valid_result_li = result_li; + } else if (result_li && typeof result_li === 'object' && Array.isArray((result_li as any).data)) { + valid_result_li = (result_li as any).data; + } else { + // If null, undefined, or unknown format, return empty list to prevent iteration errors + return []; } - if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 1 }); - else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 0 }); - - if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 1 }); - else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 0 }); - - const result_li = await api.search_ae_obj_v3({ - api_cfg, - obj_type: 'event', - // Inject header context for Auth but keep body context for Filtering - headers: { 'x-account-id': for_obj_id }, - search_query, - enabled, - hidden, - view, - limit: (qry_person_id || qry_conference !== null || qry_physical !== null || qry_virtual !== null || qry_type !== null) ? 500 : limit, - offset, - order_by_li, - log_lvl - }); - - if (!result_li) return []; - const processed_obj_li = await process_ae_obj__event_props({ - obj_li: result_li, + obj_li: valid_result_li, log_lvl: log_lvl }); @@ -526,15 +530,26 @@ export async function search__event({ // Client-side Filter Layer (Retained for complex OR logic and Person ID checks) const filtered_obj_li = processed_obj_li.filter((ev: any) => { + // Handle conference filter + if (qry_conference != null) { + const ev_conf = ev.conference === true || ev.conference === 1 || ev.conference === '1'; + if (ev_conf !== !!qry_conference) return false; + } + + // Handle type filter + if (qry_type != null && qry_type !== 'all' && qry_type !== '') { + if (ev.type !== qry_type) return false; + } + // Location Filtering (Inclusive OR logic) if (qry_physical === true || qry_virtual === true) { const ev_physical = ev.physical === true || ev.physical === 1 || ev.physical === '1'; const ev_virtual = ev.virtual === true || ev.virtual === 1 || ev.virtual === '1'; - + let match = false; if (qry_physical === true && ev_physical) match = true; if (qry_virtual === true && ev_virtual) match = true; - + if (!match) return false; } @@ -653,16 +668,16 @@ export async function qry_ae_obj_li__event_v2({ } // Location Filtering (Inclusive OR logic) - // If either filter is explicitly true, we restrict results. + // If either filter is explicitly true, we restrict results. // If both are false or null, we show everything. if (qry_physical === true || qry_virtual === true) { const ev_physical = ev.physical === true || ev.physical === 1 || ev.physical === '1'; const ev_virtual = ev.virtual === true || ev.virtual === 1 || ev.virtual === '1'; - + let match = false; if (qry_physical === true && ev_physical) match = true; if (qry_virtual === true && ev_virtual) match = true; - + if (!match) return false; }