badges(runtime): honor mod_badges_json flags (badge_id_only search, QR toggle, add/upload/mass-print gating)
This commit is contained in:
@@ -19,11 +19,11 @@ import { ae_loc, ae_api } from '$lib/stores/ae_stores';
|
|||||||
|
|
||||||
import { db_events } from '$lib/ae_events/db_events';
|
import { db_events } from '$lib/ae_events/db_events';
|
||||||
import {
|
import {
|
||||||
events_loc,
|
|
||||||
events_sess,
|
events_sess,
|
||||||
events_slct,
|
events_slct,
|
||||||
events_trigger
|
events_trigger
|
||||||
} from '$lib/stores/ae_events_stores';
|
} from '$lib/stores/ae_events_stores';
|
||||||
|
import { badges_loc } from '$lib/stores/ae_events_stores__badges.svelte';
|
||||||
import { events_func } from '$lib/ae_events/ae_events_functions';
|
import { events_func } from '$lib/ae_events/ae_events_functions';
|
||||||
|
|
||||||
import Comp_badge_search from './ae_comp__badge_search.svelte';
|
import Comp_badge_search from './ae_comp__badge_search.svelte';
|
||||||
@@ -54,24 +54,8 @@ let lq__badge_template_li = $derived(
|
|||||||
.sortBy('name');
|
.sortBy('name');
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
// *** Initialization & Store Guard ***
|
// badges_loc (PersistedState) is always initialized from badges_loc_defaults —
|
||||||
// Ensure all search fields are initialized to prevent circular undefined triggers
|
// no manual typeof guards needed. All fields are guaranteed to exist.
|
||||||
if ($events_loc.badges) {
|
|
||||||
if (typeof $events_loc.badges.search_version === 'undefined')
|
|
||||||
$events_loc.badges.search_version = 0;
|
|
||||||
if (typeof $events_loc.badges.qry__remote_first === 'undefined')
|
|
||||||
$events_loc.badges.qry__remote_first = false;
|
|
||||||
if (typeof $events_loc.badges.fulltext_search_qry_str === 'undefined')
|
|
||||||
$events_loc.badges.fulltext_search_qry_str = '';
|
|
||||||
if (typeof $events_loc.badges.search_badge_type_code === 'undefined')
|
|
||||||
$events_loc.badges.search_badge_type_code = '';
|
|
||||||
if (typeof $events_loc.badges.qry_printed_status === 'undefined')
|
|
||||||
$events_loc.badges.qry_printed_status = 'all';
|
|
||||||
if (typeof $events_loc.badges.qry_affiliations === 'undefined')
|
|
||||||
$events_loc.badges.qry_affiliations = '';
|
|
||||||
if (typeof $events_loc.badges.qry_sort_order === 'undefined')
|
|
||||||
$events_loc.badges.qry_sort_order = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
let show_create_badge_modal: boolean = $state(false);
|
let show_create_badge_modal: boolean = $state(false);
|
||||||
@@ -113,10 +97,10 @@ let lq__event_badge_obj_li = $derived.by(() => {
|
|||||||
// SCENARIO 2: Fallback broad search (Only if no active filters)
|
// SCENARIO 2: Fallback broad search (Only if no active filters)
|
||||||
if (
|
if (
|
||||||
event_id &&
|
event_id &&
|
||||||
!$events_loc.badges.fulltext_search_qry_str &&
|
!badges_loc.current.fulltext_search_qry_str &&
|
||||||
$events_loc.badges.qry_printed_status === 'all' &&
|
badges_loc.current.qry_printed_status === 'all' &&
|
||||||
!$events_loc.badges.qry_affiliations &&
|
!badges_loc.current.qry_affiliations &&
|
||||||
!$events_loc.badges.search_badge_type_code
|
!badges_loc.current.search_badge_type_code
|
||||||
) {
|
) {
|
||||||
if (log_lvl)
|
if (log_lvl)
|
||||||
console.log(
|
console.log(
|
||||||
@@ -136,16 +120,18 @@ let lq__event_badge_obj_li = $derived.by(() => {
|
|||||||
// Standardized Reactive Search Pattern (Aether UI V3)
|
// Standardized Reactive Search Pattern (Aether UI V3)
|
||||||
// 1. Isolate dependencies into a stable derived object
|
// 1. Isolate dependencies into a stable derived object
|
||||||
let search_params = $derived({
|
let search_params = $derived({
|
||||||
v: $events_loc.badges.search_version,
|
v: badges_loc.current.search_version,
|
||||||
str: ($events_loc.badges.fulltext_search_qry_str ?? '')
|
str: (badges_loc.current.fulltext_search_qry_str ?? '')
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.trim(),
|
.trim(),
|
||||||
type: $events_loc.badges.search_badge_type_code,
|
type: badges_loc.current.search_badge_type_code,
|
||||||
printed: $events_loc.badges.qry_printed_status,
|
printed: badges_loc.current.qry_printed_status,
|
||||||
aff: ($events_loc.badges.qry_affiliations ?? '').toLowerCase().trim(),
|
aff: (badges_loc.current.qry_affiliations ?? '').toLowerCase().trim(),
|
||||||
sort: $events_loc.badges.qry_sort_order,
|
sort: badges_loc.current.qry_sort_order,
|
||||||
event_id: $events_slct?.event_id,
|
event_id: $events_slct?.event_id,
|
||||||
remote_first: $events_loc.badges.qry__remote_first
|
remote_first: badges_loc.current.qry__remote_first,
|
||||||
|
// Event-level override: when true, restrict searches to badge IDs only
|
||||||
|
badge_id_only: $lq__event_obj?.mod_badges_json?.badge_id_only_search ?? false
|
||||||
});
|
});
|
||||||
|
|
||||||
// 2. Controlled effect for triggering searches
|
// 2. Controlled effect for triggering searches
|
||||||
@@ -208,7 +194,10 @@ async function handle_search_refresh(params: any) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qry_str) {
|
if (params.badge_id_only && qry_str) {
|
||||||
|
const id = (badge.event_badge_id ?? '').toLowerCase();
|
||||||
|
if (!id.includes(qry_str)) return false;
|
||||||
|
} else if (qry_str) {
|
||||||
const given_name = (
|
const given_name = (
|
||||||
badge.given_name ?? ''
|
badge.given_name ?? ''
|
||||||
).toLowerCase();
|
).toLowerCase();
|
||||||
@@ -387,7 +376,7 @@ async function handle_search_refresh(params: any) {
|
|||||||
<Comp_badge_search event_id={$events_slct?.event_id ?? ''} log_lvl={1}
|
<Comp_badge_search event_id={$events_slct?.event_id ?? ''} log_lvl={1}
|
||||||
></Comp_badge_search>
|
></Comp_badge_search>
|
||||||
|
|
||||||
{#if $ae_loc.edit_mode}
|
{#if $ae_loc.edit_mode && ($lq__event_obj?.mod_badges_json?.enable_add_badge_btn ?? true)}
|
||||||
<div class="flex justify-end px-4">
|
<div class="flex justify-end px-4">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -420,8 +409,8 @@ async function handle_search_refresh(params: any) {
|
|||||||
create_badge_dialog?.close();
|
create_badge_dialog?.close();
|
||||||
show_create_badge_modal = false;
|
show_create_badge_modal = false;
|
||||||
// Trigger a remote-first refresh so the new badge appears in results
|
// Trigger a remote-first refresh so the new badge appears in results
|
||||||
$events_loc.badges.search_version = ($events_loc.badges.search_version ?? 0) + 1;
|
badges_loc.current.search_version = (badges_loc.current.search_version ?? 0) + 1;
|
||||||
$events_loc.badges.qry__remote_first = true;
|
badges_loc.current.qry__remote_first = true;
|
||||||
}}
|
}}
|
||||||
oncancel={() => {
|
oncancel={() => {
|
||||||
create_badge_dialog?.close();
|
create_badge_dialog?.close();
|
||||||
|
|||||||
@@ -15,9 +15,19 @@ import {
|
|||||||
Search
|
Search
|
||||||
} from '@lucide/svelte';
|
} from '@lucide/svelte';
|
||||||
import { ae_loc, ae_api } from '$lib/stores/ae_stores';
|
import { ae_loc, ae_api } from '$lib/stores/ae_stores';
|
||||||
import { events_loc, events_sess } from '$lib/stores/ae_events_stores';
|
import { events_sess } from '$lib/stores/ae_events_stores';
|
||||||
|
import { badges_loc } from '$lib/stores/ae_events_stores__badges.svelte';
|
||||||
import Element_qr_scanner from '$lib/elements/element_qr_scanner.svelte';
|
import Element_qr_scanner from '$lib/elements/element_qr_scanner.svelte';
|
||||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||||
|
import { liveQuery } from 'dexie';
|
||||||
|
import { db_events } from '$lib/ae_events/db_events';
|
||||||
|
|
||||||
|
let lq__event_obj = $derived(
|
||||||
|
liveQuery(async () => {
|
||||||
|
if (!event_id) return null;
|
||||||
|
return await db_events.event.get(event_id);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
// ISHLT 2024 badge type codes
|
// ISHLT 2024 badge type codes
|
||||||
let badge_type_code_li = [
|
let badge_type_code_li = [
|
||||||
@@ -37,10 +47,7 @@ let badge_type_code_li = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
function handle_search_trigger() {
|
function handle_search_trigger() {
|
||||||
if ($events_loc.badges.search_version === undefined) {
|
badges_loc.current.search_version++;
|
||||||
$events_loc.badges.search_version = 0;
|
|
||||||
}
|
|
||||||
$events_loc.badges.search_version++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function prevent_default<T extends Event>(fn: (event: T) => void) {
|
function prevent_default<T extends Event>(fn: (event: T) => void) {
|
||||||
@@ -57,7 +64,7 @@ function handle_qr_scan_result(event: {
|
|||||||
let obj = ae_util.process_data_string(qr_scan_result);
|
let obj = ae_util.process_data_string(qr_scan_result);
|
||||||
|
|
||||||
if (obj && obj.type && obj.id && obj.type === 'event_badge') {
|
if (obj && obj.type && obj.id && obj.type === 'event_badge') {
|
||||||
$events_loc.badges.fulltext_search_qry_str = obj.id;
|
badges_loc.current.fulltext_search_qry_str = obj.id;
|
||||||
handle_search_trigger();
|
handle_search_trigger();
|
||||||
|
|
||||||
$events_sess.badges.show_form__search = true;
|
$events_sess.badges.show_form__search = true;
|
||||||
@@ -80,7 +87,7 @@ function handle_qr_scan_result(event: {
|
|||||||
class="flex grow flex-col items-center justify-center gap-1 md:flex-row">
|
class="flex grow flex-col items-center justify-center gap-1 md:flex-row">
|
||||||
{#if $ae_loc.trusted_access}
|
{#if $ae_loc.trusted_access}
|
||||||
<select
|
<select
|
||||||
bind:value={$events_loc.badges.search_badge_type_code}
|
bind:value={badges_loc.current.search_badge_type_code}
|
||||||
onchange={handle_search_trigger}
|
onchange={handle_search_trigger}
|
||||||
class="select select-sm max-w-fit px-1 text-xs">
|
class="select select-sm max-w-fit px-1 text-xs">
|
||||||
<option value="">-- All Badge Types --</option>
|
<option value="">-- All Badge Types --</option>
|
||||||
@@ -91,7 +98,7 @@ function handle_qr_scan_result(event: {
|
|||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select
|
<select
|
||||||
bind:value={$events_loc.badges.qry_printed_status}
|
bind:value={badges_loc.current.qry_printed_status}
|
||||||
onchange={handle_search_trigger}
|
onchange={handle_search_trigger}
|
||||||
class="select select-sm max-w-fit px-1 text-xs">
|
class="select select-sm max-w-fit px-1 text-xs">
|
||||||
<option value="all">-- All Print Status --</option>
|
<option value="all">-- All Print Status --</option>
|
||||||
@@ -100,7 +107,7 @@ function handle_qr_scan_result(event: {
|
|||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select
|
<select
|
||||||
bind:value={$events_loc.badges.qry_sort_order}
|
bind:value={badges_loc.current.qry_sort_order}
|
||||||
onchange={handle_search_trigger}
|
onchange={handle_search_trigger}
|
||||||
class="select select-sm max-w-fit px-1 text-xs">
|
class="select select-sm max-w-fit px-1 text-xs">
|
||||||
<option value="">-- Default Sort --</option>
|
<option value="">-- Default Sort --</option>
|
||||||
@@ -122,11 +129,11 @@ function handle_qr_scan_result(event: {
|
|||||||
<input
|
<input
|
||||||
type="search"
|
type="search"
|
||||||
placeholder="affiliations"
|
placeholder="affiliations"
|
||||||
bind:value={$events_loc.badges.qry_affiliations}
|
bind:value={badges_loc.current.qry_affiliations}
|
||||||
onkeyup={(e) => {
|
onkeyup={(e) => {
|
||||||
if (
|
if (
|
||||||
e.key === 'Enter' ||
|
e.key === 'Enter' ||
|
||||||
($events_loc.badges.qry_affiliations?.length ??
|
(badges_loc.current.qry_affiliations?.length ??
|
||||||
0) >= 3
|
0) >= 3
|
||||||
) {
|
) {
|
||||||
handle_search_trigger();
|
handle_search_trigger();
|
||||||
@@ -137,9 +144,9 @@ function handle_qr_scan_result(event: {
|
|||||||
|
|
||||||
<input
|
<input
|
||||||
type="search"
|
type="search"
|
||||||
placeholder="name, email"
|
placeholder={$lq__event_obj?.mod_badges_json?.badge_id_only_search ? 'Badge ID' : 'name, email'}
|
||||||
id="badge_fulltext_search_qry_str"
|
id="badge_fulltext_search_qry_str"
|
||||||
bind:value={$events_loc.badges.fulltext_search_qry_str}
|
bind:value={badges_loc.current.fulltext_search_qry_str}
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
data-lpignore="true"
|
data-lpignore="true"
|
||||||
class="input grow font-mono text-lg transition-all"
|
class="input grow font-mono text-lg transition-all"
|
||||||
@@ -165,14 +172,14 @@ function handle_qr_scan_result(event: {
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class:hidden={!$events_loc.badges.fulltext_search_qry_str &&
|
class:hidden={!badges_loc.current.fulltext_search_qry_str &&
|
||||||
!$events_loc.badges.search_badge_type_code &&
|
!badges_loc.current.search_badge_type_code &&
|
||||||
$events_loc.badges.qry_printed_status === 'all'}
|
badges_loc.current.qry_printed_status === 'all'}
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
$events_loc.badges.fulltext_search_qry_str = '';
|
badges_loc.current.fulltext_search_qry_str = '';
|
||||||
$events_loc.badges.search_badge_type_code = '';
|
badges_loc.current.search_badge_type_code = '';
|
||||||
$events_loc.badges.qry_printed_status = 'all';
|
badges_loc.current.qry_printed_status = 'all';
|
||||||
$events_loc.badges.qry_affiliations = '';
|
badges_loc.current.qry_affiliations = '';
|
||||||
handle_search_trigger();
|
handle_search_trigger();
|
||||||
}}
|
}}
|
||||||
class="btn btn-sm preset-outlined-tertiary-100-900 hover:preset-filled-tertiary-100-900 text-xs transition-all"
|
class="btn btn-sm preset-outlined-tertiary-100-900 hover:preset-filled-tertiary-100-900 text-xs transition-all"
|
||||||
@@ -194,17 +201,19 @@ function handle_qr_scan_result(event: {
|
|||||||
<div
|
<div
|
||||||
class="flex flex-row flex-wrap items-center justify-center gap-2 opacity-70 transition-all hover:opacity-100">
|
class="flex flex-row flex-wrap items-center justify-center gap-2 opacity-70 transition-all hover:opacity-100">
|
||||||
{#if $events_sess.badges.show_form__search}
|
{#if $events_sess.badges.show_form__search}
|
||||||
<button
|
{#if $lq__event_obj?.mod_badges_json?.enable_search_qr ?? true}
|
||||||
type="button"
|
<button
|
||||||
onclick={() => {
|
type="button"
|
||||||
$events_sess.badges.show_form__search = false;
|
onclick={() => {
|
||||||
$events_sess.badges.show_form__scan = true;
|
$events_sess.badges.show_form__search = false;
|
||||||
$events_sess.badges.qr_scan_start = true;
|
$events_sess.badges.show_form__scan = true;
|
||||||
}}
|
$events_sess.badges.qr_scan_start = true;
|
||||||
class="btn btn-sm preset-tonal-primary border-primary-500 border">
|
}}
|
||||||
<QrCode size="1em" class="mr-1" />
|
class="btn btn-sm preset-tonal-primary border-primary-500 border">
|
||||||
QR Scan
|
<QrCode size="1em" class="mr-1" />
|
||||||
</button>
|
QR Scan
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -225,7 +234,7 @@ function handle_qr_scan_result(event: {
|
|||||||
<span> Remote First </span>
|
<span> Remote First </span>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
bind:checked={$events_loc.badges.qry__remote_first}
|
bind:checked={badges_loc.current.qry__remote_first}
|
||||||
onchange={handle_search_trigger}
|
onchange={handle_search_trigger}
|
||||||
class="checkbox checkbox-sm" />
|
class="checkbox checkbox-sm" />
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@@ -122,9 +122,11 @@ async function handle_save(field_name: string, data: any) {
|
|||||||
<summary class="summary text-error-500 font-bold"
|
<summary class="summary text-error-500 font-bold"
|
||||||
>Admin Tools</summary>
|
>Admin Tools</summary>
|
||||||
<div class="space-y-4 p-4">
|
<div class="space-y-4 p-4">
|
||||||
|
{#if (event_obj?.mod_badges_json?.enable_add_badge_btn ?? true) || (event_obj?.mod_badges_json?.enable_upload_badge_li_btn ?? true)}
|
||||||
<div class="card rounded-md border p-4 text-center">
|
<div class="card rounded-md border p-4 text-center">
|
||||||
<h4 class="h4">Badge Operations</h4>
|
<h4 class="h4">Badge Operations</h4>
|
||||||
<div class="mt-2 flex flex-wrap justify-center gap-2">
|
<div class="mt-2 flex flex-wrap justify-center gap-2">
|
||||||
|
{#if event_obj?.mod_badges_json?.enable_add_badge_btn ?? true}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-primary"
|
class="btn btn-primary"
|
||||||
@@ -132,6 +134,8 @@ async function handle_save(field_name: string, data: any) {
|
|||||||
(show_create_badge_modal = true)}>
|
(show_create_badge_modal = true)}>
|
||||||
<Plus size="1em" aria-hidden="true" /> Add New Badge
|
<Plus size="1em" aria-hidden="true" /> Add New Badge
|
||||||
</button>
|
</button>
|
||||||
|
{/if}
|
||||||
|
{#if event_obj?.mod_badges_json?.enable_upload_badge_li_btn ?? true}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-primary ml-2"
|
class="btn btn-primary ml-2"
|
||||||
@@ -140,9 +144,12 @@ async function handle_save(field_name: string, data: any) {
|
|||||||
<Upload size="1em" aria-hidden="true" /> Upload Badge
|
<Upload size="1em" aria-hidden="true" /> Upload Badge
|
||||||
List
|
List
|
||||||
</button>
|
</button>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if event_obj?.mod_badges_json?.enable_mass_print ?? true}
|
||||||
<div class="card rounded-md border p-4 text-center">
|
<div class="card rounded-md border p-4 text-center">
|
||||||
<h4 class="h4">Mass Print Options</h4>
|
<h4 class="h4">Mass Print Options</h4>
|
||||||
<div class="mt-2 flex flex-wrap justify-center gap-2">
|
<div class="mt-2 flex flex-wrap justify-center gap-2">
|
||||||
@@ -165,6 +172,7 @@ async function handle_save(field_name: string, data: any) {
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div class="mt-4 flex flex-wrap justify-center gap-4">
|
<div class="mt-4 flex flex-wrap justify-center gap-4">
|
||||||
<a
|
<a
|
||||||
|
|||||||
Reference in New Issue
Block a user