Files
OSIT-AE-App-Svelte/src/routes/events_leads/exhibit/[slug]/+page.svelte

1181 lines
45 KiB
Svelte

<script lang="ts">
/** @type {import('./$types').PageData} */
export let data: any;
// console.log(`ae_events_leads exhibit [slug] +page.svelte data:`, data);
import { onMount } from 'svelte';
import { goto, invalidate, pushState, replaceState } from '$app/navigation';
import { clipboard, FileDropzone, getModalStore, localStorageStore, ProgressRadial, RadioGroup, RadioItem, TabGroup, Tab, TabAnchor } from '@skeletonlabs/skeleton';
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';
// Quickly save the data passed from the parent(s) to the Svelte stores, localStorage, and other.
$slct.account_id = data.account_id;
console.log(`$slct.account_id = `, $slct.account_id);
let ae_acct = data[$slct.account_id];
console.log(`ae_acct = `, ae_acct);
$events_slct.exhibit_id = ae_acct.slct.event_exhibit_id;
$events_slct.exhibit_obj = ae_acct.slct.event_exhibit_obj;
$events_slct.exhibit_tracking_obj_li = ae_acct.slct.event_exhibit_tracking_obj_li;
import Leads_add_scan from './leads_add_scan.svelte';
import Leads_list from './leads_list.svelte';
import Leads_manage from './leads_manage.svelte';
import Leads_payment from './leads_payment.svelte';
let event_exhibit_obj = liveQuery(
() => db_events.exhibits.get($events_slct.exhibit_id)
// () => 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($events_slct.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(`No ID! Nothing to show. Try setting the ID again.`);
$events_slct.exhibit_id = $events_slct.exhibit_id;
}
// We need to remove the url_passcode from the URL GET params after we use it. It should be safe to assume that onMount is a safe place to do this.
let url_passcode = data.url.searchParams.get('passcode');
if (url_passcode) {
console.log(`ae_events_leads exhibit [slug] +page.svelte: event_exhibit_id=${$events_slct.exhibit_id}; passcode=${url_passcode}`);
$events_sess.leads.entered_passcode = url_passcode;
// console.log('Remove the passcode from the URL.');
data.url.searchParams.delete('passcode');
let new_url = data.url.toString()
console.log(new_url);
goto(new_url, {replaceState: true});
}
// Look for a license key (email address) and passcode in the URL params. The email address may have had a plus symbol and replaced with a space. (example: test+more@example.com) This needs to be fixed.
let url_lic_key = data.url.searchParams.get('key');
let url_lic_pass = data.url.searchParams.get('pass');
if (url_lic_key && url_lic_pass) {
// Replace the space with a plus symbol.
url_lic_key = url_lic_key.replace(/ /g, '+');
console.log(`ae_events_leads exhibit [slug] +page.svelte: event_exhibit_id=${$events_slct.exhibit_id}; key=${url_lic_key}; pass=${url_lic_pass}`);
// Check the license key and passcode against the event exhibit object.
console.log($events_slct.exhibit_obj.license_li_json);
// We need to loop through the $events_slct.exhibit_obj.license_li_json list/array and check if the "email" and "passcode" matches.
if ($events_slct.exhibit_obj.license_li_json && $events_slct.exhibit_obj.license_li_json.length) {
for (let i = 0; i < $events_slct.exhibit_obj.license_li_json.length; i++) {
console.log(`${i} License email: ${$events_slct.exhibit_obj.license_li_json[i].email}; License passcode: ${$events_slct.exhibit_obj.license_li_json[i].passcode}`);
if ($events_slct.exhibit_obj.license_li_json[i].email == url_lic_key && $events_slct.exhibit_obj.license_li_json[i].passcode == url_lic_pass) {
console.log('License key passcode matched');
$events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id] = {
key: url_lic_key,
updated_on: new Date().toISOString()
};
if ($events_loc.leads.auto_hide_on_sign_in) {
$events_loc.leads.tab[$events_slct.exhibit_id] = 'add_scan';
$ae_loc.iframe = true;
}
data.url.searchParams.delete('key');
data.url.searchParams.delete('pass');
let new_url = data.url.toString()
console.log(new_url);
goto(new_url, {replaceState: true});
} else {
console.log('License key passcode does not match');
}
}
}
}
});
// console.log(`$ae_loc = `, $ae_loc);
$: if ($events_slct.exhibit_obj && $events_sess.leads.entered_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: true});
let load_event_exhibit_obj = events_func.handle_load_ae_obj_id__exhibit({api_cfg: ae_acct.api, exhibit_id: $events_slct.exhibit_id, try_cache: false})
.then(function (result) {
console.log(`load_event_exhibit_obj = `, result);
// Check if the license_li_json is an array and if not, convert it to an array.
if (result?.license_li_json && !Array.isArray(result.license_li_json)) {
console.log('Convert license_li_json to an array.');
result.license_li_json = [];
}
$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}`;
});
}
async function handle_submit_form_license_update(event) {
console.log('*** handle_submit_form_license_update() ***');
console.log(`$events_sess.leads=`, $events_sess.leads.tmp_license);
// Data in
let tmp_obj = $event_exhibit_obj;
console.log('tmp_obj:', tmp_obj);
if ($events_sess.leads.tmp_license.index === null && $events_sess.leads.tmp_license.email && $events_sess.leads.tmp_license.full_name) {
if (!Array.isArray(tmp_obj.license_li_json)) {
tmp_obj.license_li_json = [];
}
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 >= 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.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: 1
})
.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({index, lic_key, lic_pass}) {
console.log(`*** send_init_confirm_email() *** to ${lic_key}.`);
let to_email = lic_key;
let sign_in_url = encodeURI(`${data.url.origin}/events_leads/exhibit/${$events_slct.exhibit_id}?key=${lic_key}&pass=${lic_pass}`);
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[index].full_name},
<p>If this was sent to you incorrectly, please ignore.</p>
</div>
<br>
<div>
<p>Exhibit: ${$event_exhibit_obj?.name}<br>
Exhibit ID: ${$events_slct.exhibit_id}</p>
<p>Use the link below to sign in using your leads license.<br>
Copy and paste link: <a href="${sign_in_url}">${sign_in_url}</a></p>
<p>If the email or passcode for your license is changed, this link will no longer work.</p>
</div>
`;
api.send_email({
api_cfg: $ae_api,
from_email: 'noreply+leads@oneskyit.com',
from_name: 'OSIT Exhibit Leads',
to_email: to_email,
subject: subject,
body_html: body_html,
});
}
</script>
<section
class="ae_events_leads md:container h-full mx-auto flex flex-col items-center space-y-4 pt-0 pb-8"
>
<!-- <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"
>
{#if $events_loc.leads.show_option__paid_tab ?? true}
<Tab
bind:group={$events_loc.leads.tab[$events_slct.exhibit_id]}
name="tab_payment"
value={'payment'}
>
<svelte:fragment slot="lead">
{#if !$event_exhibit_obj?.priority}
<span class="fas fa-question text-red-500"></span>
{:else}
<span class="fas fa-check text-green-500"></span>
{/if}
<span class="fas fa-credit-card mx-1"></span>
</svelte:fragment>
{#if $event_exhibit_obj?.priority}
<span class="">Paid</span>
{:else}
<span class="text-xs">License
Payment</span>
{/if}
</Tab>
{/if}
<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>
<!-- Add/Scan - For adding attendee leads by manually adding their ID or scanning their QR code. -->
<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' : 'text-tertiary-500'}
>
<svelte:fragment slot="lead">
<span class="fas fa-qrcode"></span>
</svelte:fragment>
Add/Scan
</Tab>
<!-- Leads - For viewing and managing the leads that have been collected. -->
<Tab
bind:group={$events_loc.leads.tab[$events_slct.exhibit_id]}
name="tab_leads"
value={'leads'}
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-users"></span>
</svelte:fragment>
Leads
</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={
!($ae_loc.administrator_access && $events_slct.exhibit_obj)
&&
!($events_loc?.leads.auth_exhibit_kv && $events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id])
}
regionTab={
!($ae_loc.administrator_access && $events_slct.exhibit_obj)
&&
!($events_loc?.leads.auth_exhibit_kv && $events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id]) ? 'text-slate-400' : ''
}
title="Manage the exhibit settings, licenses, and other."
>
<svelte:fragment slot="lead">
<span class="fas fa-cogs"></span>
</svelte:fragment>
<!-- Manage -->
Conf
</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-ghost-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 if $events_loc.leads.auth_exhibit_kv[$events_slct.exhibit_id]}
<span class="fas fa-times text-red-500"></span>
No license key selected
{:else}
<span class="fas fa-times text-red-500"></span>
Enter the shared exhibit passcode
{/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 class="border border-slate-500/10 p-2 variant-soft-secondary">
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). Use the Clear License button to "log out" or Sign In with a different license.
</p>
{:else if $events_loc?.leads.auth_exhibit_kv[$events_slct.exhibit_id]}
<p class="border border-slate-500/10 p-2 variant-soft-warning">Please select your name from the license list below to use the lead retrieval service. You may need to add your name first. This is also used to link new leads to whoever adds them.</p>
{:else}
<p class="border border-slate-500/10 p-2 variant-soft-warning">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
autofocus
>
</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>
<div class="border border-slate-500/10 p-2 variant-soft-secondary">Use the "Sign In" or "Email" option buttons below to log in using one of the available licenses. Be sure use the one with your name and email address. If you select a license that is already in use on another device, it will be logged out.
<ul
class="list-disc list-inside"
>
<li>"<strong>Sign In</strong>" option - Use this to sign and use the license with your current browser and device.</li>
<li>"<strong>Email</strong>" option - Use this to send an email with a link to log in. You may want to use this to send the link to other staff associated with this exhibit.</li>
</ul>
</div>
{#if !Array.isArray($event_exhibit_obj?.license_li_json) || (Array.isArray($event_exhibit_obj?.license_li_json) && $event_exhibit_obj?.license_li_json.length < $event_exhibit_obj?.license_max)}
<button
class="btn btn-sm variant-ghost-primary w-40"
on:click={() => {
// let tmp_obj = $event_exhibit_obj;
$events_sess.leads.tmp_license = {
'index': null,
// '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
// The passcode should default to a random 5 digit number.
'passcode': Math.random().toString(36).substring(2, 8),
'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>
{/if} <!-- $event_exhibit_obj?.license_li_json.length < $event_exhibit_obj?.license_max -->
<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"> -->
{#if Array.isArray($event_exhibit_obj?.license_li_json) && $event_exhibit_obj?.license_li_json.length > 0}
<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 btn-group-vertical sm:btn-group-vertical md:btn-group lg:btn-group xl: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()
};
if ($events_loc.leads.auto_hide_on_sign_in) {
$events_loc.leads.tab[$events_slct.exhibit_id] = 'add_scan';
$ae_loc.iframe = true;
}
}
}}
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
if (confirm(`Are you sure you want to send an email with the login link to ${license.email}?`)) {
send_init_confirm_email({ index: index, lic_key: license.email, lic_pass: license.passcode});
}
// send_init_confirm_email({ index: index, lic_key: license.email, lic_pass: license.passcode});
}}
class="btn btn-sm text-sm variant-soft-secondary"
title={`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={encodeURI(`${data.url.origin}/events_leads/exhibit/${$events_slct.exhibit_id}?key=${license.email}&pass=${license.passcode}`)}
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 btn-group-vertical sm:btn-group-vertical md:btn-group lg:btn-group xl:btn-group text-sm">
<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 only clears their name and email address so that it can be used by someone else. (The same as editing it.')) {
// 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);
}
}}
class:hidden={!$ae_loc.trusted_access}
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>
{:else}
<div class="variant-soft-warning">No licenses found. Add a license above.</div>
{/if} <!-- Array.isArray(result.license_li_json) -->
<!-- </div> --> <!-- .ae_h_scrollfix -->
</form>
</section> <!-- .ae_license_list -->
{/if} <!-- $event_exhibit_obj?.license_max -->
{/if}
</section> <!-- .tab__start -->
<!-- BEGIN Tab: Add/Scan -->
{:else if $events_loc.leads.tab[$events_slct.exhibit_id] == 'add_scan'}
<Leads_add_scan />
<!-- BEGIN Tab: Leads -->
{:else if $events_loc.leads.tab[$events_slct.exhibit_id] == 'leads'}
<Leads_list />
<!-- BEGIN Tab: Manage -->
{:else if $events_loc.leads.tab[$events_slct.exhibit_id] == 'manage'}
<Leads_manage />
<!-- BEGIN Tab: Payment -->
{:else if $events_loc.leads.tab[$events_slct.exhibit_id] == 'payment'}
<Leads_payment />
{/if} <!-- $events_loc.leads.tab[$events_slct.exhibit_id] -->
<!-- End of tab content -->
{/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. -->
<div class="border border-slate-500/10 p-2 variant-soft-warning">
<strong>Do not use the same email address for more than one license.</strong> The email address is used as the key to log in and is linked to leads added. The full name is used to help identify the staff person.
</div>
<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 m-1"
/>
<input
type="email"
name="license_email"
placeholder="Email address"
bind:value={$events_sess.leads.tmp_license.email}
required
class="input max-w-64 m-1"
/>
{#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 m-1"
/>
{/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"
on:click={() => {
console.log('Remove License');
if (confirm('Are you sure you want to remove this license? This only clears their name and email address so that it can be used by someone else. (The same as editing it.)')) {
// 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;
$events_sess.leads.tmp_license.passcode = null;
handle_submit_form_license_update(event);
$events_sess.leads.show_form__license = false;
}
}}
class:hidden={$events_sess.leads.tmp_license.index === null}
class="btn variant-soft-warning m-1"
>
<span class="fas fa-broom mx-1"></span>
Remove
</button>
<button
type="submit"
form="form__license_single"
class="btn variant-soft-primary m-1"
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">
/* Use the div.ae_quick_modal_container to block background clicks when using the section.ae_quick_popover. */
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_popover 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>