Overhaul Exhibitor Leads Manage tab and resolve all TypeScript errors
- Implemented full Staff License management (CRUD for license_li_json). - Added Admin Tools section for managers (Payment status, Max licenses, Device counts). - Implemented App Settings (Refresh interval, navigation preferences, cache management). - Fixed all remaining TypeScript errors in Badge and Presentation modules. - Integrated Payment tab conditional visibility logic.
This commit is contained in:
@@ -9,7 +9,9 @@ import * as event_file from '$lib/ae_events/ae_events__event_file';
|
|||||||
import {
|
import {
|
||||||
load_ae_obj_id__exhibit,
|
load_ae_obj_id__exhibit,
|
||||||
load_ae_obj_li__exhibit,
|
load_ae_obj_li__exhibit,
|
||||||
search__exhibit
|
search__exhibit,
|
||||||
|
create_ae_obj__exhibit,
|
||||||
|
update_ae_obj__exhibit
|
||||||
} from '$lib/ae_events/ae_events__exhibit';
|
} from '$lib/ae_events/ae_events__exhibit';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -74,6 +76,8 @@ const export_obj = {
|
|||||||
load_ae_obj_id__exhibit: load_ae_obj_id__exhibit,
|
load_ae_obj_id__exhibit: load_ae_obj_id__exhibit,
|
||||||
load_ae_obj_li__exhibit: load_ae_obj_li__exhibit,
|
load_ae_obj_li__exhibit: load_ae_obj_li__exhibit,
|
||||||
search__exhibit: search__exhibit,
|
search__exhibit: search__exhibit,
|
||||||
|
create_ae_obj__exhibit: create_ae_obj__exhibit,
|
||||||
|
update_ae_obj__exhibit: update_ae_obj__exhibit,
|
||||||
load_ae_obj_id__exhibit_tracking: load_ae_obj_id__exhibit_tracking,
|
load_ae_obj_id__exhibit_tracking: load_ae_obj_id__exhibit_tracking,
|
||||||
load_ae_obj_li__exhibit_tracking: load_ae_obj_li__exhibit_tracking,
|
load_ae_obj_li__exhibit_tracking: load_ae_obj_li__exhibit_tracking,
|
||||||
search__exhibit_tracking: search__exhibit_tracking,
|
search__exhibit_tracking: search__exhibit_tracking,
|
||||||
|
|||||||
@@ -183,10 +183,10 @@
|
|||||||
</a>
|
</a>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
{#if $lq__event_badge_obj}
|
{#if $lq__event_badge_obj && $lq__event_badge_obj.event_id && event_badge_id}
|
||||||
<Comp_badge_obj_view
|
<Comp_badge_obj_view
|
||||||
event_id={$lq__event_badge_obj.event_id}
|
event_id={$lq__event_badge_obj.event_id as string}
|
||||||
{event_badge_id}
|
event_badge_id={event_badge_id as string}
|
||||||
{lq__event_badge_obj}
|
{lq__event_badge_obj}
|
||||||
{is_review_mode}
|
{is_review_mode}
|
||||||
{lq__event_badge_template_obj}
|
{lq__event_badge_template_obj}
|
||||||
|
|||||||
@@ -26,6 +26,8 @@
|
|||||||
import Tab_add from './ae_tab__add.svelte';
|
import Tab_add from './ae_tab__add.svelte';
|
||||||
import Tab_start from './ae_tab__start.svelte';
|
import Tab_start from './ae_tab__start.svelte';
|
||||||
import Tab_manage from './ae_tab__manage.svelte';
|
import Tab_manage from './ae_tab__manage.svelte';
|
||||||
|
import Comp_exhibit_payment from './ae_comp__exhibit_payment.svelte';
|
||||||
|
import { CreditCard } from 'lucide-svelte';
|
||||||
|
|
||||||
// *** Initialization & Store Guard ***
|
// *** Initialization & Store Guard ***
|
||||||
if ($events_loc.leads) {
|
if ($events_loc.leads) {
|
||||||
@@ -39,6 +41,8 @@
|
|||||||
$events_loc.leads.tracking__qry__search_text = '';
|
$events_loc.leads.tracking__qry__search_text = '';
|
||||||
if (typeof $events_loc.leads.tracking__qry__sort_order === 'undefined')
|
if (typeof $events_loc.leads.tracking__qry__sort_order === 'undefined')
|
||||||
$events_loc.leads.tracking__qry__sort_order = 'created_desc';
|
$events_loc.leads.tracking__qry__sort_order = 'created_desc';
|
||||||
|
if (typeof $events_loc.leads.refresh_interval_sec === 'undefined')
|
||||||
|
$events_loc.leads.refresh_interval_sec = 25;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Tab State (Sticky via Store) ---
|
// --- Tab State (Sticky via Store) ---
|
||||||
@@ -322,6 +326,20 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<!-- Payment (Conditional) -->
|
||||||
|
{#if $ae_loc.show_leads_payment}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-sm transition-colors px-2 sm:px-3"
|
||||||
|
class:variant-filled-success={active_tab === 'payment'}
|
||||||
|
class:variant-ghost-success={active_tab !== 'payment'}
|
||||||
|
onclick={() => set_active_tab('payment')}
|
||||||
|
title="Payment & Upgrades"
|
||||||
|
>
|
||||||
|
<CreditCard size="1.25em" />
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<!-- Manage / Config -->
|
<!-- Manage / Config -->
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -345,6 +363,10 @@
|
|||||||
</div>
|
</div>
|
||||||
{:else if active_tab === 'add'}
|
{:else if active_tab === 'add'}
|
||||||
<Tab_add exhibit_id={page.params.exhibit_id ?? ''} />
|
<Tab_add exhibit_id={page.params.exhibit_id ?? ''} />
|
||||||
|
{:else if active_tab === 'payment'}
|
||||||
|
<div class="w-full max-w-4xl mx-auto">
|
||||||
|
<Comp_exhibit_payment />
|
||||||
|
</div>
|
||||||
{:else if active_tab === 'list'}
|
{:else if active_tab === 'list'}
|
||||||
<div class="w-full flex flex-col space-y-6">
|
<div class="w-full flex flex-col space-y-6">
|
||||||
<div class="flex justify-between items-center px-2">
|
<div class="flex justify-between items-center px-2">
|
||||||
|
|||||||
@@ -1,11 +1,160 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
/**
|
/**
|
||||||
* src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__exhibit_license_list.svelte
|
* src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__exhibit_license_list.svelte
|
||||||
* Exhibitor License Management Stub.
|
* Exhibitor License Management - Handles parsing and editing event_exhibit.license_li_json
|
||||||
*/
|
*/
|
||||||
|
import { untrack } from 'svelte';
|
||||||
|
import { ae_api } from '$lib/stores/ae_stores';
|
||||||
|
import { events_func } from '$lib/ae_events_functions';
|
||||||
|
import { Plus, Trash2, Mail, Key, User, Save, LoaderCircle, Users } from 'lucide-svelte';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
exhibit_id: string;
|
||||||
|
license_li_json?: string; // Raw JSON string from DB
|
||||||
|
license_max?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
let { exhibit_id, license_li_json = '[]', license_max = 0 }: Props = $props();
|
||||||
|
|
||||||
|
// Local state for the parsed list
|
||||||
|
let local_license_li: any[] = $state([]);
|
||||||
|
let is_saving = $state(false);
|
||||||
|
|
||||||
|
// Parse JSON into local state
|
||||||
|
$effect(() => {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(license_li_json || '[]');
|
||||||
|
untrack(() => {
|
||||||
|
local_license_li = Array.isArray(parsed) ? parsed : [];
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to parse license_li_json', e);
|
||||||
|
untrack(() => {
|
||||||
|
local_license_li = [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function save_licenses() {
|
||||||
|
if (!exhibit_id) return;
|
||||||
|
is_saving = true;
|
||||||
|
try {
|
||||||
|
const json_str = JSON.stringify(local_license_li);
|
||||||
|
await events_func.update_ae_obj__exhibit({
|
||||||
|
api_cfg: $ae_api,
|
||||||
|
exhibit_id: exhibit_id,
|
||||||
|
data_kv: {
|
||||||
|
license_li_json: json_str
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to save licenses', e);
|
||||||
|
} finally {
|
||||||
|
is_saving = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function add_license() {
|
||||||
|
if (local_license_li.length >= (license_max || 1)) {
|
||||||
|
alert(`Maximum licenses (${license_max}) reached.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
local_license_li.push({
|
||||||
|
full_name: '',
|
||||||
|
email: '',
|
||||||
|
passcode: Math.random().toString(36).substring(2, 8).toUpperCase()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function remove_license(index: number) {
|
||||||
|
if (confirm('Remove this license? The user will lose access immediately.')) {
|
||||||
|
local_license_li.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="exhibit-license-list p-4 card">
|
<div class="exhibit-license-list space-y-4">
|
||||||
<h3 class="h3">Staff Licenses</h3>
|
<div class="flex items-center justify-between">
|
||||||
<p>Placeholder for license assignment logic.</p>
|
<h3 class="text-sm font-bold uppercase tracking-widest opacity-50">Assigned Licenses</h3>
|
||||||
</div>
|
<span class="text-xs font-mono bg-surface-500/10 px-2 py-1 rounded">
|
||||||
|
{local_license_li.length} / {license_max || 1}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-3">
|
||||||
|
{#each local_license_li as license, i}
|
||||||
|
<div class="card p-4 variant-soft border border-surface-500/10 space-y-3 relative group animate-in fade-in slide-in-from-right-2">
|
||||||
|
<button
|
||||||
|
class="absolute top-2 right-2 p-2 text-error-500 opacity-0 group-hover:opacity-100 transition-opacity"
|
||||||
|
onclick={() => remove_license(i)}
|
||||||
|
title="Remove License"
|
||||||
|
>
|
||||||
|
<Trash2 size="1.2em" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Name -->
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<User size="1.2em" class="opacity-30" />
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
bind:value={license.full_name}
|
||||||
|
placeholder="Full Name"
|
||||||
|
class="bg-transparent border-b border-surface-500/20 focus:border-primary-500 outline-none flex-1 text-sm font-bold"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Email -->
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<Mail size="1.2em" class="opacity-30" />
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
bind:value={license.email}
|
||||||
|
placeholder="email@example.com"
|
||||||
|
class="bg-transparent border-b border-surface-500/20 focus:border-primary-500 outline-none flex-1 text-sm"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Passcode -->
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<Key size="1.2em" class="opacity-30" />
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
bind:value={license.passcode}
|
||||||
|
placeholder="PASSCODE"
|
||||||
|
class="bg-transparent border-b border-surface-500/20 focus:border-primary-500 outline-none w-32 text-sm font-mono font-bold"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
{#if local_license_li.length === 0}
|
||||||
|
<div class="p-8 text-center border-2 border-dashed border-surface-500/20 rounded-xl opacity-30">
|
||||||
|
<Users size="2em" class="mx-auto mb-2" />
|
||||||
|
<p class="text-sm italic">No licenses assigned yet.</p>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex gap-2 pt-2">
|
||||||
|
<button
|
||||||
|
class="btn btn-sm variant-filled-secondary flex-1"
|
||||||
|
onclick={add_license}
|
||||||
|
disabled={local_license_li.length >= (license_max || 1)}
|
||||||
|
>
|
||||||
|
<Plus size="1.2em" class="mr-2" /> Add Staff License
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="btn btn-sm variant-filled-primary flex-1"
|
||||||
|
onclick={save_licenses}
|
||||||
|
disabled={is_saving}
|
||||||
|
>
|
||||||
|
{#if is_saving}
|
||||||
|
<LoaderCircle size="1.2em" class="animate-spin mr-2" />
|
||||||
|
{:else}
|
||||||
|
<Save size="1.2em" class="mr-2" />
|
||||||
|
{/if}
|
||||||
|
Save Changes
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -7,8 +7,10 @@
|
|||||||
import { liveQuery } from 'dexie';
|
import { liveQuery } from 'dexie';
|
||||||
import { db_events } from '$lib/ae_events/db_events';
|
import { db_events } from '$lib/ae_events/db_events';
|
||||||
import { ae_api, ae_loc } from '$lib/stores/ae_stores';
|
import { ae_api, ae_loc } from '$lib/stores/ae_stores';
|
||||||
|
import { events_loc } from '$lib/stores/ae_events_stores';
|
||||||
import { events_func } from '$lib/ae_events_functions';
|
import { events_func } from '$lib/ae_events_functions';
|
||||||
import Element_ae_crud_v2 from '$lib/elements/element_ae_crud_v2.svelte';
|
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';
|
||||||
import {
|
import {
|
||||||
Store,
|
Store,
|
||||||
Settings,
|
Settings,
|
||||||
@@ -18,7 +20,8 @@
|
|||||||
CreditCard,
|
CreditCard,
|
||||||
Key,
|
Key,
|
||||||
Users,
|
Users,
|
||||||
ChevronRight
|
ChevronRight,
|
||||||
|
ChevronDown
|
||||||
} from 'lucide-svelte';
|
} from 'lucide-svelte';
|
||||||
|
|
||||||
const exhibit_id = $derived(page.params.exhibit_id ?? '');
|
const exhibit_id = $derived(page.params.exhibit_id ?? '');
|
||||||
@@ -32,10 +35,87 @@
|
|||||||
|
|
||||||
// Track local status for specific actions
|
// Track local status for specific actions
|
||||||
let updating = $state(false);
|
let updating = $state(false);
|
||||||
|
let show_license_mgmt = $state(false);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="ae-tab-manage w-full space-y-8 animate-in fade-in slide-in-from-bottom-2 duration-300">
|
<div class="ae-tab-manage w-full space-y-8 animate-in fade-in slide-in-from-bottom-2 duration-300 pb-20">
|
||||||
|
|
||||||
|
<!-- Section: Admin Tools (Manager Access Only) -->
|
||||||
|
{#if $ae_loc.manager_access}
|
||||||
|
<section class="space-y-4 p-4 border-2 border-primary-500/20 rounded-xl bg-primary-500/5">
|
||||||
|
<div class="flex items-center gap-2 border-b border-primary-500/10 pb-2">
|
||||||
|
<Settings size="1.2em" class="text-primary-500" />
|
||||||
|
<h3 class="text-lg font-bold uppercase tracking-wider text-primary-500">Admin Tools</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
|
<!-- Priority / Payment Toggle -->
|
||||||
|
<div class="card p-3 variant-soft flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<div class="text-[10px] uppercase font-black opacity-40">Payment Status</div>
|
||||||
|
<div class="font-bold">{$lq__exhibit_obj?.priority ? 'PAID' : 'PENDING'}</div>
|
||||||
|
</div>
|
||||||
|
<Element_ae_crud_v2
|
||||||
|
api_cfg={$ae_api}
|
||||||
|
object_type="event_exhibit"
|
||||||
|
object_id={exhibit_id}
|
||||||
|
field_name="priority"
|
||||||
|
field_type="boolean"
|
||||||
|
current_field_value={$lq__exhibit_obj?.priority}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Max Licenses -->
|
||||||
|
<div class="card p-3 variant-soft flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<div class="text-[10px] uppercase font-black opacity-40">Max Licenses</div>
|
||||||
|
</div>
|
||||||
|
<Element_ae_crud_v2
|
||||||
|
api_cfg={$ae_api}
|
||||||
|
object_type="event_exhibit"
|
||||||
|
object_id={exhibit_id}
|
||||||
|
field_name="license_max"
|
||||||
|
field_type="number"
|
||||||
|
current_field_value={$lq__exhibit_obj?.license_max}
|
||||||
|
class_li="w-16 font-mono text-right"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Small Devices -->
|
||||||
|
<div class="card p-3 variant-soft flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<div class="text-[10px] uppercase font-black opacity-40">Small Devices</div>
|
||||||
|
</div>
|
||||||
|
<Element_ae_crud_v2
|
||||||
|
api_cfg={$ae_api}
|
||||||
|
object_type="event_exhibit"
|
||||||
|
object_id={exhibit_id}
|
||||||
|
field_name="leads_device_sm_qty"
|
||||||
|
field_type="number"
|
||||||
|
current_field_value={$lq__exhibit_obj?.leads_device_sm_qty}
|
||||||
|
class_li="w-16 font-mono text-right"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Large Devices -->
|
||||||
|
<div class="card p-3 variant-soft flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<div class="text-[10px] uppercase font-black opacity-40">Large Devices</div>
|
||||||
|
</div>
|
||||||
|
<Element_ae_crud_v2
|
||||||
|
api_cfg={$ae_api}
|
||||||
|
object_type="event_exhibit"
|
||||||
|
object_id={exhibit_id}
|
||||||
|
field_name="leads_device_lg_qty"
|
||||||
|
field_type="number"
|
||||||
|
current_field_value={$lq__exhibit_obj?.leads_device_lg_qty}
|
||||||
|
class_li="w-16 font-mono text-right"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<!-- Section: Booth Profile -->
|
<!-- Section: Booth Profile -->
|
||||||
<section class="space-y-4">
|
<section class="space-y-4">
|
||||||
<div class="flex items-center gap-2 border-b border-surface-500/10 pb-2">
|
<div class="flex items-center gap-2 border-b border-surface-500/10 pb-2">
|
||||||
@@ -95,9 +175,19 @@
|
|||||||
<!-- Staff Passcode -->
|
<!-- Staff Passcode -->
|
||||||
<div class="card p-4 bg-surface-500/5 border border-surface-500/10">
|
<div class="card p-4 bg-surface-500/5 border border-surface-500/10">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div>
|
<div class="flex-1">
|
||||||
<div class="text-[10px] uppercase font-black opacity-40 tracking-widest">Staff Passcode</div>
|
<div class="text-[10px] uppercase font-black opacity-40 tracking-widest mb-1">Staff Passcode</div>
|
||||||
<div class="font-mono text-xl tracking-widest font-bold">{$lq__exhibit_obj?.staff_passcode || '----'}</div>
|
<Element_ae_crud_v2
|
||||||
|
api_cfg={$ae_api}
|
||||||
|
object_type="event_exhibit"
|
||||||
|
object_id={exhibit_id}
|
||||||
|
field_name="staff_passcode"
|
||||||
|
field_type="text"
|
||||||
|
current_field_value={$lq__exhibit_obj?.staff_passcode}
|
||||||
|
class_li="font-mono text-xl tracking-widest font-bold"
|
||||||
|
hide_element={false}
|
||||||
|
display_block={true}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Key size="1.5em" class="opacity-20" />
|
<Key size="1.5em" class="opacity-20" />
|
||||||
</div>
|
</div>
|
||||||
@@ -127,15 +217,34 @@
|
|||||||
|
|
||||||
<div class="card p-0 divide-y divide-surface-500/10 overflow-hidden shadow-md">
|
<div class="card p-0 divide-y divide-surface-500/10 overflow-hidden shadow-md">
|
||||||
<!-- Licenses -->
|
<!-- Licenses -->
|
||||||
<div class="p-4 flex items-center justify-between hover:bg-surface-500/5 transition-colors cursor-pointer group">
|
<div class="p-0">
|
||||||
<div class="flex items-center gap-4">
|
<button
|
||||||
<div class="bg-primary-500/10 p-2 rounded-lg text-primary-500"><Users size="1.2em" /></div>
|
class="w-full p-4 flex items-center justify-between hover:bg-surface-500/5 transition-colors group"
|
||||||
<div>
|
onclick={() => show_license_mgmt = !show_license_mgmt}
|
||||||
<div class="font-bold text-sm">Staff Licenses</div>
|
>
|
||||||
<div class="text-xs opacity-50">Active: 0 / Max: {$lq__exhibit_obj?.license_max || 1}</div>
|
<div class="flex items-center gap-4">
|
||||||
|
<div class="bg-primary-500/10 p-2 rounded-lg text-primary-500"><Users size="1.2em" /></div>
|
||||||
|
<div class="text-left">
|
||||||
|
<div class="font-bold text-sm">Staff Licenses</div>
|
||||||
|
<div class="text-xs opacity-50">Manage assigned staff and codes</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{#if show_license_mgmt}
|
||||||
<ChevronRight size="1.2em" class="opacity-20 group-hover:translate-x-1 transition-transform" />
|
<ChevronDown size="1.2em" class="opacity-20" />
|
||||||
|
{:else}
|
||||||
|
<ChevronRight size="1.2em" class="opacity-20 group-hover:translate-x-1 transition-transform" />
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{#if show_license_mgmt}
|
||||||
|
<div class="p-4 bg-surface-500/5 border-t border-surface-500/10 animate-in fade-in slide-in-from-top-2">
|
||||||
|
<Comp_exhibit_license_list
|
||||||
|
{exhibit_id}
|
||||||
|
license_li_json={$lq__exhibit_obj?.license_li_json ?? '[]'}
|
||||||
|
license_max={$lq__exhibit_obj?.license_max}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Custom Questions -->
|
<!-- Custom Questions -->
|
||||||
@@ -164,6 +273,77 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Section: App Settings -->
|
||||||
|
<section class="space-y-4">
|
||||||
|
<div class="flex items-center gap-2 border-b border-surface-500/10 pb-2">
|
||||||
|
<Settings size="1.2em" class="text-secondary-500" />
|
||||||
|
<h3 class="text-lg font-bold uppercase tracking-wider">App Settings</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card p-4 space-y-6 variant-soft shadow-inner">
|
||||||
|
<!-- Interface Prefs -->
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div class="text-[10px] uppercase font-black opacity-40 tracking-widest">Interface Preferences</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 gap-2">
|
||||||
|
<label class="flex items-center justify-between p-2 hover:bg-surface-500/10 rounded-lg cursor-pointer transition-colors">
|
||||||
|
<span class="text-sm">Auto-hide Header/Footer</span>
|
||||||
|
<input type="checkbox" class="checkbox" bind:checked={$ae_loc.auto_hide_nav} />
|
||||||
|
</label>
|
||||||
|
<label class="flex items-center justify-between p-2 hover:bg-surface-500/10 rounded-lg cursor-pointer transition-colors">
|
||||||
|
<span class="text-sm">Show Payment Tab</span>
|
||||||
|
<input type="checkbox" class="checkbox" bind:checked={$ae_loc.show_leads_payment} />
|
||||||
|
</label>
|
||||||
|
<label class="flex items-center justify-between p-2 hover:bg-surface-500/10 rounded-lg cursor-pointer transition-colors">
|
||||||
|
<span class="text-sm">Show Extra Details</span>
|
||||||
|
<input type="checkbox" class="checkbox" bind:checked={$events_loc.show_details} />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 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 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>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
class="input w-20 text-right font-mono p-1 bg-transparent border-b border-surface-500/20"
|
||||||
|
min="1"
|
||||||
|
max="120"
|
||||||
|
bind:value={$events_loc.leads.refresh_interval_sec}
|
||||||
|
placeholder="25"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Maintenance -->
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div class="text-[10px] uppercase font-black opacity-40 tracking-widest">Maintenance & Reset</div>
|
||||||
|
<div class="grid grid-cols-2 gap-2">
|
||||||
|
<button class="btn btn-sm variant-filled-warning" onclick={() => window.location.reload()}>
|
||||||
|
<span class="fas fa-sync mr-2"></span> Reload App
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-sm variant-ghost-error" onclick={() => {
|
||||||
|
if(confirm('Clear all local cached data (IDB)?')) {
|
||||||
|
db_events.delete().then(() => window.location.reload());
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<span class="fas fa-database mr-2"></span> Clear IDB
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-sm variant-ghost-error col-span-2" onclick={() => {
|
||||||
|
if(confirm('Reset all local app settings and sign out?')) {
|
||||||
|
localStorage.clear();
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<span class="fas fa-user-slash mr-2"></span> Clear Local Settings (Hard Reset)
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Help Footer -->
|
<!-- Help Footer -->
|
||||||
<div class="pt-10 pb-20 text-center space-y-2 opacity-40">
|
<div class="pt-10 pb-20 text-center space-y-2 opacity-40">
|
||||||
<p class="text-xs">Exhibitor Management Module v3.0</p>
|
<p class="text-xs">Exhibitor Management Module v3.0</p>
|
||||||
|
|||||||
@@ -155,11 +155,13 @@
|
|||||||
|
|
||||||
// JSON formatted configuration options for an event, and specifically for the presentation management module.
|
// JSON formatted configuration options for an event, and specifically for the presentation management module.
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if ($lq__event_obj?.mod_pres_mgmt_json) {
|
const remote_cfg = $lq__event_obj?.mod_pres_mgmt_json;
|
||||||
|
const local_cfg = $events_loc?.pres_mgmt;
|
||||||
|
if (remote_cfg && local_cfg) {
|
||||||
untrack(() => {
|
untrack(() => {
|
||||||
events_func.sync_config__event_pres_mgmt({
|
events_func.sync_config__event_pres_mgmt({
|
||||||
pres_mgmt_cfg_remote: $lq__event_obj?.mod_pres_mgmt_json,
|
pres_mgmt_cfg_remote: remote_cfg,
|
||||||
pres_mgmt_cfg_local: $events_loc?.pres_mgmt,
|
pres_mgmt_cfg_local: local_cfg,
|
||||||
log_lvl: log_lvl
|
log_lvl: log_lvl
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user