Work on badge printing and the actual badge layout.

This commit is contained in:
Scott Idem
2025-10-09 19:26:35 -04:00
parent 0f05fd708f
commit 74cc5c5d0d
7 changed files with 811 additions and 79 deletions

View File

@@ -18,33 +18,34 @@ let {
}: Props = $props();
// *** Import Svelte specific
// import { browser } from '$app/environment';
import { browser } from '$app/environment';
// *** Import other supporting libraries
import { liveQuery } from "dexie";
import {
ArrowDown01, ArrowDown10, ArrowDownUp,
BetweenVerticalEnd, BetweenVerticalStart,
BookHeart, BookImage, Bookmark, BookOpenText, BriefcaseBusiness,
Check, Copy,
Expand, Eye, EyeOff,
Flag, FlagOff, FilePlus, Fingerprint,
Globe,
Library,
MessageSquareWarning, Minus,
Notebook,
Pencil, Plus,
RemoveFormatting,
SquareLibrary,
Shapes, Share2, ShieldCheck, ShieldMinus, Siren, Skull,
Tags, Target, ToggleLeft, ToggleRight, Trash2, TypeOutline,
X
} from '@lucide/svelte';
// import {
// ArrowDown01, ArrowDown10, ArrowDownUp,
// BetweenVerticalEnd, BetweenVerticalStart,
// BookHeart, BookImage, Bookmark, BookOpenText, BriefcaseBusiness,
// Check, Copy,
// Expand, Eye, EyeOff,
// Flag, FlagOff, FilePlus, Fingerprint,
// Globe,
// Library,
// MessageSquareWarning, Minus,
// Notebook,
// Pencil, Plus,
// RemoveFormatting,
// SquareLibrary,
// Shapes, Share2, ShieldCheck, ShieldMinus, Siren, Skull,
// Tags, Target, ToggleLeft, ToggleRight, Trash2, TypeOutline,
// X
// } from '@lucide/svelte';
import type { key_val } from '$lib/ae_stores';
// import { ae_util } from '$lib/ae_utils/ae_utils';
import { core_func } from '$lib/ae_core/ae_core_functions';
import { ae_snip, ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
import { db_events } from "$lib/ae_events/db_events";
import { events_loc, events_sess, events_slct, events_trigger } from '$lib/ae_events_stores';
@@ -147,9 +148,9 @@ let option_ticket_3_override: any = $state(null);
let slct_badge_type = '';
let qr_type = 'mecard';
let qr_img_src = $state(null);
let img_obj_url = $state(null);
// let qr_type = 'mecard';
// let qr_img_src = $state(null);
// let img_obj_url = $state(null);
/* *** BEGIN *** This should be moved out */
@@ -199,6 +200,36 @@ let lq__event_badge_template_obj = $derived(liveQuery(async () => {
full_name_override = $lq__event_badge_obj?.full_name_override ?? $lq__event_badge_obj?.full_name;
// if (full_name_override) {
// let name_parts = full_name_override.trim().split(' ');
// longest_full_name_override_part = 0;
// for (let part of name_parts) {
// if (part.length > longest_full_name_override_part) {
// longest_full_name_override_part = part.length;
// }
// }
// } else {
// longest_full_name_override_part = 0;
// }
professional_title_override = $lq__event_badge_obj?.professional_title_override ?? $lq__event_badge_obj?.professional_title;
affiliations_override = $lq__event_badge_obj?.affiliations_override ?? $lq__event_badge_obj?.affiliations;
location_override = $lq__event_badge_obj?.location_override ?? $lq__event_badge_obj?.location;
option_other_1_override = $lq__event_badge_obj?.option_other_1_override ?? $lq__event_badge_obj?.option_other_1;
option_other_2_override = $lq__event_badge_obj?.option_other_2_override ?? $lq__event_badge_obj?.option_other_2;
option_ticket_1_override = $lq__event_badge_obj?.option_ticket_1_override ?? $lq__event_badge_obj?.option_ticket_1;
option_ticket_2_override = $lq__event_badge_obj?.option_ticket_2_override ?? $lq__event_badge_obj?.option_ticket_2;
option_ticket_3_override = $lq__event_badge_obj?.option_ticket_3_override ?? $lq__event_badge_obj?.option_ticket_3;
// option_ticket_4_override = $lq__event_badge_obj?.option_ticket_4_override ?? $lq__event_badge_obj?.option_ticket_4;
// option_ticket_5_override = $lq__event_badge_obj?.option_ticket_5_override ?? $lq__event_badge_obj?.option_ticket_5;
// option_ticket_6_override = $lq__event_badge_obj?.option_ticket_6_override ?? $lq__event_badge_obj?.option_ticket_6;
// option_ticket_7_override = $lq__event_badge_obj?.option_ticket_7_override ?? $lq__event_badge_obj?.option_ticket_7;
// option_ticket_8_override = $lq__event_badge_obj?.option_ticket_8_override ?? $lq__event_badge_obj?.option_ticket_8;
return results;
}));
@@ -211,6 +242,11 @@ function preventDefault(fn) {
}
let qr_data_url: any = $state('');
let qr_error_message = $state('');
// Trigger doing a update for event badge
$effect(() => {
if (ae_triggers.event_badge_update) {
@@ -219,16 +255,69 @@ if (ae_triggers.event_badge_update) {
update_complete = false;
}
});
$effect(async () => {
if (browser && $lq__event_badge_obj?.event_badge_id) {
console.log('Generating QR code...');
qr_error_message = '';
qr_data_url = '';
let params: any = {};
params.obj_type = 'event_badge';
params.obj_id = $lq__event_badge_obj?.event_badge_id;
try {
// Use 'vcard' as the qr_type, passing all required params
// const data_url = await core_func.js_generate_qr_code('obj', params);
qr_data_url = core_func.js_generate_qr_code('obj', params);
} catch (error) {
qr_error_message = error.message;
console.error(error);
}
}
});
// Example VCard data
const qrParams = {
n: 'Doe, John',
fn: 'John Doe',
org: 'Acme Corp',
email: 'john.doe@example.com',
tel: '+15551234567',
adr_loc: 'Springfield', // Must be present to include address block
adr_country: 'USA'
// ... include all other necessary parameters
};
/**
* Function to call the QR generation logic
*/
async function get_qr_code() {
console.log('Generating QR code...');
qr_error_message = '';
qr_data_url = '';
try {
// Use 'vcard' as the qr_type, passing all required params
const dataUrl = await core_func.js_generate_qr_code('vcard', qrParams);
qr_data_url = dataUrl;
} catch (error) {
qr_error_message = error.message;
console.error(error);
}
}
</script>
<pre class="whitespace-pre-wrap break-words text-xs">
{JSON.stringify($lq__event_badge_obj, null, 2)}
</pre>
<!--
onclick={() => {
@@ -242,19 +331,119 @@ onkeypress={() => {
// slct_this_badge = true
}} -->
<!-- <button class="btn btn-sm preset-outlined-surface-200-800" onclick={get_qr_code}>Generate VCard QR Code</button> -->
<!-- {#if qr_error_message}
<p style="color: red;">Error: {qr_error_message}</p>
{:else if qr_data_url}
<h2>Generated QR Code:</h2>
<img src={qr_data_url} alt="QR Code" />
{:else}
<p>Click the button to generate the QR code.</p>
{/if} -->
<section
class="event_badge_wrapper event_badge print_area outline"
id="event_badge_{$lq__event_badge_obj?.event_badge_id}"
class="event_badge_wrapper event_badge print_area
flex flex-row flex-wrap gap-4
items-stretch justify-center
p-2 m-0
outline-2 outline-dashed outline-blue-500
"
>
{#if $lq__event_badge_obj && $lq__event_badge_template_obj}
<!-- *** badge_front section start *** -->
<section class="badge_front badge_type__{use_badge_type_code.toLowerCase()}">
<section
class="badge_front badge_type__{use_badge_type_code.toLowerCase()}
max-w-lg
p-0 m-0
text-center
relative
outline-2 outline-red-500/50 hover:outline-red-700/75
group
"
>
<span
class="
print:hidden absolute top-1 left-4
text-xs italic
text-gray-500 group-hover:text-red-800
transition-all
"
>
Front of badge
</span>
<div
class="
print:hidden absolute top-1 right-4
hover:preset-tonal-secondary
transition-all group
flex flex-col gap-1 items-center justify-center
"
class:preset-outlined-warning-200-800={$ae_loc.edit_mode}
class:preset-tonal-warning={$ae_loc.edit_mode}
>
<button
class="
btn btn-sm text-xs
preset-tonal-warning preset-outlined-warning-100-900 hover:preset-filled-secondary-500
transition-all group
"
onclick={() => {
show_event_badge_tools_modal = true;
$ae_loc.edit_mode = !$ae_loc.edit_mode;
}}
title="Edit Badge Information"
>
{#if $ae_loc.edit_mode}
<span class="fas fa-times m-1"></span>
{:else}
<span class="fas fa-edit m-1"></span>
{/if}
<span
class="
hidden
group-hover:inline-block
text-xs
"
>
{#if $ae_loc.edit_mode}
Close Edit
{:else}
Edit Badge Information
{/if}
</span>
</button>
<div
class="w-md max-w-lg m-1 p-1"
class:hidden={!$ae_loc.edit_mode}>
<p class="text-xs italic text-gray-500">
Show list of fields that they can edit here. This may need to broken down in to sections that can be collapsed.
</p>
<ul class="text-left list-disc list-inside text-sm">
<li>Full Name</li>
<li>Professional Title</li>
<li>Affiliations</li>
<li>Location</li>
<li>Option Ticket 1</li>
<li>Option Ticket 2</li>
<li>Option Ticket 3</li>
<li>Option Other 1</li>
<li>Option Other 2</li>
<li>Badge Type</li>
<li>Allow Tracking</li>
<li>Show Print Message</li>
<li>Hide QR Code</li>
</ul>
</div>
</div>
{#if $lq__event_badge_template_obj.header_path}
<div class="badge_header image">
<div class="badge_header image max-w-xl">
<img class="header_image" src="{$lq__event_badge_template_obj.header_path}" alt="check header path">
</div>
{:else}
@@ -267,13 +456,13 @@ onkeypress={() => {
</div>
{/if}
<div class="badge_body">
<div class="badge_body space-y-1">
<div class="person_name"
>
<!-- NOTE: Need to add some logic if any part of the name is 9 characters or more to reduce the font size OR if the total length is more than 15ish to reduce the font size :NOTE -->
<!-- Examples: mSC-tTzL_OA, QLddtYl8sfo -->
<div class="full_name_override_all"
<div class="full_name_override_all text-6xl"
class:str_05={longest_full_name_override_part==5}
class:str_06={longest_full_name_override_part==6}
class:str_07={longest_full_name_override_part==7}
@@ -303,7 +492,7 @@ onkeypress={() => {
</div>
{#if professional_title_override}
<div class="professional_title"
<div class="professional_title text-2xl"
class:str_05={professional_title_override.length==5}
class:str_06={professional_title_override.length==6}
class:str_07={professional_title_override.length==7}
@@ -340,7 +529,7 @@ onkeypress={() => {
{#if affiliations_override || location_override}
<div class="affiliations_location">
{#if affiliations_override}
<div class="affiliations"
<div class="affiliations text-4xl"
class:str_05={affiliations_override.length==5}
class:str_06={affiliations_override.length==6}
class:str_07={affiliations_override.length==7}
@@ -363,7 +552,7 @@ onkeypress={() => {
{/if}
{#if location_override}
<div class="location"
<div class="location text-2xl"
class:str_15={location_override.length>=15}
class:str_20={location_override.length>=20}
class:str_25={location_override.length>=25}
@@ -393,11 +582,11 @@ onkeypress={() => {
{/if}
</span>
{#if $lq__event_badge_template_obj.show_qr_front}
{#await initial_loading_promise}
{#await qr_data_url}
Generating...
{:then result}
{#if initial_loading_promise}
<img class="qr_code mecard_qr" style="" src="/event/qr_image/event_badge_mecard_{$lq__event_badge_obj.event_badge_id_random}?qr_filename=attendee_qr.png" alt="missing QR code">
{#if qr_data_url}
<img class="qr_code mecard_qr" style="" src={qr_data_url} alt="missing QR code">
{/if}
{/await}
{/if}
@@ -458,7 +647,7 @@ onkeypress={() => {
class:v_hide_print={hide_qr}
src={qr_img_src}
src={qr_data_url}
alt="missing QR code"
ondblclick={() => {
@@ -477,14 +666,33 @@ onkeypress={() => {
<!-- *** badge_back (fold under) section start *** -->
<section class="badge_back">
<section
class="badge_back
max-w-lg
p-0 m-0
text-left
relative
outline-2 outline-green-500/50 hover:outline-green-700/75
group
"
>
<span
class="
print:hidden absolute top-1 right-4
text-xs italic
text-gray-500 group-hover:text-green-800
"
>
Back of badge
</span>
{#if $lq__event_badge_template_obj.secondary_header_path}
<div class="badge_back_header image">
<div class="badge_back_header image max-w-xl">
<img class="header_image" src="{$lq__event_badge_template_obj.secondary_header_path}" alt="check secondary header path">
</div>
{:else if $lq__event_badge_template_obj.header_path}
<div class="badge_back_header image">
<div class="badge_back_header image max-w-xl">
<img class="header_image" src="{$lq__event_badge_template_obj.header_path}" alt="check primary header path">
</div>
{:else}
@@ -533,24 +741,25 @@ onkeypress={() => {
{$lq__event_badge_obj.given_name}'s
QR Code and Badge ID:
</div>
{#await event_badge_qr_id_get_promise}
{#await qr_data_url}
<!-- Must use this await when the image is generated. It either happens here or on the $effect with async -->
Generating...
{:then result}
{#if event_badge_qr_id_get_promise}
<div class="qr_badge_id_part_1">
{#if result}
<div class="qr_badge_id_part_1 flex flex-row items-center justify-between">
<img
class="qr_code mecard_qr"
class="qr_code mecard_qr max-w-48 hover:scale-200 transition-transform duration-200 ease-in-out hover:p-4 hover:border-2 hover:border-red-500 hover:bg-white"
class:v_hide_print={hide_qr}
src={qr_img_src}
src={result}
alt="badge QR code"
ondblclick={() => {
// (hide_qr) ? hide_qr = !hide_qr : hide_qr;
(hide_qr) ? hide_qr = false : hide_qr = true;
}}
/>
<div class="qr_badge_id_agreement fs_xs f_align_justify">
<div class="qr_badge_id_agreement fs_xs f_align_justify text-xs">
{#if allow_tracking}
<p>This was <strong>allowed</strong> at the time your badge was printed. You may opt-out at anytime.</p>
<p>By allowing this QR code to be scanned by an exhibitor and/or industry supporter, you understand and agree that they may use your personal information.</p>
@@ -570,7 +779,7 @@ onkeypress={() => {
</div>
{/if}
<div class="container app_information">
<div class="container app_information text-xs">
<strong>Download Meeting App:</strong>
<!-- <img style="width: .75in; float: right;" src="/event/qr_image/testing123" alt="missing person information QR code"> -->
<ol style="margin: 0; padding-top: 0; padding-bottom: 0;">
@@ -664,7 +873,8 @@ onkeypress={() => {
</div>
<div class="badge_back_footer">
<div class="badge_back_footer text-xxs italic text-gray-500">
<!-- This will need to be rotated with CSS for printing on the fanfold badges. -->
Fold in half here
<!-- <ol>
<li>Fold this section under the badge.</li>
@@ -678,10 +888,10 @@ onkeypress={() => {
<!-- *** receipt section start *** -->
<section class="receipt"> <!-- receipt class div start -->
<section class="receipt hidden"> <!-- receipt class div start -->
<div class="receipt_header">
<img class="badge_logo" src="{$lq__event_badge_template_obj.logo_path}" alt="check badge logo">
<img class="badge_logo max-w-sm" src="{$lq__event_badge_template_obj.logo_path}" alt="check badge logo">
<div class="banner_text">
<div class="row_one">{$lq__event_badge_template_obj.header_row_1}</div>
<div class="row_two">{$lq__event_badge_template_obj.header_row_2}</div>
@@ -731,7 +941,7 @@ onkeypress={() => {
<!-- *** ticket section start *** -->
<section class="tickets_left_container">
<section class="tickets_left_container hidden">
<div class="tickets"> <!-- Fold class div start -->
<div class="ticket_container ticket_1">
@@ -761,7 +971,7 @@ onkeypress={() => {
<!-- *** ticket section start *** -->
<section class="tickets_right_container">
<section class="tickets_right_container hidden">
<div class="tickets"> <!-- Fold class div start -->
<div class="ticket_container ticket_5">
@@ -793,3 +1003,11 @@ onkeypress={() => {
{/if} <!-- End if for lq__event_badge_template_obj -->
</section>
<pre class="whitespace-pre-wrap break-words text-xs max-h-24 overflow-auto p-2 bg-surface-200 border border-surface-300 rounded">
{JSON.stringify($lq__event_badge_obj, null, 2)}
</pre>