feat(leads): implement reactive search for exhibitors and lead tracking
- Implemented V3-style reactive search (Local Cache -> Remote Revalidation) for exhibitors. - Standardized search fields to 'name' for Exhibits and 'event_badge_full_name' for Lead Tracking. - Refactored Leads UI with standardized search components and grid layout. - Updated event routing to exclusively use string-based IDs (Triple-ID pattern). - Hardened 'ae_EventSession' type definitions to handle null values from V3 API/Dexie.
This commit is contained in:
@@ -104,7 +104,7 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
}
|
||||
const randomIdKey = `${obj_type}_id_random`;
|
||||
if (processed_obj[randomIdKey]) {
|
||||
(processed_obj as any).id = processed_obj[randomIdKey];
|
||||
(processed_obj as any).id = String(processed_obj[randomIdKey]);
|
||||
}
|
||||
|
||||
const group = processed_obj.group ?? '0';
|
||||
@@ -514,4 +514,179 @@ export async function download_export__event_exhibit_tracking({
|
||||
auto_download: true,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
// Updated 2026-01-28 to V3
|
||||
export async function search__exhibit_tracking({
|
||||
api_cfg,
|
||||
event_exhibit_id,
|
||||
fulltext_search_qry_str = null,
|
||||
enabled = 'enabled',
|
||||
hidden = 'all',
|
||||
order_by_li = { created_on: 'DESC' },
|
||||
limit = 100,
|
||||
offset = 0,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_exhibit_id: string;
|
||||
fulltext_search_qry_str?: string | null;
|
||||
enabled?: 'enabled' | 'all' | 'not_enabled';
|
||||
hidden?: 'hidden' | 'all' | 'not_hidden';
|
||||
order_by_li?: any;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventExhibitTracking[]> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** search__exhibit_tracking() *** exhibit_id=${event_exhibit_id} ft=${fulltext_search_qry_str}`);
|
||||
}
|
||||
|
||||
const search_query: any = {
|
||||
q: '',
|
||||
and: []
|
||||
};
|
||||
|
||||
const params: key_val = {};
|
||||
|
||||
if (fulltext_search_qry_str && fulltext_search_qry_str.trim().length > 0) {
|
||||
const qry = fulltext_search_qry_str.trim();
|
||||
// Search across badge name and notes
|
||||
search_query.and.push({ field: 'event_badge_full_name', op: 'like', value: `%${qry}%` });
|
||||
params['lk_qry'] = { event_badge_full_name: qry };
|
||||
}
|
||||
|
||||
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 });
|
||||
|
||||
try {
|
||||
const result_get = await api.search_ae_obj_v3({
|
||||
api_cfg,
|
||||
obj_type: 'event_exhibit_tracking',
|
||||
for_obj_type: 'event_exhibit',
|
||||
for_obj_id: event_exhibit_id,
|
||||
search_query,
|
||||
params,
|
||||
order_by_li,
|
||||
limit,
|
||||
offset,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
let result_li: ae_EventExhibitTracking[] = [];
|
||||
if (Array.isArray(result_get)) {
|
||||
result_li = result_get;
|
||||
} else if (result_get?.data && Array.isArray(result_get.data)) {
|
||||
result_li = result_get.data;
|
||||
}
|
||||
|
||||
if (result_li.length > 0) {
|
||||
const processed_obj_li = await process_ae_obj__exhibit_tracking_props({
|
||||
obj_li: result_li,
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'exhibit_tracking',
|
||||
obj_li: processed_obj_li,
|
||||
properties_to_save: properties_to_save_exhibit_tracking,
|
||||
log_lvl
|
||||
});
|
||||
return processed_obj_li;
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('search__exhibit_tracking V3 Request failed.', error);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
// Updated 2026-01-28 to V3
|
||||
export async function search__exhibit({
|
||||
api_cfg,
|
||||
event_id,
|
||||
fulltext_search_qry_str = null,
|
||||
enabled = 'enabled',
|
||||
hidden = 'not_hidden',
|
||||
order_by_li = { name: 'ASC' },
|
||||
limit = 100,
|
||||
offset = 0,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
fulltext_search_qry_str?: string | null;
|
||||
enabled?: 'enabled' | 'all' | 'not_enabled';
|
||||
hidden?: 'hidden' | 'all' | 'not_hidden';
|
||||
order_by_li?: any;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventExhibit[]> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** search__exhibit() *** event_id=${event_id} ft=${fulltext_search_qry_str}`);
|
||||
}
|
||||
|
||||
const search_query: any = {
|
||||
q: '',
|
||||
and: []
|
||||
};
|
||||
|
||||
const params: key_val = {};
|
||||
|
||||
if (fulltext_search_qry_str && fulltext_search_qry_str.trim().length > 0) {
|
||||
const qry = fulltext_search_qry_str.trim();
|
||||
search_query.and.push({ field: 'name', op: 'like', value: `%${qry}%` });
|
||||
params['lk_qry'] = { name: qry };
|
||||
}
|
||||
|
||||
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 });
|
||||
|
||||
try {
|
||||
const result_get = await api.search_ae_obj_v3({
|
||||
api_cfg,
|
||||
obj_type: 'event_exhibit',
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
search_query,
|
||||
params,
|
||||
order_by_li,
|
||||
limit,
|
||||
offset,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
let result_li: ae_EventExhibit[] = [];
|
||||
if (Array.isArray(result_get)) {
|
||||
result_li = result_get;
|
||||
} else if (result_get?.data && Array.isArray(result_get.data)) {
|
||||
result_li = result_get.data;
|
||||
}
|
||||
|
||||
if (result_li.length > 0) {
|
||||
const processed_obj_li = await process_ae_obj__exhibit_props({
|
||||
obj_li: result_li,
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'exhibit',
|
||||
obj_li: processed_obj_li,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
return processed_obj_li;
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('search__exhibit V3 Request failed.', error);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
@@ -9,6 +9,8 @@ import * as event_file from '$lib/ae_events/ae_events__event_file';
|
||||
import {
|
||||
load_ae_obj_id__exhibit,
|
||||
load_ae_obj_li__exhibit,
|
||||
search__exhibit,
|
||||
search__exhibit_tracking,
|
||||
load_ae_obj_id__exhibit_tracking,
|
||||
load_ae_obj_li__exhibit_tracking,
|
||||
create_ae_obj__exhibit_tracking,
|
||||
@@ -68,8 +70,10 @@ const export_obj = {
|
||||
// Event Exhibits
|
||||
handle_load_ae_obj_id__exhibit: load_ae_obj_id__exhibit,
|
||||
handle_load_ae_obj_li__exhibit: load_ae_obj_li__exhibit,
|
||||
search__exhibit: search__exhibit,
|
||||
handle_load_ae_obj_id__exhibit_tracking: load_ae_obj_id__exhibit_tracking,
|
||||
handle_load_ae_obj_li__exhibit_tracking: load_ae_obj_li__exhibit_tracking,
|
||||
search__exhibit_tracking: search__exhibit_tracking,
|
||||
handle_create_ae_obj__exhibit_tracking: create_ae_obj__exhibit_tracking,
|
||||
handle_update_ae_obj__exhibit_tracking: update_ae_obj__exhibit_tracking,
|
||||
handle_download_export__event_exhibit_tracking: download_export__event_exhibit_tracking,
|
||||
|
||||
@@ -209,6 +209,18 @@ const events_local_data_struct: key_val = {
|
||||
|
||||
refresh_interval__tracking_li: 30000, // 30 seconds
|
||||
|
||||
// Standardized Search Pattern 2026-01-28
|
||||
search_version: 0,
|
||||
qry__remote_first: false,
|
||||
qry__search_text: '',
|
||||
qry__sort_order: 'name_asc',
|
||||
|
||||
// Standardized Search Pattern (Tracking) 2026-01-28
|
||||
tracking__search_version: 0,
|
||||
tracking__qry__remote_first: false,
|
||||
tracking__qry__search_text: '',
|
||||
tracking__qry__sort_order: 'created_desc',
|
||||
|
||||
// The entered_passcode is the exhibit booths shared passcode for staff. This is used to initially access the lead retrieval service.
|
||||
entered_passcode: null,
|
||||
|
||||
@@ -696,4 +708,4 @@ const tmp__events_trig_kv: key_val = {};
|
||||
// 'a-rand-id-6': Promise.resolve('This is a test promise.'),
|
||||
// },
|
||||
// };
|
||||
export const events_trig_kv = writable(tmp__events_trig_kv);
|
||||
export const events_trig_kv = writable(tmp__events_trig_kv);
|
||||
@@ -550,22 +550,22 @@ export interface ae_EventSession extends ae_BaseObj {
|
||||
event_session_id_random: string;
|
||||
event_id: string;
|
||||
event_id_random: string;
|
||||
event_location_id?: string;
|
||||
event_location_id_random?: string;
|
||||
event_track_id?: string;
|
||||
event_track_id_random?: string;
|
||||
event_location_id?: string | null;
|
||||
event_location_id_random?: string | null;
|
||||
event_track_id?: string | null;
|
||||
event_track_id_random?: string | null;
|
||||
|
||||
type_code?: string;
|
||||
start_datetime?: string | Date;
|
||||
end_datetime?: string | Date;
|
||||
type_code?: string | null;
|
||||
start_datetime?: string | Date | null;
|
||||
end_datetime?: string | Date | null;
|
||||
|
||||
internal_use?: boolean;
|
||||
record_audio?: boolean;
|
||||
record_video?: boolean;
|
||||
internal_use?: boolean | null;
|
||||
record_audio?: boolean | null;
|
||||
record_video?: boolean | null;
|
||||
|
||||
status?: number;
|
||||
approve?: boolean;
|
||||
ready?: boolean;
|
||||
status?: number | null;
|
||||
approve?: boolean | null;
|
||||
ready?: boolean | null;
|
||||
|
||||
data_json?: any;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user