Files
OSIT-AE-App-Svelte/src/routes/events/[event_id]/(launcher)/launcher_session_view.svelte
Scott Idem ab2b984c25 fix(launcher): resolve metadata flickering and harden session reactivity
- Standardized default view to 'alt' for session loading to ensure persistent file counts.\n- Hardened 'No files' warning logic to prevent false positives during background refreshes.\n- Restored reactive session observable in layout for global header and idle logic.\n- Documented overwrite pitfalls in SVELTE_DEXIE_GUIDE.md.
2026-02-10 18:31:59 -05:00

571 lines
25 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script lang="ts">
interface Props {
slct__event_session_id?: string | null;
type_code?: string;
log_lvl?: number;
}
let {
slct__event_session_id = $bindable(null),
type_code = $bindable(''),
log_lvl = $bindable(1)
}: Props = $props();
import type { key_val } from '$lib/stores/ae_stores';
import { ae_util } from '$lib/ae_utils/ae_utils';
// import Element_ae_crud from '$lib/element_ae_crud.svelte';
import Event_launcher_file_cont from './launcher_file_cont.svelte';
import Launcher_presentation_view from './launcher_presentation_view.svelte';
import Launcher_presenter_view from './launcher_presenter_view.svelte';
import Launcher_presenter_view_posters from './launcher_presenter_view_posters.svelte';
import { liveQuery } from 'dexie';
// import { core_func } from '$lib/ae_core_functions';
// import { db_core } from "$lib/db_core";
import {
ae_snip,
ae_loc,
ae_sess,
ae_api,
ae_trig,
slct,
slct_trigger
} from '$lib/stores/ae_stores';
import { db_events } from '$lib/ae_events/db_events';
import {
events_loc,
events_sess,
events_slct,
events_trigger
} from '$lib/stores/ae_events_stores';
import { events_func } from '$lib/ae_events_functions';
// Event Session (Main View Trigger)
let lq__event_session_obj = $derived(
liveQuery(() => db_events.session.get(slct__event_session_id))
);
// import Event_launcher_file_cont from './launcher_file_cont.svelte';
// export let hide_description: boolean = true;
// export let show_designations: boolean = false;
// export let show_email: boolean = false;
// Event File (for a Session)
let lq__event_file_obj_li = $derived(
liveQuery(async () => {
if (log_lvl) {
console.log(
`lq__event_file_obj: event_file_id = ${$events_slct?.event_file_id}`
);
}
let results = await db_events.file
// .where('event_session_id')
.where('for_id')
.equals(slct__event_session_id)
.reverse() // Need reverse for created_on newest first.
.sortBy('created_on'); // or filename
if (log_lvl) {
console.log(`lq__event_file_obj_li: results = `, results);
}
// Check if results are different than the current $events_slct.event_file_obj_li
if ($events_slct.event_file_obj_li && results) {
if (
JSON.stringify($events_slct.event_file_obj_li) !==
JSON.stringify(results)
) {
$events_slct.event_file_obj_li = [...results];
if (log_lvl) {
console.log(
`$events_slct.event_file_obj_li has changed for event_session_id: ${slct__event_session_id}`,
$events_slct.event_file_obj_li
);
}
} else {
if (log_lvl) {
console.log(
`$events_slct.event_file_obj_li has not changed for event_session_id: ${slct__event_session_id}`
);
}
}
} else if (results) {
$events_slct.event_file_obj_li = [...results];
}
return results;
})
);
// Does not refresh when the event_file_id_li_json changes.
// let lq_get__event_file_obj_li = liveQuery(
// () => db_events.file
// .bulkGet($lq__event_session_obj?.event_file_id_li_json ?? [''])
// );
// console.log(`$lq__event_session_obj?.event_file_id_li_json = `, $lq__event_session_obj?.event_file_id_li_json);
// Event Presentation
// let lq__event_presentation_obj = liveQuery(
// () => db_events.presentation
// .get($events_slct.event_presentation_id)
// );
let lq__event_presentation_obj_li = $derived(
liveQuery(async () => {
if (log_lvl) {
console.log(
`lq__event_presentation_obj_li: slct__event_session_id = ${slct__event_session_id}`
);
}
let sort_by = 'start_datetime';
if (type_code == 'poster') {
sort_by = 'name';
}
let results = await db_events.presentation
.where('event_session_id')
.equals(slct__event_session_id)
.sortBy(sort_by);
// .sortBy('name')
if (log_lvl) {
console.log(
`lq__event_presentation_obj_li: results = `,
results
);
}
// Check if results are different than the current $events_slct.event_presentation_obj_li
if ($events_slct.event_presentation_obj_li && results) {
if (
JSON.stringify($events_slct.event_presentation_obj_li) !==
JSON.stringify(results)
) {
$events_slct.event_presentation_obj_li = { ...results };
if (log_lvl) {
console.log(
`$events_slct.event_presentation_obj_li has changed for event_session_id: ${slct__event_session_id}`,
$events_slct.event_presentation_obj_li
);
}
} else {
if (log_lvl) {
console.log(
`$events_slct.event_presentation_obj_li has not changed for event_session_id: ${slct__event_session_id}`
);
}
}
}
return results;
})
);
// FIX! This id list needs to be updated. It is currently commented out in the menu_session_list.svelte file.
// let lq_get__event_presentation_obj_li = liveQuery(
// () => db_events.presentation
// .bulkGet($events_slct.id_li__event_presentation)
// );
let lq__event_presenter_obj_li = $derived(
liveQuery(async () => {
if (log_lvl) {
console.log(
`lq__event_presenter_obj_li: slct__event_session_id = ${slct__event_session_id}`
);
}
let results = await db_events.presenter
.where('event_session_id')
.equals(slct__event_session_id)
.sortBy('full_name');
if (log_lvl) {
console.log(`lq__event_presenter_obj_li: results = `, results);
}
// Check if results are different than the current $events_slct.event_presenter_obj_li
if ($events_slct.event_presenter_obj_li && results) {
if (
JSON.stringify($events_slct.event_presenter_obj_li) !==
JSON.stringify(results)
) {
$events_slct.event_presenter_obj_li = { ...results };
if (log_lvl) {
console.log(
`$events_slct.event_presenter_obj_li has changed for event_session_id: ${slct__event_session_id}`,
$events_slct.event_presenter_obj_li
);
}
} else {
if (log_lvl) {
console.log(
`$events_slct.event_presenter_obj_li has not changed for event_session_id: ${slct__event_session_id}`
);
}
}
}
return results;
})
);
// let show_modal_upload_files: boolean = false;
// let link_to_type: null|string = null;
// let link_to_id: null|string = null;
let ae_promises: key_val = $state({});
// $events_slct.id_li__event_presenter = [];
// await tick();
// ae_promises[slct__event_session_id] = events_func.load_ae_obj_li__event_presenter({
// api_cfg: $ae_api,
// for_obj_type: 'event_session',
// for_obj_id: slct__event_session_id,
// // inc_file_li: false,
// params: {qry__enabled: 'enabled', qry__limit: 550},
// try_cache: true,
// log_lvl: 1,
// })
// .then(async function (load_results) {
// console.log(`load_results = `, load_results);
// // let event_presenter_id_li = [];
// // let tmp_li = []; // This is to prevent the array from constantly updating and triggering the liveQuery.
// // for (let i = 0; i < load_results.length; i++) {
// // let event_presenter_obj = load_results[i];
// // let event_presenter_id = event_presenter_obj.event_presenter_id;
// // tmp_li.push(event_presenter_id);
// // }
// // event_presenter_id_li = tmp_li;
// // console.log(`event_presenter_id_li:`, event_presenter_id_li);
// // $events_slct.id_li__event_presenter = event_presenter_id_li;
// return load_results;
// });
</script>
<div
class="
event_launcher_session_view
grow h-full w-full
space-y-1
relative
"
>
<!-- <slot name="event_session_message">event session message</slot> -->
{#if $events_sess.launcher.loading__session_id_status}
<span class="absolute top-0 right-0 text-sm text-center text-gray-400">
<span class="fas fa-spinner fa-spin"></span>
Loading session information...
</span>
<!-- {:else}
<span class="absolute top-0 right-0 text-sm text-center text-gray-400">
Session loaded?
</span> -->
{/if}
{#if $lq__event_session_obj && $lq__event_session_obj.event_session_id}
<header
class="event_session_about text-center border-b-2 border-gray-400 flex flex-row flex-wrap gap-2 items-center justify-between"
>
<h3
class:hidden={!$lq__event_session_obj?.start_datetime ||
$events_loc.launcher.hide__session_datetimes}
class="shrink event_session_datetimes"
>
<button
type="button"
onclick={() => {
if (
$events_loc.launcher.time_format == 'time_12_short'
) {
// $events_loc.launcher.datetime_format = 'datetime_long';
$events_loc.launcher.time_format = 'time_short';
$events_loc.launcher.time_hours = 24;
} else {
$events_loc.launcher.time_format = 'time_12_short';
// $events_loc.launcher.datetime_format = 'datetime_12_long';
$events_loc.launcher.time_hours = 12;
}
}}
>
<strong
>{ae_util.iso_datetime_formatter(
$lq__event_session_obj.start_datetime,
'week_long'
)}</strong
>
<span class="font-normal">
{ae_util.iso_datetime_formatter(
$lq__event_session_obj.start_datetime,
'date_long_month_day'
)}
</span>
<strong
>{ae_util.iso_datetime_formatter(
$lq__event_session_obj.start_datetime,
$events_loc.launcher.time_format
)}</strong
>
<span class="font-normal">
{ae_util.iso_datetime_formatter(
$lq__event_session_obj.end_datetime,
$events_loc.launcher.time_format
)}
</span>
</button>
</h3>
<span
class:justify-between={$events_loc.launcher
.hide__session_datetimes}
class:justify-end={!$events_loc.launcher
.hide__session_datetimes}
class="grow flex flex-row gap-2 items-center"
>
<h2
class="shrink text-xl"
title={`Name: ${$lq__event_session_obj.name}\nType: ${$lq__event_session_obj.type_code} \nCode: ${$lq__event_session_obj.code} \nID: ${$lq__event_session_obj.event_session_id} \nStart Date/Time: ${ae_util.iso_datetime_formatter($lq__event_session_obj.start_datetime, 'week_long')} ${ae_util.iso_datetime_formatter($lq__event_session_obj.start_datetime, $events_loc.launcher.time_format)} \nEnd Date/Time: ${ae_util.iso_datetime_formatter($lq__event_session_obj.end_datetime, $events_loc.launcher.time_format)}`}
>
{$lq__event_session_obj?.name}
</h2>
{#if $lq__event_session_obj?.code}
<span
class="text-base text-gray-500 font-normal p-1"
title="Session code {$lq__event_session_obj.code}"
>
<span class="fas fa-barcode"></span>
{$lq__event_session_obj?.code}
</span>
{/if}
</span>
</header>
<!-- <section class="event_session_description text-xs" class:d_none="{hide_description}">
{@html $lq__event_session_obj.description}
</section> -->
{#if $lq__event_session_obj?.file_count_all === 0}
<p class="text-2xl text-center text-red-500 font-bold">
<span class="fas fa-exclamation-triangle"></span>
Warning
<span class="fas fa-exclamation-triangle"></span>
<br />
No files available show for this session.
</p>
{/if}
{#if $lq__event_file_obj_li && $lq__event_file_obj_li.length}
<section class="event_session_file_list">
<div>
<div class="text-xs text-surface-600-400">
<strong>
<span class="fas fa-file-archive"></span>
Session Files:
<span
class:hidden={!$ae_loc.trusted_access ||
!$ae_loc.edit_mode}
>
({$lq__event_file_obj_li?.length}&times;)
</span>
</strong>
</div>
<!-- {#if $ae_loc.trusted_access || $events_loc.launcher.trusted_access}
<button type="button" on:click={async () => {
show_modal_upload_files = true;
link_to_type = 'event_session';
link_to_id = $lq__event_session_obj.event_session_id;
}}
type="button" class="ae_btn btn_outline_warning btn_xs" title="Upload updated or additional files"
>
<span class="fas fa-upload"></span> Upload Session File(s)
</button>
{/if} -->
</div>
<ul class="space-y-1">
{#each $lq__event_file_obj_li as event_file_obj, index}
<li
class="flex flex-row flex-wrap gap-1 items-center justify-center"
class:hidden={!$events_loc.launcher
.show_content__hidden_files &&
event_file_obj.hide}
>
<Event_launcher_file_cont
event_file_id={event_file_obj.event_file_id}
{event_file_obj}
hide_created_on={true}
show_bak_download={$ae_loc.trusted_access &&
$ae_loc.edit_mode}
session_type={event_file_obj?.event_session_type_code ??
'oral'}
open_method={event_file_obj?.event_session_type_code ==
'poster'
? 'modal'
: null}
modal_title={$lq__event_session_obj?.name}
bind:modal__title={
$events_sess.launcher.modal__title
}
bind:modal__open_event_file_id={
$events_sess.launcher
.modal__open_event_file_id
}
bind:modal__event_file_obj={
$events_sess.launcher.modal__event_file_obj
}
/>
<!-- <Launcher_file_cont {event_file_obj} hide_created_on={false} show_bak_download={($ae_loc.trusted_access || $events_loc.launcher.trusted_access)} open_file_as={$lq__event_session_obj.type_code} poster_title={$lq__event_session_obj.title} /> -->
<!-- <a
href="{$ae_api.base_url}/event/file/{event_file_obj.event_file_id}/download?filename={event_file_obj.filename}&key={$ae_api.account_id}"
class="btn btn-sm variant-soft-secondary m-0.5 *:hover:inline"
class:hidden={!ae_tmp.show__direct_download}
title={`Download this file:\n${event_file_obj.filename}\n[API] SHA256: ${event_file_obj.hash_sha256.slice(0, 10)}... Hosted ID: ${event_file_obj.hosted_file_id} Event File ID: ${event_file_obj.event_file_id}`}
>
<span class="fas fa-download mx-1"></span>
<div class="hidden">
Download
</div>
</a> -->
</li>
{/each}
</ul>
</section>
{/if}
<!-- <hr class="w-full border border-gray-200" /> -->
<section class="event_presentation_list">
<!-- {$lq__event_session_obj?.event_presentation_li?.length ?? 'loading...?'} -->
{#if $lq__event_presentation_obj_li}
<div class="text-xs text-surface-600-400">
<strong>
{#if type_code == 'poster'}
<span class="fas fa-image"></span>
Posters:
{:else}
<span class="fas fa-tv"></span>
Presentations:
{/if}
{#if $ae_loc.administrator_access && $ae_loc.edit_mode}
({$lq__event_presentation_obj_li?.length}&times;)
{/if}
</strong>
</div>
<!-- Maybe set max with? max-w-(--breakpoint-md) -->
<ul class="event_presentation_list max-w-full space-y-2">
{#each $lq__event_presentation_obj_li as event_presentation_obj}
<li
class="border-b-2 border-gray-300 my-1 py-1 text-center md:text-left"
>
<!-- The presentation information -->
<div
class="event_presentation_datetime_name flex flex-row justify-evenly gap-4"
>
<!-- <div class="event_presentation_datetime_name"> -->
{#if event_presentation_obj?.start_datetime}
<span class="event_presentation_datetime"
><strong
>{ae_util.iso_datetime_formatter(
event_presentation_obj?.start_datetime,
'time_12_short_no_leading'
)}</strong
></span
>
{/if}
<span class="event_presentation_name grow"
>{event_presentation_obj?.name}</span
>
<!-- </div> -->
<!-- Yes, this is kind of inefficient, but it works for now. -->
{#if $lq__event_presenter_obj_li && type_code == 'poster'}
{#each $lq__event_presenter_obj_li as event_presenter_obj, index}
{#if event_presenter_obj.event_presentation_id == event_presentation_obj.event_presentation_id}
<span
class="event_presentation_single_presenter italic text-sm text-gray-500"
>
{#if $lq__event_presenter_obj_li[index]?.given_name && $lq__event_presenter_obj_li[index]?.given_name != 'Group'}
<span class="fas fa-user"
></span>
{$lq__event_presenter_obj_li[
index
]?.full_name}
{:else if $lq__event_presenter_obj_li[index]?.given_name == 'Group'}
<span class="fas fa-users"
></span>
{$lq__event_presenter_obj_li[
index
]?.affiliations}
{:else}
--not set--
{/if}
</span>
{/if}
{/each}
{/if}
</div>
<!-- Presentation-level files -->
<Launcher_presentation_view
lq__event_presentation_obj={event_presentation_obj}
/>
<!-- The presenter list -->
{#if $lq__event_presenter_obj_li && $lq__event_presenter_obj_li.length}
<ul class="event_presentation_presenter_list">
{#each $lq__event_presenter_obj_li as event_presenter_obj, index}
{#if event_presenter_obj.event_presentation_id == event_presentation_obj.event_presentation_id}
<li
class="
border border-transparent
rounded-lg
hover:bg-surface-100-900
hover:border-surface-400-600
p-1
transition-all
"
>
{#if type_code == 'poster'}
<Launcher_presenter_view_posters
lq__event_presenter_obj={event_presenter_obj}
hide_name={true}
/>
{:else}
<Launcher_presenter_view
lq__event_presenter_obj={event_presenter_obj}
/>
{/if}
<!-- {index} -->
</li>
{/if}
{/each}
</ul>
{:else}
<span class="event_launcher_no_presenters"
>No presenters to display</span
>
{/if}
</li>
{/each}
</ul>
{:else}
<p>No presentations available to display.</p>
{/if}
</section>
{:else}
<span class="fas fa-spinner fa-spin"></span>
No session selected
{/if}
</div>
<style>
</style>