Files
OSIT-AE-App-Svelte/src/routes/events_leads/exhibit/[slug]/+page.svelte
2024-03-15 18:46:34 -04:00

1368 lines
50 KiB
Svelte

<script lang="ts">
export let data;
console.log(`ae_events_leads exhibit [slug] +page.svelte data:`, data);
import { onMount } from 'svelte';
import type { key_val } from '$lib/ae_stores';
import { ae_util } from '$lib/ae_utils';
import { api } from '$lib/api';
import { liveQuery } from "dexie";
import { db_events } from "$lib/db_events";
import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
import { events_loc, events_sess, events_slct, events_trigger } from '$lib/ae_events_stores';
import { events_func } from '$lib/ae_events_functions';
import { clipboard, FileDropzone, getModalStore, localStorageStore, ProgressRadial, RadioGroup, RadioItem, TabGroup, Tab, TabAnchor } from '@skeletonlabs/skeleton';
// import type { Writable } from 'svelte/store';
import Element_data_store from '$lib/element_data_store.svelte';
import Element_qr_scanner from '$lib/element_qr_scanner.svelte';
let param_slug_event_exhibit_id = data.params.slug;
let event_exhibit_obj = liveQuery(
() => db_events.exhibits.get(param_slug_event_exhibit_id)
// () => db_events.exhibits.toArray()
// () => db_events.exhibits
// .where('id_random')
// .equals($events_slct.exhibit_id)
// // .orderBy('name')
// // .offset(10).limit(5)
// .toArray()
);
let event_exhibit_obj_v2 = db_events.exhibits.get(param_slug_event_exhibit_id);
// Load the Event Exhibit Obj with ID based on the slug param.
$events_slct.exhibit_id = param_slug_event_exhibit_id;
console.log('Selected Event Exhibit ID:', $events_slct.exhibit_id);
$events_trigger = 'load__event_exhibit_obj';
let license_submit_results: Promise<any>|key_val;
if (!$events_loc.leads.tab) {
$events_loc.leads.tab = {};
$events_loc.leads.tab[$events_slct.exhibit_id] = 'start';
}
if (!$events_loc.leads.auth_exhibit_kv) {
$events_loc.leads.auth_exhibit_kv = {};
}
if ($events_loc.leads.auth_exhibit_kv && $events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id]) {
console.log('Logged in using shared exhibit staff passcode.');
if ($events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id].key) {
console.log(`Using the license key: ${$events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id].key}`);
} else {
console.log('License key (email) not used.');
$events_loc.leads.tab[$events_slct.exhibit_id] = 'start';
}
} else {
console.log('Not logged in using shared exhibit staff passcode.');
$events_loc.leads.tab[$events_slct.exhibit_id] = 'start';
}
onMount(() => {
console.log('Events Leads Exhibit [slug]: +page.svelte');
console.log(`ae_events_leads exhibit [slug] +page.svelte data:`, data);
if ($events_slct.exhibit_id) {
console.log(`Got an ID. Let's do something!?`);
} else {
console.log(`No ID. Nothing to show. Try setting the ID again.`);
$events_slct.exhibit_id = param_slug_event_exhibit_id;
}
});
// console.log(`$ae_loc = `, $ae_loc);
$: if ($events_slct.exhibit_obj && $events_sess.leads.entered_passcode) {
console.log('Check the passcode?');
if ($events_sess.leads.entered_passcode.length > 4) {
console.log('Check the passcode');
handle_check_event_exhibit_staff_passcode();
}
} else {
// console.log('Nothing at this time');
}
function handle_check_event_exhibit_staff_passcode() {
// console.log(`*** handle_check_event_exhibit_staff_passcode() *** $slct_event_exhibit_obj=`, $events_slct.exhibit_obj);
// if (!$events_loc.leads.auth_exhibit_li) {
// $events_loc.leads.auth_exhibit_li = {};
// }
if (!$events_loc.leads.auth_exhibit_kv) {
$events_loc.leads.auth_exhibit_kv = {};
}
if ($events_slct.exhibit_obj && $events_sess.leads.entered_passcode && $events_sess.leads.entered_passcode.length >= 4) {
if ($events_slct.exhibit_obj.staff_passcode == $events_sess.leads.entered_passcode) {
console.log('Passcode matched');
// disable_open_lead_retrieval_btn = false;
$events_sess.leads.entered_passcode = null;
$events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id] = {
key: null,
updated_on: new Date().toISOString()
};
} else {
// console.log('Passcode does not match');
// disable_open_lead_retrieval_btn = true;
return false;
}
} else {
console.log('Missing selected event exhibit and or staff passcode.');
// disable_open_lead_retrieval_btn = true;
return null;
}
if ($events_loc.leads.auto_view) {
// open_exhibit_tracking($events_slct.exhibit_obj.event_exhibit_id_random, event_exhibit_staff_passcode)
} else {
// console.log(document.getElementById('open_lead_retrieval_btn'));
// document.getElementById('open_lead_retrieval_btn').focus();
}
}
$: if ($events_trigger == 'load__event_exhibit_obj' && $events_slct.exhibit_id) {
console.log('Selected Event Exhibit ID:', $events_slct.exhibit_id);
$events_trigger = null;
// handle_load_ae_obj_id__event({event_exhibit_id: $events_slct.exhibit_id, try_cache: false});
let load_event_exhibit_obj = events_func.handle_load_ae_obj_id__exhibit({api_cfg: data.ae_api, exhibit_id: $events_slct.exhibit_id, try_cache: false})
.then(function (result) {
console.log(`load_event_exhibit_obj = `, result);
$events_slct.exhibit_obj = result;
// let license_key = 'example@oneskyit.com';
// $events_slct.exhibit_obj.url = `${data.url.origin}/events_leads/exhibit/${$events_slct.exhibit_id}?license_key=${license_key}&event_id=${$events_slct.event_id}`;
});
// handle_load_ae_obj_id__event_exhibit({event_exhibit_id: $events_slct.exhibit_id, try_cache: false});
}
// // Load the Event Presenter Obj with ID based on the URL param.
// // $events_slct.exhibit_id = data.url.searchParams.get('ae_id');
// $events_slct.exhibit_id = data.url.searchParams.get('event_exhibit_id');
// if ($events_slct.exhibit_id) {
// console.log('Selected Event Presenter ID:', $events_slct.exhibit_id);
// $events_trigger = 'load__event_exhibit';
// // $events_loc.leads.show_edit__event_exhibit_obj = true;
// // $events_trigger = 'show_edit__event_exhibit';
// }
async function handle_load_ae_obj_id__event_exhibit({event_exhibit_id, try_cache=false}) {
console.log(`*** handle_load_ae_obj_id__event_exhibit() *** event_exhibit_id=${event_exhibit_id}`);
let params = {};
// $ae_loc.hub.event_exhibit_id_qry_status = 'loading';
ae_event_exhibit_get_promise = api.get_ae_obj_id_crud({
api_cfg: $ae_api,
obj_type: 'event_exhibit',
obj_id: event_exhibit_id,
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
params: params,
log_lvl: 0
})
.then(function (event_exhibit_get_result) {
if (event_exhibit_get_result) {
$events_slct.exhibit_obj = event_exhibit_get_result;
console.log(`event_exhibit object:`, $events_slct.exhibit);
}
// Auto show the selected event_exhibit ID
// Is this pushState needed here?
// Set the URL param "event_exhibit_id" to the current event_exhibit ID.
// const url = new URL(location);
// url.searchParams.set('event_exhibit_id', $events_slct.exhibit_id);
// history.pushState({}, '', url);
// Is this postMessage needed here?
// let message = {'event_exhibit_id': $events_slct.exhibit_id};
// window.parent.postMessage(message, "*");
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
return ae_event_exhibit_get_promise;
}
async function handle_submit_form_license_update(event) {
console.log('*** handle_submit_form_license_update() ***');
// Data in
let tmp_obj = $event_exhibit_obj;
if ($events_sess.leads.tmp_license.index >= 0 && $events_sess.leads.tmp_license.email && $events_sess.leads.tmp_license.full_name) {
tmp_obj.license_li_json[$events_sess.leads.tmp_license.index] = $events_sess.leads.tmp_license;
console.log('Update license:', tmp_obj);
} else if ($events_sess.leads.tmp_license.index >= 0 && !$events_sess.leads.tmp_license.email && !$events_sess.leads.tmp_license.full_name) {
console.log('No license email and full_name to update and there is an index number. Remove the license.');
console.log('Remove License');
let tmp_obj = $event_exhibit_obj;
tmp_obj.license_li_json.splice($events_sess.leads.tmp_license.index, 1);
console.log('Removed license:', tmp_obj);
} else if ($events_sess.leads.tmp_license.email && $events_sess.leads.tmp_license.full_name) {
tmp_obj.license_li_json.push($events_sess.leads.tmp_license);
console.log('Add license:', tmp_obj);
} else if ($events_sess.leads.tmp_license.index === -1) {
// console.log('No license email and full_name to add or update and index is -1. This was already deleted based on the old index number! Just submit what is already there?', tmp_obj);
} else {
return false;
}
// tmp_obj.license_li_json.push($events_sess.leads.tmp_license);
// Save to local IDB
await db_events.exhibits.put(tmp_obj);
// Save to the database
// Data out
let exhibit_do: key_val = {};
exhibit_do['license_li_json'] = $event_exhibit_obj?.license_li_json;
console.log('exhibit_do:', exhibit_do);
console.log(`ae_ Exhibit Update:`, exhibit_do);
exhibit_submit_results = handle_update__exhibit({
obj_type: 'event_exhibit',
obj_id: $events_slct.exhibit_id,
data: exhibit_do
})
.then( function (exhibit_results) {
console.log(`ae_ Exhibit Update Results:`, exhibit_results);
if (exhibit_results) {
}
return exhibit_results;
})
.finally(function () {
$events_trigger == 'load__event_exhibit_obj'
// $ae_sess.ds.submit_status = 'updated';
});
$events_sess.leads.show_form__license = false;
$events_loc.leads.edit_license_li = false;
}
let exhibit_submit_results: Promise<any>|key_val;
async function handle_submit_form(event) {
console.log('*** handle_submit_form() ***');
// $ae_sess.ds.submit_status = 'processing';
// Data in
let form_data = new FormData(event.target);
console.log(form_data);
let exhibit_di: key_val = ae_util.extract_prefixed_form_data({prefix: null, form_data: form_data, trim_values: true, bool_tf_str: true, log_lvl: 0});
console.log(exhibit_di);
// Data out
let exhibit_do: key_val = {};
// let exhibit_do__license_li_json: key_val = {};
// example: {"scott.idem@oneskyit.com": {"passcode": "12345", "updated_on": "2024-03-04T15:29:59"}, "test+holly@oneskyit.com": {"passcode": "12345", "updated_on": "2024-03-13T15:20:59"}}
let exhibit_do__license_li_json: key_val[] = [];
if (typeof exhibit_di.license_max !== 'undefined') {
exhibit_do['license_max'] = exhibit_di.license_max;
// Loop through the form data licenses up to the license max and create the license list JSON object. The license related fields are prefixed with "license_". This should be pushed to the exhibit_do__license_li_json list.
// for (let i = 0; i < exhibit_di.license_max; i++) {
for (let i = 0; i < (exhibit_di.license_max && 10); i++) {
// let license_key = exhibit_di[`license_${i}`];
let license_email = exhibit_di[`license_${i}_email`];
let license_full_name = exhibit_di[`license_${i}_full_name`];
let license_passcode = exhibit_di[`license_${i}_passcode`];
if (!license_passcode) {
// Generate a random 8 character passcode using a mix of lowercase letters and numbers.
license_passcode = Math.random().toString(36).substring(2, 10);
}
// if (license_key && license_email && license_full_name && license_passcode) {
// exhibit_do__license_li_json.push({
// [license_key]: {
// "email": license_email,
// "full_name": license_full_name,
// "passcode": license_passcode,
// 'updated_on': new Date().toISOString()
// }
// });
// }
if (license_email && license_full_name && license_passcode) {
exhibit_do__license_li_json.push({
"email": license_email,
"full_name": license_full_name,
"passcode": license_passcode,
"session_count": 0, // Max 3 browser sessions?
'updated_on': new Date().toISOString()
});
}
}
}
// if (typeof exhibit_di.license_1 !== 'undefined' && typeof exhibit_di.license_1_passcode !== 'undefined') {
// exhibit_do__license_li_json['passcode'] = exhibit_di.passcode;
// }
exhibit_do['license_li_json'] = exhibit_do__license_li_json;
console.log('exhibit_do:', exhibit_do);
console.log(`ae_ Exhibit Update:`, exhibit_do);
exhibit_submit_results = handle_update__exhibit({
obj_type: 'event_exhibit',
obj_id: $events_slct.exhibit_id,
data: exhibit_do
})
.then( function (exhibit_results) {
console.log(`ae_ Exhibit Update Results:`, exhibit_results);
if (exhibit_results) {
}
return exhibit_results;
})
.finally(function () {
$events_trigger == 'load__event_exhibit_obj'
// $ae_sess.ds.submit_status = 'updated';
});
}
let ae_promises: key_val = {}; // Promise<any>;
async function handle_update__exhibit({
obj_type,
obj_id,
data
}) {
console.log('*** handle_update__exhibit() ***');
$ae_sess.ds.update_status = 'starting';
ae_promises.update__exhibit_obj = api.update_ae_obj_id_crud({
api_cfg: $ae_api,
obj_type: obj_type,
obj_id: obj_id,
fields: data,
key: $ae_api.api_crud_super_key,
log_lvl: 2
})
.then(async function (update__obj_result) {
if (!update__obj_result) {
console.log('The result was null or false.');
return false;
}
return update__obj_result;
})
.catch(function (error) {
console.log('Something went wrong.');
console.log(error);
return false;
})
.finally(function (update__obj_result) {
$ae_sess.ds.update_status = 'finished';
return update__obj_result;
})
return ae_promises.update__exhibit_obj;
}
function send_init_confirm_email({to_email}) {
console.log(`*** send_init_confirm_email() *** to ${to_email}.`);
let license_key = to_email;
let subject = `Leads License Link for ${$event_exhibit_obj.name} (ID: ${$events_slct.exhibit_id})`;
let body_html = `
<div>${$event_exhibit_obj.license_li_json[license_key].full_name},
<p>If this was sent to you incorrectly, plaese ignore.</p>
</div>
<br>
<div>
Exhibit ID: ${$events_slct.exhibit_id}<br>
<p>Use your license key login link below.<br>
Copy and paste link: <a href="${data.url.origin}/events_leads/exhibit/${$events_slct.exhibit_id}?license_key=${license_key}">${data.url.origin}/events_leads/exhibit/${$events_slct.exhibit_id}?license_key=${license_key}&event_id=${$events_slct.event_id}</a></p>
</div>`;
api.send_email({
api_cfg: $ae_api,
from_email: 'noreply+leads@oneskyit.com',
from_name: 'OSIT Events - Leads',
to_email: to_email,
subject: subject,
body_html: body_html,
});
}
function handle_qr_scan_result(event) {
console.log('*** handle_qr_scan_result() ***');
let qr_scan_result = event.detail.result;
console.log(qr_scan_result);
let qr_scan_obj = ae_util.process_data_string(qr_scan_result);
if (qr_scan_obj.qr_type == 'OBJ') {
console.log(`Got a QR type of OBJ. Type ${qr_scan_obj.type}; ID ${qr_scan_obj.id}`);
if (qr_scan_obj.type && qr_scan_obj.id && qr_scan_obj.type == 'event_badge') {
console.log(`Found an Event Badge object type and ID.`);
let event_badge_id = qr_scan_obj.id
$events_sess.leads.qr_scan_result = `Found a badge type with ID: ${event_badge_id}`;
// event_exhibit_tracking_obj_create_promise = await handle_create_event_exhibit_tracking_obj($slct.event_exhibit_id, event_badge_id);
// console.log(event_exhibit_tracking_obj_create_promise);
// if (event_exhibit_tracking_obj_create_promise) {
// console.log('Created new log entry for this badge.');
// console.log(event_exhibit_tracking_obj_create_promise);
// handle_load_event_exhibit_obj({event_exhibit_id: $slct.event_exhibit_id, try_cache: false});
// $slct.event_exhibit_tracking_obj = event_exhibit_tracking_obj_create_promise;
// $slct.event_exhibit_tracking_id = $slct.event_exhibit_tracking_obj.event_exhibit_tracking_id_random;
// // $slct.event_badge_obj = $slct.event_exhibit_tracking_obj.event_badge;
// // $slct.event_badge_id = $slct.event_badge_obj.event_badge_id_random;
// show_add_qr = false;
// qr_scan_result = '';
// qr_scan_obj = {};
// show_tracking_entry = true;
// } else if (event_exhibit_tracking_obj_create_promise === null) {
// console.log('A matching log entry probably exists for this person!');
// } else {
// console.log('Something unexpected happened???');
// }
} else if (qr_scan_obj.type && qr_scan_obj.id && qr_scan_obj.type == 'event_exhibit') {
console.log(`Ignoring.`);
} else if (qr_scan_obj.type && qr_scan_obj.id && qr_scan_obj.type == 'event_person') {
console.log(`Ignoring.`);
} else if (qr_scan_obj.type && qr_scan_obj.id && qr_scan_obj.type == 'event_session') {
console.log(`Ignoring.`);
} else {
console.log(`Ignoring. The object returned was unexpected or not valid.`);
console.log(qr_scan_obj);
}
} else if (qr_scan_obj.qr_type == 'MECARD') {
console.log(`Got a QR type of MECARD. This was not expected, but we will at least display it???`);
// https://github.com/ertant/vCard
// vcard = vCardParser.parse(qr_scan_obj.str); // vCard
// console.log(vcard);
mecard = qr_scan_obj.str.split(';'); // vCard
// NOTE: Next we need to loop through the values and split each again on ":".
// NOTE: Then probably do a second check based on the known key values (N, EMAIL, ADR).
console.log(mecard);
show_mecard = true;
} else {
console.log(`Got a QR type of ${qr_scan_obj.qr_type}. Display warning to user, but otherwise ignoring.`);
console.log(qr_scan_obj);
}
}
function handle_qr_camera(event) {
console.log('*** handle_qr_camera() ***', event.detail);
if (!$ae_loc.hub.qr) {
$ae_loc.hub.qr = {};
}
if (event.detail.status == 'allowed') {
// console.log('Camera access allowed');
$ae_loc.hub.qr.camera_status = 'allowed';
} else if (event.detail.status == 'denied') {
console.log('Camera access denied!?');
$ae_loc.hub.qr.camera_status = 'denied';
}
}
// Updated 2022-04-22
export let get_event_exhibit_tracking_export = async function get_event_exhibit_tracking_export({event_exhibit_id, file_type='CSV', return_file=true, filename=null, auto_download=false, params={}, log_lvl=0}) {
console.log('*** stores_event_api.js: get_event_exhibit_tracking_export() ***');
const endpoint = `/event/exhibit/${event_exhibit_id}/tracking/export`;
if (file_type == 'CSV' || file_type == 'Excel') {
params['file_type'] = file_type;
}
params['return_file'] = true;
let event_exhibit_tracking_export_file_get_promise = await api.get_object({api_cfg: ae_api, endpoint: endpoint, params: params, return_blob: true, filename: filename, auto_download: auto_download, log_lvl: log_lvl});
// console.log(event_exhibit_tracking_export_file_get_promise);
return event_exhibit_tracking_export_file_get_promise;
}
</script>
<section
class="ae_events_leads md:container h-full mx-auto flex flex-col items-center space-y-4"
>
<!-- <Element_data_store
ds_code="page__events_leads__exhibit_main_header"
ds_type="html"
for_type="event"
for_id={$events_slct.event_id}
display="block"
class_li=""
/> -->
<!-- <div
class="events__leads__exhibit_obj_main_about"
class:hidden={$events_loc.leads.tab[$events_slct.exhibit_id] !== 'start'}
>
<Element_data_store
ds_code="events__leads__exhibit_obj_main_about"
ds_type="html"
for_type="event"
for_id={$events_slct.event_id}
display="block"
class_li=""
/>
</div> -->
{#if $events_slct.exhibit_id && $event_exhibit_obj}
<!-- <section class="ae_h_scrollfix"> -->
<!-- <hr>
<p>Mark as logged in by using: events_loc.leads.auth_exhibit_li. This is a key (exhibit ID) and value (started datetime) pair. They can be logged into more than one exhibit at a time. Warn about log out when using the "Use License" button.</p>
<p>Check that the started datetime is still within X period and check against the tracked session timestamps. The table or object field is event_exhibit.license_sess_li.</p>
<p>Exhibit license authorization link: /events_leads/exhibit/[exhibit_id]?key=[license_key]&key_pass=[the_random_passcode]</p>
<hr> -->
<TabGroup
justify="justify-center"
active="variant-ghost-primary"
hover="hover:variant-soft-primary"
flex="flex-1 lg:flex-none"
rounded=""
border=""
class="bg-surface-100-800-token w-full"
>
<Tab
bind:group={$events_loc.leads.tab[$events_slct.exhibit_id]}
name="tab_start"
value={'start'}>
<svelte:fragment slot="lead">
<span class="fas fa-home"></span>
</svelte:fragment>
<!-- Start -->
Main
</Tab>
<!-- Manage - For changing the settings, exporting, and other. -->
<Tab
bind:group={$events_loc.leads.tab[$events_slct.exhibit_id]}
name="tab_manage"
value={'manage'}
disabled={!$events_slct.exhibit_obj || !$events_loc?.leads.auth_exhibit_kv || !$events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id]}
regionTab={!$events_slct.exhibit_obj || !$events_loc?.leads.auth_exhibit_kv || !$events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id] ? 'text-slate-400' : ''}
>
<svelte:fragment slot="lead">
<span class="fas fa-cogs"></span>
</svelte:fragment>
Manage
</Tab>
<Tab
bind:group={$events_loc.leads.tab[$events_slct.exhibit_id]}
name="tab_add_scan"
value={'add_scan'}
disabled={!$events_slct.exhibit_obj || !$events_loc?.leads.auth_exhibit_kv || !$events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id]}
regionTab={!$events_slct.exhibit_obj || !$events_loc?.leads.auth_exhibit_kv || !$events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id] ? 'text-slate-400' : ''}
>
<svelte:fragment slot="lead">
<span class="fas fa-qrcode"></span>
</svelte:fragment>
Add/Scan
</Tab>
</TabGroup>
<!-- BEGIN Tab: Main (start) -->
{#if $events_loc.leads.tab[$events_slct.exhibit_id] === 'start'}
<section class="tab__start flex flex-col wrap justify-center items-center space-y-4 ae_h_scrollfix">
<div class="flex flex-col wrap justify-center items-center">
<h2 class="h3">
<!-- {$events_slct.exhibit_obj.name} -->
<strong>{$event_exhibit_obj?.name ?? 'Welcome to Leads for Exhibits!'}</strong>
<strong>{$event_exhibit_obj?.code ?? ''}</strong>
</h2>
<h3 class="h4">
{#if $events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id] && $events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id].key}
<span class="fas fa-check text-green-500"></span>
{$events_loc?.leads.auth_exhibit_kv[$events_slct.exhibit_id].key}
<button
type="button"
class="btn btn-sm variant-soft-warning"
on:click={() => {
$events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id].key = null;
}}
>
<span class="fas fa-times mx-1"></span>
Clear License
</button>
{:else}
<span class="fas fa-times text-red-500"></span>
No license key selected.
{/if}
</h3>
</div>
{#if $events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id] && $events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id].key}
<p>
You are logged in using the shared exhibit staff passcode and are using the license key for {$events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id].key}. Any leads you collect will be associated with this license key (email address).
</p>
{:else if $events_loc?.leads.auth_exhibit_kv[$events_slct.exhibit_id]}
<p>To use the lead retrieval service, please select a license from the list below.</p>
{:else}
<p>To access this exhibit you must enter the shared staff passcode that you were given. You will then be able to select a license and use the lead retrieval service from your device.</p>
<label class="label variant-glass-warning p-2 px-4 m-2 rounded-full font-bold">Shared exhibit passcode:
<input
type="text"
name="staff_passcode"
bind:value={$events_sess.leads.entered_passcode}
placeholder="Exhibit passcode"
class="input max-w-48 font-mono"
required
>
</label>
{/if}
{#if $events_loc?.leads.auth_exhibit_kv && $events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id]}
<!-- Loop through the key value pairs. Each license key has a passcode, updated_on, etc -->
{#if $event_exhibit_obj?.license_max }
<h2 class="h3">License List (max {$event_exhibit_obj?.license_max})</h2>
{#if $event_exhibit_obj?.license_li_json && $event_exhibit_obj?.license_li_json.length < $event_exhibit_obj?.license_max}
<button
class="btn btn-sm variant-soft-primary w-40"
on:click={() => {
// let tmp_obj = $event_exhibit_obj;
$events_sess.leads.tmp_license = {
// 'index': $event_exhibit_obj?.license_li_json.length, // This is the index of the new license in the list.
'email': 'test+z@oneskyit.com',
'full_name': 'Scott X',
'passcode': 'abcdefg',
'max_reuse': 0,
'updated_on': new Date().toISOString()
};
// tmp_obj.license_li_json.push($events_sess.leads.tmp_license);
// console.log('Add License:', tmp_obj);
// db_events.exhibits.put(tmp_obj);
// This still needs to be saved to the database.
$events_sess.leads.show_form__license = true;
}}
>
<span class="fas fa-edit mx-1"></span>
Add License
</button>
{:else}
<!-- <button
class="btn btn-sm variant-soft-warning w-40"
on:click={() => {
console.log('No more licenses available. Remove the last one from the list?');
let tmp_obj = $event_exhibit_obj;
tmp_obj?.license_li_json.pop();
console.log('Remove License:', tmp_obj);
db_events.exhibits.put(tmp_obj);
// This still needs to be saved to the database.
}}
>
<span class="fas fa-trash mx-1"></span>
Delete License
</button> -->
{/if} <!-- $event_exhibit_obj?.license_li_json.length < $event_exhibit_obj?.license_max -->
<div>Use the "Sign In" or "Email" option buttons below to log in using one of the available licenses. If you select a license that is already in use on another device, it will be logged out. The "Sign In" option will use the license selected with your browser. The "Email" option will send an email with a link to log in.</div>
<section class="ae_license_list ae_h_scrollfix">
<form
on:submit|preventDefault={() => {
console.log('Save License List');
handle_submit_form(event);
}}
id="form__license_table"
class="p-0 m-0"
>
<input type="hidden" name="license_max" value={$event_exhibit_obj?.license_max} />
<!-- <div class="ae_h_scrollfix"> -->
<table class="table table-compact table-hover">
<thead>
<tr>
<th>License</th>
<th>Info</th>
<!-- <th>Email</th> -->
<!-- <th>Full Name</th> -->
<!-- <th>Passcode</th> -->
<th>Save</th>
{#if $events_loc.show_details}
<th
class="text-xs"
on:click={() => {
$events_loc.leads.show_meta__event_exhibit_obj = !$events_loc.leads.show_meta__event_exhibit_obj;
}}
>Meta</th>
{/if}
</tr>
</thead>
<tbody>
<!-- This is somewhat complicated. The license list may be null, 0 length, or other lengths up to around 10 or 15. We need to loop through each existing saved license and then continue up to the license max for the exhibitor. There should be placeholders for all available licenses. The license_max may change and be over or under the current list count. -->
<!-- example: {"scott.idem@oneskyit.com": {"passcode": "12345", "updated_on": "2024-03-04T15:29:59"}, "test+holly@oneskyit.com": {"passcode": "12345", "updated_on": "2024-03-13T15:20:59"}} -->
<!-- example: {} -->
<!-- {#each Object.keys($event_exhibit_obj?.license_li_json || {}).slice(0, $event_exhibit_obj?.license_max) as key} -->
{#each $event_exhibit_obj?.license_li_json as license, index}
<tr>
<!-- Show the current license list information. -->
<td>
<input
type="hidden"
name={`license_${index}`}
required
value={index}
placeholder="Index"
min="1"
class="input text-sm max-w-20 font-mono"
/>
{#if index < $event_exhibit_obj?.license_max}
<!-- Edit the values and save the new license list information. -->
<!-- Button to send an email with the login link -->
<div class="btn-group text-sm">
<button
type="button"
on:click={() => {
console.log(`Use license: ${license.email}`);
if (confirm('Are you sure you want to use this license?')) {
$events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id] = {
key: license.email,
updated_on: new Date().toISOString()
};
}
}}
class="btn btn-sm text-sm variant-soft-primary"
title="Sign in using this license"
>
<span class="fas fa-key mx-1"></span>
Sign In
</button>
<button
type="button"
on:click={() => {
console.log('Send Email');
// Send an email with the login link
send_init_confirm_email({ to_email: license.email });
}}
disabled={!$ae_loc.trusted_access}
class="btn btn-sm text-sm variant-soft-secondary"
title={`TEMPORARILY DISABLED: Send an email with the license login link to ${license.email}`}
>
<span class="fas fa-envelope mx-1"></span>
Email
</button>
<button
type="button"
use:clipboard={$events_slct.exhibit_obj.url}
class="btn btn-sm text-sm variant-soft-tertiary"
class:hidden={!$ae_loc.trusted_access || !$events_loc.show_details}
title={`Copy link to this exhibit (ID: ${$events_slct.exhibit_id})`}
>
<span class="fas fa-copy mx-1"></span>
Copy
</button>
</div>
{:else}
<div class="variant-soft-warning">
<span class="fas fa-lock mx-1"></span>
Disabled license
</div>
{/if}
</td>
<td>
<!-- All elements should be centered horizontally and vertically using flex. -->
<div class="
flex flex-row wrap gap-1
items-center justify-center
content-center
"
>
<div class="flex flex-col gap-1 wrap full_name_email grow">
<span class="text-sm">{license.full_name}</span>
<span class="text-sm">{license.email}</span>
</div>
<span
class="font-bold text-sm"
class:hidden={!$events_loc.show_details}
>
{license.passcode}
</span>
</div>
</td>
<td>
<!-- {#if $events_loc.leads.edit_license_li}
<button
type="submit"
disabled={index >= $event_exhibit_obj?.license_max}
class="btn btn-sm variant-soft-warning">
<span class="fas fa-save mx-1"></span>
Save
</button>
{:else} -->
<div class="btn-group">
<button
type="button"
on:click={() => {
console.log('Edit License');
$events_sess.leads.tmp_license = license;
$events_sess.leads.tmp_license['index'] = index; // This is the index of the license in the list. It will need to be removed before saving back to the list based on the index value.
$events_sess.leads.tmp_license['updated_on'] = new Date().toISOString();
// $events_loc.leads.edit_license_li = true;
$events_sess.leads.show_form__license = true;
}}
class="btn btn-sm variant-soft-warning">
<span class="fas fa-edit mx-1"></span>
Edit
</button>
<button
type="button"
on:click={() => {
console.log('Remove License');
if (confirm('Are you sure you want to remove this license?')) {
// This still needs to be saved to the database.
// Signal that this license should be removed from the list.
// $events_sess.leads.tmp_license.index = -1;
$events_sess.leads.tmp_license.index = index;
$events_sess.leads.tmp_license.email = null;
$events_sess.leads.tmp_license.full_name = null;
handle_submit_form_license_update(event);
}
// let tmp_obj = $event_exhibit_obj;
// tmp_obj?.license_li_json.splice(index, 1);
// console.log('Remove License:', tmp_obj);
// db_events.exhibits.put(tmp_obj);
// This still needs to be saved to the database.
// $events_sess.leads.tmp_license.index = -1;
// Signal that this license should be removed from the list.
// $events_sess.leads.tmp_license.index = index;
// $events_sess.leads.tmp_license.email = null;
// $events_sess.leads.tmp_license.full_name = null;
// handle_submit_form_license_update(event);
}}
class="btn btn-sm variant-soft-error">
<span class="fas fa-trash mx-1"></span>
Remove
</button>
</div>
</td>
{#if $events_loc.show_details}
<td>
<!-- class:hidden={$events_loc.leads.show_meta__event_exhibit_obj} -->
<div class="flex flex-col wrap gap-1 text-xs">
<div class="flex flex-row items-center space-x-2">
<span class="ae_label">Updated On:</span>
<span class="ae_value">{license.updated_on}</span>
</div>
<div class="flex flex-row items-center space-x-2">
<span class="ae_label">Created On:</span>
<span class="ae_value">{license.created_on}</span>
</div>
<div class="flex flex-row items-center space-x-2">
<span class="ae_label">Expires On:</span>
<span class="ae_value">{license.expires_on}</span>
</div>
</div>
</td>
{/if}
</tr>
{/each}
</tbody>
</table>
<!-- </div> --> <!-- .ae_h_scrollfix -->
</form>
</section> <!-- .ae_license_list -->
{/if} <!-- $event_exhibit_obj?.license_max -->
{/if}
</section> <!-- .tab__start -->
<!-- BEGIN Tab: Manage -->
{:else if $events_loc.leads.tab[$events_slct.exhibit_id] == 'manage'}
<section class="tab__manage flex flex-col wrap justify-center items-center space-y-4 ae_h_scrollfix">
<h2 class="h3">
<!-- <span class="fas fa-download"></span> -->
Login and License
</h2>
{#if $events_loc?.leads.auth_exhibit_kv[$events_slct.exhibit_id].key}
<div>
<strong>Logged in and using license for:</strong>
{#if $event_exhibit_obj?.license_li_json}
<!-- <div class="flex flex-row wrap gap-1"> -->
{#each $event_exhibit_obj?.license_li_json as license, index}
{#if license.email === $events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id].key}
<div class="flex flex-row items-center space-x-2">
<span class="ae_label">Name:</span>
<span class="ae_value">{license.full_name}</span>
</div>
{/if}
{/each}
<!-- </div> -->
{/if}
<div class="flex flex-row items-center space-x-2">
<span class="ae_label">Email:</span>
<span class="ae_value">{$events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id].key}
</div>
<div class="flex flex-row items-center space-x-2">
<span class="ae_label">Started:</span>
<span class="ae_value">{ae_util.iso_datetime_formatter($events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id].updated_on, 'datetime_long')}</span>
</div>
<!-- Show the full_name of the person associated with that license key email address. The license information is stored in an array. The license key is not the index number value in the array. Ideally I was planning to make the key the email address, not an array index number. -->
<button
type="button"
class="btn btn-sm variant-soft-warning w-48"
on:click={() => {
$events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id].key = null;
}}
>
<span class="fas fa-times mx-1"></span>
Clear License
</button>
<button
type="button"
on:click={() => {
console.log('Log Out');
$events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id] = null;
}}
title="Log out"
class="btn btn-sm variant-soft-warning w-48"
>
<span class="fas fa-sign-out-alt mx-1"></span>
Log Out
</button>
</div>
{:else if $events_loc?.leads.auth_exhibit_kv[$events_slct.exhibit_id]}
<div class="variant-soft-warning">You are logged in using the shared passcode for the exhibit. You will want to select a license to fully use this lead retrieval service. Please go to the Main tab and select a license to use.</div>
<button
type="button"
on:click={() => {
console.log('Log Out');
$events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id] = null;
}}
title="Log out"
class="btn btn-sm variant-soft-warning w-48"
>
<span class="fas fa-sign-out-alt mx-1"></span>
Log Out
</button>
{:else}
<div class="variant-soft-warning">Please go to the Main tab to login using the shared staff passcode for this exhibit. Then select a license to use.</div>
{/if}
{#if $events_loc?.leads.auth_exhibit_kv[$events_slct.exhibit_id].key}
<hr class="border w-full">
<h2 class="h3">
<!-- <span class="fas fa-download"></span> -->
Export Data
</h2>
<p>Use this to export the leads data for this exhibit to an Excel file format. The data can be downloaded at anytime using the export button below.</p>
<button
type="button"
on:click={() => {
if (!confirm('Download exported data Excel file?')) {
return false;
}
get_event_exhibit_tracking_export({ 'event_exhibit_id': $events_slct.exhibit_id, file_type: 'Excel', 'return_file': true, filename: `lead_retrieval_export_${$events_slct.exhibit_obj.name.replaceAll(' ', '_')}.xlsx`, auto_download: true, log_lvl: 2 });
// .replace(' ', '_')
}}
disabled={true}
class="btn btn-sm variant-soft-primary w-48 mb-1 export_data_btn"
title={`TEMPORARILY DISABLED: Download leads data for ${$events_slct.exhibit_obj.name}`}
>
<span class="fas fa-download mx-1"></span> Export Data
</button>
{/if} <!-- $events_loc?.leads.auth_exhibit_kv[$events_slct.exhibit_id].key -->
<hr class="border w-full">
<h2 class="h3">
<!-- <span class="fas fa-cogs"></span> -->
Additional Settings
</h2>
{#if $events_loc?.leads.auth_exhibit_kv[$events_slct.exhibit_id]}
Turn on iframe mode:
<button
type="button"
on:click={() => {
console.log('Turn on iframe mode');
$ae_loc.iframe = !$ae_loc.iframe;
}}
class="btn btn-sm variant-soft w-48"
>
<span class="fas fa-compress mx-1"></span>
Turn {$ae_loc.iframe ? 'off' : 'on'} iframe mode
</button>
Show or hide additional details:
<button
type="button"
on:click={() => {
console.log('Show/Hide Details');
$events_loc.show_details = !$events_loc.show_details;
}}
class="btn btn-sm variant-soft w-48"
>
<span class="fas fa-eye mx-1"></span>
Show/Hide Details
</button>
<!-- {#if $events_loc?.leads.auth_exhibit_kv && $events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id]}
<button
type="button"
on:click={() => {
console.log('Log Out');
$events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id] = null;
}}
title="Log out"
class="btn variant-soft-primary w-48"
>
<span class="fas fa-sign-out-alt mx-1"></span>
Log Out
</button>
<p>To use the lead retrieval service, please select a license from the list on the Main tab.</p>
{/if} -->
{:else}
<div>You must be logged in to view this tab.</div>
{/if} <!-- $events_loc?.leads.auth_exhibit_kv && $events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id] -->
</section>
<!-- BEGIN Tab: Add/Scan -->
{:else if $events_loc.leads.tab[$events_slct.exhibit_id] == 'add_scan'}
<section class="tab__add_section min-w-full flex flex-col wrap justify-center items-center space-y-4 ae_h_scrollfix">
{#if $events_loc?.leads.auth_exhibit_kv && $events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id]}
{#if $events_loc?.leads.auth_exhibit_kv[$events_slct.exhibit_id].key}
<div>Scanning for:
{$events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id].key}
</div>
{:else}
<div class="variant-soft-warning">Please go to the Main tab and select a license to use.</div>
{/if}
<!-- <div class=""> -->
<Element_qr_scanner show_qr_scan_result={true} show_qr_manual_badge_id_entry_option={true} on:qr_scan_result={handle_qr_scan_result} on:qr_camera={handle_qr_camera} />
<!-- </div> -->
<div class="qr_quick_results variant-soft-secondary font-bold p-4">
{@html $events_sess.leads.qr_scan_result ?? 'No results yet'}
</div>
{:else}
<div class="variant-soft-error">Not logged in. Please log in and select a user license.</div>
{/if} <!-- $events_loc?.leads.auth_exhibit_kv && $events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id] -->
</section>
{/if} <!-- $events_loc.leads.tab[$events_slct.exhibit_id] -->
{/if} <!-- $events_slct.exhibit_id && $event_exhibit_obj -->
</section>
<!-- Use the values from $events_sess.leads.tmp_license to populate the inputs -->
{#if $events_sess.leads.show_form__license}
<div class="ae_quick_modal_container">
<section
class="
ae_quick_popover
events__leads__exhibit_license
z-50
flex
flex-col
gap-4
justify-stretch
"
>
<header class="popover__header flex gap-1 justify-between items-center p-1 border-b">
<h2 class="h3">Edit License</h2>
<div class="popover__actions">
<button
type="button"
class="btn variant-soft-primary"
on:click={() => {
$events_sess.leads.show_form__license = false;
}}
>
<span class="fas fa-times mx-1"></span>
Close
</button>
</div>
</header>
<section class="popover__content grow">
<form
id="form__license_single"
class="form"
on:submit|preventDefault={handle_submit_form_license_update}
>
<!-- <input
type="hidden"
name="exhibit_id_random"
value={}
/> -->
<!-- {#if $ae_loc.trusted_access}
<label for="ds_use_account_id" class="label text-xs inline">Use Account ID
<input
type="checkbox"
name="ds_use_account_id"
class="checkbox"
value="true"
checked={$ae_ds_loc.account_id ? true : false}
/>
</label>
<input
type="text"
name="exhibit_id"
class="input max-w-48 text-xs"
placeholder="Exhibit ID"
value={$ae_ds_loc.exhibit_id}
/>
{/if} -->
<!-- The email address is used as the key, not the index number from the array of licenses. The email address is used to send the login link to the user. The passcode is used to log in. The full name is used to identify the user. The passcode is generated if not provided. -->
<input
type="email"
name="license_email"
placeholder="Email address"
bind:value={$events_sess.leads.tmp_license.email}
required
class="input max-w-48"
/>
<input
type="text"
name="license_full_name"
placeholder="Full name"
bind:value={$events_sess.leads.tmp_license.full_name}
required
class="input max-w-48"
/>
{#if $ae_loc.trusted_access}
<input
type="text"
name="license_passcode"
placeholder="Passcode"
bind:value={$events_sess.leads.tmp_license.passcode}
required
class="input max-w-48"
/>
{/if}
</form>
</section> <!-- .popover__content -->
<footer class="popover__footer flex gap-1 justify-between items-center p-1 border-t">
<div class="popover__content__actions">
<button
type="button"
class="btn variant-soft-warning"
on:click={() => {
if (confirm('Are you sure you want to delete this data store?')) {
// trigger = 'delete__ds__code';
// $slct_trigger = 'delete__ds__code';
}
$events_sess.leads.show_form__license = false;
}}
>
<span class="fas fa-trash mx-1"></span>
Delete
</button>
<button
type="submit"
form="form__license_single"
class="btn variant-soft-primary"
disabled={license_submit_results instanceof Promise && !license_submit_results}
on:click={() => {
// trigger = 'save__ds__code';
// $slct_trigger = 'save__ds__code';
}}
>
<span class="fas fa-save mx-1"></span>
Save
</button>
</div>
<div class="popover__status">
Something text
{#await license_submit_results}
<div class="modal-loading">
<span class="fas fa-spinner fa-spin"></span>
<span class="loading-text">
Saving...
</span>
</div>
{:then license_submit_results}
{#if license_submit_results}
<div>
<span class="fas fa-check text-green-500"></span>
<span class="saved-text">
Saved
</span>
</div>
{/if}
{/await}
<div
class="ae_debug"
class:hidden={!$ae_loc?.debug}
>
submit: {$events_sess?.leads.submit_status__license}
<!-- create: {$events_sess?.leads.create_status__license} -->
<!-- update: {$events_sess?.leads.update_status__license} -->
</div>
</div>
<div class="popover__actions">
<button
type="button"
class="btn variant-soft-primary"
on:click={() => {
$events_sess.leads.show_form__license = false;
}}
>
<span class="fas fa-times mx-1"></span>
Close
</button>
</div>
</footer> <!-- .popover__footer -->
</section> <!-- .ae_quick_popover -->
</div>
{/if}
<style lang="postcss">
div.ae_quick_modal_container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100;
background-color: hsla(0, 0%, 0%, .5);
}
/* The section.ae_quick_modal should be above the rest of the content and centered on the page */
section.ae_quick_popover {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 100;
background-color: hsla(0, 0%, 100%, .95);
padding: 1rem;
border-radius: .5rem;
box-shadow: 0 0 1rem hsla(0, 0%, 0%, .5);
min-height: 30%;
min-width: 80%;
}
</style>