Implement exhibitor search constraints and sync telemetry
- Restricted public exhibitor search to Priority (paid) items only. - Enforced 3-character search minimum for non-trusted users on landing page. - Implemented real-time sync telemetry (last refresh and countdown) in Manage tab. - Added auto-refresh logic with configurable intervals.
This commit is contained in:
@@ -85,17 +85,26 @@
|
||||
const current_search_id = ++last_search_id;
|
||||
const event_id = params.event_id;
|
||||
const remote_first = params.remote_first;
|
||||
const qry_str = params.str;
|
||||
|
||||
if (!event_id) return;
|
||||
|
||||
// --- Search Constraint: Min 3 characters for non-trusted users ---
|
||||
if (!$ae_loc.trusted_access && qry_str.length < 3) {
|
||||
if (log_lvl) console.log('🛑 [Trace] Search string too short for public user.');
|
||||
untrack(() => {
|
||||
exhibit_id_li = [];
|
||||
$events_sess.leads.submit_status__search = 'idle';
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (log_lvl) console.log(`🔎 [Trace] Exhibit Search #${current_search_id}: START (remote=${remote_first}, event=${event_id}, str=${params.str})`);
|
||||
|
||||
untrack(() => {
|
||||
$events_sess.leads.submit_status__search = 'searching';
|
||||
});
|
||||
|
||||
const qry_str = params.str;
|
||||
|
||||
// 1. FAST PATH: Local IDB Search
|
||||
if (!remote_first) {
|
||||
try {
|
||||
@@ -103,6 +112,9 @@
|
||||
.where('event_id')
|
||||
.equals(event_id)
|
||||
.filter((exhibit) => {
|
||||
// Priority Filter for Public
|
||||
if (!$ae_loc.manager_access && !exhibit.priority) return false;
|
||||
|
||||
if (qry_str) {
|
||||
const name = (exhibit.name ?? '').toLowerCase();
|
||||
const code = (exhibit.code ?? '').toLowerCase();
|
||||
@@ -111,6 +123,9 @@
|
||||
!code.includes(qry_str)
|
||||
)
|
||||
return false;
|
||||
} else if (!$ae_loc.trusted_access) {
|
||||
// Don't show default results to public if no search string
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
@@ -178,6 +193,7 @@
|
||||
api_cfg: $ae_api,
|
||||
event_id: event_id,
|
||||
fulltext_search_qry_str: qry_str || null,
|
||||
priority: $ae_loc.manager_access ? 'all' : 'priority',
|
||||
order_by_li,
|
||||
limit: 100
|
||||
});
|
||||
|
||||
@@ -123,6 +123,8 @@
|
||||
search_debounce_timer = setTimeout(() => {
|
||||
untrack(() => {
|
||||
handle_search_refresh(params);
|
||||
// Reset countdown on manual search
|
||||
$events_sess.leads.next_refresh_countdown = $events_loc.leads.refresh_interval_sec || 25;
|
||||
});
|
||||
}, 300);
|
||||
return () => {
|
||||
@@ -130,6 +132,25 @@
|
||||
};
|
||||
});
|
||||
|
||||
// --- Auto-Refresh Timer Logic ---
|
||||
$effect(() => {
|
||||
if (!is_signed_in) return;
|
||||
|
||||
const interval = setInterval(() => {
|
||||
untrack(() => {
|
||||
if ($events_sess.leads.next_refresh_countdown > 0) {
|
||||
$events_sess.leads.next_refresh_countdown--;
|
||||
} else {
|
||||
// Trigger refresh
|
||||
$events_loc.leads.tracking__search_version++;
|
||||
$events_sess.leads.next_refresh_countdown = $events_loc.leads.refresh_interval_sec || 25;
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
});
|
||||
|
||||
async function handle_search_refresh(params: any) {
|
||||
const qry_key = JSON.stringify(params);
|
||||
if (qry_key === last_executed_key) return;
|
||||
@@ -268,6 +289,7 @@
|
||||
untrack(() => {
|
||||
tracking_id_li = api_ids;
|
||||
$events_sess.leads.submit_status__search = 'done';
|
||||
$events_sess.leads.last_refresh_time = new Date().toISOString();
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import { liveQuery } from 'dexie';
|
||||
import { db_events } from '$lib/ae_events/db_events';
|
||||
import { ae_api, ae_loc } from '$lib/stores/ae_stores';
|
||||
import { events_loc } from '$lib/stores/ae_events_stores';
|
||||
import { events_loc, events_sess } from '$lib/stores/ae_events_stores';
|
||||
import { events_func } from '$lib/ae_events_functions';
|
||||
import Element_ae_crud_v2 from '$lib/elements/element_ae_crud_v2.svelte';
|
||||
import Comp_exhibit_license_list from './ae_comp__exhibit_license_list.svelte';
|
||||
@@ -340,9 +340,25 @@
|
||||
|
||||
<!-- List Refresh -->
|
||||
<div class="space-y-3">
|
||||
<div class="text-[10px] uppercase font-black opacity-40 tracking-widest">Data Synchronization</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="text-[10px] uppercase font-black opacity-40 tracking-widest">Data Synchronization</div>
|
||||
<div class="flex items-center gap-2 text-[10px] font-mono opacity-60">
|
||||
<span class="fas fa-clock"></span>
|
||||
{#if $events_sess.leads.last_refresh_time}
|
||||
Last: {new Date($events_sess.leads.last_refresh_time).toLocaleTimeString()}
|
||||
{:else}
|
||||
Waiting...
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4 p-2 bg-surface-500/5 rounded-lg border border-surface-500/10">
|
||||
<span class="text-sm flex-1">Refresh Interval (sec)</span>
|
||||
<div class="flex-1 space-y-1">
|
||||
<span class="text-sm block">Refresh Interval (sec)</span>
|
||||
<div class="text-[9px] opacity-40 uppercase font-bold">
|
||||
Next Sync in <span class="text-primary-500">{$events_sess.leads.next_refresh_countdown}s</span>
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
type="number"
|
||||
class="input w-20 text-right font-mono p-1 bg-transparent border-b border-surface-500/20"
|
||||
|
||||
Reference in New Issue
Block a user