feat(badges): goto() after print with per-device fallback toggle
Switch post-print navigation from window.location.href to goto() for faster SvelteKit client-side transition back to Badge Search (no full reload). A nav_to_badges() helper in print controls branches on badges_loc.print_nav_use_goto (default true). Badges Config page gains a "Local Device Settings" section with a checkbox to disable goto() and fall back to hard reload — stored in localStorage per browser, not synced to the event. Useful as an on-site escape hatch without a code deploy. Also fixes the Templates button on the config page: adds the standard border border-surface-300-700 so it looks like a button. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -138,6 +138,10 @@ export interface BadgesLocState {
|
|||||||
trusted_search_min_chars: number;
|
trusted_search_min_chars: number;
|
||||||
// Timestamp when the remote config was last mirrored locally
|
// Timestamp when the remote config was last mirrored locally
|
||||||
remote_cfg_last_synced_on: string | null;
|
remote_cfg_last_synced_on: string | null;
|
||||||
|
// After-print navigation method. true (default) = SvelteKit goto() — faster, no full reload.
|
||||||
|
// false = window.location.href — full page reload, use as a fallback if goto causes issues.
|
||||||
|
// Per-device: stored in localStorage, not synced to the event config.
|
||||||
|
print_nav_use_goto: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BadgesSessState {
|
export interface BadgesSessState {
|
||||||
@@ -203,7 +207,8 @@ export const badges_loc_defaults: BadgesLocState = {
|
|||||||
auth_search_min_chars: 2,
|
auth_search_min_chars: 2,
|
||||||
trusted_search_result_limit: 150,
|
trusted_search_result_limit: 150,
|
||||||
trusted_search_min_chars: 1,
|
trusted_search_min_chars: 1,
|
||||||
remote_cfg_last_synced_on: null
|
remote_cfg_last_synced_on: null,
|
||||||
|
print_nav_use_goto: true
|
||||||
};
|
};
|
||||||
|
|
||||||
// In-memory badge state — resets on page load.
|
// In-memory badge state — resets on page load.
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import type { key_val } from '$lib/stores/ae_stores';
|
|||||||
import { ae_api, ae_loc } from '$lib/stores/ae_stores';
|
import { ae_api, ae_loc } from '$lib/stores/ae_stores';
|
||||||
import { events_func } from '$lib/ae_events/ae_events_functions';
|
import { events_func } from '$lib/ae_events/ae_events_functions';
|
||||||
import { browser } from '$app/environment';
|
import { browser } from '$app/environment';
|
||||||
|
import { goto } from '$app/navigation';
|
||||||
|
import { badges_loc } from '$lib/stores/ae_events_stores__badges.svelte';
|
||||||
import {
|
import {
|
||||||
Check,
|
Check,
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
@@ -211,6 +213,19 @@ let can_print = $derived((is_public && !is_printed) || (is_trusted && is_global_
|
|||||||
type PrintStatus = 'idle' | 'loading' | 'done' | 'error';
|
type PrintStatus = 'idle' | 'loading' | 'done' | 'error';
|
||||||
let print_status: PrintStatus = $state('idle');
|
let print_status: PrintStatus = $state('idle');
|
||||||
|
|
||||||
|
// Navigate back to badge search after print completes.
|
||||||
|
// goto() is the default: faster SvelteKit client-side navigation, no full reload.
|
||||||
|
// Falls back to window.location.href if badges_loc.print_nav_use_goto is disabled —
|
||||||
|
// useful as an on-site escape hatch if the goto() path causes unexpected issues.
|
||||||
|
function nav_to_badges() {
|
||||||
|
if (!browser) return;
|
||||||
|
if (badges_loc.current.print_nav_use_goto) {
|
||||||
|
goto(`/events/${event_id}/badges`);
|
||||||
|
} else {
|
||||||
|
window.location.href = `/events/${event_id}/badges`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function handle_print_badge() {
|
async function handle_print_badge() {
|
||||||
if (!$lq__event_badge_obj?.event_badge_id) return;
|
if (!$lq__event_badge_obj?.event_badge_id) return;
|
||||||
print_status = 'loading';
|
print_status = 'loading';
|
||||||
@@ -232,7 +247,7 @@ async function handle_print_badge() {
|
|||||||
if (browser) window.print();
|
if (browser) window.print();
|
||||||
print_status = 'error';
|
print_status = 'error';
|
||||||
await new Promise<void>((r) => setTimeout(r, 4000));
|
await new Promise<void>((r) => setTimeout(r, 4000));
|
||||||
if (browser) window.location.href = `/events/${event_id}/badges`;
|
nav_to_badges();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,7 +273,7 @@ async function handle_print_badge() {
|
|||||||
// Hold the error state long enough for a kiosk operator to notice before
|
// Hold the error state long enough for a kiosk operator to notice before
|
||||||
// the loop returns to search for the next attendee.
|
// the loop returns to search for the next attendee.
|
||||||
await new Promise<void>((r) => setTimeout(r, 4000));
|
await new Promise<void>((r) => setTimeout(r, 4000));
|
||||||
if (browser) window.location.href = `/events/${event_id}/badges`;
|
nav_to_badges();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,13 +283,13 @@ async function handle_print_badge() {
|
|||||||
// Brief success flash, then return to badge search
|
// Brief success flash, then return to badge search
|
||||||
await new Promise<void>((r) => setTimeout(r, 1000));
|
await new Promise<void>((r) => setTimeout(r, 1000));
|
||||||
// Full navigation back to badge search — avoids goto() lint rule in child components
|
// Full navigation back to badge search — avoids goto() lint rule in child components
|
||||||
if (browser) window.location.href = `/events/${event_id}/badges`;
|
nav_to_badges();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Badge print controls: print error:', err);
|
console.error('Badge print controls: print error:', err);
|
||||||
print_status = 'error';
|
print_status = 'error';
|
||||||
if (browser) window.print();
|
if (browser) window.print();
|
||||||
await new Promise<void>((r) => setTimeout(r, 4000));
|
await new Promise<void>((r) => setTimeout(r, 4000));
|
||||||
if (browser) window.location.href = `/events/${event_id}/badges`;
|
nav_to_badges();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,9 +28,11 @@ import {
|
|||||||
ChevronUp,
|
ChevronUp,
|
||||||
FileText,
|
FileText,
|
||||||
Lock,
|
Lock,
|
||||||
|
Monitor,
|
||||||
Save,
|
Save,
|
||||||
Settings
|
Settings
|
||||||
} from '@lucide/svelte';
|
} from '@lucide/svelte';
|
||||||
|
import { badges_loc } from '$lib/stores/ae_events_stores__badges.svelte';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
data: any;
|
data: any;
|
||||||
@@ -272,9 +274,9 @@ function toggle(key: string) {
|
|||||||
<h1 class="text-xl font-bold">Badges Config</h1>
|
<h1 class="text-xl font-bold">Badges Config</h1>
|
||||||
</div>
|
</div>
|
||||||
<a href="/events/{event_id}/templates"
|
<a href="/events/{event_id}/templates"
|
||||||
class="btn btn-sm preset-tonal-surface"
|
class="btn btn-sm preset-tonal-surface border border-surface-300-700"
|
||||||
title="Manage Badge Templates">
|
title="Manage Badge Templates">
|
||||||
<FileText size="1em" class="mr-1" /> Templates
|
<FileText size="1em" /> Templates
|
||||||
</a>
|
</a>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
{#if save_status === 'success'}
|
{#if save_status === 'success'}
|
||||||
@@ -555,6 +557,35 @@ function toggle(key: string) {
|
|||||||
{/if}
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- ================================================================ -->
|
||||||
|
<!-- LOCAL DEVICE SETTINGS (localStorage only — not saved to event) -->
|
||||||
|
<!-- ================================================================ -->
|
||||||
|
<section class="border-surface-200-800 rounded-xl border">
|
||||||
|
<div class="flex w-full items-center justify-between px-4 py-3">
|
||||||
|
<span class="flex items-center gap-2 font-semibold">
|
||||||
|
<Monitor size="1em" class="text-surface-400" />
|
||||||
|
Local Device Settings
|
||||||
|
</span>
|
||||||
|
<span class="text-xs text-surface-400 italic">saved to this browser only · not synced</span>
|
||||||
|
</div>
|
||||||
|
<div class="border-surface-200-800 space-y-3 border-t px-4 py-3">
|
||||||
|
<label class="flex items-start gap-3">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="checkbox mt-0.5 shrink-0"
|
||||||
|
bind:checked={badges_loc.current.print_nav_use_goto} />
|
||||||
|
<div>
|
||||||
|
<p class="text-sm font-medium">Use fast navigation after print</p>
|
||||||
|
<p class="text-xs text-surface-400 italic">
|
||||||
|
On by default. Uses SvelteKit client-side navigation to return to Badge Search
|
||||||
|
after printing — faster and avoids a full page reload. Turn off to fall back to
|
||||||
|
a hard page reload if the print loop behaves unexpectedly on this device.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Bottom save button -->
|
<!-- Bottom save button -->
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<button
|
<button
|
||||||
|
|||||||
Reference in New Issue
Block a user